/**
 * 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;
}
Пример #2
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;
}