~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/kvilib/file/KviPackageReader.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//=============================================================================
 
2
//
 
3
//   File : KviPackageReader.cpp
 
4
//   Creation date : Tue 26 Dec 2006 05:33:33 by Szymon Stefanek
 
5
//
 
6
//   This file is part of the KVIrc IRC Client distribution
 
7
//   Copyright (C) 2006-2010 Szymon Stefanek <pragma at kvirc dot net>
 
8
//
 
9
//   This program is FREE software. You can redistribute it and/or
 
10
//   modify it under the terms of the GNU General Public License
 
11
//   as published by the Free Software Foundation; either version 2
 
12
//   of the License, or (at your opinion) any later version.
 
13
//
 
14
//   This program is distributed in the HOPE that it will be USEFUL,
 
15
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
17
//   See the GNU General Public License for more details.
 
18
//
 
19
//   You should have received a copy of the GNU General Public License
 
20
//   along with this program. If not, write to the Free Software Foundation,
 
21
//   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
22
//
 
23
//=============================================================================
 
24
 
 
25
#include "KviPackageReader.h"
 
26
 
 
27
#include "KviFile.h"
 
28
#include "KviFileUtils.h"
 
29
#include "KviLocale.h"
 
30
 
 
31
#include "kvi_inttypes.h"
 
32
 
 
33
#ifdef COMPILE_ZLIB_SUPPORT
 
34
        #include <zlib.h>
 
35
#endif
 
36
 
 
37
//
 
38
// See KviPackageIOEngine.cpp for the description of the KVIrc package file
 
39
//
 
40
 
 
41
 
 
42
KviPackageReader::KviPackageReader()
 
43
: KviPackageIOEngine()
 
44
{
 
45
}
 
46
 
 
47
KviPackageReader::~KviPackageReader()
 
48
{
 
49
}
 
50
 
 
51
bool KviPackageReader::readHeaderInternal(KviFile * pFile,const QString &)
 
52
{
 
53
        // read the PackageHeader
 
54
 
 
55
        // Magic
 
56
        char magic[4];
 
57
 
 
58
        if(pFile->read(magic,4) != 4)
 
59
                return readError();
 
60
 
 
61
        if((magic[0] != 'K') || (magic[1] != 'V') || (magic[2] != 'P') || (magic[3] != 'F'))
 
62
        {
 
63
                setLastError(__tr2qs("The file specified is not a valid KVIrc package"));
 
64
                return false;
 
65
        }
 
66
 
 
67
        // Version
 
68
        kvi_u32_t uVersion;
 
69
        if(!pFile->load(uVersion))
 
70
                return readError();
 
71
        if(uVersion != 0x1)
 
72
        {
 
73
                setLastError(__tr2qs("The package has an invalid version number, it might have been created by a newer KVIrc"));
 
74
                return false;
 
75
        }
 
76
 
 
77
        // Flags
 
78
        kvi_u32_t uFlags;
 
79
        if(!pFile->load(uFlags))
 
80
                return readError();
 
81
        // we ignore them at the moment
 
82
 
 
83
        // read PackageInfo
 
84
 
 
85
        // InfoFieldCount
 
86
        kvi_u32_t uCount;
 
87
        if(!pFile->load(uCount))
 
88
                return writeError();
 
89
 
 
90
        stringInfoFields()->clear();
 
91
        binaryInfoFields()->clear();
 
92
 
 
93
        kvi_u32_t uIdx = 0;
 
94
        while(uIdx < uCount)
 
95
        {
 
96
                QString szKey;
 
97
                if(!pFile->load(szKey))
 
98
                        return readError();
 
99
                kvi_u32_t uFieldType;
 
100
                if(!pFile->load(uFieldType))
 
101
                        return readError();
 
102
                switch(uFieldType)
 
103
                {
 
104
                        case KVI_PACKAGE_INFOFIELD_TYPE_STRING:
 
105
                        {
 
106
                                QString szValue;
 
107
                                if(!pFile->load(szValue))return readError();
 
108
                                stringInfoFields()->replace(szKey,new QString(szValue));
 
109
                        }
 
110
                        break;
 
111
                        case KVI_PACKAGE_INFOFIELD_TYPE_BINARYBUFFER:
 
112
                        {
 
113
                                QByteArray * pbValue = new QByteArray();
 
114
                                if(!pFile->load(*pbValue))
 
115
                                {
 
116
                                        delete pbValue;
 
117
                                        return readError();
 
118
                                }
 
119
                                binaryInfoFields()->replace(szKey,pbValue);
 
120
                        }
 
121
                        break;
 
122
                        default:
 
123
                                setLastError(__tr2qs("Invalid info field: the package is probably corrupt"));
 
124
                        break;
 
125
                }
 
126
                uIdx++;
 
127
        }
 
128
 
 
129
        return true;
 
130
}
 
