// Add(string) // [len] [value...] void trpgMemWriteBuffer::Add(const char *val) { int32 len = (val ? strlen(val) : 0),vlen = len; if (ness != cpuNess) vlen = trpg_byteswap_int(vlen); append(sizeof(int32),(const char *)&vlen); append(len,val); }
// Basic get functions bool trpgReadBuffer::Get(int32 &ret) { int32 val; if (!GetData((char *)&val,sizeof(int32))) return false; if (ness != cpuNess) ret = trpg_byteswap_int(val); else ret = val; return true; }
/* End() Finished defining an object. Write the length out where appropriate. */ void trpgMemWriteBuffer::End() { if (lengths.size() == 0) // Note: say something clever here return; int id = lengths.size()-1; int32 len = curLen - lengths[id]; int32 rlen = len-sizeof(int32); if (ness != cpuNess) rlen = trpg_byteswap_int(rlen); set(curLen - len,sizeof(int32),(const char *)&rlen); lengths.resize(id); }
/* Read a section of data from the given file and dump it into the given memory. Sanity check the length against the size of the memory passed into dataSize. */ bool trpgrAppFile::Read(char *data,int32 baseOffset,int32 objOffset,int32 dataSize) { if (!valid) return false; // Seek to the right place int result; if ((result = fseek(fp,baseOffset,SEEK_SET))) { valid = false; return false; } // Read the total object length int32 len; if (fread(&len,sizeof(int32),1,fp) != 1) { valid = false; return false; } // Byteswap if necessary if (ness != cpuNess) len = trpg_byteswap_int(len); if (len < 0) { valid = false; return false; } // It's all right to read less than the whole data block if (objOffset+dataSize > len) return false; // Skip to the object offset if (fseek(fp,objOffset,SEEK_CUR)) { valid = false; return false; } // Read the raw data // Note: What about byte swapping? if (fread(data,sizeof(char),dataSize,fp) != (uint32)dataSize) { valid = false; return false; } return true; }
// Read a section of data from the given file // and dump it into the given buffer bool trpgrAppFile::Read(trpgMemReadBuffer *buf,int32 offset) { if (!valid) return false; // Seek to the right location if (fseek(fp,offset,SEEK_SET)) return false; // Read a length int32 len; if (fread(&len,sizeof(int32),1,fp) != 1) { valid = false; return false; } // Byteswap if necessary if (ness != cpuNess) len = trpg_byteswap_int(len); if (len < 0) { valid = false; return false; } buf->SetLength(len); char *data = buf->GetDataPtr(); if (!data) { valid = false; return false; } if (fread(data,sizeof(char),len,fp) != (uint32)len) { valid = false; return false; } return true; }
// Open File // Open the given file and look for the file specific info bool trpgr_Archive::OpenFile(const char *name) { char file[1025]; sprintf(file,"%s" PATHSEPERATOR "%s",dir,name); CloseFile(); if (!(fp = osgDB::fopen(file,"rb"))) return false; // Look for a magic # and endianness int32 magic; if (fread(&magic,sizeof(int32),1,fp) != 1) return false; headerRead = false; // Figure out the endianness from the magic number trpgEndian cpuNess = trpg_cpu_byte_order(); if (magic == GetMagicNumber()) { ness = cpuNess; return true; } if (trpg_byteswap_int(magic) == GetMagicNumber()) { if (cpuNess == LittleEndian) ness = BigEndian; else ness = LittleEndian; return true; } if (magic != GetMagicNumber()) return false; // Not one of our files return false; }
// Read Header // Run through the rest of the header information bool trpgr_Archive::ReadHeader(bool readAllBlocks) { int ret; if (!fp || headerRead) return false; headerRead = true; // Next int64 should be the header size trpgEndian cpuNess = trpg_cpu_byte_order(); int32 headerSize; if (fread(&headerSize,sizeof(int32),1,fp) != 1) return false; if (ness != cpuNess) headerSize = trpg_byteswap_int(headerSize); int headLen = headerSize; if (headLen < 0) return false; // Read in the header whole trpgMemReadBuffer buf(ness); buf.SetLength(headLen); char *data = buf.GetDataPtr(); if ((ret = GetHeaderData(data,headLen,fp)) != headLen) return false; // Set up a parser // Catch the tables we need for the archive trpgMatTable1_0 oldMatTable; trpgTexTable1_0 oldTexTable; trpgr_Parser parser; parser.AddCallback(TRPGHEADER,&header); parser.AddCallback(TRPGMATTABLE,&materialTable); // Went back to oldest style for 2.0 parser.AddCallback(TRPGMATTABLE2,&oldMatTable); // Added 11-14-98 (1.0 material table) parser.AddCallback(TRPGTEXTABLE,&oldTexTable); parser.AddCallback(TRPGTEXTABLE2,&texTable); // Added for 2.0 parser.AddCallback(TRPGMODELTABLE,&modelTable); parser.AddCallback(TRPGLIGHTTABLE,&lightTable); // Added for 2.0 parser.AddCallback(TRPGRANGETABLE,&rangeTable); // Added for 2.0 parser.AddCallback(TRPG_TEXT_STYLE_TABLE,&textStyleTable); // Added for 2.1 parser.AddCallback(TRPG_SUPPORT_STYLE_TABLE,&supportStyleTable); parser.AddCallback(TRPG_LABEL_PROPERTY_TABLE,&labelPropertyTable); // Don't read the tile table for v1.0 archives // It's only really used for 2.0 archives parser.AddCallback(TRPGTILETABLE2,&tileTable); // Parse the buffer if (!parser.Parse(buf)) return false; if(header.GetIsMaster()) { // bool firstBlock = true; //if the master has textures, we want to use them instead of the tables in the //block archives // int numTiles = 0; //tileTable. int totalrows,totalcols; trpg2dPoint mhdr_swExtents; trpg2dPoint mhdr_neExtents; trpg3dPoint mhdr_Origin; // integrate header information from the block header. header.GetExtents(mhdr_swExtents,mhdr_neExtents); header.GetOrigin(mhdr_Origin); header.GetBlocks(totalrows,totalcols); if(readAllBlocks) { for(int row=0;row<totalrows;row++) { for(int col=0;col<totalcols;col++) { // Read each block -- Warning, this can take a while!!! ReadSubArchive( row, col, cpuNess); } } } else { ReadSubArchive( 0, 0, cpuNess);//Get the first archive! } } tileTable.SetCurrentBlock(-1,-1,false); // 1.0 Compatibility // If we see an older style material table, convert it to the new style // This isn't terribly memory efficient, but it does work if (oldMatTable.isValid()) materialTable = oldMatTable; if (oldTexTable.isValid()) texTable = oldTexTable; // Set up a tile cache, if needed trpgTileTable::TileMode tileMode; tileTable.GetMode(tileMode); if (tileMode == trpgTileTable::Local) { if (tileCache) delete tileCache; char fullBase[1060]; sprintf(fullBase,"%s" PATHSEPERATOR "tileFile",dir); tileCache = GetNewRAppFileCache(fullBase,"tpf"); } valid = true; return true; }
/** * Read a sub block from a 2.2 TXP database. This can be called any time after ReadHeader is called * if ReadHeader is called with the false parameter to specify not to read all the sub-archives. * This can make a huge improvement in startup time for loading a very large archive with many blocks. **/ bool trpgr_Archive::ReadSubArchive(int row, int col, trpgEndian cpuNess) { int ret; trpgHeader blockHeader; trpgr_Parser bparser; char blockpath[1060]; //open the block archive // the block archive will be in the base dir + \\cols\\row\\archive.txp sprintf(blockpath,"%s%s%d%s%d%sarchive.txp",dir,PATHSEPERATOR,col,PATHSEPERATOR,row,PATHSEPERATOR); FILE *bfp = osgDB::fopen(blockpath,"rb"); if(!bfp) { return false; } // Look for a magic # and endianness int32 bmagic; if (fread(&bmagic,sizeof(int32),1,bfp) != 1) { //close the block archive fclose(bfp); return false; } // The block archive will always be the same endianness as the master if ( (bmagic != GetMagicNumber()) && (trpg_byteswap_int(bmagic) != GetMagicNumber()) ) { //close the block archive fclose(bfp); return false; } int32 bheaderSize=0; if (fread(&bheaderSize,sizeof(int32),1,bfp) != 1) { //close the block archive fclose(bfp); return false; } if (ness != cpuNess) bheaderSize = trpg_byteswap_int(bheaderSize); int bheadLen = bheaderSize; if (bheadLen < 0) { //close the block archive fclose(bfp); return false; } // Read in the header whole trpgMemReadBuffer bbuf(ness); bbuf.SetLength(bheadLen); char *bdata = bbuf.GetDataPtr(); if ((ret = GetHeaderData(bdata,bheadLen,bfp)) != bheadLen) { //close the block archive fclose(bfp); return false; } //keep track of where this came from in the master table. tileTable.SetCurrentBlock(row,col,true); texTable.SetCurrentBlock(row,col); bparser.AddCallback(TRPGHEADER,&blockHeader); bparser.AddCallback(TRPGMATTABLE,&materialTable); // Went back to oldest style for 2.0 //if(!headerHasTexTable) { bparser.AddCallback(TRPGTEXTABLE2,&texTable); // Added for 2.0 //} bparser.AddCallback(TRPGMODELTABLE,&modelTable); bparser.AddCallback(TRPGLIGHTTABLE,&lightTable); // Added for 2.0 bparser.AddCallback(TRPGRANGETABLE,&rangeTable); // Added for 2.0 bparser.AddCallback(TRPG_TEXT_STYLE_TABLE,&textStyleTable); // Added for 2.1 bparser.AddCallback(TRPG_SUPPORT_STYLE_TABLE,&supportStyleTable); bparser.AddCallback(TRPG_LABEL_PROPERTY_TABLE,&labelPropertyTable); // Don't read the tile table for v1.0 archives // It's only really used for 2.0 archives bparser.AddCallback(TRPGTILETABLE2,&tileTable); // Parse the buffer if (!bparser.Parse(bbuf)) return false; //close the block archive fclose(bfp); tileTable.SetCurrentBlock(-1,-1,false); return true; }
// Add(Int32) void trpgMemWriteBuffer::Add(int32 val) { if (ness != cpuNess) val = trpg_byteswap_int(val); append(sizeof(int32),(const char *)&val); }
/* CheckpointHeader The header lives in its own file, so we can write it at any point we have a valid archive. This includes all the tables, as well as basic header info. */ bool trpgwArchive::CheckpointHeader() { trpgMemWriteBuffer buf(ness); if (!isValid()) return false; if (!header.isValid()) { if(header.getErrMess()) strcpy(errMess, header.getErrMess()); return false; } // This will close the appendable files if (tileFile) { tileFile->Flush(); } /* Build a Tile Table We need to build one from scratch here. However, we have all the relevant information collected during the WriteTile calls. */ if(header.GetIsLocal()) { int row = 0; int col = 0; header.GetBlocks(row,col); tileTable.SetCurrentBlock(row,col,true); } if (tileMode == TileExternal) { // External tiles are easy tileTable.SetMode(trpgTileTable::External); } else if( tileMode == TileExternalSaved) { if(!isRegenerate && firstHeaderWrite) { // Set up the sizes tileTable.SetMode(trpgTileTable::ExternalSaved); tileTable.SetNumLod(1); trpg2iPoint lodSize; header.GetLodSize(0,lodSize); tileTable.SetNumTiles(lodSize.x, lodSize.y, 0); firstHeaderWrite = false; } // Now set the individual tile locations for (unsigned int i=0;i<externalTiles.size();i++) { TileFileEntry &te = externalTiles[i]; trpgwAppAddress addr; addr.file = -1; addr.offset = -1; tileTable.SetTile(te.x,te.y,te.lod,addr,te.zmin,te.zmax); } externalTiles.clear(); } else { if (!isRegenerate && firstHeaderWrite) { // Local tiles require more work tileTable.SetMode(trpgTileTable::Local); if(majorVersion == 2 && minorVersion >= 1) { // Version 2.1, we store only lod 0 in the tile table // Set up the sizes tileTable.SetNumLod(1); trpg2iPoint lodSize; header.GetLodSize(0,lodSize); tileTable.SetNumTiles(lodSize.x, lodSize.y, 0); } else { // Set up the sizes int32 numLod; header.GetNumLods(numLod); tileTable.SetNumLod(numLod); for (int i=0;i<numLod;i++) { trpg2iPoint lodSize; header.GetLodSize(i,lodSize); tileTable.SetNumTiles(lodSize.x,lodSize.y,i); } } firstHeaderWrite = false; } // Now set the individual tile locations // Nothing special need to be done with version 2.1 since // only tile with lod 0 will be found in the tileFiles container for (unsigned int i=0;i<tileFiles.size();i++) { TileFile &tf = tileFiles[i]; for (unsigned int j=0;j<tf.tiles.size();j++) { TileFileEntry &te = tf.tiles[j]; trpgwAppAddress addr; addr.file = tf.id; addr.offset = te.offset; tileTable.SetTile(te.x,te.y,te.lod,addr,te.zmin,te.zmax); } tf.tiles.clear(); } } // Write all the headers into a buffer if (!header.Write(buf)) return false; // Do the mat table and texture table // These can be different depending on the version switch (majorVersion) { case 1: { trpgMatTable1_0 matTable1_0(matTable); trpgTexTable1_0 texTable1_0(texTable); trpgTileTable1_0 tileTable1_0(tileTable); if (!matTable1_0.Write(buf) || !texTable1_0.Write(buf) || !modelTable.Write(buf) || !tileTable1_0.Write(buf) || !lightTable.Write(buf) || !rangeTable.Write(buf)) return false; } break; case 2: if(!header.GetIsMaster()||texTable.isValid()) { if(!texTable.Write(buf)) { strcpy(errMess, "Error writing texture table"); if(texTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, texTable.getErrMess()); return false; } } } //These tables will not be populated if this is the master table. if(!header.GetIsMaster()) { if (!matTable.Write(buf)) { strcpy(errMess, "Error writing material table"); if(matTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, matTable.getErrMess()); return false; } } if(!modelTable.Write(buf) ) { strcpy(errMess, "Error writing model table"); if(modelTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, modelTable.getErrMess()); return false; } } } //always write the tile table, even if we are a master if(!tileTable.Write(buf)) { strcpy(errMess, "Error writing tile table"); if(tileTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, tileTable.getErrMess()); return false; } } if(!header.GetIsMaster()) { if(!lightTable.Write(buf)) { strcpy(errMess, "Error writing light table"); if(lightTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, lightTable.getErrMess()); return false; } } if(!rangeTable.Write(buf)) { strcpy(errMess, "Error writing range table"); if(rangeTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, rangeTable.getErrMess()); return false; } } if (!textStyleTable.Write(buf)) { strcpy(errMess,"Error writing text style table"); if (textStyleTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, textStyleTable.getErrMess()); return false; } } if (!supportStyleTable.Write(buf)) { strcpy(errMess,"Error writing support style table"); if (supportStyleTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, supportStyleTable.getErrMess()); return false; } } if (!labelPropertyTable.Write(buf)) { strcpy(errMess,"Error writing label property table"); if (labelPropertyTable.getErrMess()) { strcat(errMess, ": "); strcat(errMess, labelPropertyTable.getErrMess()); return false; } } } break; } // Write the disk header int32 magic = GetMagicNumber(); if (ness != cpuNess) magic = trpg_byteswap_int(magic); if (fwrite(&magic,sizeof(int32),1,fp) != 1) { strcpy(errMess, "Could not write the magic number"); return false; } // Write the header length int32 headerSize = buf.length(); int headLen = headerSize; if (ness != cpuNess) headerSize = trpg_byteswap_int(headerSize); if (fwrite(&headerSize,1,sizeof(int32),fp) != sizeof(int32)) { strcpy(errMess, "Could not write the header size"); return false; } // Write the buffer const char *data = buf.getData(); if (WriteHeaderData(data,headLen,fp) != headLen) { strcpy(errMess, "Could not write the buffer"); return false; } // Note: Not sure what this is char space[40]; if (fwrite(space,1,4,fp) != 4) return false; // Flush output fflush(fp); // Head back to the start of the file rewind(fp); return true; }