Rev 6 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
// File.cpp: implementation of the C_File class.////////////////////////////////////////////////////////////////////////#include "File.h"#include <time.h>#include <sys/types.h>#include <sys/stat.h>#ifndef _WIN32#include <unistd.h>#endif#include <iostream>#include <fstream>#include "spk.h"#include "SpkFile.h"#include "CatFile.h"#include "DirIO.h"#include "secure.h"// LZMA compression#include "lzma/Lzma86Enc.h"#include "lzma/Lzma86Dec.h"//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////void CProgressInfoDone::DoingFile ( C_File *file ){m_iDone = 0;if ( !m_bDontDoMax ){if ( file->GetData() && file->GetDataSize() )m_lMaxSize = file->GetDataSize();elsem_lMaxSize = file->GetSize();}m_pOnFile = file;}void CProgressInfoDone::DoingPackage ( SMultiSpkFile *file ){m_iDone = 0;if ( !m_bDontDoMax )m_lMaxSize = file->lSize;m_pOnPackage = file;}int C_File::m_iTempNum = 0;C_File::C_File(){m_bDontDeleteData = false;m_bUsedMalloc = false;m_sData = NULL;Reset();}C_File::C_File ( CyString filename ){m_bDontDeleteData = false;m_bUsedMalloc = false;m_sData = NULL;Reset ();SetFilename ( filename );}C_File::C_File ( const char *filename ){m_bDontDeleteData = false;m_bUsedMalloc = false;m_sData = NULL;Reset ();SetFilename ( CyString(filename) );}C_File::~C_File(){DeleteData ();if ( !m_sTmpFile.Empty() )remove ( m_sTmpFile.c_str() );}/*Func: GetDirectory()Return: Directory StringDesc: Returns the directory the file goes into, based on m_sDir and Filetype*/CyString C_File::GetDirectory ( CBaseFile *file ){if ( IsFakePatch() )return "";if ( (m_iFileType == FILETYPE_MOD) && (m_sDir == "Patch") )return "PluginManager/Patch";if ( (!m_sDir.Empty()) && (m_iFileType != FILETYPE_README) && m_sDir != "." ){CyString dir = m_sDir.FindReplace ( "\\", "/" );if ( file ){dir = dir.FindReplace ( "$scriptname", file->GetNameValidFile() );dir = dir.FindReplace ( "$scriptauthor", file->GetAuthor() );}return dir;}switch ( m_iFileType ){case FILETYPE_SCRIPT:return "Scripts";case FILETYPE_TEXT:return "T";case FILETYPE_README:{if ( file )return CyString("PluginManager/Readme/") + file->GetNameValidFile();return "PluginManager/Readme";}case FILETYPE_MAP:return "Maps";case FILETYPE_MOD:// if ( (file) && (file->IsPatch()) )// return "Mods/Patch";return "Mods";case FILETYPE_UNINSTALL:return "PluginManager/Uninstall";case FILETYPE_SOUND:if ( CFileIO(m_sName).CheckFileExtension("wav") )return "s";return "Soundtrack";case FILETYPE_EXTRA:return "PluginManager/Extras";case FILETYPE_SCREEN:return "loadscr";case FILETYPE_ADVERT:return "PluginManager/Graphics";case FILETYPE_MISSION:return "Director";}return NullString;}CyString C_File::GetNameDirectory ( CBaseFile *file ){CyString dir = GetDirectory( file );if ( !dir.Empty() )dir += "/";return CyString(dir + m_sName).FindReplace ( "\\", "/" ).FindReplace( "//", "/");}/*Func: Reset()Desc: Resets the file data, clears all data insideClears the Data stream*/void C_File::Reset (){m_iLastError = SPKERR_NONE;m_bLoaded = false;m_iFileType = -1;m_lSize = 0;m_iVersion = 0;m_bSigned = false;m_iUsed = 0;m_tTime = 0;m_lDataSize = m_lUncomprDataSize = 0;DeleteData ();m_iDataCompression = 0;m_bSkip = false;m_bShared = false;m_bCompressedToFile = false;m_bDisabled = false;m_bUpdatedSignature = false;m_iPos = -1;m_iGame = 0;}bool C_File::UpdateSigned(){switch ( m_iFileType ){// text files, readmes, screenshots can be always considered to be signedcase FILETYPE_TEXT:case FILETYPE_README:case FILETYPE_SCREEN:case FILETYPE_ADVERT:case FILETYPE_SOUND:case FILETYPE_BACKUP:m_bSigned = true;break;// mods, maps are always not signedcase FILETYPE_MOD:case FILETYPE_MAP:case FILETYPE_SHIPOTHER:case FILETYPE_SHIPMODEL:case FILETYPE_SHIPSCENE:case FILETYPE_COCKPITSCENE:m_bSigned = false;break;// extra files are a special casecase FILETYPE_EXTRA:if ( this->GetDir().Left(6).Compare("extras") )m_bSigned = true;elsem_bSigned = false;break;// script files need to checkcase FILETYPE_SCRIPT:case FILETYPE_UNINSTALL:m_bSigned = this->ReadSignedFile();break;// mission filescase FILETYPE_MISSION:m_bSigned = false;break;}return m_bSigned;}/*Func: DeleteData()Desc: Clears the data stream, uses free() if created by malloc, otherwise use delete.*/void C_File::DeleteData (){if ( m_sData ){if ( m_bUsedMalloc )free ( m_sData );elsedelete [] m_sData;m_bDontDeleteData = false;m_sData = NULL;m_bLoaded = false;m_lDataSize = 0;}m_bUsedMalloc = false;m_iDataCompression = SPKCOMPRESS_NONE;}int C_File::GetTextFileID(CyString filename){if ( m_iFileType != FILETYPE_TEXT )return -1;if ( filename.Empty() )filename = m_sName;CyString textid;if ( filename.IsIn("-L") || filename.IsIn("-l") )textid = filename.GetToken("-", 1, 1);elsetextid = filename.GetToken(".", -1).Right(4);return textid.ToInt();}bool C_File::IsAutoTextFile (){int textid = GetTextFileID();if ( textid == -1 ) return false;if ( textid <= 3 )return true;// check for original nameif ( !m_sOriginalName.Empty() ){textid = GetTextFileID(m_sOriginalName);if ( textid >= 0 && textid <= 3 )return true;}return false;}bool C_File::IsFakePatch (){if ( m_iFileType != FILETYPE_MOD )return false;if ( m_sName.GetToken ( 1, '.' ).ToInt() )return true;if ( m_sName.Left (10) == "FakePatch_" )return true;return false;}/*############################################################################################################################################################ File Pointer Functions ############################################################################################################################################################*//*Func: SetFilenameAccept: filename - String for the filename of diskDesc: Sets the file pointerReads the file size and last modifed time to store in the classSplits up the filename and dir path*/void C_File::SetFilename ( CyString filename ){CyString file = filename.FindReplace ( "\\", "/" ).FindReplace ( "//", "/" );int tok = file.NumToken ( '/' );m_sFullDir = file.GetToken ( "/", 1, -1 );m_sName = file.GetToken ( "/", -1 );if ( m_sFullDir.Right(2) == "/." )m_sFullDir = m_sFullDir.Left(-2);ReadFileSize ();ReadLastModified ();}/*Func: ReadFromFileReturn: Boolean - Returns true if read was successfullDesc: Reads data from file pointer into data streamAs its read from a file, there will be no compression, so its set to None*/bool C_File::ReadFromFile (){return this->ReadFromFile(GetFilePointer().c_str());}bool C_File::ReadFromFile (CyString filename){FILE *id = fopen ( filename.c_str(), "rb" );if ( !id ){m_iLastError = SPKERR_FILEOPEN;return false;}if ( !m_lSize ){fseek ( id, 0, SEEK_END );m_lSize = ftell ( id );rewind ( id );}m_iDataCompression = SPKCOMPRESS_NONE;m_lDataSize = m_lUncomprDataSize = m_lSize;DeleteData ();m_sData = new unsigned char[m_lSize];if ( !m_sData ) { fclose ( id ); m_iLastError = SPKERR_MALLOC; return false; }fread ( m_sData, sizeof(unsigned char), m_lSize, id );if ( ferror(id) ){m_iLastError = SPKERR_FILEREAD;DeleteData ();m_lDataSize = 0;fclose ( id );return false;}m_iLastError = SPKERR_NONE;struct stat fileStat;if ( !stat(GetFilePointer().c_str(), &fileStat) )m_tTime = fileStat.st_atime;m_bLoaded = true;fclose ( id );return true;}/*Func: ReadFromDataAccept: data - The data stream to readsize - The length of the data streamReturn: Boolean - Return true if successfullDesc: Copys data to the data stream in the fileUsed when data is already loaded into memory*/bool C_File::ReadFromData ( char *data, long size ){DeleteData ();m_lDataSize = size ;m_sData = new unsigned char[m_lDataSize];memcpy ( m_sData, data, size );return true;}/*Func: ReadFromFileAccept: id - File Pointer Stream of open filesize - amount of data to read from filedosize - Read the 4 character sizeFunc: Reads a data stream from a currently open fileCan be used to read directly from a SPK Packagedosize will read the initial 4 character uncompressed size if needed*/bool C_File::ReadFromFile ( FILE *id, long size, bool dosize ){// remove datam_lDataSize = size ;m_sData = new unsigned char[m_lDataSize];if ( dosize ){unsigned char s[4];fread ( s, sizeof(unsigned char), 4, id );}fread ( m_sData, sizeof(unsigned char), m_lDataSize, id );if ( ferror (id) ){DeleteData ();m_lDataSize = 0;return false;}return true;}/*Func: GetFilePointerDesc: Returns the file pointer nameJoins dir and name togetherWorks for relative paths as well*/CyString C_File::GetFilePointer (){CyString fullfile = m_sFullDir;if ( !fullfile.Empty() )fullfile += "/";if ( !m_sName.Empty() )fullfile += m_sName;return fullfile;}void C_File::UpdateSignature(){m_sSignature = "";bool deleteData = false;if ( !m_sData ){if ( !ReadFromFile() )return;deleteData = true;}if ( CheckPCK() )UnPCKFile();m_bUpdatedSignature = true;if ( !m_sData )return;size_t fPos = m_lDataSize;if ( fPos > 700 )fPos = 700;unsigned char *data = m_sData + (m_lDataSize - fPos);data[fPos - 1] = '\0';CyString sData ((char *)data);int pos = sData.FindPos("</codearray>", 0);if ( pos != -1 ){sData = sData.Right(sData.Length() - pos);pos = sData.FindPos("<signature>", 0);int endpos = sData.FindPos("</signature>", 0);if ( pos != -1 && endpos != -1 ){m_sSignature = sData.Mid(pos + 12, endpos - (pos + 12) + 1);m_sSignature = m_sSignature.Remove('\n').Remove('\r');}}if ( deleteData )DeleteData();}/*Func: ReadFileSize()Return: Returns the file size readDesc: Opens the file and seeks to the end*/long C_File::ReadFileSize (){FILE *id = fopen ( GetFilePointer().c_str(), "rb" );if ( id ){fseek ( id, 0, SEEK_END );m_lSize = ftell ( id );fclose ( id );}m_lUncomprDataSize = m_lSize;return m_lSize;}/*Func: ReadLastModifed()Desc: Reads the last modified time of the file and returnsUses seperate rountines for Windows and Linux*/time_t C_File::ReadLastModified (){CyString file = GetFilePointer();if ( file.Empty() )return m_tTime;#ifndef _WIN32struct stat attrib; // create a file attribute structurestat ( file.c_str(), &attrib);m_tTime = attrib.st_mtime;#else#endifreturn m_tTime;}bool C_File::CheckValidFilePointer (){CyString filename = GetFilePointer();if ( filename.Empty() )return false;FILE *id = fopen ( filename.c_str(), "rb+" );if ( !id )return false;fclose ( id );return true;}bool C_File::ReadSignedFile(){if ( (m_iFileType != FILETYPE_SCRIPT) && (m_iFileType != FILETYPE_UNINSTALL) )return false;// check file pointerCyString file = GetFilePointer();CyString ext = CFileIO(file).GetFileExtension();if ( !ext.Compare("xml") && !ext.Compare("pck") )return false;if ( m_iDataCompression != SPKCOMPRESS_NONE )return m_bSigned;// check file extenstionif ( (ext.Compare("pck")) || (CheckPCK()) ){size_t size = 0;unsigned char *data = UnPCKFile ( &size );if ( (data) && (size) )return ::ReadSignedFromData ( data, (long)size );}else if ( (m_sData) && (m_iDataCompression == SPKCOMPRESS_NONE) )return ::ReadSignedFromData ( m_sData, m_lDataSize );else{FILE *id = fopen(file.c_str(), "rb");if ( id ){CyString sRead;char read[21];fseek(id, 0, SEEK_END);int endPos = ftell(id);int pos = endPos;// move to end of the filewhile ( true ){// read blocks of 20 backwardspos -= 20;if ( pos < 0 )pos = 0;fseek(id, pos, SEEK_SET);fread(read, sizeof(char), 20, id);read[20] = '\0';sRead = CyString(read) + sRead;// find code arrayif ( sRead.FindPos("codearray") != -1 )break;if ( pos <= 2 )break;}fclose(id);// now check the find readif ( sRead.FindPos("signed") != -1 )return true;}}return false;}int C_File::ReadScriptVersion (){if ( (m_iFileType != FILETYPE_SCRIPT) && (m_iFileType != FILETYPE_UNINSTALL) )return 0;// check file pointerCyString file = GetFilePointer();// check file extenstionif ( (CFileIO(file).CheckFileExtension("pck")) || (CheckPCK()) ){size_t size = 0;unsigned char *data = UnPCKFile ( &size );if ( (data) && (size) )m_iVersion = ::ReadScriptVersionFromData ( data, (long)size );}else if ( (m_sData) && (m_iDataCompression == SPKCOMPRESS_NONE) )m_iVersion = ::ReadScriptVersionFromData ( m_sData, m_lDataSize );else{FILE *id = fopen ( file.c_str(), "rb+" );if ( id ){fclose ( id );std::string line;std::ifstream myfile ( file.c_str() );if ( myfile.is_open() ){bool inscript = false;while (! myfile.eof() ){std::getline ( myfile, line );while ( line[0] == ' ' )line.erase ( 0, 1 );CyString sLine = line;if ( !inscript ){if ( sLine.GetToken ( 1, '>' ) == "<script" )inscript = true;}else{if ( sLine.GetToken ( 1, '>' ) == "<version" ){m_iVersion = sLine.GetToken ( 2, '>' ).GetToken ( 1, '<' ).ToInt();break;}}}myfile.close();}}}return m_iVersion;}bool C_File::MatchFile ( C_File *file ){if ( file->GetFileType() != m_iFileType )return false;if ( file->GetDir() != m_sDir )return false;if ( file->GetName() != m_sName )return false;return true;}/*############################################################################################################################################################ Compression Functions ############################################################################################################################################################*/bool C_File::CompressFile ( CProgressInfo *progress ){CyString file = this->GetFilePointer();if ( !CFileIO(this->GetFilePointer()).Exists() ){if ( !this->WriteToFile("tempuncompr.dat", m_sData, m_lDataSize) )return false;file = "tempuncompr.dat";}bool ret = false;FILE *fIn = fopen(file.c_str(), "rb");if ( fIn ){FILE *fOut = fopen("tempcompr.dat", "wb");if ( fOut ){int err;if ( progress )err = zlib_def(fIn, fOut, progress->GetDonePointer());elseerr = zlib_def(fIn, fOut, 0);fclose(fOut);if ( err == Z_OK ){DeleteData ();FILE *id = fopen ( "tempcompr.dat", "rb" );if ( id ){fseek ( id, 0, SEEK_END );m_lDataSize = ftell ( id );rewind ( id );m_sData = new unsigned char[m_lDataSize];if ( !m_sData ) { fclose ( id ); m_iLastError = SPKERR_MALLOC; }else{fread ( m_sData, sizeof(unsigned char), m_lDataSize, id );if ( ferror(id) ){m_iLastError = SPKERR_FILEREAD;DeleteData ();m_lDataSize = 0;}else{ret = true;m_iLastError = SPKERR_NONE;m_iDataCompression = SPKCOMPRESS_ZLIB;}}fclose(id);}}}CFileIO("tempcompr.dat").Remove();fclose(fIn);}CFileIO("tempuncompr.dat").Remove();return ret;}bool C_File::ChangeCompression ( int compressionType, CProgressInfo *progress ){// no data to try to compressif ( (!m_sData) || (!m_lDataSize) )return false;// laready compressed to correct typeif ( compressionType == m_iDataCompression )return true;// otherwise, lets recompress the file// first we uncompress the dataif ( !this->UncompressData(progress) )return false;// next we compress to new typeif ( !this->CompressData(compressionType, progress) )return false;return true;}unsigned char *C_File::CompressToData(int compressionType, unsigned long *outSize, CProgressInfo *progress, int level){unsigned long comprLen = m_lDataSize;if ( comprLen < 100 ) comprLen = 200;else if ( comprLen < 1000 ) comprLen *= 2;comprLen += 1000;switch(compressionType){case SPKCOMPRESS_ZLIB:{unsigned char *compr = (unsigned char *)calloc(comprLen, 1);int err = Z_NOTENOUGH_BUF;while ( err == Z_NOTENOUGH_BUF ){err = compress2 ( compr, &comprLen, (const unsigned char *)m_sData, m_lDataSize, (progress) ? progress->GetDonePointer() : 0, level );if ( err == Z_NOTENOUGH_BUF ){comprLen += (CHUNK * 2);compr = (unsigned char *)realloc(compr, comprLen);}elsebreak;}// if its compressed ok, remove old data and use new oneif ( err == Z_OK ){unsigned char *retData = new unsigned char[comprLen];(*outSize) = comprLen;memcpy(retData, compr, comprLen);free(compr);return retData;}free(compr);return NULL;}break;case SPKCOMPRESS_LZMA:{unsigned char *compr = (unsigned char *)malloc(comprLen);SRes res = Lzma86_Encode((Byte *)compr, (size_t *)&comprLen, (const Byte *)m_sData, (size_t)m_lDataSize, level, LZMA_DICT, SZ_FILTER_NO, (progress) ? progress->GetDonePointer() : NULL);if ( res == SZ_OK ){unsigned char *retData = new unsigned char[comprLen];(*outSize) = comprLen;memcpy(retData, compr, comprLen);free(compr);return retData;}free(compr);return NULL;}break;}return NULL;}bool C_File::CompressData ( int compressionType, CProgressInfo *progress, int level ){// no data to try to compressif ( (!m_sData) || (!m_lDataSize) )return false;// if comopression is set to noe, dont botherif ( compressionType == SPKCOMPRESS_NONE )return true;if ( compressionType == SPKCOMPRESS_7ZIP )compressionType = SPKCOMPRESS_LZMA;// if its zlib, and we are trying to compress pcked files (ie already zlib compression) then switch to lzma insteadif ( compressionType == SPKCOMPRESS_ZLIB && (this->CheckFileExt("pck") || this->CheckFileExt("cat") || this->CheckFileExt("dat") || this->CheckFileExt("pbb") || this->CheckFileExt("pbd")) )compressionType = SPKCOMPRESS_LZMA;// if its already compressed, no need to compress againif ( compressionType == m_iDataCompression )return true;// no need to change the compressionif ( m_iDataCompression != SPKCOMPRESS_NONE )return true;m_lUncomprDataSize = m_lDataSize;unsigned long comprLen = m_lDataSize;if ( comprLen < 100 )comprLen = 200;else if ( comprLen < 1000 )comprLen *= 2;comprLen += 1000;// > 500mb (do file compressionif ( comprLen > 500000000 )return this->CompressFile(progress);// best compression, attempt to compress the file multiple times until we get the best oneif ( compressionType == SPKCOMPRESS_BEST ){int compress[] = { SPKCOMPRESS_ZLIB, SPKCOMPRESS_LZMA };int bestCompress = -1;unsigned int bestSize = 0;unsigned char *bestCompr = NULL;for ( int i = 0; i < 2; i++ ){unsigned long checkSize = 0;unsigned char *compr = this->CompressToData(compress[i], &checkSize, progress, level);if ( compr ){if ( checkSize < bestSize || bestCompress == -1 ){if ( bestCompr )delete bestCompr;bestCompr = compr;bestCompress = compress[i];bestSize = checkSize;}// not the best, no need to keep itelsedelete compr;}}if ( bestCompress != -1 && bestCompr ){DeleteData ();m_sData = bestCompr;m_bUsedMalloc = false;m_lDataSize = bestSize;m_iDataCompression = bestCompress;return true;}if ( bestCompr )delete bestCompr;}if ( compressionType == SPKCOMPRESS_ZLIB || compressionType == SPKCOMPRESS_LZMA ){unsigned char *compr = this->CompressToData(compressionType, &comprLen, progress, level);if ( compr ){DeleteData ();m_sData = compr;m_bUsedMalloc = false;m_lDataSize = comprLen;m_iDataCompression = compressionType;}// we shall always return true, files can be added in non compressed modereturn true;}return false;}bool C_File::UncompressData ( CProgressInfo *progress ){// no data to try to uncompressif ( (!m_sData) || (!m_lDataSize) )return false;if ( m_bCompressedToFile )return false;// if comopression is set to none, dont botherif ( m_iDataCompression == SPKCOMPRESS_NONE )return true;if ( m_iDataCompression == SPKCOMPRESS_ZLIB ){unsigned long uncomprLen = m_lUncomprDataSize;unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );if ( err == Z_OK ){DeleteData ();m_iDataCompression = SPKCOMPRESS_NONE;m_lDataSize = uncomprLen;m_sData = uncompr;return true;}if ( uncompr )delete [] uncompr;}else if ( m_iDataCompression == SPKCOMPRESS_LZMA ){size_t uncomprLen = m_lUncomprDataSize;unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);if ( res == SZ_OK ){DeleteData ();m_iDataCompression = SPKCOMPRESS_NONE;m_lDataSize = (long)uncomprLen;m_sData = new unsigned char[m_lDataSize];memcpy(m_sData, uncompr, m_lDataSize);delete uncompr;return true;}if ( uncompr )delete [] uncompr;}else if ( m_iDataCompression == SPKCOMPRESS_7ZIP ){long len = m_lUncomprDataSize;unsigned char *compr = LZMADecode_C ( (unsigned char *)m_sData, m_lDataSize, (size_t*)&len, NULL );if ( compr ){DeleteData ();m_sData = compr;m_lDataSize = len;m_iDataCompression = SPKCOMPRESS_NONE;return true;}}return false;}unsigned char *C_File::UncompressData ( long *size, CProgressInfo *progress ){// no data to try to uncompressif ( (!m_sData) || (!m_lDataSize) )return NULL;//if ( m_bCompressedToFile )// return NULL;// if comopression is set to none, dont botherif ( m_iDataCompression == SPKCOMPRESS_NONE ){*size = m_lDataSize;return m_sData;}if ( m_iDataCompression == SPKCOMPRESS_ZLIB ){unsigned long uncomprLen = m_lUncomprDataSize;unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];int err = uncompress ( uncompr, &uncomprLen, (const unsigned char *)m_sData, m_lDataSize );if ( err == Z_OK ){*size = uncomprLen;return uncompr;}if ( uncompr )delete [] uncompr;}if ( m_iDataCompression == SPKCOMPRESS_7ZIP ){long len = m_lUncomprDataSize;unsigned char *compr = LZMADecode_C ( m_sData, m_lDataSize, (size_t *)&len, NULL );if ( compr ){*size = len;return compr;}if ( compr )delete [] compr;}else if ( m_iDataCompression == SPKCOMPRESS_LZMA ){size_t uncomprLen = m_lUncomprDataSize;unsigned char *uncompr = new unsigned char[m_lUncomprDataSize];SRes res = Lzma86_Decode(uncompr, &uncomprLen, m_sData, (size_t*)&m_lDataSize);if ( res == SZ_OK ){*size = (long)uncomprLen;return uncompr;}if ( uncompr )delete [] uncompr;}return NULL;}bool C_File::UncompressToFile ( CyString toFile, CBaseFile *spkfile, bool includedir, CProgressInfo *progress ){#ifdef _INCLUDE7ZIPif ( (!m_sData) || (!m_lDataSize) )return false;// if theres a tmp file, open it and check it still existsif ( !m_sTmpFile.Empty() ){FILE *id = fopen ( m_sTmpFile.c_str(), "rb" );if ( id ){fclose ( id );return true;}m_sTmpFile = "";}// now uncompress to the fileCyString file = toFile;if ( file.Empty() ){m_iTempNum++;file = CyString("uncompr") + (long)m_iTempNum + ".tmp";}elsefile = GetFullFileToDir ( file, includedir, spkfile );FILE *id = fopen ( "compr.tmp", "wb" );if ( !id )return false;fwrite ( m_sData, sizeof(unsigned char), m_lDataSize, id );bool ret = false;int err = ferror(id);fclose ( id );if ( !err ){if ( LZMADecodeFile ( "compr.tmp", file.c_str(), (CProgressInfo7Zip *)progress ) ){ret = true;if ( toFile.Empty() )m_sTmpFile = file;}}remove ( "compr.tmp" );return ret;#elsereturn false;#endif}bool C_File::WriteFilePointer ( unsigned char *cData, long len ){return WriteToFile ( GetFilePointer(), cData, len );}bool C_File::WriteToFile ( CyString filename, unsigned char *cData, long len ){unsigned char *data = cData;if ( (!len) || (!data) ){len = m_lDataSize;data = m_sData;}if ( (!len) || (!data) )return false;// check for cat fileif ( filename.IsIn ( "::" ) ){CyString catfile = filename.GetToken ( "::", 1, 1 );CyString file = filename.GetToken ( "::", 2, 2 );CCatFile newcat;return newcat.AddData ( catfile, data, len, file, true, true );}else{CyString filen = filename.FindReplace ( "/", "\\" );filen = filen.FindReplace ( "\\\\", "\\" );FILE *id = fopen ( filen.c_str(), "wb" );if ( !id )return false;fwrite ( data, sizeof(unsigned char), len, id );bool ret = true;if ( ferror(id) )ret = false;fclose ( id );return ret;}return false;}CyString C_File::GetFullFileToDir ( CyString dir, bool includedir, CBaseFile *file ){CyString fullfile = dir;if ( includedir ){CyString d = GetDirectory ( file );if ( !d.Empty() ){if ( !fullfile.Empty() )fullfile += "/";fullfile += d;}}if ( !m_sName.Empty() ){if ( !fullfile.Empty() )fullfile += "/";fullfile += m_sName;}fullfile = fullfile.FindReplace ( "\\", "/" );return fullfile;}bool C_File::WriteToDir ( CyString &dir, CBaseFile *spkfile, bool includedir, CyString appendDir, unsigned char *data, long len ){CyString fullfile = GetFullFileToDir ( dir, includedir, spkfile );if ( !appendDir.Empty() ){if ( !fullfile.Empty() )fullfile += "/";fullfile += appendDir;}CyString fulldir = fullfile.GetToken ( 1, fullfile.NumToken('/') - 2, '/' );if ( !fulldir.Empty() ){if ( !CDirIO(fulldir).Create() )return false;}return WriteToFile ( fullfile, data, len );}CyString C_File::GetDataSizeString (){return SPK::GetSizeString ( m_lDataSize );}CyString C_File::GetUncompressedSizeString (){return SPK::GetSizeString ( GetUncompressedDataSize() );}CyString C_File::GetCreationTimeString (){if ( !m_tTime )return NullString;struct tm *currDate;char dateString[100];time_t n = m_tTime;currDate = localtime(&n);strftime(dateString, sizeof dateString, "(%d/%m/%Y) %H:%M", currDate);return CyString(dateString);}bool C_File::CompareNew ( C_File *file ){if ( !m_iVersion )ReadScriptVersion ();// if version, check if its later versionif ( (m_iVersion) && (file->GetVersion()) ){if ( m_iVersion > file->GetVersion() )return false;}// now check for last modified timeif ( (m_tTime) && (file->GetLastModified()) ){if ( m_tTime > file->GetLastModified() )return false;}// assume same or newerreturn true;}CyString GetFileTypeString ( int type ){switch ( type ){case FILETYPE_SCRIPT:return "Script";case FILETYPE_TEXT:return "Text";case FILETYPE_README:return "Readme";case FILETYPE_MAP:return "Map";case FILETYPE_MOD:return "Mod";case FILETYPE_UNINSTALL:return "Uninstall";case FILETYPE_SOUND:return "Sound";case FILETYPE_EXTRA:return "Extra";case FILETYPE_SCREEN:return "Screen";case FILETYPE_ADVERT:return "Advert";case FILETYPE_MISSION:return "Mission";case FILETYPE_BACKUP:return "Backup";case FILETYPE_SHIPOTHER:return "ShipOther";case FILETYPE_SHIPMODEL:return "ShipModel";case FILETYPE_SHIPSCENE:return "ShipScene";case FILETYPE_COCKPITSCENE:return "CockpitScene";}return NullString;}int GetFileTypeFromString ( CyString type ){CyString ltype = type.ToLower();if ( ltype == "script" )return FILETYPE_SCRIPT;else if ( ltype == "text" )return FILETYPE_TEXT;else if ( ltype == "readme" )return FILETYPE_README;else if ( ltype == "map" )return FILETYPE_MAP;else if ( ltype == "mod" )return FILETYPE_MOD;else if ( ltype == "uninstall" )return FILETYPE_UNINSTALL;else if ( ltype == "sound" )return FILETYPE_SOUND;else if ( ltype == "extra" )return FILETYPE_EXTRA;else if ( ltype == "screen" )return FILETYPE_SCREEN;else if ( ltype == "advert" )return FILETYPE_ADVERT;else if ( ltype == "mission" )return FILETYPE_MISSION;else if ( ltype == "backup" )return FILETYPE_BACKUP;else if ( ltype == "shipother" )return FILETYPE_SHIPOTHER;else if ( ltype == "shipmodel" )return FILETYPE_SHIPMODEL;else if ( ltype == "shipscene" )return FILETYPE_SHIPSCENE;else if ( ltype == "cockpitscene" )return FILETYPE_COCKPITSCENE;return -1;}CyString FormatErrorString(int error, CyString rest){int max = 0;CyString *args = 0;if ( !rest.Empty() )args = rest.SplitToken('~', &max);CyString errorStr;switch ( error ){case SPKINSTALL_CREATEDIRECTORY:errorStr = "Creating Directory: %1";break;case SPKINSTALL_CREATEDIRECTORY_FAIL:errorStr = "Unable to Creating Directory: %1";break;case SPKINSTALL_WRITEFILE:errorStr = "Writing File: %1";break;case SPKINSTALL_WRITEFILE_FAIL:errorStr = "Unable to Write File: %1";break;case SPKINSTALL_DELETEFILE:errorStr = "Deleting File: %1";break;case SPKINSTALL_DELETEFILE_FAIL:errorStr = "Unable to delete File: %1";break;case SPKINSTALL_REMOVEDIR:errorStr = "Removing Directory: %1";break;case SPKINSTALL_SKIPFILE:errorStr = "Skipping File (older): %1";break;case SPKINSTALL_ENABLEFILE:errorStr = "Enabled File: %1";break;case SPKINSTALL_DISABLEFILE:errorStr = "Disabled File: %1";break;case SPKINSTALL_ENABLEFILE_FAIL:errorStr = "Failed to enable File: %1";break;case SPKINSTALL_DISABLEFILE_FAIL:errorStr = "Failed to disable File: %1";break;case SPKINSTALL_UNINSTALL_MOVE:errorStr = "Moving uninstall file: %1";break;case SPKINSTALL_UNINSTALL_MOVE_FAIL:errorStr = "Unable to Move uninstall file: %1";break;case SPKINSTALL_UNINSTALL_COPY:errorStr = "Coping uninstall file: %1";break;case SPKINSTALL_UNINSTALL_COPY_FAIL:errorStr = "Unable to Copy uninstall file: %1";break;case SPKINSTALL_UNINSTALL_REMOVE:errorStr = "Removing Uninstall file: %1";break;case SPKINSTALL_UNINSTALL_REMOVE_FAIL:errorStr = "Unable to remove Uninstall file: %1";break;case SPKINSTALL_SHARED:errorStr = "Removing Unused Shared file: %1";break;case SPKINSTALL_SHARED_FAIL:errorStr = "Unable to remove Unused Shared file: %1";break;case SPKINSTALL_ORIGINAL_BACKUP:errorStr = "Backing up original file: %1";break;case SPKINSTALL_ORIGINAL_BACKUP_FAIL:errorStr = "Unable to back up original file: %1";break;case SPKINSTALL_ORIGINAL_RESTORE:errorStr = "Restoring original file: %1";break;case SPKINSTALL_ORIGINAL_RESTORE_FAIL:errorStr = "Unable to restore original file: %1";break;case SPKINSTALL_FAKEPATCH:errorStr = "Shifted fake patch: %1 to %2";break;case SPKINSTALL_FAKEPATCH_FAIL:errorStr = "Unable to shift fake patch: %1 to %2";break;case SPKINSTALL_AUTOTEXT:errorStr = "Shifted text file: %1 to %2";break;case SPKINSTALL_AUTOTEXT_FAIL:errorStr = "Unable to shift text file: %1 to %2";break;case SPKINSTALL_MISSINGFILE:errorStr = "File is missing: %1";break;case SPKINSTALL_ORPHANED:errorStr = "Orphaned File removed: %1";break;case SPKINSTALL_ORPHANED_FAIL:errorStr = "Unable to remove Orphaned File: %1";break;}CyString ret = errorStr.Args(args, max);CLEANSPLIT(args, max)return ret;}bool C_File::CheckPCK (){if ( (m_sData) && (m_lDataSize) && (m_iDataCompression == SPKCOMPRESS_NONE) )return IsDataPCK ( m_sData, m_lDataSize );CyString filename = GetFilePointer();if ( !filename.Empty() ){FILE *id = fopen ( filename.c_str(), "rb+" );if ( id ){unsigned char data[3];fread ( data, sizeof(unsigned char), 3, id );fclose ( id );return IsDataPCK ( data, 3 );}}if ( CheckFileExt("pck") || CheckFileExt("pbb") || CheckFileExt("pbd") )return true;return false;}bool C_File::PCKFile(){if ( !m_lDataSize || !m_sData ){if ( !this->ReadFromFile() )return false;}if ( m_lDataSize && m_sData ){if ( !this->UncompressData() )return false;size_t size;unsigned char *data = PCKData(m_sData, m_lDataSize, &size);if ( data && size ){this->DeleteData();m_lUncomprDataSize = m_lDataSize;m_bUsedMalloc = false;m_lDataSize = (long)size;m_sData = new unsigned char[size];memcpy(m_sData, data, size);delete [] data;}return true;}return false;}unsigned char *C_File::UnPCKFile ( size_t *len ){unsigned char *data = NULL;size_t datasize = 0;if ( CheckValidFilePointer() ){FILE *id = fopen ( GetFilePointer().c_str(), "rb+" );if ( id ){fseek ( id, 0, SEEK_END );datasize = ftell ( id );rewind ( id );data = new unsigned char[datasize];fread ( data, sizeof(unsigned char), datasize, id );fclose ( id );}}if ( !data ){if ( !m_lDataSize ){if ( !this->ReadFromFile() )return NULL;}datasize = m_lDataSize;data = new unsigned char[datasize];memcpy ( data, m_sData, datasize );}if ( data ){unsigned char *newdata = UnPCKData ( data, datasize, len, CheckPCK() );delete data;return newdata;}return NULL;}bool C_File::UnPCKFile(){if ( !m_lDataSize || !m_sData ){if ( !this->ReadFromFile() )return false;}if ( m_lDataSize && m_sData ){if ( !this->UncompressData() )return false;size_t size;unsigned char *data = UnPCKData(m_sData, m_lDataSize, &size, CheckPCK());if ( data && size ){this->DeleteData();m_lUncomprDataSize = m_lDataSize;m_bUsedMalloc = false;m_sData = new unsigned char[size];memcpy(m_sData, data, size);m_lDataSize = (long)size;delete []data;}return true;}return false;}unsigned char *UnPCKFile ( const char *file, size_t *len, bool nocrypt ){FILE *id = fopen ( file, "rb" );if ( !id )return NULL;fseek ( id, 0, SEEK_END );size_t size = ftell ( id );fseek ( id, 0, SEEK_SET );unsigned char *data = new unsigned char[size];fread ( data, sizeof(unsigned char), size, id );if ( ferror(id) ){delete data;data = NULL;}fclose ( id );if ( data ){unsigned char *unData = UnPCKData ( data, size, len, nocrypt );delete data;return unData;}return NULL;}unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len ) { return UnPCKData(data, datasize, len, IsDataPCK(data, datasize)); }unsigned char *UnPCKData ( unsigned char *data, size_t datasize, size_t *len, bool nocrypt ){//IsDataPCK(data, datasize)if ( nocrypt ){unsigned char magic = data[0] ^ 0xC8;for ( size_t i = 1; i < datasize; i++ )data[i] ^= magic;++data;--datasize;}// create data buffersize_t *uncomprLenSize = (size_t*)(data + (datasize - 4));unsigned long uncomprLen = (unsigned long)*uncomprLenSize;if ( uncomprLen > (datasize * 100) ){*len = 0;return NULL;}unsigned char *uncompr = new unsigned char[uncomprLen];if ( !uncompr )return NULL;memset ( uncompr, 0, sizeof(uncompr) );// find header sizeunsigned char *buf = data + PCKHEADERSIZE;// buf = data + (6 + sizeof(time_t));char flag = data[3];if ( flag & GZ_FLAG_EXTRA ){size_t xlen = *((short int*)(buf));buf += xlen;}if ( flag & GZ_FLAG_FILENAME ){char *origname = (char*)(buf);buf += strlen (origname) + 1;}if ( flag & GZ_FLAG_COMMENT ){char *comment = (char*)(buf);buf += strlen(comment) + 1;}if ( flag & GZ_FLAG_HCRC )buf += 2;long bufSize = (long)(datasize - (buf-data) - 8);int err = uncompress2 ( uncompr, &uncomprLen, buf, bufSize );if ( err != Z_OK ){delete uncompr;*len = 0;return NULL;}*len = uncomprLen;uncompr[uncomprLen - 1] = '\0';return uncompr;}bool IsDataPCK ( const unsigned char *data, size_t size ){if ( size >=3 ){unsigned char magic=data[0] ^ 0xC8;return ((data[1] ^ magic)==0x1F && (data[2] ^ magic)==0x8B);}elsereturn false;}bool ReadSignedFromData ( unsigned char *data, long size ){if ( IsDataPCK ( data, size ) ){size_t unpckSize = 0;unsigned char *unpckData = UnPCKData ( data, size, &unpckSize, false );if ( (unpckData) && (unpckSize) )return ReadSignedFromData ( unpckData, (long)unpckSize );return false;}// work backwardsint pos = size - 1;// find the first tagewhile ( pos > 0 ){while ( data[pos] != '>' && pos > 0 )pos--;char tag[100];bool checked = false;if ( data[pos] == '>' ){int pos2 = pos - 1;// now find the frontwhile ( data[pos2] != '<' && pos2 > 0 )pos2--;// now get the tagif ( data[pos2] == '<' ){checked = true;memcpy(tag, data + pos2, pos - pos2);tag[pos - pos2] = '\0';// check if tag is signedCyString sTag(tag);if ( sTag.Compare("</signature") || sTag.Compare("<signature") )return true;// check if tag is codearrayif ( sTag.Compare("</codearray") || sTag.Compare("<codearray") )return false;pos = pos2;}--pos;}if ( !checked )break;}return false;}int ReadScriptVersionFromData ( unsigned char *data, long size ){if ( IsDataPCK ( data, size ) ){size_t unpckSize = 0;unsigned char *unpckData = UnPCKData ( data, size, &unpckSize );if ( (unpckData) && (unpckSize) )return ReadScriptVersionFromData ( unpckData, (long)unpckSize );return 0;}int pos = 0;bool found = false;int iVersion = 0;// skip past initial spacewhile ( !found ){while ( (pos < size) && (data[pos] == ' ') )++pos;if ( data[pos] == '<' ){CyString checktag;while ( (pos < size) && (data[pos] != '>') ){checktag += (char)data[pos];++pos;}++pos;if ( checktag == "<version" ){CyString version;while ( (pos < size) && (data[pos] != '<') ){version += (char)data[pos];++pos;}iVersion = version.ToInt();found = true;break;}}if ( found )break;// skip to next linewhile ( (pos < size) && (data[pos] != '\n') )++pos;++pos;if ( pos >= size )break;}return iVersion;}CyString C_File::GetBaseName (){// remove any directoryCyString file = m_sName.GetToken ( "/", m_sName.NumToken ( '/' ) );// remove file extensionfile = file.GetToken ( ".", 1, file.NumToken ( '.' ) - 1 );return file;}void C_File::CopyData(C_File *oldFile, bool includeData){SetFilename(oldFile->GetFullFilename());m_sDir = oldFile->GetDir();m_tTime = oldFile->GetCreationTime();m_bShared = oldFile->IsShared();m_bSigned = oldFile->IsSigned();m_iFileType = oldFile->GetFileType();m_lSize = oldFile->GetSize();if ( includeData ){m_lDataSize = oldFile->GetDataSize();if ( m_sData )this->DeleteData();m_sData = NULL;if ( oldFile->GetData() && m_lDataSize ){m_sData = new unsigned char[m_lDataSize];m_bUsedMalloc = false;memcpy((char *)m_sData, (char *)oldFile->GetData(), m_lDataSize);}m_lUncomprDataSize = oldFile->GetUncompressedDataSize();}m_iDataCompression = oldFile->GetCompressionType();}float GetLibraryVersion() { return (float)LIBRARYVERSION; }float GetFileFormatVersion() { return (float)FILEVERSION; }CyString C_File::ChangeFileExt(CyString ext){m_sName = CFileIO(m_sName).ChangeFileExtension(ext);return m_sName;}bool C_File::CheckPackedExtension(){CyString ext = this->GetFileExt();if ( ext == "pck" )return true;else if ( ext == "pbb" )return true;else if ( ext == "pbd" )return true;return false;}bool C_File::BobDecompile(){bool bRes=false;CyStringList outData;outData.PushBack("// Converted by SPK Libraries\n");/*bob_with_errors *e=0;char *pszTime;char *name="";time_t tm=time(0);pszTime=ctime(&tm);pszTime[strlen(pszTime)-1]=0;clearErrors();os << "// Converted with x2bc from \"" << is.name() << "\" at " << pszTime << endl;if(settings->convert()==false)os << "// Raw mode - values are not converted" << endl;os << endl;*//*switch(m_sData[0]){case bob_dom_bob::hdr_begin:{bob_dom_bob *bob = new bob_dom_bob(NULL);//bRes=bob->load(is);//if(bRes) bRes=bob->toFile(os);delete bob;break;}case bob_dom_cut::hdr_begin:{bob_dom_cut *cut = new bob_dom_cut(NULL);//bRes=cut->convert(is, os);delete cut;break;}default:return false;}if(e){for(bob_with_errors::ErrorIterator &it=e->errors.begin(); it!=e->errors.end(); ++it){bob_error(it->severity, it->code, "%s->%s", name, it->text);}}return bRes;bob_dom_ibufferstream<unsigned char> is((const unsigned char *)m_sData, m_lDataSize);bob_dom_otextrealfile os;if(is.fail() || os.fail()) return false;bool bRes=doc.convert(is, os);*/return bRes;}bool C_File::BodCompile(){return true;}bool C_File::RenameScript(CyString baseName){if ( !m_sData || !m_lDataSize ){if ( !this->ReadFromFile() )return false;}// uncompress the fileif ( !this->UncompressData() )return false;// un pck the fileif ( this->CheckFileExt("pck") ){if ( !this->UnPCKFile() )return false;}// now we should have the raw dataCyString data((const char *)m_sData);data.Truncate(m_lDataSize);data = data.FindReplace(this->GetBaseName(), baseName);this->DeleteData();m_sData = new unsigned char[data.Length()];memcpy(m_sData, data.c_str(), data.Length());m_lDataSize = (long)data.Length();// repck the fileif ( this->CheckFileExt("pck") ){if ( !this->PCKFile() )return false;}return true;}