void Serialize<Deserializer>(Deserializer& ar, Animation& data, unsigned int version) { const ChunkHeader knspHeader = ReadChunkHeader(ar); if (knspHeader.id != MakeId('K','N','S','P')) { ar.Rewind(chunkHeaderSize); return; } int major; ar(major, 1); int minor; ar(minor, 1); data.version = major * 0x100 + minor; ar.Skip(knspHeader.size - 2); for (;!ar.IsEof();) { const ChunkHeader header = ReadChunkHeader(ar); switch(header.id) { case MakeId('P','I','C','T'): data.textureName.resize(header.size); ar(&data.textureName[0], header.size); break; case MakeId('A','N','I','M'): { size_t count; ar(count, 4); data.sheetList.resize(count); for (auto i : data.sheetList) { Serialize(ar, i, version); } break; } default: ar.Skip(header.size); break; } } }
// 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 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; }
bool LoadModel_Studio(FileSpecifier& Spec, Model3D& Model) { ModelPtr = &Model; Model.Clear(); if (DBOut) { // Name buffer const int BufferSize = 256; char Buffer[BufferSize]; Spec.GetName(Buffer); fprintf(DBOut,"Loading 3D Studio Max model file %s\n",Buffer); } OpenedFile OFile; if (!Spec.Open(OFile)) { if (DBOut) fprintf(DBOut,"ERROR opening the file\n"); return false; } ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; if (ChunkHeader.ID != MASTER) { if (DBOut) fprintf(DBOut,"ERROR: not a 3DS Max model file\n"); return false; } if (!ReadContainer(OFile,ChunkHeader,ReadMaster)) return false; return (!Model.Positions.empty() && !Model.VertIndices.empty()); }
// 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; }
HRESULT CRiffParser::MoveToNextChunk() { // chunk offset is always bigger than container offset, // and both are always non-negative. assert(m_llCurrentChunkOffset > m_llContainerOffset); assert(m_llCurrentChunkOffset >= 0); assert(m_llContainerOffset >= 0); HRESULT hr = S_OK; LONGLONG maxChunkSize = 0; // Update current chunk offset to the start of the next chunk m_llCurrentChunkOffset = m_llCurrentChunkOffset + ChunkActualSize(); // Are we at the end? if ((m_llCurrentChunkOffset - m_llContainerOffset) >= m_dwContainerSize) { return E_FAIL; } // Current chunk offset + size of current chunk if (MAXLONGLONG - m_llCurrentChunkOffset <= ChunkActualSize()) { return E_INVALIDARG; } // Seek to the start of the chunk. hr = m_pStream->SetCurrentPosition(m_llCurrentChunkOffset); // Read the header. if (SUCCEEDED(hr)) { hr = ReadChunkHeader(); } // This chunk cannot be any larger than (container size - (chunk offset - container offset) ) if (SUCCEEDED(hr)) { maxChunkSize = (LONGLONG)m_dwContainerSize - (m_llCurrentChunkOffset - m_llContainerOffset); if (maxChunkSize < ChunkActualSize()) { hr = E_INVALIDARG; } } if (SUCCEEDED(hr)) { m_dwBytesRemaining = m_chunk.DataSize(); } return hr; }
// 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; }
void Serialize<Deserializer>(Deserializer& ar, Sheet& data, unsigned int version) { const ChunkHeader chunk = ReadChunkHeader(ar); if (chunk.id != MakeId('S','H','E','E')) { ar.Rewind(chunkHeaderSize); return; } { size_t size; ar(size, 4); data.chipList.resize(size); for (auto i : data.chipList) { Serialize(ar, i, version); } } { size_t size; ar(size, 4); data.rectList.resize(size); for (auto i : data.rectList) { Serialize(ar, i, version); } } }
bool LoadModel_Studio(FileSpecifier& Spec, Model3D& Model) { ModelPtr = &Model; Model.Clear(); Path = Spec.GetPath(); logNote1("Loading 3D Studio Max model file %s",Path); OpenedFile OFile; if (!Spec.Open(OFile)) { logError1("ERROR opening %s",Path); return false; } ChunkHeaderData ChunkHeader; if (!ReadChunkHeader(OFile,ChunkHeader)) return false; if (ChunkHeader.ID != MASTER) { logError1("ERROR: not a 3DS Max model file: %s",Path); return false; } if (!ReadContainer(OFile,ChunkHeader,ReadMaster)) return false; if (Model.Positions.empty()) { logError1("ERROR: no vertices found in %s",Path); return false; } if (Model.VertIndices.empty()) { logError1("ERROR: no faces found in %s",Path); return false; } return true; }
void CLevel::LoadNewFormat(FILE* aFile) { int version = ReadInt( aFile ); while ( !feof( aFile ) ) { TChunk blockType; int blockLength; try { ReadChunkHeader( blockType, blockLength, aFile); } catch ( CEOFException& e ) { LOG1("%s\n", e.what() ); return; // file end reached } switch ( blockType ) { case KLevelData: { iWidth = ReadInt( aFile ); iHeight = ReadInt( aFile ); iLevelData = new TBlock[iHeight*iWidth]; for (int a=0;a<iWidth * iHeight;a++) { iLevelData[a].iType = (TBlockType)(ReadInt( aFile)); iLevelData[a].iNumber = ReadInt( aFile ); iLevelData[a].iHeight = ReadInt( aFile ); } break; } case KPlayerStartPoints: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int x = ReadInt( aFile ); int y = ReadInt( aFile ); iPlStart.push_back( CCoord<int>( x,y ) ); } break; } case KSpotLights: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { AddSpotLight( aFile ); } break; } case KSteams: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { AddSteam( aFile ); } break; } case KGeneralLevelInfo: { // FIXME: endianness problem int ret = fread(&iGeneralLevelInfo,sizeof(iGeneralLevelInfo),1,aFile); if ( ret != 1 ) throw CFailureException("CLevel::LoadNewFormat: KGeneralLevelInfo chunk read failed!"); break; } case KRandomWeaponCrateAmountNormal: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int crateAmount = ReadInt( aFile ); iRandomCratesNormal.push_back( TRandomCrateInfo(0,a,crateAmount) ); }; break; } case KRandomBulletCrateAmountNormal: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int crateAmount = ReadInt( aFile ); iRandomCratesNormal.push_back( TRandomCrateInfo(1,a,crateAmount) ); }; break; } case KRandomOtherCrateAmountNormal: { int amount = ReadInt( aFile ); ASSERT( amount == 1 ); int crateAmount = ReadInt( aFile ); iRandomCratesNormal.push_back( TRandomCrateInfo(2,0,crateAmount) ); break; } case KRandomWeaponCrateAmountDM: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int crateAmount = ReadInt( aFile ); iRandomCratesDM.push_back( TRandomCrateInfo(0,a,crateAmount) ); }; break; } case KRandomBulletCrateAmountDM: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int crateAmount = ReadInt( aFile ); iRandomCratesDM.push_back( TRandomCrateInfo(1,a,crateAmount) ); }; break; } case KRandomOtherCrateAmountDM: { int amount = ReadInt( aFile ); ASSERT( amount == 1 ); int crateAmount = ReadInt( aFile ); iRandomCratesDM.push_back( TRandomCrateInfo(2,0,crateAmount) ); break; } case KPlacedCratesNormal: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { TCrateInfo tmpCrate; // FIXME: endianness problem if (fread(&tmpCrate, sizeof(TCrateInfo), 1, aFile)!=1) throw CFailureException("CLevel::LoadNewFormat: File loading error 1"); iPlacedCratesNormal.push_back( tmpCrate ); } break; } case KPlacedCratesDM: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { TCrateInfo tmpCrate; // FIXME: endianness problem if (fread(&tmpCrate, sizeof(TCrateInfo), 1, aFile)!=1) throw CFailureException("CLevel::LoadNewFormat: File loading error 2"); iPlacedCratesDM.push_back( tmpCrate ); } break; } case KOutblockData: { iOutBlock.iNumber = ReadInt( aFile ); iOutBlock.iType = (TBlockType)(ReadInt( aFile )); break; } case KPlacedEnemies: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { TEnemyCoords tmpEnemy; // FIXME: endianness problem if (fread(&tmpEnemy, sizeof(TEnemyCoords), 1, aFile)!=1) throw CFailureException("CLevel::LoadNewFormat: File loading error 3"); iEnemy.push_back( tmpEnemy ); } break; } case KOutblockHeight: { iOutBlock.iHeight = ReadInt( aFile ); break; } case KRandomCratesNormal: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int t1,t2,amo; t1 = ReadInt( aFile ); t2 = ReadInt( aFile ); amo = ReadInt( aFile ); iRandomCratesNormal.push_back( TRandomCrateInfo( t1, t2, amo ) ); } break; } case KRandomCratesDM: { int amount = ReadInt( aFile ); for (int a=0;a<amount;a++) { int t1,t2,amo; t1 = ReadInt( aFile ); t2 = ReadInt( aFile ); amo = ReadInt( aFile ); iRandomCratesDM.push_back( TRandomCrateInfo( t1, t2, amo ) ); } break; } case KUnknown: fseek( aFile, blockLength, SEEK_CUR ); // skip unknown blocktype break; default: throw CFailureException("CLevel::LoadNewFormat: Chunk detection failure!"); }; } }
HRESULT CRiffParser::ReadRiffHeader() { // Riff chunks must be WORD aligned if ((m_llContainerOffset % 2) != 0) { return E_INVALIDARG; } // Offset must be positive. if (m_llContainerOffset < 0) { return E_INVALIDARG; } // Offset + the size of header must not overflow. if (MAXLONGLONG - m_llContainerOffset <= sizeof(RIFFLIST)) { return E_INVALIDARG; } HRESULT hr = S_OK; RIFFLIST header = { 0 }; ULONG cbRead = 0; // Seek to the start of the container. hr = m_pStream->SetCurrentPosition(m_llContainerOffset); // Read the header. if (SUCCEEDED(hr)) { hr = m_pStream->Read((BYTE*)&header, sizeof(header), &cbRead); } // Make sure we read the number of bytes we expected. if (SUCCEEDED(hr)) { if (cbRead != sizeof(header)) { hr = E_INVALIDARG; } } // Make sure the header ID matches what the caller expected. if (SUCCEEDED(hr)) { if (header.fcc != m_fccID) { hr = E_INVALIDARG; } } if (SUCCEEDED(hr)) { // The size given in the RIFF header does not include the 8-byte header. // However, our m_llContainerOffset is the offset from the start of the // header. Therefore our container size = listed size + size of header. m_dwContainerSize = header.cb + sizeof(RIFFCHUNK); m_fccType = header.fccListType; // Start of the first chunk = start of container + size of container header m_llCurrentChunkOffset = m_llContainerOffset + sizeof(RIFFLIST); hr = ReadChunkHeader(); } return hr; }
//------------------------------------------------------------------------- CIwSoundData* CIwSoundWAV::Create(const CIwStringL& pathname, void* buffer, u_int file_size) { IW_CALLSTACK("CIwSoundWAV::Create") CIwSoundData* pData = NULL; // Object to return // Open file s3eFile* pFile = NULL; if (buffer != NULL) pFile = s3eFileOpenFromMemory(buffer, file_size); else pFile = IwFileOpenPrefixed(pathname.c_str(), "rb"); IwAssertMsg(SOUND, pFile, ("Could not load file %s", pathname.c_str())); if (!pFile) return NULL; // Read RIFF header - Gives the file size and checks that this is a WAVE // file as expected IwRIFFHeader riffHeader; if ((s3eFileRead(&riffHeader, sizeof(IwRIFFHeader), 1, pFile) != 1) || (strncmp(riffHeader.typeID, "RIFF", 4) != 0) || (strncmp(riffHeader.subTypeID, "WAVE", 4) != 0)) { IwAssertMsg(SOUND, false, ("Invalid header in %s (RIFF Header)", pathname.c_str())); s3eFileClose(pFile); return NULL; } // Read in RIFF chunks until we reach the end of the file // Read the RIFF chunk header. This tells us what type of chunk follows. IwRIFFChunkHeader chunkHeader; bool readData = false; uint32 fileSize = s3eFileGetSize(pFile); while (ReadChunkHeader(chunkHeader, *(s3eFile*)pFile)) { uint32 chunkStartPos = s3eFileTell(pFile); // Next action depends on chunk type. The order of this is important and we may fail // if an unexpected chunk type is found if (!strncmp(chunkHeader.typeID, "fmt ", 4)) { // Read WAVE info chunk if (!ReadChunkFormat(pathname, chunkHeader, pData, *(s3eFile*)pFile)) { s3eFileClose(pFile); return NULL; } } else if (!strncmp(chunkHeader.typeID, "data", 4)) { if (!ReadChunkData(pathname, chunkHeader, pData, *(s3eFile*)pFile)) { s3eFileClose(pFile); return NULL; } readData = true; } else if (!strncmp(chunkHeader.typeID, "fact", 4)) { if (!ReadChunkFact(pathname, chunkHeader, pData, *(s3eFile*)pFile)) { s3eFileClose(pFile); return NULL; } } else { // Unknown chunk type // Make a proper string from the chunk type info char typeID[5]; strncpy(typeID, chunkHeader.typeID, 4); typeID[4] = 0; // Terminate const char* g_IgnoreTypes = "LIST" //LIST is just copyright info etc. "DISP"; //DISP seems to be info about what package exported it IwAssertMsg(SOUND, strstr(g_IgnoreTypes, typeID), ("Unhandled chunk type '%s' in %s. Ignoring this data.", typeID, pathname.c_str())); } // Exit if at end of file if (chunkStartPos + chunkHeader.length >= fileSize) break; // Move to next chunk s3eFileSeek(pFile, chunkStartPos + chunkHeader.length, S3E_FILESEEK_SET); } // Check that we have read the sample data IwAssertMsg(SOUND, readData, ("No data chunk read in %s", pathname.c_str())); s3eFileClose(pFile); return pData; }