// 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);
}
示例#10
0
/* 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;
}