* * Loads a chunk from the old savegame * */
| 118 | * |
| 119 | */ |
| 120 | bool LoadChunk(LoadgameState &ls, void *base, const OldChunks *chunks) |
| 121 | { |
| 122 | for (const OldChunks *chunk = chunks; chunk->type != OC_END; chunk++) { |
| 123 | if (((chunk->type & OC_TTD) && _savegame_type == SGT_TTO) || |
| 124 | ((chunk->type & OC_TTO) && _savegame_type != SGT_TTO)) { |
| 125 | /* TTD(P)-only chunk, but TTO savegame || TTO-only chunk, but TTD/TTDP savegame */ |
| 126 | continue; |
| 127 | } |
| 128 | |
| 129 | uint8_t *ptr = (uint8_t*)chunk->ptr; |
| 130 | |
| 131 | for (uint i = 0; i < chunk->amount; i++) { |
| 132 | /* Handle simple types */ |
| 133 | if (GetOldChunkType(chunk->type) != 0) { |
| 134 | switch (GetOldChunkType(chunk->type)) { |
| 135 | /* Just read the byte and forget about it */ |
| 136 | case OC_NULL: ReadByte(ls); break; |
| 137 | |
| 138 | case OC_CHUNK: |
| 139 | /* Call function, with 'i' as parameter to tell which item we |
| 140 | * are going to read */ |
| 141 | if (!chunk->proc(ls, i)) return false; |
| 142 | break; |
| 143 | |
| 144 | case OC_ASSERT: |
| 145 | Debug(oldloader, 4, "Assert point: 0x{:X} / 0x{:X}", ls.total_read, reinterpret_cast<size_t>(chunk->ptr) + _bump_assert_value); |
| 146 | if (ls.total_read != reinterpret_cast<size_t>(chunk->ptr) + _bump_assert_value) throw std::exception(); |
| 147 | default: break; |
| 148 | } |
| 149 | } else { |
| 150 | uint64_t res = 0; |
| 151 | |
| 152 | /* Reading from the file: bits 16 to 23 have the FILE type */ |
| 153 | switch (GetOldChunkFileType(chunk->type)) { |
| 154 | case OC_FILE_I8: res = (int8_t)ReadByte(ls); break; |
| 155 | case OC_FILE_U8: res = ReadByte(ls); break; |
| 156 | case OC_FILE_I16: res = (int16_t)ReadUint16(ls); break; |
| 157 | case OC_FILE_U16: res = ReadUint16(ls); break; |
| 158 | case OC_FILE_I32: res = (int32_t)ReadUint32(ls); break; |
| 159 | case OC_FILE_U32: res = ReadUint32(ls); break; |
| 160 | default: NOT_REACHED(); |
| 161 | } |
| 162 | |
| 163 | /* When both pointers are nullptr, we are just skipping data */ |
| 164 | if (base == nullptr && chunk->ptr == nullptr) continue; |
| 165 | |
| 166 | /* Chunk refers to a struct member, get address in base. */ |
| 167 | if (chunk->ptr == nullptr) ptr = (uint8_t *)chunk->offset(base); |
| 168 | |
| 169 | /* Write the data */ |
| 170 | switch (GetOldChunkVarType(chunk->type)) { |
| 171 | case OC_VAR_I8: *(int8_t *)ptr = GB(res, 0, 8); break; |
| 172 | case OC_VAR_U8: *(uint8_t *)ptr = GB(res, 0, 8); break; |
| 173 | case OC_VAR_I16:*(int16_t *)ptr = GB(res, 0, 16); break; |
| 174 | case OC_VAR_U16:*(uint16_t*)ptr = GB(res, 0, 16); break; |
| 175 | case OC_VAR_I32:*(int32_t *)ptr = res; break; |
| 176 | case OC_VAR_U32:*(uint32_t*)ptr = res; break; |
| 177 | case OC_VAR_I64:*(int64_t *)ptr = res; break; |
no test coverage detected