131
 
 
132
bool KviPackageReader::readHeader(const QString &szLocalFileName)
 
133
{
 
134
        KviFile f(szLocalFileName);
 
135
        if(!f.open(QFile::ReadOnly))
 
136
        {
 
137
                setLastError(__tr2qs("Can't open file for reading"));
 
138
                return false;
 
139
        }
 
140
 
 
141
        return readHeaderInternal(&f,szLocalFileName);
 
142
}
 
143
 
 
144
#define BUFFER_SIZE 32768
 
145
 
 
146
 
 
147
bool KviPackageReader::unpackFile(KviFile * pFile,const QString &szUnpackPath)
 
148
{
 
149
        // Flags
 
150
        kvi_u32_t uFlags;
 
151
        if(!pFile->load(uFlags))
 
152
                return readError();
 
153
 
 
154
#ifndef COMPILE_ZLIB_SUPPORT
 
155
        if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE)
 
156
        {
 
157
                setLastError(__tr2qs("The package contains compressed data but this executable does not support compression"));
 
158
                return false;
 
159
        }
 
160
#endif
 
161
 
 
162
        // Path
 
163
        QString szPath;
 
164
        if(!pFile->load(szPath))
 
165
                return readError();
 
166
 
 
167
        QString szFileName = szUnpackPath;
 
168
        KviQString::ensureLastCharIs(szFileName,QChar(KVI_PATH_SEPARATOR_CHAR));
 
169
 
 
170
        szFileName += szPath;
 
171
 
 
172
        // no attacks please :)
 
173
        szFileName.replace(QString("..\\"),QString(""));
 
174
        szFileName.replace(QString("..//"),QString(""));
 
175
 
 
176
        KviFileUtils::adjustFilePath(szFileName);
 
177
 
 
178
        int idx = szFileName.lastIndexOf(QChar(KVI_PATH_SEPARATOR_CHAR),0,Qt::CaseSensitive);
 
179
        if(idx != -1)
 
180
        {
 
181
                QString szPrefixPath = szFileName.left(idx);
 
182
                if(!KviFileUtils::makeDir(szPrefixPath))
 
183
                {
 
184
                        setLastError(__tr2qs("Failed to create the target directory"));
 
185
                        return false;
 
186
                }
 
187
        }
 
188
 
 
189
        KviFile dest(szFileName);
 
190
        if(!dest.open(QFile::WriteOnly | QFile::Truncate))
 
191
        {
 
192
                setLastError(__tr2qs("Failed to open a source file for reading"));
 
193
                return false;
 
194
        }
 
195
 
 
196
        QString szProgressText = QString(__tr2qs("Unpacking file %1")).arg(szFileName);
 
197
        if(!updateProgress(pFile->pos(),szProgressText))
 
198
                return false; // aborted
 
199
 
 
200
        // Size
 
201
        kvi_u32_t uSize;
 
202
        if(!pFile->load(uSize))
 
203
                return readError();
 
204
 
 
205
        // FilePayload
 
206
#ifdef COMPILE_ZLIB_SUPPORT
 
207
        if(uFlags & KVI_PACKAGE_DATAFIELD_FLAG_FILE_DEFLATE)
 
