Rev 317 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "CatFile.h"#include <time.h>#include "File.h"#include "DirIO.h"#include "logging/Log.h"CCatFile::CCatFile () : m_bCatChanged(false){m_iDataType = CATFILE_NONE;m_sData = NULL;m_lSize = 0;m_bCreate = false;_lFiles = new std::vector<SInCatFile *>;}CCatFile::~CCatFile (){m_fDatFile.close();m_fCatFile.close();if ( m_bCatChanged ) {WriteCatFile ();m_fCatFile.close();}_clearFiles();delete _lFiles;if ( m_sData ) delete []m_sData;}void CCatFile::_clearFiles(){for(auto itr = _lFiles->begin(); itr != _lFiles->end(); itr++){if ((*itr)->sData )delete [](*itr)->sData;delete (*itr);}_lFiles->clear();}bool CCatFile::IsAddonDir(const Utils::WString &dir){Utils::WString d = dir.findReplace(L"\\", L"/");d = d.token(L"/", 1);if (d.Compare(L"types"))return true;if (d.Compare(L"scripts"))return true;if (d.Compare(L"t"))return true;if (d.Compare(L"mov"))return true;if (d.Compare(L"loadscr"))return true;if (d.Compare(L"l"))return true;if ( d.Compare(L"maps") )return true;if ( d.Compare(L"director") )return true;if ( d.Compare(L"cutscenes") )return true;return false;}bool CCatFile::Opened(int error, bool allowCreate){if ( error == CATERR_NONE ) return true;if ( allowCreate && error == CATERR_CREATED ) return true;return false;}int CCatFile::open(const Utils::WString &sCatfile, const Utils::WString &addon, int readtype, bool create){Utils::WString catfile = sCatfile;m_bCreate = false;Utils::WString datfile;if ( !catfile.right(4).Compare(L".cat") ) {datfile = catfile + L".dat";catfile += L".cat";}else datfile = CFileIO(catfile).changeFileExtension(L"dat");if ( readtype == CATREAD_JUSTCONTENTS ) create = false;// first check if the dat file exists and opensbool created = false;if ( readtype != CATREAD_JUSTCONTENTS ) {if ( !CFileIO::Exists(datfile) ) {if ( create ) created = true;else return CATERR_NODATFILE;}}// now open the cat file to readCFileIO File(catfile);if ( !File.startRead() ) {if ( create ) created = true;else return CATERR_NOCATFILE;}if ( created ) {m_fCatFile.open(catfile);m_fDatFile.open(datfile);m_bCreate = true;return CATERR_CREATED;}// find the file sizeif ( !File.fileSize() ) {File.close();return CATERR_FILEEMPTY;}// size must be multiples of 5size_t size = File.fileSize() + ((File.fileSize() % 5) ? 5 - (File.fileSize() % 5) : 0);// read cat to buffertry {if ( m_sData ) delete [] m_sData;m_sData = new unsigned char[size + 1];}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"Memory Exception error, unable to alloc enough memory to store file data, %d (%hs)", size + 1, e.what());return CATERR_MALLOC;}m_lSize = size;try {File.read(m_sData, m_lSize);} catch (std::exception &e) {CLog::logf(CLog::Log_IO, 3, L"CCatFile::Open() unable to read from cat file, %hs", e.what());RemoveData ();File.close();return CATERR_READCAT;}m_sData[size] = 0;m_iDataType = CATFILE_READ;File.close();if ( readtype != CATREAD_CAT ) {if ( !DecryptData () ) return CATERR_DECRYPT;m_sData[File.fileSize()] = 0;readFiles ();}_sAddonDir = addon;m_fCatFile.open ( catfile );if ( readtype != CATREAD_JUSTCONTENTS ) {m_fDatFile.open ( datfile );// check the file size matchessize_t compare = 0;if ( m_fDatFile.startRead() ) {compare = m_fDatFile.fileSize();m_fDatFile.close();}if (!_lFiles->empty()){SInCatFile* c = _lFiles->back();if (c && (c->lSize + c->lOffset) != compare) {// return CATERR_MISMATCH;}}}if ( readtype >= CATREAD_DAT ) LoadDatFile ();return CATERR_NONE;}bool CCatFile::removeFile(const Utils::WString &file){if ( !_sAddonDir.empty() ) {SInCatFile *f = findData(_sAddonDir + L"\\" + file);if ( f )removeFile(f);}{SInCatFile *f = findData(L"addon\\" + file);if ( f )removeFile(f);}SInCatFile *f = findData(file);if ( !f ){m_iError = CATERR_NOFILE;return false;}return removeFile(f);}void CCatFile::LoadDatFile (){if ( m_fDatFile.NoFile() )return;if ( m_fDatFile.startRead() ){for(auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr){SInCatFile *c = *itr;if ( c->sData ) delete c->sData;try {c->sData = new unsigned char[c->lSize + 1];}catch (std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::LoadDatFile() unable to malloc data storage: %s, %d (%hs)", c->sFile.c_str(), c->lSize, e.what());continue;}try {m_fDatFile.read(c->sData, c->lSize);}catch(std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::LoadDatFile() unable to read file data: %s, %d (%hs)", c->sFile.c_str(), c->lSize, e.what());continue;}c->bDecrypted = false;this->DecryptDAT(c);}m_fDatFile.close();}}bool CCatFile::readFiles (){size_t offset = 0;std::vector<Utils::WString> lines;Utils::WString::FromString(m_sData).tokenise(L"\n", lines);_clearFiles();if (!lines.empty()) {size_t start = 1;_sReadFilename = lines[0];if ( _sReadFilename.token(L" ", -1).isNumber() ) {_sReadFilename.clear();start = 0;}for(size_t i = start; i < lines.size(); i++) {Utils::WString l = lines[i];if (!l.empty()){SInCatFile* catfile = new SInCatFile;catfile->lSize = static_cast<size_t>(l.token(L" ", -1).toLong());catfile->sFile = l.tokens(L" ", 1, -2);catfile->lOffset = offset;catfile->sData = 0;offset += catfile->lSize;_lFiles->push_back(catfile);}}}/*unsigned char *data = m_sData;int spacePos = -1;while ( m_sData[num] != '\0' ) {if ( m_sData[num] == '\n' ) {m_sData[num] = 0;if ( spacePos != -1 ){Utils::String file;int size = 0;m_sData[spacePos] = '\0';file = (char *)data;data = (m_sData + (spacePos + 1));if ( !Utils::String((char *)data).isNumber() )size = 0;elsesize = atoi((const char *)data);if ( size ){SInCatFile *catfile = new SInCatFile;catfile->lSize = size;catfile->sFile = file;catfile->lOffset = offset;catfile->sData = 0;offset += catfile->lSize;m_lFiles.push_back ( catfile );}}data = (m_sData + (num + 1));spacePos = -1;}else if ( m_sData[num] == ' ' )spacePos = num;++num;}*/return true;}bool CCatFile::DecryptData ( unsigned char *data, size_t size ){unsigned char cl=0xDB, dh=0xDC, dl=0xDD, ah=0xDE, ch=0xDF, al;unsigned char *ptr = data, *end = data + size;for ( ptr = data; ptr < end; ptr += 5){al=ch;ch+=5;*(ptr + 4) ^= al;al=ah;ah+=5;*(ptr + 3) ^= al;al=dl;dl+=5;*(ptr + 2) ^= al;al=dh;dh+=5;*(ptr + 1) ^= al;al=cl;cl+=5;*(ptr + 0) ^= al;}return true;}bool CCatFile::DecryptData (){if ( !DecryptData ( m_sData, m_lSize ) ) return false;m_iDataType = CATERR_DECRYPT;return true;}void CCatFile::RemoveData (){delete m_sData;m_sData = NULL;m_iDataType = CATFILE_NONE;m_lSize = 0;}bool CCatFile::readFileToData(const Utils::WString &filename){SInCatFile *c = findData(filename);return readFileToData(c);}bool CCatFile::readFileToData(SInCatFile *c){if ( !c ) return false;size_t size = 0;if ( !c->sData ) c->sData = readData ( c, &size );if ( c->sData ) return true;return false;}unsigned char *CCatFile::readData(SInCatFile *c, size_t *size){*size = c->lSize;if ( !c->sData ) {if ( m_fDatFile.startRead() ) {m_fDatFile.seek(c->lOffset);c->sData = m_fDatFile.read(c->lSize);c->bDecrypted = false;m_fDatFile.close();if ( !c->sData ) (*size) = 0;else {c->sData[c->lSize] = '\0';DecryptDAT(c);}}}return c->sData;}void CCatFile::DecryptDAT(SInCatFile *pFile){if ( pFile->bDecrypted ) return;pFile->bDecrypted = true;this->DecryptDAT(pFile->sData, pFile->lSize);}void CCatFile::DecryptDAT(unsigned char *buffer, size_t size){for(unsigned char *pos=buffer, *end=buffer + size; pos < end; pos++){*pos^=0x33;}}unsigned char *CCatFile::readData(const Utils::WString &filename, size_t *size){*size = 0;if ( !m_fDatFile.NoFile() ) {SInCatFile *c = findData(filename);if ( c ) return readData ( c, size );}return NULL;}unsigned char *CCatFile::UnpackFile ( SInCatFile *c, size_t *size){*size = 0;if ( !c )return NULL;this->DecryptDAT(c);int iFiletype = this->_checkFiletype(c->sData, 3);// plain fileif ( iFiletype == FILETYPE_PLAIN ) {*size = c->lSize;return c->sData;}//otherwise unpack it// if ( IsDataPCK ( (const unsigned char *)c->sData, c->lSize ) || forcepck )/*int iOffset = 0;if ( iFiletype == FILETYPE_PCK ) {iOffset = 1;for(size_t i=0; i < c->lSize; i++){c->sData[i] ^= magic;}}return UnPCKData ( c->sData + iOffset, c->lSize - iOffset, size );*/unsigned char *data = UnPCKData(c->sData, c->lSize, size, false);if ( !data ) data = UnPCKData(c->sData, c->lSize, size, true);return data;}bool CCatFile::removeFile(SInCatFile *f){if ( (m_bCreate) || (_lFiles->empty()) )return false;if ( !f )return false;int err = m_fDatFile.TruncateFile ( f->lOffset, f->lSize );if ( err == FILEERR_TOSMALL ){if ( (int)m_fDatFile.GetFilesize() > this->endOffset() )m_fDatFile.TruncateFile( this->endOffset(), m_fDatFile.GetFilesize() - this->endOffset() );}else if ( err != FILEERR_NONE )return false;// adjust the file positionssize_t iOffset = SIZE_MAX;for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr){SInCatFile *c = *itr;if (c == f) {iOffset = c->lOffset;}else if ( iOffset != SIZE_MAX ) {c->lOffset = iOffset;iOffset += c->lSize;}}// now just write the new cat fileauto findItr = std::find(_lFiles->begin(), _lFiles->end(), f);if (findItr != _lFiles->end())_lFiles->erase(findItr);m_bCatChanged = true;return true;}bool CCatFile::WriteCatFile (){if ( (m_bCreate) && (_lFiles->empty()) ) return false;Utils::WString cat = m_fDatFile.filename() + L"\n";for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr){SInCatFile *c = *itr;if ( !c ) continue;if ( c->sFile.empty() ) continue;Utils::WString str = c->sFile;cat += str.findReplace(L"/", L"\\").findReplace(L"\\\\", L"\\") + L" " + (long)c->lSize + L"\n";}if ( !cat.length() ) return false;Utils::String str = cat.toString();// make sure the len is in multiples of 5, otherwise decryptData could cause heap problemssize_t len = str.length() + ((str.length() % 5) ? 5 - (str.length() % 5) : 0);bool ret = false;try {unsigned char *data = new unsigned char[len + 1];memcpy(data, str.c_str(), str.length() * sizeof(unsigned char));for ( size_t i = len; i >= str.length(); i-- ) data[i] = '\0';this->DecryptData(data, len);bool ret = m_fCatFile.write(data, str.length());delete []data;}catch(std::exception &e) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::WriteCatFile() unable to malloc, %d (%hs)", len + 1, e.what());return false;}m_fCatFile.close();m_bCatChanged = false;return ret;}std::vector<SInCatFile *> *CCatFile::GetFiles() const{return _lFiles;}bool CCatFile::checkExtensionPck(const Utils::WString &filename) const{Utils::WString ext = CFileIO(filename).extension().lower();if ( ext == L"xml" )return true;else if ( ext == L"txt" )return true;else if ( ext == L"bob" )return true;else if ( ext == L"bod" )return true;return false;}bool CCatFile::CheckPackedExtension(const Utils::WString &sFilename){Utils::WString ext = CFileIO(sFilename).extension().lower();if ( ext == L"pck" )return true;else if ( ext == L"pbb" )return true;else if ( ext == L"pbd" )return true;return false;}Utils::WString CCatFile::PckChangeExtension(const Utils::WString &f){CFileIO fo ( f );Utils::WString ext = fo.extension ().lower();if (ext == L"txt")return fo.changeFileExtension(L"pck");else if (ext == L"xml")return fo.changeFileExtension(L"pck");else if ( ext == L"bob" )return fo.changeFileExtension(L"pbb");else if ( ext == L"bod" )return fo.changeFileExtension(L"pbd");return f;}bool CCatFile::appendFile(const Utils::WString &filename, const Utils::WString &sTo, bool pck, bool bXor, Utils::WString *sChangeTo){CLog::logf(CLog::Log_IO, 1, L"CCatFile::AppendFile() Adding file, %s, into cat file, %s::%s [PCK:%s XOR:%s]", filename.c_str(), this->m_fCatFile.filename().c_str(), sTo.c_str(), (pck) ? L"Yes" : L"No", (bXor) ? L"Yes" : L"No");if ( filename.isin (L"::" ) ) return writeFromCat(filename.token(L"::", 1), filename.token(L"::", 2));if ( (!m_bCreate) && (!m_fDatFile.exists ()) ) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() Cat File: %s, doesn't exist, quitting...", m_fCatFile.fullFilename().c_str());return false;}Utils::WString to = sTo;if ( !_sAddonDir.empty() && CCatFile::IsAddonDir(to) ) {CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() changing destination to included addon fir, %s => %s", to, _sAddonDir + L"/" + to);to = _sAddonDir + L"\\" + to;}// change the file extension and remove the file againif ( pck && checkExtensionPck(filename) ) {CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() changing file extension for packed file, %s => %s", to.c_str(), PckChangeExtension(to).c_str());to = PckChangeExtension(to);}if ( sChangeTo ) *sChangeTo = to;if ( !_lFiles->empty() ) {SInCatFile *checkf = findData(to);if ( checkf ) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() removing existing filechanging file extension for packed file, %s => %s", to.c_str(), PckChangeExtension(to).c_str());if ( !removeFile(checkf) ) {CLog::logf(CLog::Log_IO, 1, L"CCatFile::AppendFile() unable to remove existing file, quitting...");return false;}}}bool append = false;SInCatFile *f = new SInCatFile;f->sData = 0;f->lOffset = this->endOffset();bool dofile = true;if ( _lFiles->empty() ) {CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() no existing files found, wipeing the existing dat file");m_fDatFile.WipeFile();}CFileIO File(filename);if ( !File.startRead() ) {CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() unable to open file, %s, for reading", filename.c_str());return false;}CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() reading file data, %s:%d", filename.c_str(), File.fileSize());unsigned char *data = File.readAll();File.close();// check if we need to pack the fileint iFileType = this->_checkFiletype(data, 3);CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() preparing to append file data, Type=%d", iFileType);if ( iFileType == FILETYPE_PLAIN && CheckPackedExtension(to) ) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() plain text file needs to packed");size_t newsize = 0;unsigned char *newdata = PCKData(data, File.fileSize(), &newsize, bXor);CLog::logf(CLog::Log_IO, 1, L"CCatFile::AppendFile() file has been packed, %d => %d", File.fileSize(), newsize);f->lSize = newsize;CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() Decrypting data");this->DecryptDAT(newdata, f->lSize);CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() appending data to Dat file, Offset:%d", f->lOffset);append = m_fDatFile.AppendDataToPos ( (const char *)newdata, newsize, f->lOffset );delete [] newdata;}else {CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() Decrypting data");this->DecryptDAT(data, File.fileSize());f->lSize = File.fileSize();CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() appending data to Dat file, Offset:%d", f->lOffset);append = m_fDatFile.AppendDataToPos ( (const char *)data, f->lSize, f->lOffset );}CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() cleaning up memory");delete [] data;m_fDatFile.close();if ( append ) {CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() append complete, adding file into cat list");m_bCreate = false;f->sFile = to;_lFiles->push_back(f);CLog::logf(CLog::Log_IO, 3, L"CCatFile::AppendFile() writing the new cat file");m_bCatChanged = true;}else {CLog::logf(CLog::Log_IO, 2, L"CCatFile::AppendFile() appending failed, cleaning up file data");delete f;}CLog::logf(CLog::Log_IO, 4, L"CCatFile::AppendFile() function complete");return append;}bool CCatFile::addData(const Utils::WString &catfile, unsigned char *data, size_t size, const Utils::WString &to, bool pck, bool create){int err = open(catfile, L"", CATREAD_CATDECRYPT, create);if ( (err != CATERR_NONE) && (err != CATERR_CREATED) )return false;return appendData(data, size, to, pck);}size_t CCatFile::endOffset() const{if ( _lFiles->empty() )return 0;else {return _lFiles->back()->lOffset + _lFiles->back()->lSize;}}size_t CCatFile::GetNumFiles() const{return _lFiles->size();}SInCatFile *CCatFile::GetFile(size_t num) const{return (num >= 0 && num < _lFiles->size()) ? _lFiles->at(num) : NULL;}bool CCatFile::appendData(unsigned char *data, size_t size, const Utils::WString &aTo, bool pck, bool bXor){if ( (!m_bCreate) && (!m_fCatFile.exists ()) )return false;if ( (size <= 0) || (!data) )return false;Utils::WString to = aTo;// then check if the file already existsif ( !_lFiles->empty() ){SInCatFile *f = findData(to);if ( f ){if (!removeFile ( f ))return false;}}bool append = false;if (_lFiles->empty())m_fDatFile.WipeFile();SInCatFile *f = new SInCatFile;f->sData = 0;if (_lFiles->empty())f->lOffset = 0;elsef->lOffset = m_fDatFile.GetFilesize();// if file extension is packed but not the file, then pack it, "pck" forces it to be packed unless it already isf->lSize = size;if ( (((pck) && (checkExtensionPck (to))) || ((CheckPackedExtension (to)))) && (!IsDataPCK ( data, size )) ){to = PckChangeExtension ( to );if (!_lFiles->empty()){SInCatFile *f = findData(to);if ( f ){if (!removeFile(f))return false;}}size_t newsize = 0;unsigned char *d = PCKData ( data, size, &newsize, bXor );f->lSize = newsize;this->DecryptDAT(d, newsize);append = m_fDatFile.AppendDataToPos ( (const char *)d, newsize, f->lOffset );delete [] d;}else {this->DecryptDAT(data, size);append = m_fDatFile.AppendDataToPos ( (const char *)data, size, f->lOffset );}m_fDatFile.close();if ( append ) {m_bCreate = false;f->sFile = to;_lFiles->push_back(f);m_bCatChanged = true;}elsedelete f;return true;}Utils::WString CCatFile::RenameFileExtension(SInCatFile *f){CFileIO fo(f->sFile);Utils::WString ext = fo.extension().lower();if ( ext == L"pck" ){Utils::WString firstDir = f->sFile.findReplace(L"/", L"\\").token(L"\\", 1).lower();if ( firstDir == L"t" )return fo.changeFileExtension(L"xml");else if ( firstDir == L"director" )return fo.changeFileExtension(L"xml");return fo.changeFileExtension(L"txt");}else if ( ext == L"pbb" )return fo.changeFileExtension(L"bob");else if ( ext == L"pbd" )return fo.changeFileExtension(L"bod");return f->sFile;}void CCatFile::findFiles(Utils::WStringList &files, const Utils::WString &filemask) const{if (_lFiles->empty())return;for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr){if (filemask.match((*itr)->sFile))files.pushBack((*itr)->sFile);}}bool CCatFile::extractAll(const Utils::WString &dir){if (_lFiles->empty())return false;for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr){if ( !extractFile(*itr, dir, true) )return false;}return true;}bool CCatFile::extractFile(const Utils::WString &filename, const Utils::WString &to, bool preserve){if (_lFiles->empty())return false;// check if file existsif ( !_sAddonDir.empty() ) {SInCatFile *f = findData(_sAddonDir + L"\\" + filename);if ( f )return extractFile(f, to, preserve);}{SInCatFile *f = findData(L"addon\\" + filename);if ( f )return extractFile(f, to, preserve);}SInCatFile *f = findData(filename);if ( !f ){m_iError = CATERR_NOFILE;return false;}return extractFile(f, to, preserve);}int CCatFile::_checkFiletype(const unsigned char *pBuffer, int iSize){if(iSize >= 3) {unsigned char magic = pBuffer[0] ^ 0xC8;if( (pBuffer[1] ^ magic) == 0x1F && (pBuffer[2] ^ magic) == 0x8B) {return FILETYPE_PCK;}}if ( iSize >= 2 && (pBuffer[0] == 0x1F && pBuffer[1] == 0x8B) ) {return FILETYPE_DEFLATE;}return FILETYPE_PLAIN;}bool CCatFile::extractFile(SInCatFile* f, const Utils::WString &to, bool preserve){unsigned char *data = 0;size_t size = 0;// load the data from filereadFileToData(f);data = this->UnpackFile(f, &size);if ( !data ) {m_iError = CATERR_CANTREAD;return false;}CFileIO fo(CCatFile::RenameFileExtension(f));// check for a file nameUtils::WString checkFile = to;Utils::WString todir, tofile = to;if ( checkFile.containsAny(L"\\/") ){checkFile = checkFile.findReplace (L"\\", L"/" );checkFile = checkFile.findReplace (L"//", L"/" );tofile = checkFile.token(L"/", checkFile.countToken(L"/"));if ( !checkFile.contains(L".") || preserve ){tofile = fo.filename();todir = checkFile;}else{todir = CFileIO(checkFile).dir();tofile = CFileIO(checkFile).filename();}}if ( tofile.empty() ){if ( !tofile.empty() )tofile += L"/";tofile += fo.filename();todir = CFileIO(tofile).dir();tofile = CFileIO(tofile).filename();}else if (CDirIO(tofile).isDir()){todir = tofile;tofile = fo.filename();}if ( preserve ){if ( !fo.dir().Compare(todir.right(- (int)fo.dir().length())) ){if ( !todir.empty() && todir.right(1) != L"/" )todir += L"/";todir += fo.dir();}}if ( tofile.empty() )tofile = fo.filename();bool bWritten = false;// create the directory to extract toif ( !todir.empty() && !CDirIO(todir).create() )m_iError = CATERR_CANTCREATEDIR;else{Utils::WString file = todir;if ( !file.empty() )file += L"/";file += tofile;file = file.findReplace(L"/", L"\\");file = file.findReplace(L"\\\\", L"\\");CFileIO File(file);if ( !File.startWrite() ) m_iError = CATERR_INVALIDDEST;else bWritten = File.write(data, size);}delete data;f->sData = 0;if ( bWritten ) this->clearError();return bWritten;}const Utils::WString &CCatFile::internalDatFilename() const{return _sReadFilename;}Utils::WString CCatFile::getErrorString () const{switch ( m_iError ){case CATERR_NONE:return Utils::WString::Null();case CATERR_NODATFILE:return L"Unable to open Dat file";case CATERR_NOCATFILE:return L"Unable to open Cat file";case CATERR_FILEEMPTY:return L"Cat file is empty";case CATERR_READCAT:return L"Unable to read from cat file";case CATERR_DECRYPT:return L"Unable to decrypt cat file";case CATERR_MISMATCH:return L"File size mismatch with Dat file";case CATERR_NOFILE:return L"Unable to find file in archive";case CATERR_CANTREAD:return L"Unable to read file in archive";case CATERR_CANTCREATEDIR:return L"Unable to create destiantion directory";case CATERR_INVALIDDEST:return L"Unable to write to destiantion file";}return L"Invalid";}unsigned char *CompressPCKData ( unsigned char *buffer, size_t size, size_t *retsize, time_t mtime ){size_t newsize = (size * 2) + 20;unsigned char *data = (unsigned char *)malloc ( sizeof(unsigned char) * newsize );z_stream zs;char flags=0;// error(0);unsigned char *d = data;// if(m_pszComment && strlen(m_pszComment) > 0) flags|=GZ_F_COMMENT;// if(m_pszFileName && strlen(m_pszFileName) > 0) flags|=GZ_F_FILENAME;int pos = PCKHEADERSIZE;*d = 0x1F; d++;*d = 0x8B; d++;*d = 8; d++;*d = flags; d++;memcpy(d, &mtime, sizeof(mtime));d += 4;*d = 0; d++;*d = 11; d++;// if(flags & GZ_F_FILENAME) put((const char *)m_pszFileName);// if(flags & GZ_F_COMMENT) put((const char *)m_pszComment);memset(&zs, 0, sizeof(zs));zs.next_in=buffer;zs.avail_in=(long)size;int ret;unsigned long ubound;ret=deflateInit2(&zs, 9, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY);if(ret!=Z_OK)return false;ubound=deflateBound(&zs, (unsigned long)size);if ( newsize < ubound){newsize += ubound;data = (unsigned char *)realloc ( data, sizeof(unsigned char) * newsize );if (!data)return nullptr;}zs.next_out=d;zs.avail_out=(unsigned int)newsize - pos;while((ret=deflate(&zs, Z_FINISH))==Z_OK){newsize += 1024;data = (unsigned char *)realloc ( data, sizeof(unsigned char) * newsize );if (!data)return nullptr;zs.next_out=data + zs.total_out;zs.avail_out=(unsigned int)newsize - zs.total_out;}pos += zs.total_out;deflateEnd(&zs);unsigned long crc=crc32(0, NULL, 0);crc=crc32(crc, buffer, (unsigned int)size);int s = sizeof(crc) + sizeof(size);if ( newsize < (size_t)(s + pos) ){newsize += (s + pos) - newsize;data = (unsigned char *)realloc ( data, sizeof(unsigned char) * newsize );if (!data)return nullptr;}unsigned long lSize = static_cast<unsigned long>(size);memcpy(&data[pos], &crc, sizeof(crc));pos += sizeof(crc);memcpy(&data[pos], &lSize, sizeof(lSize));pos += sizeof(lSize);newsize = pos;unsigned char *retdata = NULL;if ( ret == Z_STREAM_END ){*retsize = newsize;retdata = new unsigned char[newsize];memcpy ( retdata, data, newsize );}free ( data );return retdata;}unsigned char *PCKData ( unsigned char *data, size_t oldsize, size_t *newsize, bool bXor ){unsigned char *newdata = CompressPCKData ( data, oldsize, newsize, time(NULL) );if ( !bXor )return newdata;if ( newdata ){char magic = (char)clock(), m;m=magic ^ 0xC8;unsigned char *ptr = newdata, *end = newdata + *newsize;// XOR encryptionif ( bXor ){for ( ; ptr < end; ptr++ )(*ptr)^=magic;}unsigned char *finalData = new unsigned char[*newsize + 1];finalData[0] = m;memcpy ( finalData + 1, newdata, *newsize );delete [] newdata;(*newsize)++;return finalData;}return NULL;}bool CCatFile::writeFromCat(CCatFile *fcat, const Utils::WString &file){// now find the file in the cat fileSInCatFile *getfile = fcat->findData(file);if ( !getfile )return false;// read the dat from the cat filesize_t size = 0;unsigned char *data = fcat->readData ( getfile, &size );if ( !data )return false;// now check if it exists in this fileremoveFile(file);size_t offset = (_lFiles->empty()) ? 0 : (_lFiles->back()->lOffset + _lFiles->back()->lSize);// now write to the new fileif ( getfile->bDecrypted ) this->DecryptDAT(getfile->sData, getfile->lSize);getfile->bDecrypted = false;if ( !m_fDatFile.AppendDataToPos((const char *)getfile->sData, getfile->lSize, offset) ) return false;m_fDatFile.close();// finally add to the listSInCatFile *f = new SInCatFile;f->sData = 0;if (_lFiles->empty())f->lOffset = 0;elsef->lOffset = _lFiles->back()->lOffset + _lFiles->back()->lSize;f->sFile = file;f->lSize = size;_lFiles->push_back(f);m_bCatChanged = true;return true;}bool CCatFile::writeFromCat(const Utils::WString &catfile, const Utils::WString &file){CCatFile fcat;if ( fcat.open(catfile, L"", CATREAD_CATDECRYPT, false) )return false;return this->writeFromCat(&fcat, file);}SInCatFile *CCatFile::findData(const Utils::WString &filename) const{if (_lFiles->empty())return NULL;Utils::WString check = filename;check = check.findReplace(L"\\", L"/");for (auto itr = _lFiles->cbegin(); itr != _lFiles->cend(); ++itr){Utils::WString f = (*itr)->sFile;f = f.findReplace(L"\\", L"/");if (f.Compare(check))return *itr;}return NULL;}bool CCatFile::markRemoveFile(const Utils::WString &file){SInCatFile *f = findData(file);if ( !f ){m_iError = CATERR_NOFILE;return false;}return markRemoveFile(f);}bool CCatFile::markRemoveFile ( SInCatFile *f ){f->bDelete = true;return true;}