summaryrefslogtreecommitdiffstats
path: root/src/kvilib/file
diff options
context:
space:
mode:
Diffstat (limited to 'src/kvilib/file')
-rw-r--r--src/kvilib/file/Makefile.am5
-rw-r--r--src/kvilib/file/kvi_file.cpp256
-rw-r--r--src/kvilib/file/kvi_file.h120
-rw-r--r--src/kvilib/file/kvi_fileutils.cpp505
-rw-r--r--src/kvilib/file/kvi_fileutils.h112
-rw-r--r--src/kvilib/file/kvi_packagefile.cpp1028
-rw-r--r--src/kvilib/file/kvi_packagefile.h142
7 files changed, 2168 insertions, 0 deletions
diff --git a/src/kvilib/file/Makefile.am b/src/kvilib/file/Makefile.am
new file mode 100644
index 00000000..c84487eb
--- /dev/null
+++ b/src/kvilib/file/Makefile.am
@@ -0,0 +1,5 @@
+###############################################################################
+# KVirc IRC client Makefile - 16.12.98 Szymon Stefanek <stefanek@tin.it>
+###############################################################################
+
+EXTRA_DIST = *.cpp *.h
diff --git a/src/kvilib/file/kvi_file.cpp b/src/kvilib/file/kvi_file.cpp
new file mode 100644
index 00000000..8ab1e739
--- /dev/null
+++ b/src/kvilib/file/kvi_file.cpp
@@ -0,0 +1,256 @@
+//=============================================================================
+//
+// File : kvi_file.cpp
+// Creation date : Mon Dec 17 2001 00:04:12 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001-2007 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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#include "kvi_file.h"
+#include "kvi_byteorder.h"
+
+
+KviFile::KviFile()
+: QFile()
+{
+}
+
+KviFile::KviFile(const QString &name)
+: QFile(name)
+{
+}
+
+KviFile::~KviFile()
+{
+}
+
+bool KviFile::openForReading()
+{
+#ifdef COMPILE_USE_QT4
+ return open(QFile::ReadOnly);
+#else
+ return open(IO_ReadOnly);
+#endif
+}
+
+bool KviFile::openForWriting(bool bAppend)
+{
+#ifdef COMPILE_USE_QT4
+ return open(QFile::WriteOnly | (bAppend ? QFile::Append : QFile::Truncate));
+#else
+ return open(IO_WriteOnly | (bAppend ? IO_Append : IO_Truncate));
+#endif
+}
+
+
+bool KviFile::save(const QByteArray &bData)
+{
+ if(!save((kvi_u32_t)(bData.size())))return false;
+ return (writeBlock(bData.data(),bData.size()) == ((int)(bData.size())));
+}
+
+bool KviFile::load(QByteArray &bData)
+{
+ kvi_u32_t iLen;
+ if(!load(iLen))return false;
+ bData.resize(iLen); // it is automatically null terminated in Qt 4.x... BLEAH :D
+ if(readBlock((char *)(bData.data()),iLen) != iLen)return false;
+ return true;
+}
+
+#ifndef COMPILE_USE_QT4
+
+bool KviFile::save(const KviQCString &szData)
+{
+ if(!save((kvi_u32_t)(szData.length())))return false;
+ return (writeBlock(szData.data(),szData.length()) == ((int)(szData.length())));
+}
+
+bool KviFile::load(KviQCString &szData)
+{
+ kvi_u32_t iLen;
+ if(!load(iLen))return false;
+ szData.resize(iLen + 1); // this would allocate one extra byte with Qt 4.x...
+ if(readBlock((char *)(szData.data()),iLen) != iLen)return false;
+ *(szData.data() + iLen) = 0;
+ return true;
+}
+
+#endif
+
+
+bool KviFile::save(const QString &szData)
+{
+ KviQCString c = KviQString::toUtf8(szData);
+ if(!save((kvi_u32_t)(c.length())))return false;
+ return (writeBlock(c.data(),c.length()) == ((int)(c.length())));
+}
+
+bool KviFile::load(QString &szData)
+{
+ kvi_u32_t iLen;
+ if(!load(iLen))return false;
+ KviQCString tmp;
+ tmp.resize(iLen + 1);
+ if(readBlock((char *)(tmp.data()),iLen) != iLen)return false;
+ *(tmp.data() + iLen) = 0;
+ szData = QString::fromUtf8(tmp.data());
+ return true;
+}
+
+bool KviFile::save(const KviStr &szData)
+{
+ if(!save((kvi_u32_t)(szData.len())))return false;
+ return (writeBlock(szData.ptr(),szData.len()) == (int) szData.len());
+}
+
+bool KviFile::load(KviStr &szData)
+{
+ kvi_u32_t iLen;
+ if(!load(iLen))return false;
+ szData.setLength(iLen);
+ return (readBlock((char *)(szData.ptr()),iLen) == iLen);
+}
+
+bool KviFile::save(kvi_u32_t t)
+{
+#ifndef LOCAL_CPU_LITTLE_ENDIAN
+ t = kvi_localCpuToLittleEndian32(t);
+#endif
+ return (writeBlock((const char *)(&t),sizeof(kvi_u32_t)) == sizeof(kvi_u32_t));
+}
+
+bool KviFile::load(kvi_u32_t &t)
+{
+ if(!(readBlock((char *)(&t),sizeof(kvi_u32_t)) == sizeof(kvi_u32_t)))return false;
+#ifndef LOCAL_CPU_LITTLE_ENDIAN
+ t = kvi_littleEndianToLocalCpu32(t);
+#endif
+ return true;
+}
+
+bool KviFile::save(kvi_u64_t t)
+{
+#ifndef LOCAL_CPU_LITTLE_ENDIAN
+ t = kvi_localCpuToLittleEndian64(t);
+#endif
+ return (writeBlock((const char *)(&t),sizeof(kvi_u64_t)) == sizeof(kvi_u64_t));
+}
+
+bool KviFile::load(kvi_u64_t &t)
+{
+ if(!(readBlock((char *)(&t),sizeof(kvi_u32_t)) == sizeof(kvi_u32_t)))return false;
+#ifndef LOCAL_CPU_LITTLE_ENDIAN
+ t = kvi_littleEndianToLocalCpu32(t);
+#endif
+ return true;
+}
+
+
+bool KviFile::save(kvi_u16_t t)
+{
+#ifndef LOCAL_CPU_LITTLE_ENDIAN
+ t = kvi_localCpuToLittleEndian16(t);
+#endif
+ return (writeBlock((const char *)(&t),sizeof(kvi_u16_t)) == sizeof(kvi_u16_t));
+}
+
+bool KviFile::load(kvi_u16_t &t)
+{
+ if(!(readBlock((char *)(&t),sizeof(kvi_u16_t)) == sizeof(kvi_u16_t)))return false;
+#ifndef LOCAL_CPU_LITTLE_ENDIAN
+ t = kvi_littleEndianToLocalCpu16(t);
+#endif
+ return true;
+}
+
+bool KviFile::save(kvi_u8_t t)
+{
+ return (writeBlock((const char *)(&t),sizeof(kvi_u8_t)) == sizeof(kvi_u8_t));
+}
+
+bool KviFile::load(kvi_u8_t &t)
+{
+ return (readBlock((char *)(&t),sizeof(kvi_u8_t)) == sizeof(kvi_u8_t));
+}
+
+
+bool KviFile::save(KviPointerList<KviStr> * pData)
+{
+ if(!save((int)(pData->count())))return false;
+ for(KviStr * s = pData->first();s;s = pData->next())
+ {
+ if(!save(*s))return false;
+ }
+ return true;
+}
+
+bool KviFile::load(KviPointerList<KviStr> * pData)
+{
+ pData->clear();
+ int iCount;
+ if(!load(iCount))return false;
+ for(int i=0;i<iCount;i++)
+ {
+ KviStr * s = new KviStr();
+ if(!load(*s))
+ {
+ delete s;
+ s = 0;
+ return false;
+ }
+ pData->append(s);
+ }
+ return true;
+}
+
+bool KviFile::skipFirst(char t,unsigned int maxdist)
+{
+ while(maxdist > 0)
+ {
+ char c;
+ if(!getChar(&c))return false;
+ if(((char)c) == t)return true;
+ maxdist--;
+ }
+ return false;
+}
+
+bool KviFile::skipFirst(const KviStr &t,unsigned int maxdist)
+{
+ char * ptr = t.ptr();
+ while(maxdist > 0)
+ {
+ char c;
+ if(!getChar(&c))return false;
+ if(c == *ptr)
+ {
+ ptr++;
+ if(!*ptr)return true;
+ } else {
+ ptr = t.ptr();
+ }
+ maxdist--;
+ }
+ return false;
+}
+
diff --git a/src/kvilib/file/kvi_file.h b/src/kvilib/file/kvi_file.h
new file mode 100644
index 00000000..188a9dad
--- /dev/null
+++ b/src/kvilib/file/kvi_file.h
@@ -0,0 +1,120 @@
+#ifndef _KVI_FILE_H_
+#define _KVI_FILE_H_
+
+//=============================================================================
+//
+// File : kvi_file.h
+// Creation date : Mon Dec 17 2001 00:05:04 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 2001-2007 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 "kvi_heapobject.h"
+#include "kvi_qstring.h"
+#include "kvi_string.h"
+#include "kvi_pointerlist.h"
+#include "kvi_inttypes.h"
+#include "kvi_qcstring.h"
+
+#include <qfile.h>
+#include <time.h>
+
+#ifdef COMPILE_USE_QT4
+ #define kvi_file_offset_t qlonglong
+#else
+ #define kvi_file_offset_t QFile::Offset
+#endif
+
+
+class KVILIB_API KviFile : public QFile, public KviHeapObject
+{
+public:
+ KviFile();
+ KviFile(const QString &name);
+ ~KviFile();
+public:
+ // Wrappers portable across Qt 3.x and Qt 4.x
+ bool openForReading();
+ bool openForWriting(bool bAppend = false);
+
+#ifndef COMPILE_USE_QT4
+ // Functions present in Qt 4.x but not Qt 3.x
+ bool putChar(char c){ return putch(c) != -1; };
+ bool ungetChar(char c){ return ungetch(c) != -1; };
+ bool getChar(char * c){ *c = getch(); return *c != -1; };
+ bool seek(kvi_file_offset_t o){ return at(o); };
+ kvi_file_offset_t pos(){ return at(); };
+#endif
+
+#ifdef COMPILE_USE_QT4
+ // Missing functions in Qt 4.x
+ quint64 writeBlock(const char * data,quint64 uLen){ return write(data,uLen); };
+ quint64 readBlock(char * data,quint64 uLen){ return read(data,uLen); };
+#endif
+
+ // This stuff loads and saves LITTLE ENDIAN DATA!
+ bool save(kvi_u64_t t);
+ bool load(kvi_u64_t &t);
+
+ bool save(kvi_i64_t t){ return save((kvi_u64_t)t); };
+ bool load(kvi_i64_t &t){ return load((kvi_u64_t &)t); };
+
+ bool save(kvi_u32_t t);
+ bool load(kvi_u32_t &t);
+
+ bool save(kvi_i32_t t){ return save((kvi_u32_t)t); };
+ bool load(kvi_i32_t &t){ return load((kvi_u32_t &)t); };
+
+ bool save(kvi_u16_t t);
+ bool load(kvi_u16_t &t);
+
+ bool save(kvi_i16_t t){ return save((kvi_u16_t)t); };
+ bool load(kvi_i16_t &t){ return load((kvi_u16_t &)t); };
+
+ bool save(kvi_u8_t t);
+ bool load(kvi_u8_t &t);
+
+ bool save(kvi_i8_t t){ return save((kvi_u8_t)t); };
+ bool load(kvi_i8_t &t){ return load((kvi_u8_t &)t); };;
+
+ bool save(const KviStr &szData);
+ bool load(KviStr &szData);
+
+#ifndef COMPILE_USE_QT4
+ // Under Qt 4.x these collide with QByteArray
+ bool save(const KviQCString &szData);
+ bool load(KviQCString &szData);
+#endif
+
+ bool save(const QByteArray &bData);
+ bool load(QByteArray &bData);
+
+ bool save(const QString &szData);
+ bool load(QString &szData);
+
+ bool skipFirst(char t,unsigned int maxdist = 0xffffffff);
+ bool skipFirst(const KviStr &t,unsigned int maxdist = 0xffffffff);
+
+ bool save(KviPointerList<KviStr> * pData);
+ bool load(KviPointerList<KviStr> * pData);
+};
+
+
+#endif //_KVI_FILE_H_
diff --git a/src/kvilib/file/kvi_fileutils.cpp b/src/kvilib/file/kvi_fileutils.cpp
new file mode 100644
index 00000000..648d9125
--- /dev/null
+++ b/src/kvilib/file/kvi_fileutils.cpp
@@ -0,0 +1,505 @@
+//=============================================================================
+//
+// File : kvi_fileutils.cpp
+// Creation date : Fri Dec 25 1998 18:26:48 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1998-2007 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.
+//
+//=============================================================================
+
+#define __KVILIB__
+
+
+#define _KVI_FILEUTLIS_CPP_
+#include "kvi_fileutils.h"
+#include "kvi_qstring.h"
+#include "kvi_file.h"
+#include "kvi_malloc.h"
+
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qglobal.h>
+#include <qtextcodec.h>
+#include <qtextstream.h>
+
+
+namespace KviFileUtils
+{
+ /*
+ WORKING CODE BUT UNUSED FOR NOW
+ bool readLine(QFile * f,QString &szBuffer,bool bClearBuffer)
+ {
+ // FIXME: Should this assume UTF8 encoding ?
+ char tmp_buf[256];
+ int cur_len = 0;
+ //char *cur_ptr = tmp_buf;
+ if(bClearBuffer)szBuffer = "";
+ int ch = f->getch();
+
+ while((ch != -1)&&(ch != '\n')&&(ch != 0))
+ {
+ tmp_buf[cur_len] = ch;
+ cur_len++;
+ if(cur_len > 255)
+ {
+ if(tmp_buf[255] == '\r')cur_len--; //Ignore CR...
+ int lastlen = szBuffer.length();
+ szBuffer.setLength(lastlen + cur_len);
+ QChar *p1 = szBuffer.unicode() + lastlen;
+ char * p2 = tmp_buf;
+ for(int i=0;i<cur_len;i++)*p1++ = *p2++;
+ cur_len = 0;
+ }
+ ch = f->getch();
+ }
+ if(ch == 0)
+ {
+ debug("Warning : %s is not an ascii file",f->name().latin1());
+ }
+ if(cur_len > 0)
+ {
+ if(tmp_buf[cur_len - 1] == '\r')cur_len--; //Ignore CR...
+ int lastlen = szBuffer.length();
+ szBuffer.setLength(lastlen + cur_len);
+ QChar *p1 = szBuffer.unicode() + lastlen;
+ char * p2 = tmp_buf;
+ for(int i=0;i<cur_len;i++)*p1++ = *p2++;
+ }
+ return (ch == '\n'); //more data to read else a broken file or EOF
+ }
+
+ bool loadFileStripCR(const QString &szPath,QString &szBuffer)
+ {
+ QFile f(szPath);
+ if(!f.open(IO_ReadOnly))return false;
+ szBuffer = "";
+ while(readLine(&f,szBuffer,false))
+ {
+ szBuffer.append('\n'); // readLine returned true...last char was a newline
+ }
+ // readLine returned false , no ending newline encountered
+ return true;
+ }
+ */
+
+ bool makeDir(const QString &szPath)
+ {
+ QDir d;
+ QString dir = KviQString::trimmed(szPath);
+ adjustFilePath(dir);
+ QString createdDir;
+
+#ifdef COMPILE_ON_WINDOWS
+#ifdef COMPILE_USE_QT4
+ int idx = dir.indexOf(':');
+#else
+ int idx = dir.find(':');
+#endif
+ if(idx == 1)
+ {
+ createdDir = dir.left(2);
+ dir.remove(0,2);
+ }
+#endif
+
+ KviQString::stripLeft(dir,KVI_PATH_SEPARATOR_CHAR);
+ while(!dir.isEmpty())
+ {
+ createdDir += KVI_PATH_SEPARATOR;
+ createdDir += KviQString::getToken(dir,KVI_PATH_SEPARATOR_CHAR);
+ if(!directoryExists(createdDir))
+ {
+ if(!d.mkdir(createdDir))
+ {
+ debug("Can't create directory %s",KviQString::toUtf8(createdDir).data());
+ return false;
+ }
+ }
+ KviQString::stripLeft(dir,KVI_PATH_SEPARATOR_CHAR);
+ }
+ return true;
+ }
+
+ bool makeDir(const char* path)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return makeDir(szPath);
+ }
+
+ bool renameFile(const QString &szSrc,const QString &szDst)
+ {
+ QDir d;
+ return d.rename(szSrc,szDst);
+ }
+
+ bool renameFile(const char* path,const char* path2)
+ {
+ QString szPath=QString::fromUtf8(path);
+ QString szPath2=QString::fromUtf8(path2);
+ return renameFile(szPath,szPath2);
+ }
+
+ bool copyFile(const QString &szSrc,const QString &szDst)
+ {
+ KviFile f1(szSrc);
+ if(!f1.openForReading())return false;
+ KviFile f2(szDst);
+ if(!f2.openForWriting())
+ {
+ f1.close();
+ return false;
+ }
+ char buffer[1024];
+ while(!f1.atEnd())
+ {
+ int len = f1.readBlock(buffer,1024);
+ if(len <= 0)
+ {
+ f1.close();
+ f2.close();
+ return false; //"serious error"
+ }
+ f2.writeBlock(buffer,len);
+ }
+ f1.close();
+ f2.close();
+ return true;
+ }
+
+ bool copyFile(const char* path,const char* path2)
+ {
+ QString szPath=QString::fromUtf8(path);
+ QString szPath2=QString::fromUtf8(path2);
+ return copyFile(szPath,szPath2);
+ }
+
+ bool loadFile(const QString &szPath,QString &szBuffer,bool bUtf8)
+ {
+ KviFile f(szPath);
+ if(!f.openForReading())return false;
+ if(bUtf8)
+ {
+ QByteArray ba = f.readAll();
+ szBuffer = QString::fromUtf8(ba.data(),ba.size());
+ //debug("BUFFERLEN: %d",szBuffer.length());
+ } else {
+ szBuffer = QString(f.readAll());
+ }
+ return true;
+ }
+
+ bool loadFile(const char* path,QString &szBuffer,bool bUtf8)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return loadFile(szPath,szBuffer,bUtf8);
+ }
+
+ void adjustFilePath(QString &szPath)
+ {
+#ifdef COMPILE_ON_WINDOWS
+ szPath.replace('/',"\\");
+#ifdef COMPILE_USE_QT4
+ szPath.replace("\\\\","\\");
+#else
+ while(szPath.find("\\\\") != -1)szPath.replace("\\\\","\\");
+#endif
+ // FIXME: Use the default drive here ?
+ if(szPath.startsWith("\\"))szPath.prepend("C:");
+#else
+ szPath.replace('\\',"/");
+#ifdef COMPILE_USE_QT4
+ szPath.replace("//","/");
+#else
+ while(KviQString::find(szPath,"//") != -1)szPath.replace("//","/");
+#endif
+ // deal with windows paths
+ if((szPath.length() > 2) && (szPath.at(0) != QChar('/')))
+ {
+ if((szPath.at(1) == QChar(':')) && (szPath.at(2) == QChar('/')))
+ {
+ szPath.remove(0,2);
+ }
+ }
+#ifdef COMPILE_USE_QT4
+ szPath=QDir::cleanPath(szPath);
+#else
+ szPath=QDir::cleanDirPath(szPath);
+#endif
+#endif
+
+ }
+
+ bool directoryExists(const QString &szPath)
+ {
+ QFileInfo f(szPath);
+ return (f.exists() && f.isDir());
+ }
+
+ bool directoryExists(const char* path)
+ {
+ QString szPath=QString::fromUtf8(path);
+ QFileInfo f(szPath);
+ return (f.exists() && f.isDir());
+ }
+
+ bool fileExists(const QString &szPath)
+ {
+ QFileInfo f(szPath);
+ return (f.exists() && f.isFile());
+ }
+
+ bool fileExists(const char* path)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return fileExists(szPath);
+ }
+
+ bool removeFile(const QString &szPath)
+ {
+ QDir d;
+ return d.remove(szPath);
+ }
+
+ bool removeFile(const char* path)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return removeFile(szPath);
+ }
+
+ bool removeDir(const QString &szPath)
+ {
+ QDir d;
+ return d.rmdir(szPath);
+ }
+
+ bool removeDir(const char* path)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return removeDir(szPath);
+ }
+
+ bool deleteDir(const QString &szPath)
+ {
+ QDir d(szPath);
+ QStringList sl = d.entryList(QDir::Dirs);
+ QStringList::Iterator it;
+ for(it=sl.begin();it != sl.end();it++)
+ {
+ QString szSubdir = *it;
+ if(!(KviQString::equalCS(szSubdir,"..") || KviQString::equalCS(szSubdir,".")))
+ {
+ QString szSubPath = szPath;
+ KviQString::ensureLastCharIs(szSubPath,QChar(KVI_PATH_SEPARATOR_CHAR));
+ szSubPath += szSubdir;
+ if(!KviFileUtils::deleteDir(szSubPath))
+ return false;
+ }
+ }
+
+ sl = d.entryList(QDir::Files);
+ for(it=sl.begin();it != sl.end();it++)
+ {
+ QString szFilePath = szPath;
+ KviQString::ensureLastCharIs(szFilePath,QChar(KVI_PATH_SEPARATOR_CHAR));
+ szFilePath += *it;
+ if(!KviFileUtils::removeFile(szFilePath))
+ return false;
+ }
+
+ return KviFileUtils::removeDir(szPath);
+ }
+
+ bool writeFile(const QString &szPath,const QString &szData,bool bAppend)
+ {
+ KviFile f(szPath);
+ if(!f.openForWriting(bAppend))return false;
+ KviQCString szTmp = KviQString::toUtf8(szData);
+ if(!szTmp.data())return true;
+ if(f.writeBlock(szTmp.data(),szTmp.length()) != ((int)(szTmp.length())))return false;
+ return true;
+ }
+
+ bool writeFile(const char* path,const QString &szData,bool bAppend)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return writeFile(szPath,szData,bAppend);
+ }
+
+ bool writeFileLocal8Bit(const QString &szPath,const QString &szData,bool bAppend)
+ {
+ KviFile f(szPath);
+ if(!f.openForWriting(bAppend))return false;
+ KviQCString szTmp = QTextCodec::codecForLocale()->fromUnicode(szData);
+ if(!szTmp.data())return true;
+ if(f.writeBlock(szTmp.data(),szTmp.length()) != ((int)(szTmp.length())))return false;
+ return true;
+ }
+
+ bool writeFileLocal8Bit(const char* path,const QString &szData,bool bAppend)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return writeFileLocal8Bit(szPath,szData,bAppend);
+ }
+
+ bool readFile(const QString &szPath,QString &szBuffer,unsigned int uMaxSize)
+ {
+ KviFile f(szPath);
+ if(!f.openForReading())return false;
+ if(f.size() < 1)
+ {
+ szBuffer = "";
+ f.close();
+ return true;
+ }
+ if(f.size() > uMaxSize)return false;
+ char * buf = new char[f.size() + 1];
+ if(f.readBlock(buf,f.size()) != ((long int)f.size()))
+ {
+ delete buf;
+ buf = 0;
+ return false;
+ }
+ buf[f.size()] = '\0';
+ szBuffer = QString::fromUtf8(buf);
+ delete[] buf;
+ return true;
+ }
+
+ bool readFile(const char* path,QString &szBuffer,unsigned int uMaxSize)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return readFile(szPath,szBuffer,uMaxSize);
+ }
+
+
+ QString extractFileName(const QString &szFileNameWithPath)
+ {
+ return QFileInfo(szFileNameWithPath).fileName();
+ }
+
+ QString extractFilePath(const QString &szFileNameWithPath)
+ {
+ return QFileInfo(szFileNameWithPath).dirPath(true);
+ }
+
+ bool readLine(QFile * f,QString &szBuffer,bool bUtf8)
+ {
+ QTextStream stream(f);
+ stream.setEncoding(bUtf8 ? QTextStream::UnicodeUTF8 : QTextStream::Locale);
+ szBuffer=stream.readLine();
+ return !szBuffer.isNull();
+ }
+
+ bool readLines(QFile * f,QStringList &buffer,int iStartLine, int iCount, bool bUtf8)
+ {
+ QTextStream stream( f );
+ stream.setEncoding(bUtf8 ? QTextStream::UnicodeUTF8 : QTextStream::Locale);
+ for(int i=0;i<iStartLine;i++)
+ stream.readLine();
+
+ if(iCount>0)
+ {
+ for(; (iCount>0 && !stream.atEnd()) ; iCount-- )
+ buffer.append(stream.readLine());
+ } else {
+ while(!stream.atEnd()) {
+ buffer.append(stream.readLine());
+ }
+ }
+ return buffer.count()!= 0;
+ }
+
+ bool isReadable(const QString &szFname)
+ {
+ QFileInfo f(szFname);
+ return (f.exists() && f.isFile() && f.isReadable());
+ }
+
+ bool isReadable(const char* path)
+ {
+ QString szPath=QString::fromUtf8(path);
+ return isReadable(szPath);
+ }
+
+ bool isAbsolutePath(const QString &szPath)
+ {
+ QFileInfo f(szPath);
+ return !f.isRelative();
+ }
+};
+
+static char hexchars[16] = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' };
+
+
+void kvi_encodeFileName(KviStr & path)
+{
+ QString szPath(path.ptr());
+ kvi_encodeFileName(szPath);
+ path=szPath;
+}
+
+void kvi_encodeFileName(QString & path)
+{
+ QString src(path);
+ path="";
+ for(int i=0;i<src.length();i++)
+ {
+ QChar cur=src[i];
+ if( ! (cur.isLetter() || cur.isDigit() || cur==' ' || cur=='_' || cur=='.' || cur=='#' || cur=='%') )
+ {
+ if(cur.row()!=0)
+ {
+ path+='%';
+ path+=hexchars[cur.row() >> 4];
+ path+=hexchars[cur.row() & 15];
+ }
+ path+='%';
+ path+=hexchars[cur.cell() >> 4];
+ path+=hexchars[cur.cell() & 15];
+ } else if (cur=='%')
+ {
+ path+="%%";
+ } else {
+ path+=cur;
+ }
+ }
+}
+
+//================ kvi_isAbsolutePath ===============//
+
+bool kvi_isAbsolutePath(const char *path)
+{
+ if(*path == '/')return true;
+ if(isalpha(*path))
+ {
+ if((*(path + 1)) == ':')return true;
+ }
+ return false;
+}
+
+//=================== kvi_readLine =====================//
+
+bool kvi_readLine(QFile *f,KviStr &str)
+{
+ QTextStream stream(f);
+ QString szBuff=stream.readLine();
+ str=szBuff;
+ return szBuff.isNull() ? 1 : 0;
+}
+
+
diff --git a/src/kvilib/file/kvi_fileutils.h b/src/kvilib/file/kvi_fileutils.h
new file mode 100644
index 00000000..dcead8ae
--- /dev/null
+++ b/src/kvilib/file/kvi_fileutils.h
@@ -0,0 +1,112 @@
+#ifndef _KVI_FILEUTILS_H_
+#define _KVI_FILEUTILS_H_
+
+//
+// File : kvi_fileutils.h
+// Creation date : Fri Dec 25 1998 18:27:04 by Szymon Stefanek
+//
+// This file is part of the KVirc irc client distribution
+// Copyright (C) 1999-2000 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 "kvi_string.h"
+
+#include <qfile.h>
+#include <qstringlist.h>
+
+#include <time.h>
+
+
+#ifdef COMPILE_ON_WINDOWS
+ #define KVI_PATH_SEPARATOR "\\"
+ #define KVI_PATH_SEPARATOR_CHAR '\\'
+#else
+ #define KVI_PATH_SEPARATOR "/"
+ #define KVI_PATH_SEPARATOR_CHAR '/'
+#endif
+
+// #warning "Add kvi_trashFile(const char * path) ? - is it needed in the whole app"
+// #warning "or should it be availible only for dirbrowser module ?"
+namespace KviFileUtils
+{
+ //extern KVILIB_API bool readLine(QFile * f,QString &szBuffer,bool bClearBuffer = true);
+ //extern KVILIB_API bool loadFileStripCR(const QString &szPath,QString &szBuffer);
+
+ // loads the file at szPath to szBuffer eventually converting from utf8
+ extern KVILIB_API bool loadFile(const QString &szPath,QString &szBuffer,bool bUtf8 = true);
+ extern KVILIB_API bool loadFile(const char* szPath,QString &szBuffer,bool bUtf8 = true);
+ // adjusts the file path to the current platform
+ extern KVILIB_API void adjustFilePath(QString &szPath);
+ // returns true if szPath points to an existing directory
+ extern KVILIB_API bool directoryExists(const QString &szPath);
+ extern KVILIB_API bool directoryExists(const char* path);
+ // returns true if szPath points to an existing file
+ extern KVILIB_API bool fileExists(const QString &szPath);
+ extern KVILIB_API bool fileExists(const char* szPath);
+ // removes a file
+ extern KVILIB_API bool removeFile(const QString &szPath);
+ extern KVILIB_API bool removeFile(const char* path);
+ // removes a dir (must be empty)
+ extern KVILIB_API bool removeDir(const QString &szPath);
+ extern KVILIB_API bool removeDir(const char* path);
+ // removes a dir recursively
+ extern KVILIB_API bool deleteDir(const QString &szPath);
+ // writes a complete file (utf8 version)
+ extern KVILIB_API bool writeFile(const QString &szPath,const QString &szData,bool bAppend = false);
+ extern KVILIB_API bool writeFile(const char* path,const QString &szData,bool bAppend = false);
+ // writes a complete file (local 8 bit version)
+ extern KVILIB_API bool writeFileLocal8Bit(const QString &szPath,const QString &szData,bool bAppend = false);
+ extern KVILIB_API bool writeFileLocal8Bit(const char* path,const QString &szData,bool bAppend = false);
+ // reads a complete file and puts it in the string szBuffer, if the file is smaller than uMaxSize bytes
+ extern KVILIB_API bool readFile(const QString &szPath,QString &szBuffer,unsigned int uMaxSize = 65535);
+ extern KVILIB_API bool readFile(const char* path,QString &szBuffer,unsigned int uMaxSize = 65535);
+ // extracts the filename from a complete path (strips leading path)
+ extern KVILIB_API QString extractFileName(const QString &szFileNameWithPath);
+
+ extern KVILIB_API QString extractFilePath(const QString &szFileNameWithPath);
+ // cp -f
+ extern KVILIB_API bool copyFile(const QString &szSrc,const QString &szDst);
+ extern KVILIB_API bool copyFile(const char* src,const char* dst);
+ // mv
+ extern KVILIB_API bool renameFile(const QString &szSrc,const QString &szDst);
+ extern KVILIB_API bool renameFile(const char* src,const char* dst);
+ // mkdir
+ extern KVILIB_API bool makeDir(const QString &szPath);
+ extern KVILIB_API bool makeDir(const char* path);
+ // reads a text line, returns false if EOF is reached
+ extern KVILIB_API bool readLine(QFile * f,QString &szBuffer,bool bUtf8 = true);
+ extern KVILIB_API bool readLines(QFile * f,QStringList &buffer,int iStartLine = 0, int iCount = -1, bool bUtf8 = true);
+ extern KVILIB_API bool isReadable(const QString &szFname);
+ extern KVILIB_API bool isAbsolutePath(const QString &szPath);
+};
+
+// ALL THIS STUFF BELOW SHOULD DIE: IF YOU SEE IT, REPLACE WITH THE FUNCTIONS IN THE NAMESPACE ABOVE
+
+// Returns true if the path begins with '/'
+KVILIB_API extern bool kvi_isAbsolutePath(const char *path);
+// Translates ANY string into a valid filename (with no path!)
+// There is NO way to come back to the original string
+// the algo is one-way only
+KVILIB_API extern void kvi_encodeFileName(KviStr & path);
+KVILIB_API extern void kvi_encodeFileName(QString & path);
+
+// Reads a single line from the file and returns false if EOF was encountered.
+KVILIB_API extern bool kvi_readLine(QFile *f,KviStr &str);
+// Removes a file
+
+#endif //_KVI_FILEUTILS_H_INCLUDED_
diff --git a/src/kvilib/file/kvi_packagefile.cpp b/src/kvilib/file/kvi_packagefile.cpp
new file mode 100644
index 00000000..3e7bcc17
--- /dev/null
+++ b/src/kvilib/file/kvi_packagefile.cpp
@@ -0,0 +1,1028 @@
+//=============================================================================
+//
+// File : kvi_packagefile.cpp
+// Created on Tue 26 Dec 2006 05:33:33 by Szymon Stefanek
+//
+// This file is part of the KVIrc IRC Client distribution
+// Copyright (C) 2006 Szymon Stefanek <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.
+//
+//=============================================================================
+
+#define __KVILIB__
+#include "kvi_packagefile.h"
+
+#include "kvi_file.h"
+#include "kvi_fileutils.h"
+#include "kvi_locale.h"
+#include "kvi_inttypes.h"
+
+#include <qprogressdialog.h>
+#include <qlabel.h>
+
+#include <qdir.h>
+
+#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;
+#ifdef COMPILE_USE_QT4
+ m_pProgressDialog->setValue(iProgress);
+#else
+ m_pProgressDialog->setProgress(iProgress);
+#endif
+ 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)
+{
+#ifdef COMPILE_USE_QT4
+ m_pProgressDialog = new QProgressDialog(QString(""),__tr2qs("Cancel"),0,iTotalSteps,0);
+ m_pProgressDialog->setModal(true);
+ m_pProgressDialog->setWindowTitle(szCaption);
+#else
+ m_pProgressDialog = new QProgressDialog(QString(""),__tr2qs("Cancel"),iTotalSteps,0,"",true);
+ m_pProgressDialog->setCaption(szCaption);
+#endif
+ 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);
+#ifdef COMPILE_USE_QT4
+ QDir::Filters iFlags;
+#else
+ int iFlags;
+#endif
+ iFlags = QDir::Files | QDir::Readable;
+ if(!(uAddFileFlags & FollowSymLinks))
+ iFlags |= QDir::NoSymLinks;
+
+ // QT4SUX: Because the QDir::entryInfoList() breaks really a lot of code by returning an object that behaves in a _totally_ different way.. it's also much slower
+
+#ifdef COMPILE_USE_QT4
+ int j;
+ QFileInfoList sl = d.entryInfoList(iFlags);
+ for(j=0;j<sl.size();j++)
+ {
+#else
+ const QFileInfoList * sl = d.entryInfoList(iFlags);
+ if(!sl)return false;
+ QFileInfoListIterator it(*sl);
+ while(QFileInfo * fi = it.current())
+ {
+#endif
+ QString szSFileName = szLocalDirectoryName;
+ KviQString::ensureLastCharIs(szSFileName,QChar(KVI_PATH_SEPARATOR_CHAR));
+#ifdef COMPILE_USE_QT4
+ QFileInfo slowCopy = sl.at(j);
+ szSFileName += slowCopy.fileName();
+#else
+ szSFileName += fi->fileName();
+#endif
+ QString szDFileName = szTargetDirectoryPrefix;
+ KviQString::ensureLastCharIs(szDFileName,QChar(KVI_PATH_SEPARATOR_CHAR));
+#ifdef COMPILE_USE_QT4
+ szDFileName += slowCopy.fileName();
+ if(!addFileInternal(&slowCopy,szSFileName,szDFileName,uAddFileFlags))
+ return false;
+#else
+ szDFileName += fi->fileName();
+ if(!addFileInternal(fi,szSFileName,szDFileName,uAddFileFlags))
+ return false;
+#endif
+#ifndef COMPILE_USE_QT4
+ ++it;
+#endif
+ }
+ iFlags = QDir::Dirs | QDir::Readable;
+ if(!(uAddFileFlags & FollowSymLinks))
+ iFlags |= QDir::NoSymLinks;
+ sl = d.entryInfoList(iFlags);
+#ifdef COMPILE_USE_QT4
+ for(j=0;j<sl.size();j++)
+ {
+ QString szDir = sl.at(j).fileName();
+#else
+ if(!sl)return false;
+ QFileInfoListIterator it2(*sl);
+ while(QFileInfo * fi2 = it2.current())
+ {
+ QString szDir = fi2->fileName();
+#endif
+ 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;
+ }
+#ifndef COMPILE_USE_QT4
+ ++it2;
+#endif
+ }
+
+ 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.openForReading())
+ {
+ setLastError(__tr2qs("Failed to open a source file for reading"));
+ return false;
+ }
+
+ kvi_u32_t uSize = source.size();
+
+ // Flags
+#ifdef COMPILE_ZLIB_SUPPORT
+ kvi_u32_t uFlags = pDataField->m_bFileAllowCompression ?
+ (uSize > 64 ? KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE : 0)
+ : 0;
+#else
+ kvi_u32_t uFlags = 0;
+#endif
+
+ if(!pFile->save(uFlags))return writeError();
+
+ KviQCString 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.readBlock((char *)ibuffer,BUFFER_SIZE);
+ if(iReaded < 0)
+ return readError();
+
+ z_stream zstr;
+ zstr.zalloc = Z_NULL;
+ zstr.zfree = Z_NULL;
+ zstr.opaque = Z_NULL;
+ zstr.next_in = ibuffer;
+ zstr.avail_in = iReaded;
+ zstr.next_out = obuffer;
+ zstr.avail_out = BUFFER_SIZE;
+
+ if(deflateInit(&zstr,9) != Z_OK)
+ {
+ setLastError(__tr2qs("Compression library initialization error"));
+ return false;
+ }
+
+ while(iReaded > 0)
+ {
+ zstr.next_out = obuffer;
+ zstr.avail_out = BUFFER_SIZE;
+
+ if(deflate(&zstr,Z_NO_FLUSH) != Z_OK)
+ {
+ setLastError(__tr2qs("Compression library error"));
+ return false;
+ }
+
+ if(zstr.avail_out < BUFFER_SIZE)
+ {
+ int iCompressed = zstr.next_out - obuffer;
+ pDataField->m_uWrittenFieldLength += iCompressed;
+ if(pFile->writeBlock((char *)obuffer,iCompressed) != iCompressed)
+ {
+ deflateEnd(&zstr);
+ return writeError();
+ }
+ }
+
+ if(zstr.avail_in < BUFFER_SIZE)
+ {
+ int iDataToRead = BUFFER_SIZE - zstr.avail_in;
+ if(iDataToRead < BUFFER_SIZE)
+ {
+ if(ibuffer != zstr.next_in)
+ {
+ // hum, there is still some data in the buffer to be readed
+ // and it is not at the beginning...move it to the beginning of ibuffer
+ memmove(ibuffer,zstr.next_in,zstr.avail_in);
+ }
+ }
+ iReaded = source.readBlock((char *)(ibuffer + zstr.avail_in),iDataToRead);
+ if(iReaded < 0)
+ {
+ deflateEnd(&zstr);
+ return readError();
+ }
+ zstr.avail_in += iReaded;
+ zstr.next_in = ibuffer;
+
+ if((zstr.total_in % 2000000) == 0)
+ {
+ 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->writeBlock((char *)obuffer,iCompressed) != iCompressed)
+ {
+ deflateEnd(&zstr);
+ return writeError();
+ }
+ } else {
+ deflateEnd(&zstr);
+ setLastError(__tr2qs("Compression library internal error"));
+ return false;
+ }
+
+ zstr.next_out = obuffer;
+ zstr.avail_out = BUFFER_SIZE;
+ }
+
+ } while(ret == Z_OK);
+
+ // store the compressed data size
+ kvi_file_offset_t here = pFile->pos();
+ pFile->seek(savedSizeOffset);
+ uSize = zstr.total_out;
+
+ deflateEnd(&zstr);
+ if(!pFile->save(uSize))return writeError();
+
+ if(ret != Z_STREAM_END)
+ {
+ setLastError(__tr2qs("Error while compressing a file stream"));
+ return false;
+ }
+
+ pFile->seek(here);
+ } else {
+#endif
+ unsigned char buffer[BUFFER_SIZE];
+ int iTotalFileSize = 0;
+ kvi_i32_t iReaded = source.readBlock((char *)buffer,BUFFER_SIZE);
+ if(iReaded < 0)
+ return readError();
+ while(iReaded > 0)
+ {
+ iTotalFileSize += iReaded;
+ if((iTotalFileSize % 1000000) == 0)
+ {
+ 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->writeBlock((char *)buffer,iReaded) != iReaded)
+ return writeError();
+ iReaded = source.readBlock((char *)buffer,BUFFER_SIZE);
+ }
+#ifdef COMPILE_ZLIB_SUPPORT
+ }
+#endif
+ source.close();
+
+ return true;
+}
+
+bool KviPackageWriter::pack(const 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 uPackFlags)
+{
+
+ KviFile f(szFileName);
+ if(!f.openForWriting())
+ {
+ setLastError(__tr2qs("Can't open file for writing"));
+ return false;
+ }
+
+ // write the PackageHeader
+
+ // Magic
+ char magic[4];
+ magic[0] = 'K';
+ magic[1] = 'V';
+ magic[2] = 'P';
+ magic[3] = 'F';
+ if(f.writeBlock(magic,4) != 4)return writeError();
+
+ // Version
+ kvi_u32_t uVersion = 0x1;
+ if(!f.save(uVersion))return writeError();
+
+ // Flags
+ kvi_u32_t uFlags = 0x0;
+ if(!f.save(uFlags))return writeError();
+
+ // write PackageInfo
+
+ // InfoFieldCount
+ kvi_u32_t uCount = m_pStringInfoFields->count() + m_pBinaryInfoFields->count();
+ if(!f.save(uCount))return writeError();
+
+ m_iCurrentProgress = 5;
+ if(!updateProgress(m_iCurrentProgress,__tr2qs("Writing informational fields")))
+ return false; // aborted
+
+ // InfoFields (string)
+ KviPointerHashTableIterator<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 &szLocalFileName)
+{
+ // read the PackageHeader
+
+ // Magic
+ char magic[4];
+
+ if(pFile->readBlock(magic,4) != 4)return readError();
+ if((magic[0] != 'K') || (magic[1] != 'V') || (magic[2] != 'P') || (magic[3] != 'F'))
+ {
+ setLastError(__tr2qs("The file specified is not a valid KVIrc package"));
+ return false;
+ }
+
+ // Version
+ kvi_u32_t uVersion;
+ if(!pFile->load(uVersion))return readError();
+ if(uVersion != 0x1)
+ {
+ setLastError(__tr2qs("The package has an invalid version number, it might have been created by a newer KVIrc"));
+ return false;
+ }
+
+ // Flags
+ kvi_u32_t uFlags;
+ if(!pFile->load(uFlags))return readError();
+ // we ignore them at the moment
+
+ // read PackageInfo
+
+ // InfoFieldCount
+ kvi_u32_t uCount;
+ if(!pFile->load(uCount))return writeError();
+
+ m_pStringInfoFields->clear();
+ m_pBinaryInfoFields->clear();
+
+ kvi_u32_t uIdx = 0;
+ while(uIdx < uCount)
+ {
+ 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.openForReading())
+ {
+ 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.openForWriting())
+ {
+ 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->readBlock((char *)ibuffer,iToRead);
+ iRemainingSize -= iReaded;
+
+ z_stream zstr;
+ zstr.zalloc = Z_NULL;
+ zstr.zfree = Z_NULL;
+ zstr.opaque = Z_NULL;
+ zstr.next_in = ibuffer;
+ zstr.avail_in = iReaded;
+ zstr.next_out = obuffer;
+ zstr.avail_out = BUFFER_SIZE;
+
+ if(inflateInit(&zstr) != Z_OK)
+ {
+ setLastError(__tr2qs("Compression library initialization error"));
+ return false;
+ }
+
+ while((iReaded > 0) && (iRemainingSize > 0))
+ {
+ zstr.next_out = obuffer;
+ zstr.avail_out = BUFFER_SIZE;
+
+ if(inflate(&zstr,Z_NO_FLUSH) != Z_OK)
+ {
+ setLastError(__tr2qs("Compression library error"));
+ return false;
+ }
+
+ if(zstr.avail_out < BUFFER_SIZE)
+ {
+ int iDecompressed = zstr.next_out - obuffer;
+ if(dest.writeBlock((char *)obuffer,iDecompressed) != iDecompressed)
+ {
+ inflateEnd(&zstr);
+ return writeError();
+ }
+ }
+
+ if(zstr.avail_in < BUFFER_SIZE)
+ {
+ int iDataToRead = BUFFER_SIZE - zstr.avail_in;
+ if(iDataToRead < BUFFER_SIZE)
+ {
+ if(ibuffer != zstr.next_in)
+ {
+ // hum, there is still some data in the buffer to be readed
+ // and it is not at the beginning...move it to the beginning of ibuffer
+ memmove(ibuffer,zstr.next_in,zstr.avail_in);
+ }
+ }
+
+ if(iDataToRead > iRemainingSize)
+ iDataToRead = iRemainingSize;
+
+ iReaded = pFile->readBlock((char *)(ibuffer + zstr.avail_in),iDataToRead);
+ if(iReaded < 0)
+ {
+ inflateEnd(&zstr);
+ return readError();
+ }
+
+ iRemainingSize -= iReaded;
+ zstr.avail_in += iReaded;
+ zstr.next_in = ibuffer;
+
+ if((zstr.total_in % 2000000) == 0)
+ {
+ 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.writeBlock((char *)obuffer,iDecompressed) != iDecompressed)
+ {
+ inflateEnd(&zstr);
+ return writeError();
+ }
+ } /* else { THIS HAPPENS FOR ZERO SIZE FILES
+ debug("hum.... internal, rEWq (ret = %d) (avail_out = %d)",ret,zstr.avail_out);
+
+ inflateEnd(&zstr);
+ setLastError(__tr2qs("Compression library internal error"));
+ return false;
+ } */
+ zstr.next_out = obuffer;
+ zstr.avail_out = BUFFER_SIZE;
+ }
+
+ } while((ret == Z_OK) || (ret == Z_BUF_ERROR));
+
+ inflateEnd(&zstr);
+
+ if(ret != Z_STREAM_END)
+ {
+ setLastError(__tr2qs("Error in compressed file stream"));
+ return false;
+ }
+
+ } else {
+#endif
+ unsigned char buffer[BUFFER_SIZE];
+ int iTotalFileSize = 0;
+ int iRemainingData = uSize;
+ int iToRead = iRemainingData;
+ if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE;
+ int iReaded = 1;
+
+ while((iReaded > 0) && (iToRead > 0))
+ {
+ iReaded = pFile->readBlock((char *)buffer,iToRead);
+ if(iReaded > 0)
+ {
+ iTotalFileSize += iReaded;
+ iRemainingData -= iReaded;
+
+ if((iTotalFileSize % 3000000) == 0)
+ {
+ 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.writeBlock((char *)buffer,iReaded) != iReaded)
+ return writeError();
+ }
+
+ int iToRead = iRemainingData;
+ if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE;
+ }
+#ifdef COMPILE_ZLIB_SUPPORT
+ }
+#endif
+ dest.close();
+
+ return true;
+}
+
+bool KviPackageReader::getStringInfoField(const 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.openForReading())
+ {
+ setLastError(__tr2qs("Can't open file for reading"));
+ return false;
+ }
+
+ kvi_file_offset_t size = f.size();
+
+ if(!(uUnpackFlags & NoProgressDialog))
+ {
+ showProgressDialog(__tr2qs("Reading package..."),size);
+ updateProgress(0,__tr2qs("Reading package header"));
+ }
+
+
+ if(!readHeaderInternal(&f,szLocalFileName))
+ return false;
+
+ if(!updateProgress(f.pos(),__tr2qs("Reading package data")))
+ return false; // aborted
+
+ while(!f.atEnd())
+ {
+ // DataFieldType
+ kvi_u32_t uDataFieldType;
+ if(!f.load(uDataFieldType))return readError();
+ // DataFieldLen
+ kvi_u32_t uDataFieldLen;
+ if(!f.load(uDataFieldLen))return readError();
+
+ switch(uDataFieldType)
+ {
+ case KVI_PACKAGE_DATAFIELD_TYPE_FILE:
+ if(!unpackFile(&f,szUnpackPath))
+ return false;
+ break;
+ default:
+ setLastError(__tr2qs("Invalid data field: the package is probably corrupt"));
+ return false;
+ break;
+ }
+
+ }
+
+ return true;
+}
+
+
+
diff --git a/src/kvilib/file/kvi_packagefile.h b/src/kvilib/file/kvi_packagefile.h
new file mode 100644
index 00000000..3e330554
--- /dev/null
+++ b/src/kvilib/file/kvi_packagefile.h
@@ -0,0 +1,142 @@
+#ifndef _KVI_PACKAGEFILE_H_
+#define _KVI_PACKAGEFILE_H_
+//=============================================================================
+//
+// File : kvi_packagefile.h
+// Created on Tue 26 Dec 2006 05:33:33 by Szymon Stefanek
+//
+// This file is part of the KVIrc IRC Client distribution
+// Copyright (C) 2006 Szymon Stefanek <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 "kvi_qstring.h"
+#include "kvi_pointerhashtable.h"
+#include "kvi_qcstring.h" // QByteArray anyway
+#include <qobject.h>
+#include "kvi_pointerlist.h"
+
+class KviFile;
+class QProgressDialog;
+class QLabel;
+class QFileInfo;
+
+//
+// This class is used for creating KVIrc package files.
+// You simply instantiate it, add some info fields, add some files and then call pack().
+//
+
+class KVILIB_API KviPackageIOEngine
+{
+public:
+ KviPackageIOEngine();
+ virtual ~KviPackageIOEngine();
+protected:
+ QString m_szLastError;
+ KviPointerHashTable<QString,QString> * m_pStringInfoFields;
+ KviPointerHashTable<QString,QByteArray> * m_pBinaryInfoFields;
+ QProgressDialog * m_pProgressDialog;
+ QLabel * m_pProgressDialogLabel;
+public:
+ const QString & lastError(){ return m_szLastError; };
+ void setLastError(const QString &szLastError){ m_szLastError = szLastError; };
+ KviPointerHashTable<QString,QString> * stringInfoFields(){ return m_pStringInfoFields; };
+ KviPointerHashTable<QString,QByteArray> * binaryInfoFields(){ return m_pBinaryInfoFields; };
+protected:
+ void showProgressDialog(const QString &szCaption,int iTotalSteps);
+ void hideProgressDialog();
+ bool updateProgress(int iProgress,const QString &szLabel);
+ bool writeError();
+ bool readError();
+};
+
+#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 KVILIB_API KviPackageWriter : public KviPackageIOEngine
+{
+public:
+ KviPackageWriter();
+ virtual ~KviPackageWriter();
+protected:
+
+ class DataField
+ {
+ public:
+ kvi_u32_t m_uType;
+ // output length of the field
+ kvi_u32_t m_uWrittenFieldLength;
+ // data fields for the File DataFieldType
+ bool m_bFileAllowCompression;
+ QString m_szFileLocalName;
+ QString m_szFileTargetName;
+ };
+
+ KviPointerList<DataField> * m_pDataFields;
+ int m_iCurrentProgress;
+public:
+ // Adds a file to the package. The file must be specified as absolute local
+ // path and as target path relative to the KVIrc local directory.
+ // ... more ?
+ enum AddFileFlags {
+ NoCompression = 1,
+ FollowSymLinks = 2
+ };
+ bool addFile(const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags = 0);
+ bool addDirectory(const QString &szLocalDirectoryName,const QString &szTargetDirectoryPrefix,kvi_u32_t uAddFileFlags = 0);
+ // Adds an info field as a name=value pair
+ void addInfoField(const QString &szName,const QString &szValue);
+ void addInfoField(const QString &szName,QByteArray * pArray);
+ // Attempts to pack everything and store it as the specified file.
+ // There is no mandatory extension but you *should* use KVI_FILEEXTENSION_THEMEPACKAGE for themes
+ // and KVI_FILEEXTENSION_ADDONPACKAGE for addons. See kvi_fileextension.h
+ enum PackFlags {
+ NoProgressDialog = 1
+ };
+ bool pack(const QString &szFileName,kvi_u32_t uPackFlags = 0);
+private:
+ bool packInternal(const QString &szFileName,kvi_u32_t uPackFlags = 0);
+ bool packFile(KviFile * pFile,DataField * pDataField);
+ bool addFileInternal(const QFileInfo * fi,const QString &szLocalFileName,const QString &szTargetFileName,kvi_u32_t uAddFileFlags = 0);
+};
+
+class KVILIB_API KviPackageReader : public KviPackageIOEngine
+{
+public:
+ KviPackageReader();
+ virtual ~KviPackageReader();
+public:
+ bool readHeader(const QString &szLocalFileName);
+ enum UnpackFlags {
+ NoProgressDialog = 1
+ };
+ bool getStringInfoField(const QString &szName,QString &szBuffer);
+ bool unpack(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags = 0);
+private:
+ bool unpackInternal(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags = 0);
+ bool unpackFile(KviFile * pFile,const QString &szUnpackPath);
+ bool readHeaderInternal(KviFile * pFile,const QString &szLocalFileName);
+};
+
+
+
+#endif //!_KVI_PACKAGEFILE_H_