208
        {
 
209
        //      qDebug ("loading compressed data");
 
210
                int iRemainingSize = uSize;
 
211
                unsigned char ibuffer[BUFFER_SIZE];
 
212
                unsigned char obuffer[BUFFER_SIZE];
 
213
 
 
214
                int iToRead = iRemainingSize;
 
215
                if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE;
 
216
                int iReaded = pFile->read((char *)ibuffer,iToRead);
 
217
                iRemainingSize -= iReaded;
 
218
 
 
219
                z_stream zstr;
 
220
                zstr.zalloc = Z_NULL;
 
221
                zstr.zfree = Z_NULL;
 
222
                zstr.opaque = Z_NULL;
 
223
                zstr.next_in = ibuffer;
 
224
                zstr.avail_in = iReaded;
 
225
                zstr.next_out = obuffer;
 
226
                zstr.avail_out = BUFFER_SIZE;
 
227
 
 
228
                if(inflateInit(&zstr) != Z_OK)
 
229
                {
 
230
                        setLastError(__tr2qs("Compression library initialization error"));
 
231
                        return false;
 
232
                }
 
233
 
 
234
                while((iReaded > 0) && (iRemainingSize > 0))
 
235
                {
 
236
                        zstr.next_out = obuffer;
 
237
                        zstr.avail_out = BUFFER_SIZE;
 
238
 
 
239
                        if(inflate(&zstr,Z_NO_FLUSH) != Z_OK)
 
240
                        {
 
241
                                setLastError(__tr2qs("Compression library error"));
 
242
                                return false;
 
243
                        }
 
244
 
 
245
                        if(zstr.avail_out < BUFFER_SIZE)
 
246
                        {
 
247
                                int iDecompressed = zstr.next_out - obuffer;
 
248
                                if(dest.write((char *)obuffer,iDecompressed) != iDecompressed)
 
249
                                {
 
250
                                        inflateEnd(&zstr);
 
251
                                        return writeError();
 
252
                                }
 
253
                        }
 
254
 
 
255
                        if(zstr.avail_in < BUFFER_SIZE)
 
256
                        {
 
257
                                int iDataToRead = BUFFER_SIZE - zstr.avail_in;
 
258
                                if(iDataToRead < BUFFER_SIZE)
 
259
                                {
 
260
                                        if(ibuffer != zstr.next_in)
 
261
                                        {
 
262
                                                // hum, there is still some data in the buffer to be readed
 
263
                                                // and it is not at the beginning...move it to the beginning of ibuffer
 
264
                                                memmove(ibuffer,zstr.next_in,zstr.avail_in);
 
265
                                        }
 
266
                                }
 
267
 
 
268
                                if(iDataToRead > iRemainingSize)
 
269
                                        iDataToRead = iRemainingSize;
 
270
 
 
271
                                iReaded = pFile->read((char *)(ibuffer + zstr.avail_in),iDataToRead);
 
272
                                if(iReaded < 0)
 
273
                                {
 
274
                                        inflateEnd(&zstr);
 
275
                                        return readError();
 
276
                                }
 
277
 
 
278
                                iRemainingSize -= iReaded;
 
279
                                zstr.avail_in += iReaded;
 
280
                                zstr.next_in = ibuffer;
 
281
 
 
282
                                if((zstr.total_in % 2000000) == 0)
 
283
                                {
 
284
                                        QString szTmp = QString(" (%1 of %2 bytes)").arg(zstr.total_in,uSize);
 
285
                                        QString szPrg = szProgressText + szTmp;
 
286
                                        if(!updateProgress(pFile->pos(),szPrg))
 
287
                                                return false; // aborted
 
288
                                }
 
289
                        }
 
290
                }
 
291
 
 
292
                // flush pending output
 
293
                zstr.next_out = obuffer;
 
294
                zstr.avail_out = BUFFER_SIZE;
 
295
 
 
296
                int ret;
 
297
 
 
298
                do {
 
299
                        ret = inflate(&zstr,Z_FINISH);
 
300
 
 
301
                        if((ret == Z_OK) || (ret == Z_STREAM_END) || (ret == Z_BUF_ERROR))
 
302
                        {
 
303
                                if(zstr.avail_out < BUFFER_SIZE)
 
304
                                {
 
305
                                        int iDecompressed = zstr.next_out - obuffer;
 
306
                                        if(dest.write((char *)obuffer,iDecompressed) != iDecompressed)
 
307
                                        {
 
308
                                                inflateEnd(&zstr);
 
309
                                                return writeError();
 
310
                                        }
 
311
                                } else {
 
312
                                        //THIS HAPPENS FOR ZERO SIZE FILES
 
313
                                        qDebug("hum.... internal, rEWq (ret = %d) (avail_out = %d)",ret,zstr.avail_out);
 
314
 
 
315
                                        inflateEnd(&zstr);
 
316
                                        setLastError(__tr2qs("Compression library internal error"));
 
317
                                        return false;
 
318
                                }
 
319
                                zstr.next_out = obuffer;
 
320
                                zstr.avail_out = BUFFER_SIZE;
 
321
                        }
 
322
 
 
323
                } while((ret == Z_OK) || (ret == Z_BUF_ERROR));
 
324
 
 
325
                inflateEnd(&zstr);
 
326
 
 
327
                if(ret != Z_STREAM_END)
 
328
                {
 
329
                        setLastError(__tr2qs("Error in compressed file stream"));
 
330
                        return false;
 
331
                }
 
332
 
 
333
        } else {
 
334
#endif
 
335
        //      qDebug("Load uncompressed data");
 
336
                unsigned char buffer[BUFFER_SIZE];
 
337
                int iTotalFileSize = 0;
 
338
                int iRemainingData = uSize;
 
339
                int iToRead = iRemainingData;
 
340
                if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE;
 
341
                int iReaded = 1;
 
342
        //      qDebug("iReaded %i and iToRead %i and index %i",iReaded,iToRead,pFile->pos());
 
343
                while((iReaded > 0) && (iToRead > 0))
 
344
                {
 
345
                        iReaded = pFile->read((char *)buffer,iToRead);
 
346
                        if(iReaded > 0)
 
347
                        {
 
348
                                iTotalFileSize += iReaded;
 
349
                                iRemainingData -= iReaded;
 
350
 
 
351
                                if((iTotalFileSize % 3000000) == 0)
 
352
                                {
 
353
                                        QString szTmp = QString(" (%1 of %2 bytes)").arg(iTotalFileSize).arg(uSize);
 
354
                                        QString szPrg = szProgressText + szTmp;
 
355
                                        if(!updateProgress(pFile->pos(),szPrg))
 
356
                                                return false; // aborted
 
357
                                }
 
358
                        //      qDebug("write file with size %i and name %s",iReaded,dest.fileName().toUtf8().data());
 
359
                                if(dest.write((char *)buffer,iReaded) != iReaded)
 
360
                                        return writeError();
 
361
                        }
 
362
                        //qDebug("Remains %i", iRemainingData);
 
363
                        iToRead = iRemainingData;
 
364
                        if(iToRead > BUFFER_SIZE)iToRead = BUFFER_SIZE;
 
365
                }
 
366
        //      qDebug("finish to read %i and index %i",iReaded,pFile->pos());
 
367
#ifdef COMPILE_ZLIB_SUPPORT
 
368
        }
 
