aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Szymon Tomasz Stefanek2010-12-29 05:32:48 +0000
committerGravatar Szymon Tomasz Stefanek2010-12-29 05:32:48 +0000
commitf6d426be0e871770a0be51cca7f6fe5267591d5a (patch)
tree8abd0c2bf2296b2a3400ea79e30dde212b7de3e6
parentMore renames, fix the spelling of KVIrc etc... (diff)
downloadKVIrc-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.txt4
-rw-r--r--src/kvilib/file/KviPackageFile.cpp993
-rw-r--r--src/kvilib/file/KviPackageIOEngine.cpp162
-rw-r--r--src/kvilib/file/KviPackageIOEngine.h139
-rw-r--r--src/kvilib/file/KviPackageReader.cpp439
-rw-r--r--src/kvilib/file/KviPackageReader.h129
-rw-r--r--src/kvilib/file/KviPackageWriter.cpp465
-rw-r--r--src/kvilib/file/KviPackageWriter.h (renamed from src/kvilib/file/KviPackageFile.h)199
-rw-r--r--src/kvilib/irc/KviNickServRule.cpp80
-rw-r--r--src/kvilib/irc/KviNickServRule.h84
-rw-r--r--src/modules/addon/addonfunctions.cpp2
-rw-r--r--src/modules/addon/packaddondialog.cpp2
-rw-r--r--src/modules/theme/managementdialog.cpp2
-rw-r--r--src/modules/theme/packthemedialog.cpp2
-rw-r--r--src/modules/theme/savethemedialog.cpp2
-rw-r--r--src/modules/theme/themefunctions.cpp2
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"