SleepIsDeath/gameSource/packSaver.cpp

423 lines
13 KiB
C++

#include "packSaver.h"
#include "common.h"
#include "resourceManager.h"
#include "fixOldResources.h"
#include "minorGems/util/SimpleVector.h"
#include "minorGems/util/stringUtils.h"
#include "minorGems/util/log/AppLog.h"
#include "minorGems/io/file/File.h"
#include <zlib.h>
typedef struct packRecord {
const char *type;
uniqueID id;
char *wordString;
unsigned char *data;
int length;
} packRecord;
SimpleVector<packRecord> runningPack;
void initPackSaver() {
}
void freePackSaver() {
for( int i=0; i<runningPack.size(); i++ ) {
packRecord *r = runningPack.getElement( i );
delete [] r->wordString;
delete [] r->data;
}
runningPack.deleteAll();
}
char alreadyInPack( uniqueID inID ) {
// already present?
for( int i=0; i<runningPack.size(); i++ ) {
packRecord *r = runningPack.getElement( i );
if( equal( r->id, inID ) ) {
return true;
}
}
return false;
}
void addToPack( const char *inResourceType,
uniqueID inID,
char *inWordString,
unsigned char *inData, int inLength ) {
if( alreadyInPack( inID ) ) {
return;
}
// not found
// add
unsigned char *data = new unsigned char[ inLength ];
memcpy( data, inData, inLength );
packRecord r = {
inResourceType,
inID,
stringDuplicate( inWordString ),
data,
inLength };
runningPack.push_back( r );
}
// saves the pack and clears the running pack
void savePack() {
File packDir( NULL, "resourcePacks" );
if( !packDir.exists() ) {
packDir.makeDirectory();
}
if( packDir.exists() && packDir.isDirectory() ) {
int numFiles;
File **childFiles = packDir.getChildFiles( &numFiles );
int largestNumber = 0;
for( int i=0; i<numFiles; i++ ) {
char *name = childFiles[i]->getFileName();
int number;
int numRead = sscanf( name, "%d", &number );
if( numRead == 1 ) {
if( number > largestNumber ) {
largestNumber = number;
}
}
delete [] name;
delete childFiles[i];
}
delete [] childFiles;
int newFileNumber = largestNumber + 1;
char *fileName = autoSprintf( "%d.pak", newFileNumber );
File *packFile = packDir.getChildFile( fileName );
delete [] fileName;
char *fullFileName = packFile->getFullFileName();
SimpleVector<unsigned char> dataAccum;
// first, output number of chunks
unsigned char *countChars = getChars( runningPack.size() );
dataAccum.push_back( countChars, 4 );
for( int i=0; i<runningPack.size(); i++ ) {
packRecord *r = runningPack.getElement( i );
dataAccum.push_back( (unsigned char *)( r->type ),
strlen( r->type ) + 1 );
dataAccum.push_back( r->id.bytes, U );
dataAccum.push_back( (unsigned char *)( r->wordString ),
strlen( r->wordString ) + 1 );
unsigned char *lengthChars = getChars( r->length );
dataAccum.push_back( lengthChars, 4 );
dataAccum.push_back( r->data, r->length );
}
unsigned char *data = dataAccum.getElementArray();
int numBytes = dataAccum.size();
uLongf compressSize = compressBound( numBytes );
unsigned char *compressData = new unsigned char[ compressSize + 4 ];
// first 4 bytes are uncompressed size
unsigned char *sizeChars = getChars( numBytes );
memcpy( compressData, sizeChars, 4 );
int result = compress2( &( compressData[4] ), &compressSize,
data, numBytes,
Z_BEST_COMPRESSION );
if( result == Z_OK ) {
char result = packFile->writeToFile( compressData,
compressSize + 4 );
if( !result ) {
AppLog::error( "Failed to write to pack file:" );
AppLog::error( fullFileName );
}
}
else {
AppLog::error( "Zlib compression failed\n" );
}
delete [] data;
delete [] compressData;
delete packFile;
delete [] fullFileName;
}
for( int i=0; i<runningPack.size(); i++ ) {
packRecord *r = runningPack.getElement( i );
delete [] r->wordString;
delete [] r->data;
}
runningPack.deleteAll();
}
void loadPacks() {
File loadDir( NULL, "loadingBay" );
if( !loadDir.exists() ) {
loadDir.makeDirectory();
}
if( loadDir.exists() && loadDir.isDirectory() ) {
int numFiles;
File **childFiles = loadDir.getChildFiles( &numFiles );
for( int i=0; i<numFiles; i++ ) {
char *name = childFiles[i]->getFullFileName();
if( strstr( name, ".pak" ) != NULL ) {
// a pack file
char *shortName = childFiles[i]->getFileName();
char found;
char *doneFlagName =
replaceOnce( shortName, ".pak",
".done", &found );
delete [] shortName;
File *doneFlagFile = loadDir.getChildFile( doneFlagName );
delete [] doneFlagName;
if( !doneFlagFile->exists() ) {
int bytesLeft;
unsigned char *bytes = NULL;
int compressSize;
unsigned char *compressData =
childFiles[i]->readFileContents( &compressSize );
if( compressData != NULL ) {
// first 4 are uncompressed size
int numUsed;
bytesLeft =
readInt( compressData, compressSize, &numUsed );
if( numUsed > 0 ) {
bytes = new unsigned char[ bytesLeft ];
uLongf destLen = bytesLeft;
int result = uncompress(
bytes, &destLen,
&( compressData[numUsed] ),
compressSize - numUsed );
if( result != Z_OK ||
destLen != (unsigned int)bytesLeft ) {
AppLog::error( "Zlib decompression failed" );
delete [] bytes;
bytes = NULL;
}
}
delete [] compressData;
}
unsigned char *allBytes = bytes;
if( bytes != NULL ) {
SimpleVector<uniqueID> importedScenes;
SimpleVector<uniqueID> importedObjects;
int numUsed;
int numChunks = readInt( bytes, bytesLeft, &numUsed );
if( numUsed > 0 ) {
bytesLeft -= numUsed;
bytes = &( bytes[numUsed] );
char chunkSuccess = true;
for( int c=0; c<numChunks && chunkSuccess; c++ ) {
chunkSuccess = false;
char *type = stringDuplicate( (char*)bytes );
numUsed = strlen( type ) + 1;
bytesLeft -= numUsed;
bytes = &( bytes[numUsed] );
uniqueID id =
readUniqueID( bytes, bytesLeft, &numUsed );
if( numUsed == U ) {
bytesLeft -= numUsed;
bytes = &( bytes[numUsed] );
char *wordString =
stringDuplicate( (char*)bytes );
numUsed = strlen( wordString ) + 1;
bytesLeft -= numUsed;
bytes = &( bytes[numUsed] );
int dataLength = readInt( bytes, bytesLeft,
&numUsed );
if( numUsed > 0 ) {
bytesLeft -= numUsed;
bytes = &( bytes[numUsed] );
if( bytesLeft >= dataLength ) {
saveResourceData( type,
id,
wordString,
bytes,
dataLength );
if( strcmp( type, "object" ) == 0 ) {
importedObjects.push_back( id );
}
else if(
strcmp( type, "scene" ) == 0 ) {
importedScenes.push_back( id );
}
AppLog::trace( "Saved pack chunk" );
chunkSuccess = true;
bytesLeft -= dataLength;
bytes = &( bytes[dataLength] );
}
}
delete [] wordString;
}
delete [] type;
}
if( chunkSuccess ) {
AppLog::info( "Successfully loaded all chunks"
" from pack file." );
}
else {
AppLog::error( "Failed to load a chunk"
" from pack file." );
}
// create a flag file
doneFlagFile->writeToFile( "done loading" );
AppLog::info( "Running fix script on imported"
" resources from pack." );
uniqueID *sceneArray =
importedScenes.getElementArray();
uniqueID *objectArray =
importedObjects.getElementArray();
fixOldResources( sceneArray, importedScenes.size(),
objectArray, importedObjects.size() );
delete [] sceneArray;
delete [] objectArray;
AppLog::info( "Done running fix script." );
}
delete [] allBytes;
}
else {
AppLog::error( "Failed to read pack file:" );
AppLog::error( name );
}
} // end check for done file existing
else {
AppLog::info( "Done flag file present for pak file:" );
AppLog::info( name );
}
delete doneFlagFile;
}
delete [] name;
delete childFiles[i];
}
delete [] childFiles;
}
}