369
#endif
 
370
        dest.close();
 
371
 
 
372
        return true;
 
373
}
 
374
 
 
375
bool KviPackageReader::getStringInfoField(const QString &szName,QString &szBuffer)
 
376
{
 
377
        QString * pVal = stringInfoFields()->find(szName);
 
378
        if(!pVal)
 
379
                return false;
 
380
        szBuffer = *pVal;
 
381
        return true;
 
382
}
 
383
 
 
384
bool KviPackageReader::unpack(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags)
 
385
{
 
386
        bool bRet = unpackInternal(szLocalFileName,szUnpackPath,uUnpackFlags);
 
387
        hideProgressDialog();
 
388
        return bRet;
 
389
}
 
390
 
 
391
bool KviPackageReader::unpackInternal(const QString &szLocalFileName,const QString &szUnpackPath,kvi_u32_t uUnpackFlags)
 
392
{
 
393
 
 
394
        KviFile f(szLocalFileName);
 
395
        if(!f.open(QFile::ReadOnly))
 
396
        {
 
397
                setLastError(__tr2qs("Can't open file for reading"));
 
398
                return false;
 
399
        }
 
400
 
 
401
        kvi_file_offset_t size = f.size();
 
402
 
 
403
        if(!(uUnpackFlags & NoProgressDialog))
 
404
        {
 
405
                showProgressDialog(__tr2qs("Reading package..."),size);
 
406
                updateProgress(0,__tr2qs("Reading package header"));
 
407
        }
 
408
 
 
409
        if(!readHeaderInternal(&f,szLocalFileName))
 
410
                return false;
 
411
 
 
412
        if(!updateProgress(f.pos(),__tr2qs("Reading package data")))
 
413
                return false; // aborted
 
414
 
 
415
        while(!f.atEnd())
 
416
        {
 
417
                // DataFieldType
 
418
                kvi_u32_t uDataFieldType;
 
419
                if(!f.load(uDataFieldType))return readError();
 
420
                // DataFieldLen
 
421
                kvi_u32_t uDataFieldLen;
 
422
                if(!f.load(uDataFieldLen))return readError();
 
423
 
 
424
                switch(uDataFieldType)
 
425
                {
 
426
                        case KVI_PACKAGE_DATAFIELD_TYPE_FILE:
 
427
                                if(!unpackFile(&f,szUnpackPath))
 
428
                                        return false;
 
429
                        break;
 
430
                        default:
 
431
                                setLastError(__tr2qs("Invalid data field: the package is probably corrupt"));
 
432
                                return false;
 
433
                        break;
 
434
                }
 
435
        }
 
436
 
 
437
        return true;
 
438
}
 
439