diff options
| author | 2010-12-29 05:32:48 +0000 | |
|---|---|---|
| committer | 2010-12-29 05:32:48 +0000 | |
| commit | f6d426be0e871770a0be51cca7f6fe5267591d5a (patch) | |
| tree | 8abd0c2bf2296b2a3400ea79e30dde212b7de3e6 | |
| parent | More renames, fix the spelling of KVIrc etc... (diff) | |
| download | KVIrc-f6d426be0e871770a0be51cca7f6fe5267591d5a.tar.gz KVIrc-f6d426be0e871770a0be51cca7f6fe5267591d5a.tar.bz2 KVIrc-f6d426be0e871770a0be51cca7f6fe5267591d5a.zip | |
More file splitting
git-svn-id: https://svn.kvirc.de/svn/trunk/kvirc@5255 17fca916-40b9-46aa-a4ea-0a15b648b75c
| -rw-r--r-- | src/kvilib/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageFile.cpp | 993 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageIOEngine.cpp | 162 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageIOEngine.h | 139 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageReader.cpp | 439 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageReader.h | 129 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageWriter.cpp | 465 | ||||
| -rw-r--r-- | src/kvilib/file/KviPackageWriter.h (renamed from src/kvilib/file/KviPackageFile.h) | 199 | ||||
| -rw-r--r-- | src/kvilib/irc/KviNickServRule.cpp | 80 | ||||
| -rw-r--r-- | src/kvilib/irc/KviNickServRule.h | 84 | ||||
| -rw-r--r-- | src/modules/addon/addonfunctions.cpp | 2 | ||||
| -rw-r--r-- | src/modules/addon/packaddondialog.cpp | 2 | ||||
| -rw-r--r-- | src/modules/theme/managementdialog.cpp | 2 | ||||
| -rw-r--r-- | src/modules/theme/packthemedialog.cpp | 2 | ||||
| -rw-r--r-- | src/modules/theme/savethemedialog.cpp | 2 | ||||
| -rw-r--r-- | src/modules/theme/themefunctions.cpp | 2 |
16 files changed, 1514 insertions, 1192 deletions
diff --git a/src/kvilib/CMakeLists.txt b/src/kvilib/CMakeLists.txt index 5201776f1..cc1438229 100644 --- a/src/kvilib/CMakeLists.txt +++ b/src/kvilib/CMakeLists.txt @@ -89,7 +89,9 @@ SET(kvilib_SRCS ext/KviStringConversion.cpp file/KviFile.cpp file/KviFileUtils.cpp - file/KviPackageFile.cpp + file/KviPackageIOEngine.cpp + file/KviPackageReader.cpp + file/KviPackageWriter.cpp irc/KviAvatar.cpp irc/KviAvatarCache.cpp irc/KviIdentityProfile.cpp diff --git a/src/kvilib/file/KviPackageFile.cpp b/src/kvilib/file/KviPackageFile.cpp deleted file mode 100644 index 7d897fea2..000000000 --- a/src/kvilib/file/KviPackageFile.cpp +++ /dev/null @@ -1,993 +0,0 @@ -//============================================================================= -// -// File : KviPackageFile.cpp -// Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek -// -// This file is part of the KVIrc IRC Client distribution -// Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net> -// -// 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. -// -//============================================================================= - -#include "KviPackageFile.h" - -#include "KviFile.h" -#include "KviFileUtils.h" -#include "KviLocale.h" -#include "kvi_inttypes.h" - -#include <QProgressDialog> -#include <QLabel> -#include <QDir> - -#ifdef COMPILE_ZLIB_SUPPORT - #include <zlib.h> -#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<QString,QString>(); - m_pStringInfoFields->setAutoDelete(true); - m_pBinaryInfoFields = new KviPointerHashTable<QString,QByteArray>(); - m_pBinaryInfoFields->setAutoDelete(true); -} - -KviPackageIOEngine::~KviPackageIOEngine() -{ - if(m_pProgressDialog)delete m_pProgressDialog; - delete m_pStringInfoFields; - delete m_pBinaryInfoFields; -} - -bool KviPackageIOEngine::updateProgress(int iProgress,const QString &szLabel) -{ - if(!m_pProgressDialog)return true; - - m_pProgressDialog->setValue(iProgress); - m_pProgressDialogLabel->setText(szLabel); - qApp->processEvents(); - if(m_pProgressDialog->wasCanceled()) - { - setLastError(__tr2qs("Operation cancelled")); - return false; - } - return true; -} - -void KviPackageIOEngine::showProgressDialog(const QString &szCaption,int iTotalSteps) -{ - m_pProgressDialog = new QProgressDialog(QString(""),__tr2qs("Cancel"),0,iTotalSteps,0); - m_pProgressDialog->setModal(true); - m_pProgressDialog->setWindowTitle(szCaption); - - m_pProgressDialogLabel = new QLabel(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<DataField>(); - m_pDataFields->setAutoDelete(true); -} - -KviPackageWriter::~KviPackageWriter() -{ - delete m_pDataFields; -} - -void KviPackageWriter::addInfoField(const QString &szName,const QString &szValue) -{ - m_pStringInfoFields->replace(szName,new QString(szValue)); -} - -void KviPackageWriter::addInfoField(const QString &szName,QByteArray * pValue) -{ - m_pBinaryInfoFields->replace(szName,pValue); -} - -bool KviPackageWriter::addFile(const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags) -{ - QFileInfo fi(szLocalFileName); - return addFileInternal(&fi,szLocalFileName,szTargetFileName,uAddFileFlags); -} - -bool KviPackageWriter::addFileInternal(const QFileInfo * fi,const QString &szLocalFileName,const QString &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 QString &szLocalDirectoryName,const QString &szTargetDirectoryPrefix,kvi_u32_t uAddFileFlags) -{ - QDir d(szLocalDirectoryName); - QDir::Filters iFlags; - - iFlags = QDir::Files | QDir::Readable; - if(!(uAddFileFlags & FollowSymLinks)) - iFlags |= QDir::NoSymLinks; - - int j; - QFileInfoList sl = d.entryInfoList(iFlags); - for(j=0;j<sl.size();j++) - { - QString szSFileName = szLocalDirectoryName; - KviQString::ensureLastCharIs(szSFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); - QFileInfo slowCopy = sl.at(j); - szSFileName += slowCopy.fileName(); - - QString szDFileName = szTargetDirectoryPrefix; - KviQString::ensureLastCharIs(szDFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); - szDFileName += slowCopy.fileName(); - if(!addFileInternal(&slowCopy,szSFileName,szDFileName,uAddFileFlags)) - return false; - } - iFlags = QDir::Dirs | QDir::Readable; - if(!(uAddFileFlags & FollowSymLinks)) - iFlags |= QDir::NoSymLinks; - sl = d.entryInfoList(iFlags); - - for(j=0;j<sl.size();j++) - { - QString szDir = sl.at(j).fileName(); - if(!KviQString::equalCS(szDir,"..") && !KviQString::equalCS(szDir,".")) - { - QString szSDirName = szLocalDirectoryName; - KviQString::ensureLastCharIs(szSDirName,QChar(KVI_PATH_SEPARATOR_CHAR)); - szSDirName += szDir; - QString szDDirName = szTargetDirectoryPrefix; - KviQString::ensureLastCharIs(szDDirName,QChar(KVI_PATH_SEPARATOR_CHAR)); - szDDirName += szDir; - if(!addDirectory(szSDirName,szDDirName,uAddFileFlags)) - return false; - } - } - return true; -} - -#define BUFFER_SIZE 32768 - -bool KviPackageWriter::packFile(KviFile * pFile,DataField * pDataField) -{ - QString szProgressText; - KviQString::sprintf(szProgressText,__tr2qs("Packaging file %Q"),&(pDataField->m_szFileLocalName)); - if(!updateProgress(m_iCurrentProgress,szProgressText)) - return false; // aborted - - - KviFile source(pDataField->m_szFileLocalName); - if(!source.open(QFile::ReadOnly)) - { - 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(); - - QByteArray szTargetFileName = KviQString::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.read((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->write((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.read((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) - { - QString szTmp; - KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),zstr.total_in,uSize); - QString 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->write((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.read((char *)buffer,BUFFER_SIZE); - if(iReaded < 0) - return readError(); - while(iReaded > 0) - { - iTotalFileSize += iReaded; - if((iTotalFileSize % 1000000) == 0) - { - QString szTmp; - KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),iTotalFileSize,uSize); - QString szPrg = szProgressText + szTmp; - if(!updateProgress(m_iCurrentProgress,szPrg)) - return false; // aborted - } - pDataField->m_uWrittenFieldLength += iReaded; - if(pFile->write((char *)buffer,iReaded) != iReaded) - return writeError(); - iReaded = source.read((char *)buffer,BUFFER_SIZE); - } -#ifdef COMPILE_ZLIB_SUPPORT - } -#endif - source.close(); - - return true; -} - -bool KviPackageWriter::pack(const QString &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 QString &szFileName,kvi_u32_t) -{ - - KviFile f(szFileName); - if(!f.open(QFile::WriteOnly | QFile::Truncate)) - { - 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.write(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<QString,QString> it(*m_pStringInfoFields); - while(QString * 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<QString,QByteArray> it2(*m_pBinaryInfoFields); - while(QByteArray * 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 QString &) -{ - // read the PackageHeader - - // Magic - char magic[4]; - - if(pFile->read(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) - { - QString 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: - { - QString szValue; - if(!pFile->load(szValue))return readError(); - m_pStringInfoFields->replace(szKey,new QString(szValue)); - } - break; - case KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER: - { - QByteArray * pbValue = new QByteArray(); - 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 QString &szLocalFileName) -{ - KviFile f(szLocalFileName); - if(!f.open(QFile::ReadOnly)) - { - setLastError(__tr2qs("Can't open file for reading")); - return false; - } - - return readHeaderInternal(&f,szLocalFileName); -} - -bool KviPackageReader::unpackFile(KviFile * pFile,const QString &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 - QString szPath; - if(!pFile->load(szPath)) - return readError(); - - QString szFileName = szUnpackPath; - KviQString::ensureLastCharIs(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); - - szFileName += szPath; - - // no attacks please :) - szFileName.replace(QString("..\\"),QString("")); - szFileName.replace(QString("..//"),QString("")); - - KviFileUtils::adjustFilePath(szFileName); - - int idx = KviQString::findRev(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); - if(idx != -1) - { - QString szPrefixPath = szFileName.left(idx); - if(!KviFileUtils::makeDir(szPrefixPath)) - { - setLastError(__tr2qs("Failed to create the target directory")); - return false; - } - } - - KviFile dest(szFileName); - if(!dest.open(QFile::WriteOnly | QFile::Truncate)) - { - setLastError(__tr2qs("Failed to open a source file for reading")); - return false; - } - - QString szProgressText; - KviQString::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->read((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.write((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->read((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) - { - QString szTmp; - KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),zstr.total_in,uSize); - QString 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.write((char *)obuffer,iDecompressed) != iDecompressed) - { - inflateEnd(&zstr); - return writeError(); - } - } else { - //THIS HAPPENS FOR ZERO SIZE FILES - qDebug("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->read((char *)buffer,iToRead); - if(iReaded > 0) - { - iTotalFileSize += iReaded; - iRemainingData -= iReaded; - - if((iTotalFileSize % 3000000) == 0) - { - QString szTmp; - KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),iTotalFileSize,uSize); - QString szPrg = szProgressText + szTmp; - if(!updateProgress(pFile->pos(),szPrg)) - return false; // aborted - } - - if(dest.write((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 QString &szName,QString &szBuffer) -{ - QString * pVal = m_pStringInfoFields->find(szName); - if(!pVal) - return false; - szBuffer = *pVal; - return true; -} - -bool KviPackageReader::unpack(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags) -{ - bool bRet = unpackInternal(szLocalFileName,szUnpackPath,uUnpackFlags); - hideProgressDialog(); - return bRet; -} - -bool KviPackageReader::unpackInternal(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags) -{ - - KviFile f(szLocalFileName); - if(!f.open(QFile::ReadOnly)) - { - 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; -} diff --git a/src/kvilib/file/KviPackageIOEngine.cpp b/src/kvilib/file/KviPackageIOEngine.cpp new file mode 100644 index 000000000..f36f3e564 --- /dev/null +++ b/src/kvilib/file/KviPackageIOEngine.cpp @@ -0,0 +1,162 @@ +//============================================================================= +// +// File : KviPackageIOEngine.cpp +// Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net> +// +// 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. +// +//============================================================================= + +#include "KviPackageIOEngine.h" +#include "KviLocale.h" + +#include <QProgressDialog> +#include <QLabel> + + +// +// 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<QString,QString>(); + m_pStringInfoFields->setAutoDelete(true); + m_pBinaryInfoFields = new KviPointerHashTable<QString,QByteArray>(); + m_pBinaryInfoFields->setAutoDelete(true); +} + +KviPackageIOEngine::~KviPackageIOEngine() +{ + if(m_pProgressDialog)delete m_pProgressDialog; + delete m_pStringInfoFields; + delete m_pBinaryInfoFields; +} + +bool KviPackageIOEngine::updateProgress(int iProgress,const QString &szLabel) +{ + if(!m_pProgressDialog)return true; + + m_pProgressDialog->setValue(iProgress); + m_pProgressDialogLabel->setText(szLabel); + qApp->processEvents(); + if(m_pProgressDialog->wasCanceled()) + { + setLastError(__tr2qs("Operation cancelled")); + return false; + } + return true; +} + +void KviPackageIOEngine::showProgressDialog(const QString &szCaption,int iTotalSteps) +{ + m_pProgressDialog = new QProgressDialog(QString(""),__tr2qs("Cancel"),0,iTotalSteps,0); + m_pProgressDialog->setModal(true); + m_pProgressDialog->setWindowTitle(szCaption); + + m_pProgressDialogLabel = new QLabel(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; +} + + diff --git a/src/kvilib/file/KviPackageIOEngine.h b/src/kvilib/file/KviPackageIOEngine.h new file mode 100644 index 000000000..c71f1930a --- /dev/null +++ b/src/kvilib/file/KviPackageIOEngine.h @@ -0,0 +1,139 @@ +#ifndef _KviPackageIOEngine_h_ +#define _KviPackageIOEngine_h_ +//============================================================================= +// +// File : KviPackageIOEngine.h +// Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net> +// +// 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. +// +//============================================================================= + +/** +* \file KviPackageIOEngine.h +* \author Szymon Stefanek +* \brief File packaging utilities +*/ + +#include "kvi_settings.h" + +#include "KviQString.h" +#include "KviPointerHashTable.h" + +#include <QObject> +#include <QByteArray> + +class QProgressDialog; +class QLabel; + + +#define KVI_PACKAGE_INFOFIELD_TYPE_STRING 1 +#define KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER 2 +#define KVI_PACKAGE_DATAFIELD_TYPE_FILE 1 +#define KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE 1 + +/** +* \class KviPackageIOEngine +* \brief This class is the base class engine to work with KVIrc package files. +*/ +class KVILIB_API KviPackageIOEngine +{ +public: + /** + * \brief Creates the I/O engine object + * \return KviPackageIOEngine + */ + KviPackageIOEngine(); + + /** + * \brief Destroys the object + */ + virtual ~KviPackageIOEngine(); +protected: + QString m_szLastError; + KviPointerHashTable<QString,QString> * m_pStringInfoFields; + KviPointerHashTable<QString,QByteArray> * m_pBinaryInfoFields; + QProgressDialog * m_pProgressDialog; + QLabel * m_pProgressDialogLabel; +public: + /** + * \brief Returns the last error + * \return const QString & + */ + const QString & lastError(){ return m_szLastError; }; + + /** + * \brief Sets the last error + * \param szLastError The string error + * \return void + */ + void setLastError(const QString & szLastError){ m_szLastError = szLastError; }; + + /** + * \brief Returns the string info fields + * \return KviPointerHashTable<QString,QString> * + */ + KviPointerHashTable<QString,QString> * stringInfoFields(){ return m_pStringInfoFields; }; + + /** + * \brief Returns the binary info fields + * \return KviPointerHashTable<QString,QByteArray> * + */ + KviPointerHashTable<QString,QByteArray> * binaryInfoFields(){ return m_pBinaryInfoFields; }; +protected: + /** + * \brief Shows the progress dialog + * \param szCaption The caption of the dialog window + * \param iTotalSteps The total number of steps + * \return void + */ + void showProgressDialog(const QString & szCaption, int iTotalSteps); + + /** + * \brief Hides the progress dialog + * \return void + */ + void hideProgressDialog(); + + /** + * \brief Updates the progress dialog + * \param iProgress The value in steps of the progress bar + * \param szLabel The label of the step + * \return bool + */ + bool updateProgress(int iProgress, const QString & szLabel); + + /** + * \brief Sets the last error as write error + * + * This is a shortcut to setLastError() + * \return bool + */ + bool writeError(); + + /** + * \brief Sets the last error as read error + * + * This is a shortcut to setLastError() + * \return bool + */ + bool readError(); +}; + + +#endif //_KviPackageIOEngine_h_ diff --git a/src/kvilib/file/KviPackageReader.cpp b/src/kvilib/file/KviPackageReader.cpp new file mode 100644 index 000000000..b0f8dcd98 --- /dev/null +++ b/src/kvilib/file/KviPackageReader.cpp @@ -0,0 +1,439 @@ +//============================================================================= +// +// File : KviPackageReader.cpp +// Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net> +// +// 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. +// +//============================================================================= + +#include "KviPackageReader.h" + +#include "KviFile.h" +#include "KviFileUtils.h" +#include "KviLocale.h" + +#include "kvi_inttypes.h" + +#ifdef COMPILE_ZLIB_SUPPORT + #include <zlib.h> +#endif + +// +// See KviPackageIOEngine.cpp for the description of the KVIrc package file +// + + +KviPackageReader::KviPackageReader() +: KviPackageIOEngine() +{ +} + +KviPackageReader::~KviPackageReader() +{ +} + +bool KviPackageReader::readHeaderInternal(KviFile * pFile,const QString &) +{ + // read the PackageHeader + + // Magic + char magic[4]; + + if(pFile->read(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) + { + QString 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: + { + QString szValue; + if(!pFile->load(szValue))return readError(); + m_pStringInfoFields->replace(szKey,new QString(szValue)); + } + break; + case KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER: + { + QByteArray * pbValue = new QByteArray(); + 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 QString &szLocalFileName) +{ + KviFile f(szLocalFileName); + if(!f.open(QFile::ReadOnly)) + { + setLastError(__tr2qs("Can't open file for reading")); + return false; + } + + return readHeaderInternal(&f,szLocalFileName); +} + +#define BUFFER_SIZE 32768 + + +bool KviPackageReader::unpackFile(KviFile * pFile,const QString &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 + QString szPath; + if(!pFile->load(szPath)) + return readError(); + + QString szFileName = szUnpackPath; + KviQString::ensureLastCharIs(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); + + szFileName += szPath; + + // no attacks please :) + szFileName.replace(QString("..\\"),QString("")); + szFileName.replace(QString("..//"),QString("")); + + KviFileUtils::adjustFilePath(szFileName); + + int idx = KviQString::findRev(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); + if(idx != -1) + { + QString szPrefixPath = szFileName.left(idx); + if(!KviFileUtils::makeDir(szPrefixPath)) + { + setLastError(__tr2qs("Failed to create the target directory")); + return false; + } + } + + KviFile dest(szFileName); + if(!dest.open(QFile::WriteOnly | QFile::Truncate)) + { + setLastError(__tr2qs("Failed to open a source file for reading")); + return false; + } + + QString szProgressText; + KviQString::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->read((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.write((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->read((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) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),zstr.total_in,uSize); + QString 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.write((char *)obuffer,iDecompressed) != iDecompressed) + { + inflateEnd(&zstr); + return writeError(); + } + } else { + //THIS HAPPENS FOR ZERO SIZE FILES + qDebug("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->read((char *)buffer,iToRead); + if(iReaded > 0) + { + iTotalFileSize += iReaded; + iRemainingData -= iReaded; + + if((iTotalFileSize % 3000000) == 0) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),iTotalFileSize,uSize); + QString szPrg = szProgressText + szTmp; + if(!updateProgress(pFile->pos(),szPrg)) + return false; // aborted + } + + if(dest.write((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 QString &szName,QString &szBuffer) +{ + QString * pVal = m_pStringInfoFields->find(szName); + if(!pVal) + return false; + szBuffer = *pVal; + return true; +} + +bool KviPackageReader::unpack(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags) +{ + bool bRet = unpackInternal(szLocalFileName,szUnpackPath,uUnpackFlags); + hideProgressDialog(); + return bRet; +} + +bool KviPackageReader::unpackInternal(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags) +{ + + KviFile f(szLocalFileName); + if(!f.open(QFile::ReadOnly)) + { + 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; +} + diff --git a/src/kvilib/file/KviPackageReader.h b/src/kvilib/file/KviPackageReader.h new file mode 100644 index 000000000..dbcaee85d --- /dev/null +++ b/src/kvilib/file/KviPackageReader.h @@ -0,0 +1,129 @@ +#ifndef _KviPackageReader_h_ +#define _KviPackageReader_h_ +//============================================================================= +// +// File : KviPackageReader.h +// Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net> +// +// 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. +// +//============================================================================= + +/** +* \file KviPackageReader.h +* \author Szymon Stefanek +* \brief File packaging utilities +*/ + +#include "kvi_settings.h" + +#include "KviQString.h" +#include "KviPackageIOEngine.h" + +class KviFile; + + + +/** +* \class KviPackageReader +* \brief This class is used to read KVIrc package files. +* +* You simply instantiate it and then call unpack(). +*/ +class KVILIB_API KviPackageReader : public KviPackageIOEngine +{ +public: + /** + * \brief Creates the package reader object + * \return KviPackageReader + */ + KviPackageReader(); + + /** + * \brief Destroys the object + */ + virtual ~KviPackageReader(); +public: + /** + * \enum UnpackFlags + */ + enum UnpackFlags { + NoProgressDialog = 1 /**< If you want to avoid the progress dialog */ + }; + + /** + * \brief Read the header of the package + * + * This is a shortcut to readHeaderInternal() + * \param szLocalFileName The source package + * \return bool + */ + bool readHeader(const QString & szLocalFileName); + + /** + * \brief Get the string info field contained in the package + * \param szName The name of the info field + * \param szBuffer The buffer where to store data + * \return bool + */ + bool getStringInfoField(const QString & szName, QString & szBuffer); + + /** + * \brief Unpack the KVIrc package file + * + * This is a shortcut to unpackInternal() hiding the progress dialog + * \param szLocalFileName The source package + * \param szUnpackPath The path where to unpack the package + * \param uUnpackFlags The flags to unpack + * \return bool + */ + bool unpack(const QString & szLocalFileName, const QString & szUnpackPath, kvi_u32_t uUnpackFlags = 0); +private: + /** + * \brief Unpack the KVIrc package file + * + * This is a shortcut to unpackFile() performing some checks + * \param szLocalFileName The source package + * \param szUnpackPath The path where to unpack the package + * \param uUnpackFlags The flags to unpack + * \return bool + */ + bool unpackInternal(const QString & szLocalFileName, const QString & szUnpackPath, kvi_u32_t uUnpackFlags = 0); + + /** + * \brief Unpack the KVIrc package file + * + * This is the real unpack() function. + * \param pFile The source file package + * \param szUnpackPath The path where to unpack the package + * \return bool + */ + bool unpackFile(KviFile * pFile, const QString & szUnpackPath); + + /** + * \brief Read the header of the package + * + * This is the real readHeader() function + * \param pFile The pointer to the real file + * \param szLocalFileName The source package + * \return bool + */ + bool readHeaderInternal(KviFile * pFile, const QString & szLocalFileName); +}; + +#endif //_KviPackageReader_h_ diff --git a/src/kvilib/file/KviPackageWriter.cpp b/src/kvilib/file/KviPackageWriter.cpp new file mode 100644 index 000000000..48fb1851e --- /dev/null +++ b/src/kvilib/file/KviPackageWriter.cpp @@ -0,0 +1,465 @@ +//============================================================================= +// +// File : KviPackageWriter.cpp +// Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek +// +// This file is part of the KVIrc IRC Client distribution +// Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net> +// +// 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. +// +//============================================================================= + +#include "KviPackageWriter.h" + +#include "KviFile.h" +#include "KviFileUtils.h" +#include "KviLocale.h" +#include "kvi_inttypes.h" + +#include <QDir> + +#ifdef COMPILE_ZLIB_SUPPORT + #include <zlib.h> +#endif + +// +// See KviPackageIOEngine.cpp for the description of the KVIrc package file +// + + +KviPackageWriter::KviPackageWriter() +: KviPackageIOEngine() +{ + m_pDataFields = new KviPointerList<DataField>(); + m_pDataFields->setAutoDelete(true); +} + +KviPackageWriter::~KviPackageWriter() +{ + delete m_pDataFields; +} + +void KviPackageWriter::addInfoField(const QString &szName,const QString &szValue) +{ + m_pStringInfoFields->replace(szName,new QString(szValue)); +} + +void KviPackageWriter::addInfoField(const QString &szName,QByteArray * pValue) +{ + m_pBinaryInfoFields->replace(szName,pValue); +} + +bool KviPackageWriter::addFile(const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags) +{ + QFileInfo fi(szLocalFileName); + return addFileInternal(&fi,szLocalFileName,szTargetFileName,uAddFileFlags); +} + +bool KviPackageWriter::addFileInternal(const QFileInfo * fi,const QString &szLocalFileName,const QString &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 QString &szLocalDirectoryName,const QString &szTargetDirectoryPrefix,kvi_u32_t uAddFileFlags) +{ + QDir d(szLocalDirectoryName); + QDir::Filters iFlags; + + iFlags = QDir::Files | QDir::Readable; + if(!(uAddFileFlags & FollowSymLinks)) + iFlags |= QDir::NoSymLinks; + + int j; + QFileInfoList sl = d.entryInfoList(iFlags); + for(j=0;j<sl.size();j++) + { + QString szSFileName = szLocalDirectoryName; + KviQString::ensureLastCharIs(szSFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); + QFileInfo slowCopy = sl.at(j); + szSFileName += slowCopy.fileName(); + + QString szDFileName = szTargetDirectoryPrefix; + KviQString::ensureLastCharIs(szDFileName,QChar(KVI_PATH_SEPARATOR_CHAR)); + szDFileName += slowCopy.fileName(); + if(!addFileInternal(&slowCopy,szSFileName,szDFileName,uAddFileFlags)) + return false; + } + iFlags = QDir::Dirs | QDir::Readable; + if(!(uAddFileFlags & FollowSymLinks)) + iFlags |= QDir::NoSymLinks; + sl = d.entryInfoList(iFlags); + + for(j=0;j<sl.size();j++) + { + QString szDir = sl.at(j).fileName(); + if(!KviQString::equalCS(szDir,"..") && !KviQString::equalCS(szDir,".")) + { + QString szSDirName = szLocalDirectoryName; + KviQString::ensureLastCharIs(szSDirName,QChar(KVI_PATH_SEPARATOR_CHAR)); + szSDirName += szDir; + QString szDDirName = szTargetDirectoryPrefix; + KviQString::ensureLastCharIs(szDDirName,QChar(KVI_PATH_SEPARATOR_CHAR)); + szDDirName += szDir; + if(!addDirectory(szSDirName,szDDirName,uAddFileFlags)) + return false; + } + } + return true; +} + +#define BUFFER_SIZE 32768 + +bool KviPackageWriter::packFile(KviFile * pFile,DataField * pDataField) +{ + QString szProgressText; + KviQString::sprintf(szProgressText,__tr2qs("Packaging file %Q"),&(pDataField->m_szFileLocalName)); + if(!updateProgress(m_iCurrentProgress,szProgressText)) + return false; // aborted + + + KviFile source(pDataField->m_szFileLocalName); + if(!source.open(QFile::ReadOnly)) + { + 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(); + + QByteArray szTargetFileName = KviQString::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.read((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->write((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.read((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) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),zstr.total_in,uSize); + QString 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->write((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.read((char *)buffer,BUFFER_SIZE); + if(iReaded < 0) + return readError(); + while(iReaded > 0) + { + iTotalFileSize += iReaded; + if((iTotalFileSize % 1000000) == 0) + { + QString szTmp; + KviQString::sprintf(szTmp,QString(" (%d of %d bytes)"),iTotalFileSize,uSize); + QString szPrg = szProgressText + szTmp; + if(!updateProgress(m_iCurrentProgress,szPrg)) + return false; // aborted + } + pDataField->m_uWrittenFieldLength += iReaded; + if(pFile->write((char *)buffer,iReaded) != iReaded) + return writeError(); + iReaded = source.read((char *)buffer,BUFFER_SIZE); + } +#ifdef COMPILE_ZLIB_SUPPORT + } +#endif + source.close(); + + return true; +} + +bool KviPackageWriter::pack(const QString &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 QString &szFileName,kvi_u32_t) +{ + + KviFile f(szFileName); + if(!f.open(QFile::WriteOnly | QFile::Truncate)) + { + 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.write(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<QString,QString> it(*m_pStringInfoFields); + while(QString * 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<QString,QByteArray> it2(*m_pBinaryInfoFields); + while(QByteArray * 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; +} + + diff --git a/src/kvilib/file/KviPackageFile.h b/src/kvilib/file/KviPackageWriter.h index a07a5275f..88fcf3cf4 100644 --- a/src/kvilib/file/KviPackageFile.h +++ b/src/kvilib/file/KviPackageWriter.h @@ -1,8 +1,8 @@ -#ifndef _KVI_PACKAGEFILE_H_ -#define _KVI_PACKAGEFILE_H_ +#ifndef _KviPackageWriter_h_ +#define _KviPackageWriter_h_ //============================================================================= // -// File : KviPackageFile.h +// File : KviPackageWriter.h // Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek // // This file is part of the KVIrc IRC Client distribution @@ -25,122 +25,22 @@ //============================================================================= /** -* \file KviPackageFile.h +* \file KviPackageWriter.h * \author Szymon Stefanek * \brief File packaging utilities -* -* \def KVI_PACKAGE_INFOFIELD_TYPE_STRING Defines the string type of the info field -* \def KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER Defines the binary type of the info field -* \def KVI_PACKAGE_DATAFIELD_TYPE_FILE Defines the file type of the data field -* \def KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE Defines the type of file compression of the data field */ #include "kvi_settings.h" + #include "KviQString.h" -#include "KviPointerHashTable.h" #include "KviPointerList.h" +#include "KviPackageIOEngine.h" -#include <QObject> #include <QByteArray> -class QProgressDialog; -class QLabel; class QFileInfo; class KviFile; -#define KVI_PACKAGE_INFOFIELD_TYPE_STRING 1 -#define KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER 2 -#define KVI_PACKAGE_DATAFIELD_TYPE_FILE 1 -#define KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE 1 - -/** -* \class KviPackageIOEngine -* \brief This class is the base class engine to work with KVIrc package files. -*/ -class KVILIB_API KviPackageIOEngine -{ -public: - /** - * \brief Creates the I/O engine object - * \return KviPackageIOEngine - */ - KviPackageIOEngine(); - - /** - * \brief Destroys the object - */ - virtual ~KviPackageIOEngine(); -protected: - QString m_szLastError; - KviPointerHashTable<QString,QString> * m_pStringInfoFields; - KviPointerHashTable<QString,QByteArray> * m_pBinaryInfoFields; - QProgressDialog * m_pProgressDialog; - QLabel * m_pProgressDialogLabel; -public: - /** - * \brief Returns the last error - * \return const QString & - */ - const QString & lastError(){ return m_szLastError; }; - - /** - * \brief Sets the last error - * \param szLastError The string error - * \return void - */ - void setLastError(const QString & szLastError){ m_szLastError = szLastError; }; - - /** - * \brief Returns the string info fields - * \return KviPointerHashTable<QString,QString> * - */ - KviPointerHashTable<QString,QString> * stringInfoFields(){ return m_pStringInfoFields; }; - - /** - * \brief Returns the binary info fields - * \return KviPointerHashTable<QString,QByteArray> * - */ - KviPointerHashTable<QString,QByteArray> * binaryInfoFields(){ return m_pBinaryInfoFields; }; -protected: - /** - * \brief Shows the progress dialog - * \param szCaption The caption of the dialog window - * \param iTotalSteps The total number of steps - * \return void - */ - void showProgressDialog(const QString & szCaption, int iTotalSteps); - - /** - * \brief Hides the progress dialog - * \return void - */ - void hideProgressDialog(); - - /** - * \brief Updates the progress dialog - * \param iProgress The value in steps of the progress bar - * \param szLabel The label of the step - * \return bool - */ - bool updateProgress(int iProgress, const QString & szLabel); - - /** - * \brief Sets the last error as write error - * - * This is a shortcut to setLastError() - * \return bool - */ - bool writeError(); - - /** - * \brief Sets the last error as read error - * - * This is a shortcut to setLastError() - * \return bool - */ - bool readError(); -}; - /** * \class KviPackageWriter * \brief This class is used to create KVIrc package files. @@ -281,91 +181,6 @@ private: bool addFileInternal(const QFileInfo * fi, const QString & szLocalFileName, const QString & szTargetFileName, kvi_u32_t uAddFileFlags = 0); }; -/** -* \class KviPackageReader -* \brief This class is used to read KVIrc package files. -* -* You simply instantiate it and then call unpack(). -*/ -class KVILIB_API KviPackageReader : public KviPackageIOEngine -{ -public: - /** - * \brief Creates the package reader object - * \return KviPackageReader - */ - KviPackageReader(); - /** - * \brief Destroys the object - */ - virtual ~KviPackageReader(); -public: - /** - * \enum UnpackFlags - */ - enum UnpackFlags { - NoProgressDialog = 1 /**< If you want to avoid the progress dialog */ - }; - - /** - * \brief Read the header of the package - * - * This is a shortcut to readHeaderInternal() - * \param szLocalFileName The source package - * \return bool - */ - bool readHeader(const QString & szLocalFileName); - - /** - * \brief Get the string info field contained in the package - * \param szName The name of the info field - * \param szBuffer The buffer where to store data - * \return bool - */ - bool getStringInfoField(const QString & szName, QString & szBuffer); - - /** - * \brief Unpack the KVIrc package file - * - * This is a shortcut to unpackInternal() hiding the progress dialog - * \param szLocalFileName The source package - * \param szUnpackPath The path where to unpack the package - * \param uUnpackFlags The flags to unpack - * \return bool - */ - bool unpack(const QString & szLocalFileName, const QString & szUnpackPath, kvi_u32_t uUnpackFlags = 0); -private: - /** - * \brief Unpack the KVIrc package file - * - * This is a shortcut to unpackFile() performing some checks - * \param szLocalFileName The source package - * \param szUnpackPath The path where to unpack the package - * \param uUnpackFlags The flags to unpack - * \return bool - */ - bool unpackInternal(const QString & szLocalFileName, const QString & szUnpackPath, kvi_u32_t uUnpackFlags = 0); - - /** - * \brief Unpack the KVIrc package file - * - * This is the real unpack() function. - * \param pFile The source file package - * \param szUnpackPath The path where to unpack the package - * \return bool - */ - bool unpackFile(KviFile * pFile, const QString & szUnpackPath); - - /** - * \brief Read the header of the package - * - * This is the real readHeader() function - * \param pFile The pointer to the real file - * \param szLocalFileName The source package - * \return bool - */ - bool readHeaderInternal(KviFile * pFile, const QString & szLocalFileName); -}; -#endif //_KVI_PACKAGEFILE_H_ +#endif //_KviPackageWriter_h_ diff --git a/src/kvilib/irc/KviNickServRule.cpp b/src/kvilib/irc/KviNickServRule.cpp new file mode 100644 index 000000000..69de08882 --- /dev/null +++ b/src/kvilib/irc/KviNickServRule.cpp @@ -0,0 +1,80 @@ +//============================================================================= +// +// File : KviNickServRule.cpp +// Creation date : Thu Aug 09 2001 17:44:56 by Szymon Stefanek +// +// This file is part of the KVIrc irc client distribution +// Copyright (C) 2001-2010 Szymon Stefanek (pragma at kvirc dot net) +// +// 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. +// +//============================================================================= + +#include "KviNickServRule.h" +#include "KviConfigurationFile.h" +#include "KviIrcMask.h" + +void KviNickServRule::copyFrom(const KviNickServRule &src) +{ + m_szRegisteredNick = src.m_szRegisteredNick; + m_szNickServMask = src.m_szNickServMask; + m_szMessageRegexp = src.m_szMessageRegexp; + m_szIdentifyCommand = src.m_szIdentifyCommand; + m_szServerMask = src.m_szServerMask; +} + +void KviNickServRule::save(KviConfigurationFile * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QRegisteredNick",&prefix); + cfg->writeEntry(tmp,m_szRegisteredNick); + KviQString::sprintf(tmp,"%QNickServMask",&prefix); + cfg->writeEntry(tmp,m_szNickServMask); + KviQString::sprintf(tmp,"%QMessageRegexp",&prefix); + cfg->writeEntry(tmp,m_szMessageRegexp); + KviQString::sprintf(tmp,"%QIdentifyCommand",&prefix); + cfg->writeEntry(tmp,m_szIdentifyCommand); + KviQString::sprintf(tmp,"%QServerMask",&prefix); + cfg->writeEntry(tmp,m_szServerMask); +} + +bool KviNickServRule::load(KviConfigurationFile * cfg,const QString &prefix) +{ + QString tmp; + KviQString::sprintf(tmp,"%QRegisteredNick",&prefix); + m_szRegisteredNick = KviQString::trimmed(cfg->readEntry(tmp)); + if(m_szRegisteredNick.isEmpty())return false; + KviQString::sprintf(tmp,"%QNickServMask",&prefix); + m_szNickServMask = cfg->readEntry(tmp); + if(m_szNickServMask.isEmpty())return false; + KviQString::sprintf(tmp,"%QServerMask",&prefix); + m_szServerMask = cfg->readEntry(tmp,QString()); + KviQString::sprintf(tmp,"%QMessageRegexp",&prefix); + m_szMessageRegexp = cfg->readEntry(tmp); + if(m_szMessageRegexp.isEmpty())return false; + KviQString::sprintf(tmp,"%QIdentifyCommand",&prefix); + m_szIdentifyCommand = cfg->readEntry(tmp); + return !m_szIdentifyCommand.isEmpty(); +} + +KviNickServRule * KviNickServRule::createInstance(const QString &szRegisteredNick, + const QString &szNickServMask, + const QString &szMessageRegexp, + const QString &szIdentifyCommand, + const QString &szServerMask) +{ + return new KviNickServRule(szRegisteredNick,szNickServMask,szMessageRegexp,szIdentifyCommand,szServerMask); +} + diff --git a/src/kvilib/irc/KviNickServRule.h b/src/kvilib/irc/KviNickServRule.h new file mode 100644 index 000000000..fb7f63182 --- /dev/null +++ b/src/kvilib/irc/KviNickServRule.h @@ -0,0 +1,84 @@ +#ifndef _KviNickServRule_h_ +#define _KviNickServRule_h_ +//============================================================================= +// +// File : KviNickServRule.h +// Creation date : Thu Aug 09 2001 16:43:56 by Szymon Stefanek +// +// This file is part of the KVIrc irc client distribution +// Copyright (C) 2001-2010 Szymon Stefanek (pragma at kvirc dot net) +// +// 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. +// +//============================================================================= + +#include "kvi_settings.h" + +#include "KviQString.h" +#include "KviHeapObject.h" + +class KviConfigurationFile; +class KviIrcMask; + +class KVILIB_API KviNickServRule : public KviHeapObject +{ +protected: + QString m_szRegisteredNick; // my registered nickname + QString m_szNickServMask; // the NickServ service mask + QString m_szMessageRegexp; // the NickServ message regexp + QString m_szIdentifyCommand; // the IDENTIFY command to send to server + QString m_szServerMask; // the mask that the server must match (not used in per-network rules) +public: + KviNickServRule() : KviHeapObject() {}; + KviNickServRule( + const QString &szRegisteredNick, + const QString &szNickServMask, + const QString &szMessageRegexp, + const QString &szIdentifyCommand, + const QString &szServerMask = QString::null) + : KviHeapObject(), + m_szRegisteredNick(szRegisteredNick), + m_szNickServMask(szNickServMask), + m_szMessageRegexp(szMessageRegexp), + m_szIdentifyCommand(szIdentifyCommand), + m_szServerMask(szServerMask) + {}; +public: + const QString & registeredNick() const { return m_szRegisteredNick; }; + const QString & nickServMask() const { return m_szNickServMask; }; + const QString & messageRegexp() const { return m_szMessageRegexp; }; + const QString & identifyCommand() const { return m_szIdentifyCommand; }; + const QString & serverMask() const { return m_szServerMask; }; + void setRegisteredNick(const QString &szRegisteredNick){ m_szRegisteredNick = szRegisteredNick; }; + void setNickServMask(const QString &szNickServMask){ m_szNickServMask = szNickServMask; }; + void setMessageRegexp(const QString &szMessageRegexp){ m_szMessageRegexp = szMessageRegexp; }; + void setIdentifyCommand(const QString &szIdentifyCommand){ m_szIdentifyCommand = szIdentifyCommand; }; + void setServerMask(const QString &szServerMask){ m_szServerMask = szServerMask; }; +public: + // avoid crashes under windows + static KviNickServRule * createInstance(const QString &szRegisteredNick, + const QString &szNickServMask, + const QString &szMessageRegexp, + const QString &szIdentifyCommand, + const QString &szServerMask = QString::null); + + void save(KviConfigurationFile * cfg,const QString &prefix); + // returns false if the loaded data has no sense + bool load(KviConfigurationFile * cfg,const QString &prefix); + void copyFrom(const KviNickServRule &src); +}; + + +#endif // _KviNickServRule_h_ diff --git a/src/modules/addon/addonfunctions.cpp b/src/modules/addon/addonfunctions.cpp index e1d10d40e..590935319 100644 --- a/src/modules/addon/addonfunctions.cpp +++ b/src/modules/addon/addonfunctions.cpp @@ -24,7 +24,7 @@ #include "addonfunctions.h" -#include "KviPackageFile.h" +#include "KviPackageReader.h" #include "KviLocale.h" #include "KviMessageBox.h" #include "KviApplication.h" diff --git a/src/modules/addon/packaddondialog.cpp b/src/modules/addon/packaddondialog.cpp index 45dabc6cb..ce2c52890 100644 --- a/src/modules/addon/packaddondialog.cpp +++ b/src/modules/addon/packaddondialog.cpp @@ -29,7 +29,7 @@ #include "KviFileUtils.h" #include "KviApplication.h" #include "KviIconManager.h" -#include "KviPackageFile.h" +#include "KviPackageWriter.h" #include "kvi_fileextensions.h" #include "kvi_sourcesdate.h" #include "KviOptions.h" diff --git a/src/modules/theme/managementdialog.cpp b/src/modules/theme/managementdialog.cpp index 3a76d82f4..6e9032bd9 100644 --- a/src/modules/theme/managementdialog.cpp +++ b/src/modules/theme/managementdialog.cpp @@ -35,7 +35,7 @@ #include "KviMainWindow.h" #include "KviIconManager.h" #include "KviInternalCommand.h" -#include "KviPackageFile.h" +#include "KviPackageReader.h" #include "kvi_fileextensions.h" #include "KviFileDialog.h" #include "KviDynamicToolTip.h" diff --git a/src/modules/theme/packthemedialog.cpp b/src/modules/theme/packthemedialog.cpp index bfaec19ca..ba44c006c 100644 --- a/src/modules/theme/packthemedialog.cpp +++ b/src/modules/theme/packthemedialog.cpp @@ -33,7 +33,7 @@ #include "KviApplication.h" #include "KviMainWindow.h" #include "KviIconManager.h" -#include "KviPackageFile.h" +#include "KviPackageWriter.h" #include "kvi_fileextensions.h" #include "KviFileDialog.h" //#include "KviMessageBox.h" diff --git a/src/modules/theme/savethemedialog.cpp b/src/modules/theme/savethemedialog.cpp index 072eceb38..4e65b550c 100644 --- a/src/modules/theme/savethemedialog.cpp +++ b/src/modules/theme/savethemedialog.cpp @@ -32,7 +32,7 @@ #include "KviApplication.h" #include "KviMainWindow.h" #include "KviIconManager.h" -#include "KviPackageFile.h" +#include "KviPackageWriter.h" #include "kvi_fileextensions.h" #include "KviFileDialog.h" #include "KviMessageBox.h" diff --git a/src/modules/theme/themefunctions.cpp b/src/modules/theme/themefunctions.cpp index 677c31e8c..ba7150b88 100644 --- a/src/modules/theme/themefunctions.cpp +++ b/src/modules/theme/themefunctions.cpp @@ -24,7 +24,7 @@ #include "themefunctions.h" -#include "KviPackageFile.h" +#include "KviPackageReader.h" #include "KviLocale.h" #include "KviMessageBox.h" #include "KviApplication.h" |
