// For reading the master chunk (ideally, whole file) static bool ReadMaster(OpenedFile& OFile, int32 ParentChunkEnd) { int32 Location = 0; OFile.GetPosition(Location); while(Location < ParentChunkEnd) { ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; switch(ChunkHeader.ID) { case EDITOR: if (!ReadContainer(OFile,ChunkHeader,ReadEditor)) return false; break; default: if (!SkipChunk(OFile,ChunkHeader)) return false; } // Where are we now? OFile.GetPosition(Location); } if (Location > ParentChunkEnd) { if (DBOut) fprintf(DBOut,"ERROR: Overran parent chunk: %ld > %ld\n",Location,ParentChunkEnd); return false; } return true; }
// For reading the face-data chunk static bool ReadFaceData(OpenedFile& OFile, int32 ParentChunkEnd) { uint8 NFBuffer[2]; uint16 NumFaces; if (!OFile.Read(2,NFBuffer)) { logError1("ERROR reading number of faces in %s",Path); return false; } uint8 *S = NFBuffer; StreamToValue(S,NumFaces); int32 DataSize = 4*sizeof(uint16)*int(NumFaces); SetChunkBufferSize(DataSize); if (!OFile.Read(DataSize,ChunkBufferBase())) { logError1("ERROR reading face-chunk contents in %s",Path); return false; } S = ChunkBufferBase(); ModelPtr->VertIndices.resize(3*NumFaces); for (int k=0; k<NumFaces; k++) { uint16 *CurrPoly = ModelPtr->VIBase() + 3*k; uint16 Flags; StreamToList(S,CurrPoly,3); StreamToValue(S,Flags); } int32 Location = 0; OFile.GetPosition(Location); while(Location < ParentChunkEnd) { ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; switch(ChunkHeader.ID) { /* case OBJECT: if (!ReadContainer(OFile,ChunkHeader,ReadObject)) return false; break; */ default: if (!SkipChunk(OFile,ChunkHeader)) return false; } // Where are we now? OFile.GetPosition(Location); } if (Location > ParentChunkEnd) { logError3("ERROR: Overran parent chunk: %d > %d in %s",Location,ParentChunkEnd,Path); return false; } return true; }
// For reading the editor-data chunk static bool ReadEditor(OpenedFile& OFile, int32 ParentChunkEnd) { int32 Location = 0; OFile.GetPosition(Location); while(Location < ParentChunkEnd) { ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; switch(ChunkHeader.ID) { case OBJECT: if (!ReadContainer(OFile,ChunkHeader,ReadObject)) return false; break; default: if (!SkipChunk(OFile,ChunkHeader)) return false; } // Where are we now? OFile.GetPosition(Location); } if (Location > ParentChunkEnd) { logError3("ERROR: Overran parent chunk: %d > %d in %s",Location,ParentChunkEnd,Path); return false; } return true; }
// For reading the object-data chunk static bool ReadObject(OpenedFile& OFile, int32 ParentChunkEnd) { // Read the name if (DBOut) fprintf(DBOut,"Object Name: "); while(true) { char c; if (!OFile.Read(1,&c)) { if (DBOut) fprintf(DBOut,"ERROR in reading name"); return false; } if (c == 0) { if (DBOut) fprintf(DBOut,"\n"); break; } else { if (DBOut) fprintf(DBOut,"%c",c); } } int32 Location = 0; OFile.GetPosition(Location); while(Location < ParentChunkEnd) { ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; switch(ChunkHeader.ID) { case TRIMESH: if (!ReadContainer(OFile,ChunkHeader,ReadTrimesh)) return false; break; default: if (!SkipChunk(OFile,ChunkHeader)) return false; } // Where are we now? OFile.GetPosition(Location); } if (Location > ParentChunkEnd) { if (DBOut) fprintf(DBOut,"ERROR: Overran parent chunk: %ld > %ld\n",Location,ParentChunkEnd); return false; } return true; }
// For reading the triangle-mesh-data chunk static bool ReadTrimesh(OpenedFile& OFile, int32 ParentChunkEnd) { int32 Location = 0; OFile.GetPosition(Location); assert(ModelPtr); while(Location < ParentChunkEnd) { ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; switch(ChunkHeader.ID) { case VERTICES: if (!LoadChunk(OFile,ChunkHeader)) return false; LoadVertices(); break; case TXTR_COORDS: if (!LoadChunk(OFile,ChunkHeader)) return false; LoadTextureCoordinates(); break; case FACE_DATA: if (!ReadContainer(OFile,ChunkHeader,ReadFaceData)) return false; break; default: if (!SkipChunk(OFile,ChunkHeader)) return false; } // Where are we now? OFile.GetPosition(Location); } if (Location > ParentChunkEnd) { if (DBOut) fprintf(DBOut,"ERROR: Overran parent chunk: %ld > %ld\n",Location,ParentChunkEnd); return false; } return true; }
// For reading the object-data chunk static bool ReadObject(OpenedFile& OFile, int32 ParentChunkEnd) { // Read the name char c; do { if (!OFile.Read(1,&c)) { logError1("ERROR when reading name in %s",Path); return false; } } while(c != 0); int32 Location = 0; OFile.GetPosition(Location); while(Location < ParentChunkEnd) { ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; switch(ChunkHeader.ID) { case TRIMESH: if (!ReadContainer(OFile,ChunkHeader,ReadTrimesh)) return false; break; default: if (!SkipChunk(OFile,ChunkHeader)) return false; } // Where are we now? OFile.GetPosition(Location); } if (Location > ParentChunkEnd) { logError3("ERROR: Overran parent chunk: %d > %d in %s",Location,ParentChunkEnd,Path); return false; } return true; }
bool SkipChunk(OpenedFile& OFile, ChunkHeaderData& ChunkHeader) { logTrace2("Skipping chunk 0x%04hx size %u",ChunkHeader.ID,ChunkHeader.Size); int32 DataSize = ChunkHeader.Size - SIZEOF_ChunkHeaderData; int32 Location = 0; OFile.GetPosition(Location); if (!OFile.SetPosition(Location + DataSize)) return false; return true; }
static void import_m1_physics_data() { OpenedFile PhysicsFile; if (!PhysicsFileSpec.Open(PhysicsFile)) { return; } int32 position = 0; int32 length; PhysicsFile.GetLength(length); while (position < length) { std::vector<uint8> header(12); PhysicsFile.Read(header.size(), &header[0]); AIStreamBE header_stream(&header[0], header.size()); uint32 tag; uint16 count; uint16 size; header_stream >> tag; header_stream.ignore(4); // unused header_stream >> count; header_stream >> size; std::vector<uint8> data(count * size); PhysicsFile.Read(data.size(), &data[0]); switch (tag) { case M1_MONSTER_PHYSICS_TAG: unpack_m1_monster_definition(&data[0], count); break; case M1_EFFECTS_PHYSICS_TAG: unpack_m1_effect_definition(&data[0], count); break; case M1_PROJECTILE_PHYSICS_TAG: unpack_m1_projectile_definition(&data[0], count); break; case M1_PHYSICS_PHYSICS_TAG: unpack_m1_physics_constants(&data[0], count); break; case M1_WEAPONS_PHYSICS_TAG: unpack_m1_weapon_definition(&data[0], count); break; } PhysicsFile.GetPosition(position); } }
// Generic container-chunk reader bool ReadContainer(OpenedFile& OFile, ChunkHeaderData& ChunkHeader, bool (*ContainerCallback)(OpenedFile&,int32)) { logTrace2("Entering chunk 0x%04hx size %u",ChunkHeader.ID,ChunkHeader.Size); int32 ChunkEnd = 0; OFile.GetPosition(ChunkEnd); ChunkEnd += ChunkHeader.Size - SIZEOF_ChunkHeaderData; if (!ContainerCallback(OFile,ChunkEnd)) return false; logTrace2("Exiting chunk 0x%04hx size %u",ChunkHeader.ID,ChunkHeader.Size); return true; }
/* This is gross, (Alain wrote it, not me!) but I don't have time to clean it up */ static bool vblFSRead( OpenedFile& File, int32 *count, void *dest, bool& HitEOF) { int32 fsread_count; bool status = true; assert(replay.fsread_buffer); // LP: way for testing whether hitting end-of-file; // doing that by testing for whether a read was complete. HitEOF = false; if (replay.bytes_in_cache < *count) { assert(replay.bytes_in_cache + *count < int(DISK_CACHE_SIZE)); if (replay.bytes_in_cache) { memcpy(replay.fsread_buffer, replay.location_in_cache, replay.bytes_in_cache); } replay.location_in_cache = replay.fsread_buffer; fsread_count= DISK_CACHE_SIZE - replay.bytes_in_cache; int32 PrevPos; File.GetPosition(PrevPos); int32 replay_left= replay.header.length - PrevPos; if(replay_left < fsread_count) fsread_count= replay_left; if(fsread_count > 0) { assert(fsread_count > 0); // LP: wrapped the routines with some for finding out the file positions; // this finds out how much is read indirectly status = File.Read(fsread_count,replay.fsread_buffer+replay.bytes_in_cache); int32 CurrPos; File.GetPosition(CurrPos); int32 new_fsread_count = CurrPos - PrevPos; int32 FileLen; File.GetLength(FileLen); HitEOF = (new_fsread_count < fsread_count) && (CurrPos == FileLen); fsread_count = new_fsread_count; if(status) replay.bytes_in_cache += fsread_count; } } // If we're still low, then we've consumed the disk cache if(replay.bytes_in_cache < *count) { HitEOF = true; } // Ignore EOF if we still have cache if (HitEOF && replay.bytes_in_cache < *count) { *count= replay.bytes_in_cache; } else { status = true; HitEOF = false; } memcpy(dest, replay.location_in_cache, *count); replay.bytes_in_cache -= *count; replay.location_in_cache += *count; return status; }