/** * Get the data section size of a GRF. * @param f GRF. * @return Size of the data section or SIZE_MAX if the file has no separate data section. */ size_t GRFGetSizeOfDataSection(FILE *f) { extern const byte _grf_cont_v2_sig[]; static const uint header_len = 14; byte data[header_len]; if (fread(data, 1, header_len, f) == header_len) { if (data[0] == 0 && data[1] == 0 && MemCmpT(data + 2, _grf_cont_v2_sig, 8) == 0) { /* Valid container version 2, get data section size. */ size_t offset = (data[13] << 24) | (data[12] << 16) | (data[11] << 8) | data[10]; return header_len + offset; } } return SIZE_MAX; }
/** * Read the header of a standard MIDI file. * The function will consume 14 bytes from the current file pointer position. * @param[in] file open file to read from (should be in binary mode) * @param[out] header filled with data read * @return true if a header in correct format could be read from the file */ bool MidiFile::ReadSMFHeader(FILE *file, SMFHeader &header) { /* Try to read header, fixed size */ byte buffer[14]; if (fread(buffer, sizeof(buffer), 1, file) != 1) { return false; } /* Check magic, 'MThd' followed by 4 byte length indicator (always = 6 in SMF) */ const byte magic[] = { 'M', 'T', 'h', 'd', 0x00, 0x00, 0x00, 0x06 }; if (MemCmpT(buffer, magic, sizeof(magic)) != 0) { return false; } /* Read the parameters of the file */ header.format = (buffer[8] << 8) | buffer[9]; header.tracks = (buffer[10] << 8) | buffer[11]; header.tickdiv = (buffer[12] << 8) | buffer[13]; return true; }
/** * Get the data section size of a GRF. * @param f GRF. * @return Size of the data section or SIZE_MAX if the file has no separate data section. */ size_t GRFGetSizeOfDataSection(FILE *f) { extern const byte _grf_cont_v2_sig[]; static const uint header_len = 14; byte data[header_len]; if (fread(data, 1, header_len, f) == header_len) { if (data[0] == 0 && data[1] == 0 && MemCmpT(data + 2, _grf_cont_v2_sig, 8) == 0) { /* Valid container version 2, get data section size. */ size_t offset = ((size_t)data[13] << 24) | ((size_t)data[12] << 16) | ((size_t)data[11] << 8) | (size_t)data[10]; if (offset >= 1 * 1024 * 1024 * 1024) { DEBUG(grf, 0, "Unexpectedly large offset for NewGRF"); /* Having more than 1 GiB of data is very implausible. Mostly because then * all pools in OpenTTD are flooded already. Or it's just Action C all over. * In any case, the offsets to graphics will likely not work either. */ return SIZE_MAX; } return header_len + offset; } } return SIZE_MAX; }
/** * Check the validity of some of the caches. * Especially in the sense of desyncs between * the cached value and what the value would * be when calculated from the 'base' data. */ static void CheckCaches() { /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ if (_debug_desync_level <= 1) return; /* Check the town caches. */ SmallVector<TownCache, 4> old_town_caches; Town *t; FOR_ALL_TOWNS(t) { MemCpyT(old_town_caches.Append(), &t->cache); } extern void RebuildTownCaches(); RebuildTownCaches(); RebuildSubsidisedSourceAndDestinationCache(); uint i = 0; FOR_ALL_TOWNS(t) { if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) { DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index); } i++; } /* Check company infrastructure cache. */ SmallVector<CompanyInfrastructure, 4> old_infrastructure; Company *c; FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); extern void AfterLoadCompanyStats(); AfterLoadCompanyStats(); i = 0; FOR_ALL_COMPANIES(c) { if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index); } i++; } /* Strict checking of the road stop cache entries */ const RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { if (IsStandardRoadStopTile(rs->xy)) continue; assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } Vehicle *v; FOR_ALL_VEHICLES(v) { extern void FillNewGRFVehicleCache(const Vehicle *v); if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; uint length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) length++; NewGRFCache *grf_cache = CallocT<NewGRFCache>(length); VehicleCache *veh_cache = CallocT<VehicleCache>(length); GroundVehicleCache *gro_cache = CallocT<GroundVehicleCache>(length); TrainCache *tra_cache = CallocT<TrainCache>(length); length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); grf_cache[length] = u->grf_cache; veh_cache[length] = u->vcache; switch (u->type) { case VEH_TRAIN: gro_cache[length] = Train::From(u)->gcache; tra_cache[length] = Train::From(u)->tcache; break; case VEH_ROAD: gro_cache[length] = RoadVehicle::From(u)->gcache; break; default: break; } length++; } switch (v->type) { case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; case VEH_SHIP: Ship::From(v)->UpdateCache(); break; default: break; } length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) { DEBUG(desync, 2, "vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } switch (u->type) { case VEH_TRAIN: if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { DEBUG(desync, 2, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; case VEH_ROAD: if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; default: break; } length++; } free(grf_cache); free(veh_cache); free(gro_cache); free(tra_cache); } /* Check whether the caches are still valid */ FOR_ALL_VEHICLES(v) { byte buff[sizeof(VehicleCargoList)]; memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); v->cargo.InvalidateCache(); assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { byte buff[sizeof(StationCargoList)]; memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); st->goods[c].cargo.InvalidateCache(); assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); } } }