//============================================================================= // // File : kvi_packagefile.cpp // Created on Tue 26 Dec 2006 05:33:33 by Szymon Stefanek // // This file is part of the KVIrc IRC Client distribution // Copyright (C) 2006 Szymon Stefanek // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your opinion) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #define __KVILIB__ #include "kvi_packagefile.h" #include "kvi_file.h" #include "kvi_fileutils.h" #include "kvi_locale.h" #include "kvi_inttypes.h" #include #include #include #ifdef COMPILE_ZLIB_SUPPORT #include #endif // // A KVIrc Package File is basically a simple zip file with some additional meta-data. // The package file has the following format // // Field Type Bytes Description //------------------------------------------------------------------------------- // Package: // PackageHeader // PackageInfo // PackageData // PackageHeader: // Magic Bytes 4 'KVPF': Signature for the Kvirc Package File // Version uint32 4 0x00000001: Version of this package file // Flags uint32 4 0x00000000: Flags, in version 1 is reserved and must be zero // // PackageInfo: // InfoFieldCount uint32 4 Number of package info fields // InfoField InfoField Variable A list of informational name-value pairs // InfoField InfoField Variable A list of informational name-value pairs // InfoField InfoField Variable A list of informational name-value pairs // .... .... .... // PackageData: // DataField DataField Variable A list of data fields with format defined below // DataField DataField Variable A list of data fields with format defined below // DataField DataField Variable A list of data fields with format defined below // .... .... .... // InfoField: // Name UniString Variable The "name" element of the info field // ValueType uint32 4 The type of the following ValueData field // ValueData ValueData Variable // ValueData for ValueType 1 (string field) // Value UniString Variable The value element of type string of the the info field // ValueData for ValueType 2 (binary buffer field) // BufferLen uint32 4 The length of the binary buffer // BufferData Bytes Variable The data for the binary buffer // UniString: // StringLen uint32 4 The length of the string data in BYTES (null terminator NOT included) // StringData Bytes StringLen An utf8 encoded string (do NOT write the NULL terminator) // Bytes: // Byte uint8 1 A byte // Byte uint8 1 A byte // .... .... .... // DataField: // FieldType uint32 4 The type of the field, see below for defined values // FieldLen uint32 4 FieldData length in bytes (useful for skipping a field if unsupported) // FieldData Variable FieldLen The data of the field, see below for defined values // FieldData for FieldType 1 (file field) // Flags uint32 4 Bitmask. Bits: 1=FileIsDeflated // Path UniString Variable A relative path expressed as utf8 string. \ AND / are considered to be separators // Size uint32 4 Size of the following file data // FilePayload Bytes Variable // Everything is stored in LITTLE ENDIAN byte order. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Da Base Engine KviPackageIOEngine::KviPackageIOEngine() { m_pProgressDialog = 0; m_pStringInfoFields = new KviPointerHashTable(); m_pStringInfoFields->setAutoDelete(true); m_pBinaryInfoFields = new KviPointerHashTable(); m_pBinaryInfoFields->setAutoDelete(true); } KviPackageIOEngine::~KviPackageIOEngine() { if(m_pProgressDialog)delete m_pProgressDialog; delete m_pStringInfoFields; delete m_pBinaryInfoFields; } bool KviPackageIOEngine::updateProgress(int iProgress,const TQString &szLabel) { if(!m_pProgressDialog)return true; #ifdef COMPILE_USE_QT4 m_pProgressDialog->setValue(iProgress); #else m_pProgressDialog->setProgress(iProgress); #endif m_pProgressDialogLabel->setText(szLabel); tqApp->processEvents(); if(m_pProgressDialog->wasCanceled()) { setLastError(__tr2qs("Operation cancelled")); return false; } return true; } void KviPackageIOEngine::showProgressDialog(const TQString &szCaption,int iTotalSteps) { #ifdef COMPILE_USE_QT4 m_pProgressDialog = new TQProgressDialog(TQString(""),__tr2qs("Cancel"),0,iTotalSteps,0); m_pProgressDialog->setModal(true); m_pProgressDialog->setWindowTitle(szCaption); #else m_pProgressDialog = new TQProgressDialog(TQString(""),__tr2qs("Cancel"),iTotalSteps,0,"",true); m_pProgressDialog->setCaption(szCaption); #endif m_pProgressDialogLabel = new TQLabel(m_pProgressDialog); m_pProgressDialogLabel->setMaximumSize(500,300); m_pProgressDialog->setLabel(m_pProgressDialogLabel); } void KviPackageIOEngine::hideProgressDialog() { if(!m_pProgressDialog)return; delete m_pProgressDialog; m_pProgressDialog = 0; } bool KviPackageIOEngine::writeError() { setLastError(__tr2qs("File write error")); return false; } bool KviPackageIOEngine::readError() { setLastError(__tr2qs("File read error")); return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Da Writer KviPackageWriter::KviPackageWriter() : KviPackageIOEngine() { m_pDataFields = new KviPointerList(); m_pDataFields->setAutoDelete(true); } KviPackageWriter::~KviPackageWriter() { delete m_pDataFields; } void KviPackageWriter::addInfoField(const TQString &szName,const TQString &szValue) { m_pStringInfoFields->replace(szName,new TQString(szValue)); } void KviPackageWriter::addInfoField(const TQString &szName,TQByteArray * pValue) { m_pBinaryInfoFields->replace(szName,pValue); } bool KviPackageWriter::addFile(const TQString &szLocalFileName,const TQString &szTargetFileName,kvi_u32_t uAddFileFlags) { TQFileInfo fi(szLocalFileName); return addFileInternal(&fi,szLocalFileName,szTargetFileName,uAddFileFlags); } bool KviPackageWriter::addFileInternal(const TQFileInfo * fi,const TQString &szLocalFileName,const TQString &szTargetFileName,kvi_u32_t uAddFileFlags) { if(!(fi->isFile() && fi->isReadable())) return false; if(!(uAddFileFlags & FollowSymLinks)) { if(fi->isSymLink()) return true; // do NOT add a symlink } DataField * f = new DataField(); f->m_uType = KVI_PACKAGE_DATAFIELD_TYPE_FILE; f->m_bFileAllowCompression = !(uAddFileFlags & NoCompression); f->m_szFileLocalName = szLocalFileName; f->m_szFileTargetName = szTargetFileName; m_pDataFields->append(f); return true; } bool KviPackageWriter::addDirectory(const TQString &szLocalDirectoryName,const TQString &szTargetDirectoryPrefix,kvi_u32_t uAddFileFlags) { TQDir d(szLocalDirectoryName); #ifdef COMPILE_USE_QT4 TQDir::Filters iFlags; #else int iFlags; #endif iFlags = TQDir::Files | TQDir::Readable; if(!(uAddFileFlags & FollowSymLinks)) iFlags |= TQDir::NoSymLinks; // QT4SUX: Because the TQDir::entryInfoList() breaks really a lot of code by returning an object that behaves in a _totally_ different way.. it's also much slower #ifdef COMPILE_USE_QT4 int j; TQFileInfoList sl = d.entryInfoList(iFlags); for(j=0;jfileName(); #endif TQString szDFileName = szTargetDirectoryPrefix; KviTQString::ensureLastCharIs(szDFileName,TQChar(KVI_PATH_SEPARATOR_CHAR)); #ifdef COMPILE_USE_QT4 szDFileName += slowCopy.fileName(); if(!addFileInternal(&slowCopy,szSFileName,szDFileName,uAddFileFlags)) return false; #else szDFileName += fi->fileName(); if(!addFileInternal(fi,szSFileName,szDFileName,uAddFileFlags)) return false; #endif #ifndef COMPILE_USE_QT4 ++it; #endif } iFlags = TQDir::Dirs | TQDir::Readable; if(!(uAddFileFlags & FollowSymLinks)) iFlags |= TQDir::NoSymLinks; sl = d.entryInfoList(iFlags); #ifdef COMPILE_USE_QT4 for(j=0;jfileName(); #endif if(!KviTQString::equalCS(szDir,"..") && !KviTQString::equalCS(szDir,".")) { TQString szSDirName = szLocalDirectoryName; KviTQString::ensureLastCharIs(szSDirName,TQChar(KVI_PATH_SEPARATOR_CHAR)); szSDirName += szDir; TQString szDDirName = szTargetDirectoryPrefix; KviTQString::ensureLastCharIs(szDDirName,TQChar(KVI_PATH_SEPARATOR_CHAR)); szDDirName += szDir; if(!addDirectory(szSDirName,szDDirName,uAddFileFlags)) return false; } #ifndef COMPILE_USE_QT4 ++it2; #endif } return true; } #define BUFFER_SIZE 32768 bool KviPackageWriter::packFile(KviFile * pFile,DataField * pDataField) { TQString szProgressText; KviTQString::sprintf(szProgressText,__tr2qs("Packaging file %Q"),&(pDataField->m_szFileLocalName)); if(!updateProgress(m_iCurrentProgress,szProgressText)) return false; // aborted KviFile source(pDataField->m_szFileLocalName); if(!source.openForReading()) { setLastError(__tr2qs("Failed to open a source file for reading")); return false; } kvi_u32_t uSize = source.size(); // Flags #ifdef COMPILE_ZLIB_SUPPORT kvi_u32_t uFlags = pDataField->m_bFileAllowCompression ? (uSize > 64 ? KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE : 0) : 0; #else kvi_u32_t uFlags = 0; #endif if(!pFile->save(uFlags))return writeError(); KviTQCString szTargetFileName = KviTQString::toUtf8(pDataField->m_szFileTargetName); // Path if(!pFile->save(szTargetFileName))return writeError(); kvi_file_offset_t savedSizeOffset = pFile->pos(); // Size : will update it if compression is requested if(!pFile->save(uSize))return writeError(); pDataField->m_uWrittenFieldLength = 4 + 4 + 4 + szTargetFileName.length(); // sizeof(flags + uncompressed size + path len + path) // FilePayload #ifdef COMPILE_ZLIB_SUPPORT if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE) { unsigned char ibuffer[BUFFER_SIZE]; unsigned char obuffer[BUFFER_SIZE]; kvi_i32_t iReaded = source.readBlock((char *)ibuffer,BUFFER_SIZE); if(iReaded < 0) return readError(); z_stream zstr; zstr.zalloc = Z_NULL; zstr.zfree = Z_NULL; zstr.opaque = Z_NULL; zstr.next_in = ibuffer; zstr.avail_in = iReaded; zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; if(deflateInit(&zstr,9) != Z_OK) { setLastError(__tr2qs("Compression library initialization error")); return false; } while(iReaded > 0) { zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; if(deflate(&zstr,Z_NO_FLUSH) != Z_OK) { setLastError(__tr2qs("Compression library error")); return false; } if(zstr.avail_out < BUFFER_SIZE) { int iCompressed = zstr.next_out - obuffer; pDataField->m_uWrittenFieldLength += iCompressed; if(pFile->writeBlock((char *)obuffer,iCompressed) != iCompressed) { deflateEnd(&zstr); return writeError(); } } if(zstr.avail_in < BUFFER_SIZE) { int iDataToRead = BUFFER_SIZE - zstr.avail_in; if(iDataToRead < BUFFER_SIZE) { if(ibuffer != zstr.next_in) { // hum, there is still some data in the buffer to be readed // and it is not at the beginning...move it to the beginning of ibuffer memmove(ibuffer,zstr.next_in,zstr.avail_in); } } iReaded = source.readBlock((char *)(ibuffer + zstr.avail_in),iDataToRead); if(iReaded < 0) { deflateEnd(&zstr); return readError(); } zstr.avail_in += iReaded; zstr.next_in = ibuffer; if((zstr.total_in % 2000000) == 0) { TQString szTmp; KviTQString::sprintf(szTmp,TQString(" (%d of %d bytes)"),zstr.total_in,uSize); TQString szPrg = szProgressText + szTmp; if(!updateProgress(m_iCurrentProgress,szPrg)) return false; // aborted } } } // flush pending output zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; int ret; do { ret = deflate(&zstr,Z_FINISH); if((ret == Z_OK) || (ret == Z_STREAM_END)) { if(zstr.avail_out < BUFFER_SIZE) { int iCompressed = zstr.next_out - obuffer; pDataField->m_uWrittenFieldLength += iCompressed; if(pFile->writeBlock((char *)obuffer,iCompressed) != iCompressed) { deflateEnd(&zstr); return writeError(); } } else { deflateEnd(&zstr); setLastError(__tr2qs("Compression library internal error")); return false; } zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; } } while(ret == Z_OK); // store the compressed data size kvi_file_offset_t here = pFile->pos(); pFile->seek(savedSizeOffset); uSize = zstr.total_out; deflateEnd(&zstr); if(!pFile->save(uSize))return writeError(); if(ret != Z_STREAM_END) { setLastError(__tr2qs("Error while compressing a file stream")); return false; } pFile->seek(here); } else { #endif unsigned char buffer[BUFFER_SIZE]; int iTotalFileSize = 0; kvi_i32_t iReaded = source.readBlock((char *)buffer,BUFFER_SIZE); if(iReaded < 0) return readError(); while(iReaded > 0) { iTotalFileSize += iReaded; if((iTotalFileSize % 1000000) == 0) { TQString szTmp; KviTQString::sprintf(szTmp,TQString(" (%d of %d bytes)"),iTotalFileSize,uSize); TQString szPrg = szProgressText + szTmp; if(!updateProgress(m_iCurrentProgress,szPrg)) return false; // aborted } pDataField->m_uWrittenFieldLength += iReaded; if(pFile->writeBlock((char *)buffer,iReaded) != iReaded) return writeError(); iReaded = source.readBlock((char *)buffer,BUFFER_SIZE); } #ifdef COMPILE_ZLIB_SUPPORT } #endif source.close(); return true; } bool KviPackageWriter::pack(const TQString &szFileName,kvi_u32_t uPackFlags) { m_iCurrentProgress = 0; if(!(uPackFlags & NoProgressDialog)) { showProgressDialog(__tr2qs("Creating package..."),100); updateProgress(m_iCurrentProgress,__tr2qs("Writing package header")); } bool bRet = packInternal(szFileName,uPackFlags); hideProgressDialog(); return bRet; } bool KviPackageWriter::packInternal(const TQString &szFileName,kvi_u32_t uPackFlags) { KviFile f(szFileName); if(!f.openForWriting()) { setLastError(__tr2qs("Can't open file for writing")); return false; } // write the PackageHeader // Magic char magic[4]; magic[0] = 'K'; magic[1] = 'V'; magic[2] = 'P'; magic[3] = 'F'; if(f.writeBlock(magic,4) != 4)return writeError(); // Version kvi_u32_t uVersion = 0x1; if(!f.save(uVersion))return writeError(); // Flags kvi_u32_t uFlags = 0x0; if(!f.save(uFlags))return writeError(); // write PackageInfo // InfoFieldCount kvi_u32_t uCount = m_pStringInfoFields->count() + m_pBinaryInfoFields->count(); if(!f.save(uCount))return writeError(); m_iCurrentProgress = 5; if(!updateProgress(m_iCurrentProgress,__tr2qs("Writing informational fields"))) return false; // aborted // InfoFields (string) KviPointerHashTableIterator it(*m_pStringInfoFields); while(TQString * s = it.current()) { if(!f.save(it.currentKey()))return writeError(); kvi_u32_t uType = KVI_PACKAGE_INFOFIELD_TYPE_STRING; if(!f.save(uType))return writeError(); if(!f.save(*s))return writeError(); ++it; } // InfoFields (binary) KviPointerHashTableIterator it2(*m_pBinaryInfoFields); while(TQByteArray * b = it2.current()) { if(!f.save(it2.currentKey()))return writeError(); kvi_u32_t uType = KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER; if(!f.save(uType))return writeError(); if(!f.save(*b))return writeError(); ++it2; } m_iCurrentProgress = 10; if(!updateProgress(m_iCurrentProgress,__tr2qs("Writing package data"))) return false; // aborted // write PackageData int iIdx = 0; for(DataField * pDataField = m_pDataFields->first();pDataField;pDataField = m_pDataFields->next()) { kvi_u32_t uDataFieldType = pDataField->m_uType; if(!f.save(uDataFieldType))return writeError(); kvi_file_offset_t savedLenOffset = f.pos(); // here we will store the length of the field once it's written if(!f.save(uDataFieldType))return writeError(); m_iCurrentProgress = 10 + ((90 * iIdx) / m_pDataFields->count()); switch(pDataField->m_uType) { case KVI_PACKAGE_DATAFIELD_TYPE_FILE: if(!packFile(&f,pDataField)) return false; break; default: setLastError(__tr2qs("Internal error")); return false; break; } kvi_file_offset_t savedEndOffset = f.pos(); f.seek(savedLenOffset); if(!f.save(pDataField->m_uWrittenFieldLength)) return writeError(); f.seek(savedEndOffset); iIdx++; } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Da Reader KviPackageReader::KviPackageReader() : KviPackageIOEngine() { } KviPackageReader::~KviPackageReader() { } bool KviPackageReader::readHeaderInternal(KviFile * pFile,const TQString &szLocalFileName) { // read the PackageHeader // Magic char magic[4]; if(pFile->readBlock(magic,4) != 4)return readError(); if((magic[0] != 'K') || (magic[1] != 'V') || (magic[2] != 'P') || (magic[3] != 'F')) { setLastError(__tr2qs("The file specified is not a valid KVIrc package")); return false; } // Version kvi_u32_t uVersion; if(!pFile->load(uVersion))return readError(); if(uVersion != 0x1) { setLastError(__tr2qs("The package has an invalid version number, it might have been created by a newer KVIrc")); return false; } // Flags kvi_u32_t uFlags; if(!pFile->load(uFlags))return readError(); // we ignore them at the moment // read PackageInfo // InfoFieldCount kvi_u32_t uCount; if(!pFile->load(uCount))return writeError(); m_pStringInfoFields->clear(); m_pBinaryInfoFields->clear(); kvi_u32_t uIdx = 0; while(uIdx < uCount) { TQString szKey; if(!pFile->load(szKey))return readError(); kvi_u32_t uFieldType; if(!pFile->load(uFieldType))return readError(); switch(uFieldType) { case KVI_PACKAGE_INFOFIELD_TYPE_STRING: { TQString szValue; if(!pFile->load(szValue))return readError(); m_pStringInfoFields->replace(szKey,new TQString(szValue)); } break; case KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER: { TQByteArray * pbValue = new TQByteArray(); if(!pFile->load(*pbValue)) { delete pbValue; return readError(); } m_pBinaryInfoFields->replace(szKey,pbValue); } break; default: setLastError(__tr2qs("Invalid info field: the package is probably corrupt")); break; } uIdx++; } return true; } bool KviPackageReader::readHeader(const TQString &szLocalFileName) { KviFile f(szLocalFileName); if(!f.openForReading()) { setLastError(__tr2qs("Can't open file for reading")); return false; } return readHeaderInternal(&f,szLocalFileName); } bool KviPackageReader::unpackFile(KviFile * pFile,const TQString &szUnpackPath) { // Flags kvi_u32_t uFlags; if(!pFile->load(uFlags))return readError(); #ifndef COMPILE_ZLIB_SUPPORT if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE) { setLastError(__tr2qs("The package contains compressed data but this executable does not support compression")); return false; } #endif // Path TQString szPath; if(!pFile->load(szPath))return readError(); TQString szFileName = szUnpackPath; KviTQString::ensureLastCharIs(szFileName,TQChar(KVI_PATH_SEPARATOR_CHAR)); szFileName += szPath; // no attacks please :) szFileName.replace(TQString("..\\"),TQString("")); szFileName.replace(TQString("..//"),TQString("")); KviFileUtils::adjustFilePath(szFileName); int idx = KviTQString::findRev(szFileName,TQChar(KVI_PATH_SEPARATOR_CHAR)); if(idx != -1) { TQString szPrefixPath = szFileName.left(idx); if(!KviFileUtils::makeDir(szPrefixPath)) { setLastError(__tr2qs("Failed to create the target directory")); return false; } } KviFile dest(szFileName); if(!dest.openForWriting()) { setLastError(__tr2qs("Failed to open a source file for reading")); return false; } TQString szProgressText; KviTQString::sprintf(szProgressText,__tr2qs("Unpacking file %Q"),&szFileName); if(!updateProgress(pFile->pos(),szProgressText)) return false; // aborted // Size kvi_u32_t uSize; if(!pFile->load(uSize))return readError(); // FilePayload #ifdef COMPILE_ZLIB_SUPPORT if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE) { int iRemainingSize = uSize; unsigned char ibuffer[BUFFER_SIZE]; unsigned char obuffer[BUFFER_SIZE]; int iToRead = iRemainingSize; if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE; int iReaded = pFile->readBlock((char *)ibuffer,iToRead); iRemainingSize -= iReaded; z_stream zstr; zstr.zalloc = Z_NULL; zstr.zfree = Z_NULL; zstr.opaque = Z_NULL; zstr.next_in = ibuffer; zstr.avail_in = iReaded; zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; if(inflateInit(&zstr) != Z_OK) { setLastError(__tr2qs("Compression library initialization error")); return false; } while((iReaded > 0) && (iRemainingSize > 0)) { zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; if(inflate(&zstr,Z_NO_FLUSH) != Z_OK) { setLastError(__tr2qs("Compression library error")); return false; } if(zstr.avail_out < BUFFER_SIZE) { int iDecompressed = zstr.next_out - obuffer; if(dest.writeBlock((char *)obuffer,iDecompressed) != iDecompressed) { inflateEnd(&zstr); return writeError(); } } if(zstr.avail_in < BUFFER_SIZE) { int iDataToRead = BUFFER_SIZE - zstr.avail_in; if(iDataToRead < BUFFER_SIZE) { if(ibuffer != zstr.next_in) { // hum, there is still some data in the buffer to be readed // and it is not at the beginning...move it to the beginning of ibuffer memmove(ibuffer,zstr.next_in,zstr.avail_in); } } if(iDataToRead > iRemainingSize) iDataToRead = iRemainingSize; iReaded = pFile->readBlock((char *)(ibuffer + zstr.avail_in),iDataToRead); if(iReaded < 0) { inflateEnd(&zstr); return readError(); } iRemainingSize -= iReaded; zstr.avail_in += iReaded; zstr.next_in = ibuffer; if((zstr.total_in % 2000000) == 0) { TQString szTmp; KviTQString::sprintf(szTmp,TQString(" (%d of %d bytes)"),zstr.total_in,uSize); TQString szPrg = szProgressText + szTmp; if(!updateProgress(pFile->pos(),szPrg)) return false; // aborted } } } // flush pending output zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; int ret; do { ret = inflate(&zstr,Z_FINISH); if((ret == Z_OK) || (ret == Z_STREAM_END) || (ret == Z_BUF_ERROR)) { if(zstr.avail_out < BUFFER_SIZE) { int iDecompressed = zstr.next_out - obuffer; if(dest.writeBlock((char *)obuffer,iDecompressed) != iDecompressed) { inflateEnd(&zstr); return writeError(); } } /* else { THIS HAPPENS FOR ZERO SIZE FILES tqDebug("hum.... internal, rEWq (ret = %d) (avail_out = %d)",ret,zstr.avail_out); inflateEnd(&zstr); setLastError(__tr2qs("Compression library internal error")); return false; } */ zstr.next_out = obuffer; zstr.avail_out = BUFFER_SIZE; } } while((ret == Z_OK) || (ret == Z_BUF_ERROR)); inflateEnd(&zstr); if(ret != Z_STREAM_END) { setLastError(__tr2qs("Error in compressed file stream")); return false; } } else { #endif unsigned char buffer[BUFFER_SIZE]; int iTotalFileSize = 0; int iRemainingData = uSize; int iToRead = iRemainingData; if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE; int iReaded = 1; while((iReaded > 0) && (iToRead > 0)) { iReaded = pFile->readBlock((char *)buffer,iToRead); if(iReaded > 0) { iTotalFileSize += iReaded; iRemainingData -= iReaded; if((iTotalFileSize % 3000000) == 0) { TQString szTmp; KviTQString::sprintf(szTmp,TQString(" (%d of %d bytes)"),iTotalFileSize,uSize); TQString szPrg = szProgressText + szTmp; if(!updateProgress(pFile->pos(),szPrg)) return false; // aborted } if(dest.writeBlock((char *)buffer,iReaded) != iReaded) return writeError(); } int iToRead = iRemainingData; if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE; } #ifdef COMPILE_ZLIB_SUPPORT } #endif dest.close(); return true; } bool KviPackageReader::getStringInfoField(const TQString &szName,TQString &szBuffer) { TQString * pVal = m_pStringInfoFields->find(szName); if(!pVal)return false; szBuffer = *pVal; return true; } bool KviPackageReader::unpack(const TQString &szLocalFileName,const TQString &szUnpackPath,kvi_u32_t uUnpackFlags) { bool bRet = unpackInternal(szLocalFileName,szUnpackPath,uUnpackFlags); hideProgressDialog(); return bRet; } bool KviPackageReader::unpackInternal(const TQString &szLocalFileName,const TQString &szUnpackPath,kvi_u32_t uUnpackFlags) { KviFile f(szLocalFileName); if(!f.openForReading()) { setLastError(__tr2qs("Can't open file for reading")); return false; } kvi_file_offset_t size = f.size(); if(!(uUnpackFlags & NoProgressDialog)) { showProgressDialog(__tr2qs("Reading package..."),size); updateProgress(0,__tr2qs("Reading package header")); } if(!readHeaderInternal(&f,szLocalFileName)) return false; if(!updateProgress(f.pos(),__tr2qs("Reading package data"))) return false; // aborted while(!f.atEnd()) { // DataFieldType kvi_u32_t uDataFieldType; if(!f.load(uDataFieldType))return readError(); // DataFieldLen kvi_u32_t uDataFieldLen; if(!f.load(uDataFieldLen))return readError(); switch(uDataFieldType) { case KVI_PACKAGE_DATAFIELD_TYPE_FILE: if(!unpackFile(&f,szUnpackPath)) return false; break; default: setLastError(__tr2qs("Invalid data field: the package is probably corrupt")); return false; break; } } return true; }