~ubuntu-branches/ubuntu/precise/stellarium/precise

« back to all changes in this revision

Viewing changes to src/external/kfilter/kzip.cpp

  • Committer: Andrew Starr-Bochicchio
  • Date: 2010-03-30 00:04:15 UTC
  • mfrom: (7.1.1 stellarium)
  • Revision ID: a.starr.b@gmail.com-20100330000415-0wsxd2ha67125l0f
Tags: 0.10.4-0ubuntu1
New upstream release. (LP: #548963)

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
/*
21
21
        This class implements a kioslave to access ZIP files from KDE.
22
 
    you can use it in QIODevice::ReadOnly or in QIODevice::WriteOnly mode, and it
23
 
    behaves just as expected (i hope ;-) ).
24
 
    It can also be used in QIODevice::ReadWrite mode, in this case one can
25
 
    append files to an existing zip archive. when you append new files, which
26
 
    are not yet in the zip, it works as expected, they are appended at the end.
27
 
    when you append a file, which is already in the file, the reference to the
28
 
    old file is dropped and the new one is added to the zip. but the
29
 
    old data from the file itself is not deleted, it is still in the
30
 
    zipfile. so when you want to have a small and garbagefree zipfile,
31
 
    just read the contents of the appended zipfile and write it to a new one
32
 
    in QIODevice::WriteOnly mode. especially take care of this, when you don't want
33
 
    to leak information of how intermediate versions of files in the zip
34
 
    were looking.
35
 
    For more information on the zip fileformat go to
36
 
    http://www.pkware.com/support/appnote.html .
 
22
        you can use it in QIODevice::ReadOnly or in QIODevice::WriteOnly mode, and it
 
23
        behaves just as expected (i hope ;-) ).
 
24
        It can also be used in QIODevice::ReadWrite mode, in this case one can
 
25
        append files to an existing zip archive. when you append new files, which
 
26
        are not yet in the zip, it works as expected, they are appended at the end.
 
27
        when you append a file, which is already in the file, the reference to the
 
28
        old file is dropped and the new one is added to the zip. but the
 
29
        old data from the file itself is not deleted, it is still in the
 
30
        zipfile. so when you want to have a small and garbagefree zipfile,
 
31
        just read the contents of the appended zipfile and write it to a new one
 
32
        in QIODevice::WriteOnly mode. especially take care of this, when you don't want
 
33
        to leak information of how intermediate versions of files in the zip
 
34
        were looking.
 
35
        For more information on the zip fileformat go to
 
36
        http://www.pkware.com/support/appnote.html .
37
37
 
38
38
*/
39
39
 
54
54
#include <string.h>
55
55
#include <sys/stat.h>
56
56
 
57
 
#ifdef WIN32
 
57
#ifdef Q_OS_WIN
58
58
#include "kdewin32/sys/stat.h"
59
59
#endif
60
60
 
62
62
 
63
63
static void transformToMsDos(const QDateTime& dt, char* buffer)
64
64
{
65
 
    if ( dt.isValid() )
66
 
    {
67
 
        const quint16 time =
68
 
             ( dt.time().hour() << 11 )    // 5 bit hour
69
 
           | ( dt.time().minute() << 5 )   // 6 bit minute
70
 
           | ( dt.time().second() >> 1 );  // 5 bit double seconds
71
 
 
72
 
        buffer[0] = char(time);
73
 
        buffer[1] = char(time >> 8);
74
 
 
75
 
        const quint16 date =
76
 
             ( ( dt.date().year() - 1980 ) << 9 ) // 7 bit year 1980-based
77
 
           | ( dt.date().month() << 5 )           // 4 bit month
78
 
           | ( dt.date().day() );                 // 5 bit day
79
 
 
80
 
        buffer[2] = char(date);
81
 
        buffer[3] = char(date >> 8);
82
 
    }
83
 
    else // !dt.isValid(), assume 1980-01-01 midnight
84
 
    {
85
 
        buffer[0] = 0;
86
 
        buffer[1] = 0;
87
 
        buffer[2] = 33;
88
 
        buffer[3] = 0;
89
 
    }
 
65
        if ( dt.isValid() )
 
66
        {
 
67
                const quint16 time =
 
68
                         ( dt.time().hour() << 11 )    // 5 bit hour
 
69
                   | ( dt.time().minute() << 5 )   // 6 bit minute
 
70
                   | ( dt.time().second() >> 1 );  // 5 bit double seconds
 
71
 
 
72
                buffer[0] = char(time);
 
73
                buffer[1] = char(time >> 8);
 
74
 
 
75
                const quint16 date =
 
76
                         ( ( dt.date().year() - 1980 ) << 9 ) // 7 bit year 1980-based
 
77
                   | ( dt.date().month() << 5 )           // 4 bit month
 
78
                   | ( dt.date().day() );                 // 5 bit day
 
79
 
 
80
                buffer[2] = char(date);
 
81
                buffer[3] = char(date >> 8);
 
82
        }
 
83
        else // !dt.isValid(), assume 1980-01-01 midnight
 
84
        {
 
85
                buffer[0] = 0;
 
86
                buffer[1] = 0;
 
87
                buffer[2] = 33;
 
88
                buffer[3] = 0;
 
89
        }
90
90
}
91
91
 
92
92
static time_t transformFromMsDos(const char* buffer)
93
93
{
94
 
    quint16 time = (uchar)buffer[0] | ( (uchar)buffer[1] << 8 );
95
 
    int h = time >> 11;
96
 
    int m = ( time & 0x7ff ) >> 5;
97
 
    int s = ( time & 0x1f ) * 2 ;
98
 
    QTime qt(h, m, s);
99
 
 
100
 
    quint16 date = (uchar)buffer[2] | ( (uchar)buffer[3] << 8 );
101
 
    int y = ( date >> 9 ) + 1980;
102
 
    int o = ( date & 0x1ff ) >> 5;
103
 
    int d = ( date & 0x1f );
104
 
    QDate qd(y, o, d);
105
 
 
106
 
    QDateTime dt( qd, qt );
107
 
    return dt.toTime_t();
 
94
        quint16 time = (uchar)buffer[0] | ( (uchar)buffer[1] << 8 );
 
95
        int h = time >> 11;
 
96
        int m = ( time & 0x7ff ) >> 5;
 
97
        int s = ( time & 0x1f ) * 2 ;
 
98
        QTime qt(h, m, s);
 
99
 
 
100
        quint16 date = (uchar)buffer[2] | ( (uchar)buffer[3] << 8 );
 
101
        int y = ( date >> 9 ) + 1980;
 
102
        int o = ( date & 0x1ff ) >> 5;
 
103
        int d = ( date & 0x1f );
 
104
        QDate qd(y, o, d);
 
105
 
 
106
        QDateTime dt( qd, qt );
 
107
        return dt.toTime_t();
108
108
}
109
109
 
110
110
// == parsing routines for zip headers
123
123
 
124
124
  // parsing related info
125
125
  bool exttimestamp_seen;       // true if extended timestamp extra field
126
 
                                // has been parsed
 
126
                                // has been parsed
127
127
  bool newinfounix_seen;        // true if Info-ZIP Unix New extra field has
128
 
                                // been parsed
 
128
                                // been parsed
129
129
 
130
130
  ParseFileInfo() : perm(0100644), uid(-1), gid(-1), extralen(0),
131
 
        exttimestamp_seen(false), newinfounix_seen(false) {
132
 
    ctime = mtime = atime = time(0);
 
131
        exttimestamp_seen(false), newinfounix_seen(false) {
 
132
        ctime = mtime = atime = time(0);
133
133
  }
134
134
};
135
135
 
144
144
static bool parseExtTimestamp(const char *buffer, int size, bool islocal,
145
145
                        ParseFileInfo &pfi) {
146
146
  if (size < 1) {
147
 
    qDebug() << "premature end of extended timestamp (#1)";
148
 
    return false;
 
147
        qDebug() << "premature end of extended timestamp (#1)";
 
148
        return false;
149
149
  }/*end if*/
150
150
  int flags = *buffer;          // read flags
151
151
  buffer += 1;
152
152
  size -= 1;
153
153
 
154
154
  if (flags & 1) {              // contains modification time
155
 
    if (size < 4) {
156
 
      qDebug() << "premature end of extended timestamp (#2)";
157
 
      return false;
158
 
    }/*end if*/
159
 
    pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
160
 
                        | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
161
 
    buffer += 4;
162
 
    size -= 4;
 
155
        if (size < 4) {
 
156
          qDebug() << "premature end of extended timestamp (#2)";
 
157
          return false;
 
158
        }/*end if*/
 
159
        pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
 
160
                                | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
 
161
        buffer += 4;
 
162
        size -= 4;
163
163
  }/*end if*/
164
164
  // central extended field cannot contain more than the modification time
165
165
  // even if other flags are set
166
166
  if (!islocal) {
167
 
    pfi.exttimestamp_seen = true;
168
 
    return true;
 
167
        pfi.exttimestamp_seen = true;
 
168
        return true;
169
169
  }/*end if*/
170
170
 
171
171
  if (flags & 2) {              // contains last access time
172
 
    if (size < 4) {
173
 
      qDebug() << "premature end of extended timestamp (#3)";
174
 
      return true;
175
 
    }/*end if*/
176
 
    pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
177
 
                        | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
178
 
    buffer += 4;
179
 
    size -= 4;
 
172
        if (size < 4) {
 
173
          qDebug() << "premature end of extended timestamp (#3)";
 
174
          return true;
 
175
        }/*end if*/
 
176
        pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
 
177
                                | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
 
178
        buffer += 4;
 
179
        size -= 4;
180
180
  }/*end if*/
181
181
 
182
182
  if (flags & 4) {              // contains creation time
183
 
    if (size < 4) {
184
 
      qDebug() << "premature end of extended timestamp (#4)";
185
 
      return true;
186
 
    }/*end if*/
187
 
    pfi.ctime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
188
 
                        | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
189
 
    buffer += 4;
 
183
        if (size < 4) {
 
184
          qDebug() << "premature end of extended timestamp (#4)";
 
185
          return true;
 
186
        }/*end if*/
 
187
        pfi.ctime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
 
188
                                | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
 
189
        buffer += 4;
190
190
  }/*end if*/
191
191
 
192
192
  pfi.exttimestamp_seen = true;
207
207
  if (pfi.exttimestamp_seen || pfi.newinfounix_seen) return true;
208
208
 
209
209
  if (size < 8) {
210
 
    qDebug() << "premature end of Info-ZIP unix extra field old";
211
 
    return false;
 
210
        qDebug() << "premature end of Info-ZIP unix extra field old";
 
211
        return false;
212
212
  }/*end if*/
213
213
 
214
214
  pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
215
 
                        | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
 
215
                                | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
216
216
  buffer += 4;
217
217
  pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
218
 
                        | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
 
218
                                | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
219
219
  buffer += 4;
220
220
  if (islocal && size >= 12) {
221
 
    pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
222
 
    buffer += 2;
223
 
    pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
224
 
    buffer += 2;
 
221
        pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
 
222
        buffer += 2;
 
223
        pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
 
224
        buffer += 2;
225
225
  }/*end if*/
226
226
  return true;
227
227
}
238
238
static bool parseInfoZipUnixNew(const char *buffer, int size, bool islocal,
239
239
                        ParseFileInfo &pfi) {
240
240
  if (!islocal) {       // contains nothing in central field
241
 
    pfi.newinfounix = true;
242
 
    return true;
 
241
        pfi.newinfounix = true;
 
242
        return true;
243
243
  }/*end if*/
244
244
 
245
245
  if (size < 4) {
246
 
    qDebug() << "premature end of Info-ZIP unix extra field new";
247
 
    return false;
 
246
        qDebug() << "premature end of Info-ZIP unix extra field new";
 
247
        return false;
248
248
  }/*end if*/
249
249
 
250
250
  pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
272
272
  if (!islocal) return true;
273
273
 
274
274
  while (size >= 4) {   // as long as a potential extra field can be read
275
 
    int magic = (uchar)buffer[0] | (uchar)buffer[1] << 8;
276
 
    buffer += 2;
277
 
    int fieldsize = (uchar)buffer[0] | (uchar)buffer[1] << 8;
278
 
    buffer += 2;
279
 
    size -= 4;
280
 
 
281
 
    if (fieldsize > size) {
282
 
      //qDebug() << "fieldsize: " << fieldsize << " size: " << size;
283
 
      qDebug() << "premature end of extra fields reached";
284
 
      break;
285
 
    }/*end if*/
286
 
 
287
 
    switch (magic) {
288
 
      case 0x5455:              // extended timestamp
289
 
        if (!parseExtTimestamp(buffer, fieldsize, islocal, pfi)) return false;
 
275
        int magic = (uchar)buffer[0] | (uchar)buffer[1] << 8;
 
276
        buffer += 2;
 
277
        int fieldsize = (uchar)buffer[0] | (uchar)buffer[1] << 8;
 
278
        buffer += 2;
 
279
        size -= 4;
 
280
 
 
281
        if (fieldsize > size) {
 
282
          //qDebug() << "fieldsize: " << fieldsize << " size: " << size;
 
283
          qDebug() << "premature end of extra fields reached";
 
284
          break;
 
285
        }/*end if*/
 
286
 
 
287
        switch (magic) {
 
288
          case 0x5455:          // extended timestamp
 
289
                if (!parseExtTimestamp(buffer, fieldsize, islocal, pfi)) return false;
290
290
        break;
291
 
      case 0x5855:              // old Info-ZIP unix extra field
292
 
        if (!parseInfoZipUnixOld(buffer, fieldsize, islocal, pfi)) return false;
 
291
          case 0x5855:          // old Info-ZIP unix extra field
 
292
                if (!parseInfoZipUnixOld(buffer, fieldsize, islocal, pfi)) return false;
293
293
        break;
294
294
#if 0   // not needed yet
295
 
      case 0x7855:              // new Info-ZIP unix extra field
296
 
        if (!parseInfoZipUnixNew(buffer, fieldsize, islocal, pfi)) return false;
 
295
          case 0x7855:          // new Info-ZIP unix extra field
 
296
                if (!parseInfoZipUnixNew(buffer, fieldsize, islocal, pfi)) return false;
297
297
        break;
298
298
#endif
299
 
      default:
300
 
        /* ignore everything else */;
301
 
    }/*end switch*/
 
299
          default:
 
300
                /* ignore everything else */;
 
301
        }/*end switch*/
302
302
 
303
 
    buffer += fieldsize;
304
 
    size -= fieldsize;
 
303
        buffer += fieldsize;
 
304
        size -= fieldsize;
305
305
  }/*wend*/
306
306
  return true;
307
307
}
313
313
class KZip::KZipPrivate
314
314
{
315
315
public:
316
 
    KZipPrivate()
317
 
        : m_crc( 0 ),
318
 
          m_currentFile( 0 ),
319
 
          m_currentDev( 0 ),
320
 
          m_compression( 8 ),
321
 
          m_extraField( KZip::NoExtraField ),
 
316
        KZipPrivate()
 
317
                : m_crc( 0 ),
 
318
                  m_currentFile( 0 ),
 
319
                  m_currentDev( 0 ),
 
320
                  m_compression( 8 ),
 
321
                  m_extraField( KZip::NoExtraField ),
322
322
          m_offset( 0 )
323
 
    {}
 
323
        {}
324
324
 
325
 
    unsigned long           m_crc;         // checksum
326
 
    KZipFileEntry*          m_currentFile; // file currently being written
327
 
    QIODevice*              m_currentDev;  // filterdev used to write to the above file
328
 
    QList<KZipFileEntry*> m_fileList;    // flat list of all files, for the index (saves a recursive method ;)
329
 
    int                     m_compression;
330
 
    KZip::ExtraField        m_extraField;
331
 
    // m_offset holds the offset of the place in the zip,
332
 
    // where new data can be appended. after openarchive it points to 0, when in
333
 
    // writeonly mode, or it points to the beginning of the central directory.
334
 
    // each call to writefile updates this value.
335
 
    unsigned int            m_offset;
 
325
        unsigned long           m_crc;         // checksum
 
326
        KZipFileEntry*          m_currentFile; // file currently being written
 
327
        QIODevice*              m_currentDev;  // filterdev used to write to the above file
 
328
        QList<KZipFileEntry*> m_fileList;    // flat list of all files, for the index (saves a recursive method ;)
 
329
        int                     m_compression;
 
330
        KZip::ExtraField        m_extraField;
 
331
        // m_offset holds the offset of the place in the zip,
 
332
        // where new data can be appended. after openarchive it points to 0, when in
 
333
        // writeonly mode, or it points to the beginning of the central directory.
 
334
        // each call to writefile updates this value.
 
335
        unsigned int            m_offset;
336
336
};
337
337
 
338
338
KZip::KZip( const QString& fileName )
339
 
    : KArchive( fileName ),d(new KZipPrivate)
 
339
        : KArchive( fileName ),d(new KZipPrivate)
340
340
{
341
341
}
342
342
 
343
343
KZip::KZip( QIODevice * dev )
344
 
    : KArchive( dev ),d(new KZipPrivate)
 
344
        : KArchive( dev ),d(new KZipPrivate)
345
345
{
346
346
}
347
347
 
348
348
KZip::~KZip()
349
349
{
350
 
    //qDebug() << this;
351
 
    if( isOpen() )
352
 
        close();
353
 
    delete d;
 
350
        //qDebug() << this;
 
351
        if( isOpen() )
 
352
                close();
 
353
        delete d;
354
354
}
355
355
 
356
356
bool KZip::openArchive( QIODevice::OpenMode mode )
357
357
{
358
 
    //qDebug();
359
 
    d->m_fileList.clear();
360
 
 
361
 
    if ( mode == QIODevice::WriteOnly )
362
 
        return true;
363
 
 
364
 
    char buffer[47];
365
 
 
366
 
    // Check that it's a valid ZIP file
367
 
    // KArchive::open() opened the underlying device already.
368
 
 
369
 
    uint offset = 0; // holds offset, where we read
370
 
    int n;
371
 
 
372
 
    // contains information gathered from the local file headers
373
 
    QHash<QByteArray, ParseFileInfo> pfi_map;
374
 
 
375
 
    QIODevice* dev = device();
376
 
 
377
 
    // We set a bool for knowing if we are allowed to skip the start of the file
378
 
    bool startOfFile = true;
379
 
 
380
 
    for (;;) // repeat until 'end of entries' signature is reached
381
 
    {
382
 
        //qDebug() << "loop starts";
383
 
        //qDebug() << "dev->pos() now : " << dev->pos();
384
 
        n = dev->read( buffer, 4 );
385
 
 
386
 
        if (n < 4)
387
 
        {
388
 
            qWarning() << "Invalid ZIP file. Unexpected end of file. (#1)";
389
 
 
390
 
            return false;
391
 
        }
392
 
 
393
 
        if ( !memcmp( buffer, "PK\5\6", 4 ) ) // 'end of entries'
394
 
        {
395
 
            //qDebug() << "PK56 found end of archive";
396
 
            startOfFile = false;
397
 
            break;
 
358
        //qDebug();
 
359
        d->m_fileList.clear();
 
360
 
 
361
        if ( mode == QIODevice::WriteOnly )
 
362
                return true;
 
363
 
 
364
        char buffer[47];
 
365
 
 
366
        // Check that it's a valid ZIP file
 
367
        // KArchive::open() opened the underlying device already.
 
368
 
 
369
        uint offset = 0; // holds offset, where we read
 
370
        int n;
 
371
 
 
372
        // contains information gathered from the local file headers
 
373
        QHash<QByteArray, ParseFileInfo> pfi_map;
 
374
 
 
375
        QIODevice* dev = device();
 
376
 
 
377
        // We set a bool for knowing if we are allowed to skip the start of the file
 
378
        bool startOfFile = true;
 
379
 
 
380
        for (;;) // repeat until 'end of entries' signature is reached
 
381
        {
 
382
                //qDebug() << "loop starts";
 
383
                //qDebug() << "dev->pos() now : " << dev->pos();
 
384
                n = dev->read( buffer, 4 );
 
385
 
 
386
                if (n < 4)
 
387
                {
 
388
                        qWarning() << "Invalid ZIP file. Unexpected end of file. (#1)";
 
389
 
 
390
                        return false;
 
391
                }
 
392
 
 
393
                if ( !memcmp( buffer, "PK\5\6", 4 ) ) // 'end of entries'
 
394
                {
 
395
                //qDebug() << "PK56 found end of archive";
 
396
                        startOfFile = false;
 
397
                break;
398
398
        }
399
399
 
400
400
        if ( !memcmp( buffer, "PK\3\4", 4 ) ) // local file header
401
 
        {
402
 
            //qDebug() << "PK34 found local file header";
403
 
            startOfFile = false;
404
 
            // can this fail ???
405
 
            dev->seek( dev->pos() + 2 ); // skip 'version needed to extract'
406
 
 
407
 
            // read static header stuff
408
 
            n = dev->read( buffer, 24 );
409
 
            if (n < 24) {
410
 
                qWarning() << "Invalid ZIP file. Unexpected end of file. (#4)";
411
 
                return false;
412
 
            }
413
 
 
414
 
            int gpf = (uchar)buffer[0]; // "general purpose flag" not "general protection fault" ;-)
415
 
            int compression_mode = (uchar)buffer[2] | (uchar)buffer[3] << 8;
416
 
            time_t mtime = transformFromMsDos( buffer+4 );
417
 
 
418
 
            qint64 compr_size = (uchar)buffer[12] | (uchar)buffer[13] << 8
419
 
                                | (uchar)buffer[14] << 16 | (uchar)buffer[15] << 24;
420
 
            qint64 uncomp_size = (uchar)buffer[16] | (uchar)buffer[17] << 8
421
 
                                | (uchar)buffer[18] << 16 | (uchar)buffer[19] << 24;
422
 
            int namelen = (uchar)buffer[20] | (uchar)buffer[21] << 8;
423
 
            int extralen = (uchar)buffer[22] | (uchar)buffer[23] << 8;
424
 
 
425
 
            /*
426
 
            qDebug() << "general purpose bit flag: " << gpf;
427
 
            qDebug() << "compressed size: " << compr_size;
428
 
            qDebug() << "uncompressed size: " << uncomp_size;
429
 
            qDebug() << "namelen: " << namelen;
430
 
            qDebug() << "extralen: " << extralen;
431
 
            qDebug() << "archive size: " << dev->size();
432
 
            */
433
 
 
434
 
            // read fileName
435
 
            Q_ASSERT( namelen > 0 );
436
 
            QByteArray fileName = dev->read(namelen);
437
 
            if ( fileName.size() < namelen ) {
438
 
                qWarning() << "Invalid ZIP file. Name not completely read (#2)";
 
401
                {
 
402
                //qDebug() << "PK34 found local file header";
 
403
                        startOfFile = false;
 
404
                        // can this fail ???
 
405
                dev->seek( dev->pos() + 2 ); // skip 'version needed to extract'
 
406
 
 
407
                // read static header stuff
 
408
                        n = dev->read( buffer, 24 );
 
409
                if (n < 24) {
 
410
                                qWarning() << "Invalid ZIP file. Unexpected end of file. (#4)";
 
411
                                return false;
 
412
                }
 
413
 
 
414
                int gpf = (uchar)buffer[0];     // "general purpose flag" not "general protection fault" ;-)
 
415
                int compression_mode = (uchar)buffer[2] | (uchar)buffer[3] << 8;
 
416
                time_t mtime = transformFromMsDos( buffer+4 );
 
417
 
 
418
                qint64 compr_size = (uchar)buffer[12] | (uchar)buffer[13] << 8
 
419
                                        | (uchar)buffer[14] << 16 | (uchar)buffer[15] << 24;
 
420
                qint64 uncomp_size = (uchar)buffer[16] | (uchar)buffer[17] << 8
 
421
                                        | (uchar)buffer[18] << 16 | (uchar)buffer[19] << 24;
 
422
                int namelen = (uchar)buffer[20] | (uchar)buffer[21] << 8;
 
423
                int extralen = (uchar)buffer[22] | (uchar)buffer[23] << 8;
 
424
 
 
425
                        /*
 
426
                qDebug() << "general purpose bit flag: " << gpf;
 
427
                qDebug() << "compressed size: " << compr_size;
 
428
                qDebug() << "uncompressed size: " << uncomp_size;
 
429
                qDebug() << "namelen: " << namelen;
 
430
                qDebug() << "extralen: " << extralen;
 
431
                qDebug() << "archive size: " << dev->size();
 
432
                */
 
433
 
 
434
                // read fileName
 
435
                        Q_ASSERT( namelen > 0 );
 
436
                QByteArray fileName = dev->read(namelen);
 
437
                        if ( fileName.size() < namelen ) {
 
438
                                qWarning() << "Invalid ZIP file. Name not completely read (#2)";
439
439
                return false;
440
 
            }
441
 
 
442
 
            ParseFileInfo pfi;
443
 
            pfi.mtime = mtime;
444
 
 
445
 
            // read and parse the beginning of the extra field,
446
 
            // skip rest of extra field in case it is too long
447
 
            unsigned int extraFieldEnd = dev->pos() + extralen;
448
 
            pfi.extralen = extralen;
449
 
            int handledextralen = qMin(extralen, (int)sizeof buffer);
450
 
 
451
 
            //if ( handledextralen )
452
 
            //    qDebug() << "handledextralen: " << handledextralen;
453
 
 
454
 
            n = dev->read(buffer, handledextralen);
455
 
            // no error msg necessary as we deliberately truncate the extra field
456
 
            if (!parseExtraField(buffer, handledextralen, true, pfi))
457
 
            {
458
 
                qWarning() << "Invalid ZIP File. Broken ExtraField.";
459
 
                return false;
460
 
            }
461
 
 
462
 
            // jump to end of extra field
463
 
            dev->seek( extraFieldEnd );
464
 
 
465
 
            // we have to take care of the 'general purpose bit flag'.
466
 
            // if bit 3 is set, the header doesn't contain the length of
467
 
            // the file and we look for the signature 'PK\7\8'.
468
 
            if ( gpf & 8 )
469
 
            {
470
 
                // here we have to read through the compressed data to find
 
440
                }
 
441
 
 
442
                ParseFileInfo pfi;
 
443
                pfi.mtime = mtime;
 
444
 
 
445
                        // read and parse the beginning of the extra field,
 
446
                        // skip rest of extra field in case it is too long
 
447
                        unsigned int extraFieldEnd = dev->pos() + extralen;
 
448
                pfi.extralen = extralen;
 
449
                int handledextralen = qMin(extralen, (int)sizeof buffer);
 
450
 
 
451
                        //if ( handledextralen )
 
452
                        //    qDebug() << "handledextralen: " << handledextralen;
 
453
 
 
454
                n = dev->read(buffer, handledextralen);
 
455
                // no error msg necessary as we deliberately truncate the extra field
 
456
                if (!parseExtraField(buffer, handledextralen, true, pfi))
 
457
                {
 
458
                        qWarning() << "Invalid ZIP File. Broken ExtraField.";
 
459
                        return false;
 
460
                }
 
461
 
 
462
                        // jump to end of extra field
 
463
                        dev->seek( extraFieldEnd );
 
464
 
 
465
                // we have to take care of the 'general purpose bit flag'.
 
466
                        // if bit 3 is set, the header doesn't contain the length of
 
467
                        // the file and we look for the signature 'PK\7\8'.
 
468
                        if ( gpf & 8 )
 
469
                        {
 
470
                        // here we have to read through the compressed data to find
471
471
                // the next PKxx
472
 
                qDebug() << "trying to seek for next PK78";
473
 
                bool foundSignature = false;
474
 
 
475
 
                while (!foundSignature)
476
 
                {
477
 
                    n = dev->read( buffer, 1 );
478
 
                    if (n < 1)
479
 
                    {
480
 
                        qWarning() << "Invalid ZIP file. Unexpected end of file. (#2)";
481
 
                        return false;
482
 
                    }
483
 
 
484
 
                    if ( buffer[0] != 'P' )
485
 
                        continue;
486
 
 
487
 
                    n = dev->read( buffer, 3 );
488
 
                    if (n < 3)
489
 
                    {
490
 
                        qWarning() << "Invalid ZIP file. Unexpected end of file. (#3)";
491
 
                        return false;
492
 
                    }
493
 
 
494
 
                    // we have to detect three magic tokens here:
495
 
                    // PK34 for the next local header in case there is no data descriptor
496
 
                    // PK12 for the central header in case there is no data descriptor
497
 
                    // PK78 for the data descriptor in case it is following the compressed data
498
 
 
499
 
                    if ( buffer[0] == 'K' && buffer[1] == 7 && buffer[2] == 8 )
500
 
                    {
501
 
                        foundSignature = true;
502
 
                        dev->seek( dev->pos() + 12 ); // skip the 'data_descriptor'
503
 
                    }
504
 
                    else if ( ( buffer[0] == 'K' && buffer[1] == 1 && buffer[2] == 2 )
505
 
                         || ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 ) )
506
 
                    {
507
 
                        foundSignature = true;
508
 
                        dev->seek( dev->pos() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
509
 
                    }
510
 
                    else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
511
 
                    {
512
 
                        // We have another P character so we must go back a little to check if it is a magic
513
 
                        dev->seek( dev->pos() - 3 );
514
 
                    }
515
 
 
516
 
                }
517
 
            }
518
 
            else
519
 
            {
520
 
                // here we skip the compressed data and jump to the next header
521
 
                //qDebug() << "general purpose bit flag indicates, that local file header contains valid size";
 
472
                        qDebug() << "trying to seek for next PK78";
 
473
                                bool foundSignature = false;
 
474
 
 
475
                                while (!foundSignature)
 
476
                                {
 
477
                                        n = dev->read( buffer, 1 );
 
478
                                        if (n < 1)
 
479
                                        {
 
480
                                                qWarning() << "Invalid ZIP file. Unexpected end of file. (#2)";
 
481
                                                return false;
 
482
                                        }
 
483
 
 
484
                                        if ( buffer[0] != 'P' )
 
485
                                                continue;
 
486
 
 
487
                                        n = dev->read( buffer, 3 );
 
488
                                        if (n < 3)
 
489
                                        {
 
490
                                                qWarning() << "Invalid ZIP file. Unexpected end of file. (#3)";
 
491
                                                return false;
 
492
                                        }
 
493
 
 
494
                                        // we have to detect three magic tokens here:
 
495
                        // PK34 for the next local header in case there is no data descriptor
 
496
                        // PK12 for the central header in case there is no data descriptor
 
497
                        // PK78 for the data descriptor in case it is following the compressed data
 
498
 
 
499
                        if ( buffer[0] == 'K' && buffer[1] == 7 && buffer[2] == 8 )
 
500
                                        {
 
501
                                                foundSignature = true;
 
502
                                                dev->seek( dev->pos() + 12 ); // skip the 'data_descriptor'
 
503
                                        }
 
504
                        else if ( ( buffer[0] == 'K' && buffer[1] == 1 && buffer[2] == 2 )
 
505
                                 || ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 ) )
 
506
                                        {
 
507
                                                foundSignature = true;
 
508
                                                dev->seek( dev->pos() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
 
509
                                        }
 
510
                                        else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
 
511
                                        {
 
512
                                                // We have another P character so we must go back a little to check if it is a magic
 
513
                                                dev->seek( dev->pos() - 3 );
 
514
                                        }
 
515
 
 
516
                                }
 
517
                        }
 
518
                        else
 
519
                        {
 
520
                        // here we skip the compressed data and jump to the next header
 
521
                        //qDebug() << "general purpose bit flag indicates, that local file header contains valid size";
522
522
                // check if this could be a symbolic link
523
523
                if (compression_mode == NoCompression
524
 
                        && uncomp_size <= max_path_len
 
524
                                && uncomp_size <= max_path_len
525
525
                        && uncomp_size > 0) {
526
 
                    // read content and store it
527
 
                    // If it's not a symlink, then we'll just discard the data for now.
528
 
                    pfi.guessed_symlink = dev->read(uncomp_size);
529
 
                    if (pfi.guessed_symlink.size() < uncomp_size) {
 
526
                        // read content and store it
 
527
                                        // If it's not a symlink, then we'll just discard the data for now.
 
528
                        pfi.guessed_symlink = dev->read(uncomp_size);
 
529
                        if (pfi.guessed_symlink.size() < uncomp_size) {
530
530
                        qWarning() << "Invalid ZIP file. Unexpected end of file. (#5)";
531
531
                        return false;
532
 
                    }
 
532
                        }
533
533
                } else {
534
534
 
535
 
                    if ( compr_size > dev->size() )
536
 
                    {
537
 
                        // here we cannot trust the compressed size, so scan through the compressed
 
535
                                if ( compr_size > dev->size() )
 
536
                        {
 
537
                                // here we cannot trust the compressed size, so scan through the compressed
538
538
                        // data to find the next header
539
539
                        bool foundSignature = false;
540
540
 
577
577
                                        // in the next cycle...
578
578
                                }
579
579
                        }
580
 
                    }
581
 
                    else
582
 
                    {
 
580
                        }
 
581
                        else
 
582
                        {
583
583
//                      qDebug() << "before interesting dev->pos(): " << dev->pos();
584
584
                        bool success = dev->seek( dev->pos() + compr_size ); // can this fail ???
585
585
                        success = success; // annoying unused variable warning
586
 
                        Q_ASSERT( success ); // let's see...
 
586
                                                Q_ASSERT( success ); // let's see...
587
587
/*                      qDebug() << "after interesting dev->pos(): " << dev->pos();
588
588
                        if ( success )
589
589
                                qDebug() << "dev->at was successful... ";
590
590
                        else
591
591
                                qDebug() << "dev->at failed... ";*/
592
 
                    }
 
592
                        }
593
593
 
594
594
                }
595
595
 
596
596
// not needed any more
597
597
/*                // here we calculate the length of the file in the zip
598
 
                // with headers and jump to the next header.
599
 
                uint skip = compr_size + namelen + extralen;
600
 
                offset += 30 + skip;*/
601
 
            }
602
 
            pfi_map.insert(fileName, pfi);
603
 
        }
604
 
        else if ( !memcmp( buffer, "PK\1\2", 4 ) ) // central block
605
 
        {
606
 
            //qDebug() << "PK12 found central block";
607
 
            startOfFile = false;
608
 
 
609
 
            // so we reached the central header at the end of the zip file
610
 
            // here we get all interesting data out of the central header
611
 
            // of a file
612
 
            offset = dev->pos() - 4;
613
 
 
614
 
            //set offset for appending new files
615
 
            if ( d->m_offset == 0L ) d->m_offset = offset;
616
 
 
617
 
            n = dev->read( buffer + 4, 42 );
618
 
            if (n < 42) {
619
 
                qWarning() << "Invalid ZIP file, central entry too short"; // not long enough for valid entry
620
 
                return false;
621
 
            }
622
 
 
623
 
            //int gpf = (uchar)buffer[9] << 8 | (uchar)buffer[10];
624
 
            //kDebug() << "general purpose flag=" << gpf;
625
 
            // length of the fileName (well, pathname indeed)
626
 
            int namelen = (uchar)buffer[29] << 8 | (uchar)buffer[28];
627
 
            Q_ASSERT( namelen > 0 );
628
 
            QByteArray bufferName = dev->read( namelen );
629
 
            if ( bufferName.size() < namelen )
630
 
                qWarning() << "Invalid ZIP file. Name not completely read";
631
 
 
632
 
            ParseFileInfo pfi = pfi_map.value( bufferName, ParseFileInfo() );
633
 
 
634
 
            QString name( QFile::decodeName(bufferName) );
635
 
 
636
 
            //qDebug() << "name: " << name;
637
 
            // only in central header ! see below.
638
 
            // length of extra attributes
639
 
            int extralen = (uchar)buffer[31] << 8 | (uchar)buffer[30];
640
 
            // length of comment for this file
641
 
            int commlen =  (uchar)buffer[33] << 8 | (uchar)buffer[32];
642
 
            // compression method of this file
643
 
            int cmethod =  (uchar)buffer[11] << 8 | (uchar)buffer[10];
644
 
 
645
 
            //qDebug() << "cmethod: " << cmethod;
646
 
            //qDebug() << "extralen: " << extralen;
647
 
 
648
 
            // crc32 of the file
649
 
            uint crc32 = (uchar)buffer[19] << 24 | (uchar)buffer[18] << 16 |
650
 
                       (uchar)buffer[17] << 8 | (uchar)buffer[16];
651
 
 
652
 
            // uncompressed file size
653
 
            uint ucsize = (uchar)buffer[27] << 24 | (uchar)buffer[26] << 16 |
654
 
                        (uchar)buffer[25] << 8 | (uchar)buffer[24];
655
 
            // compressed file size
656
 
            uint csize = (uchar)buffer[23] << 24 | (uchar)buffer[22] << 16 |
657
 
                        (uchar)buffer[21] << 8 | (uchar)buffer[20];
658
 
 
659
 
            // offset of local header
660
 
            uint localheaderoffset = (uchar)buffer[45] << 24 | (uchar)buffer[44] << 16 |
 
598
                                // with headers and jump to the next header.
 
599
                                uint skip = compr_size + namelen + extralen;
 
600
                                offset += 30 + skip;*/
 
601
                        }
 
602
                        pfi_map.insert(fileName, pfi);
 
603
                }
 
604
                else if ( !memcmp( buffer, "PK\1\2", 4 ) ) // central block
 
605
                {
 
606
                //qDebug() << "PK12 found central block";
 
607
                        startOfFile = false;
 
608
 
 
609
                        // so we reached the central header at the end of the zip file
 
610
                        // here we get all interesting data out of the central header
 
611
                        // of a file
 
612
                        offset = dev->pos() - 4;
 
613
 
 
614
                        //set offset for appending new files
 
615
                        if ( d->m_offset == 0L ) d->m_offset = offset;
 
616
 
 
617
                        n = dev->read( buffer + 4, 42 );
 
618
                        if (n < 42) {
 
619
                                qWarning() << "Invalid ZIP file, central entry too short"; // not long enough for valid entry
 
620
                                return false;
 
621
                        }
 
622
 
 
623
                        //int gpf = (uchar)buffer[9] << 8 | (uchar)buffer[10];
 
624
                        //kDebug() << "general purpose flag=" << gpf;
 
625
                        // length of the fileName (well, pathname indeed)
 
626
                        int namelen = (uchar)buffer[29] << 8 | (uchar)buffer[28];
 
627
                        Q_ASSERT( namelen > 0 );
 
628
                        QByteArray bufferName = dev->read( namelen );
 
629
                        if ( bufferName.size() < namelen )
 
630
                                qWarning() << "Invalid ZIP file. Name not completely read";
 
631
 
 
632
                        ParseFileInfo pfi = pfi_map.value( bufferName, ParseFileInfo() );
 
633
 
 
634
                        QString name( QFile::decodeName(bufferName) );
 
635
 
 
636
                        //qDebug() << "name: " << name;
 
637
                        // only in central header ! see below.
 
638
                        // length of extra attributes
 
639
                        int extralen = (uchar)buffer[31] << 8 | (uchar)buffer[30];
 
640
                        // length of comment for this file
 
641
                        int commlen =  (uchar)buffer[33] << 8 | (uchar)buffer[32];
 
642
                        // compression method of this file
 
643
                        int cmethod =  (uchar)buffer[11] << 8 | (uchar)buffer[10];
 
644
 
 
645
                        //qDebug() << "cmethod: " << cmethod;
 
646
                        //qDebug() << "extralen: " << extralen;
 
647
 
 
648
                        // crc32 of the file
 
649
                        uint crc32 = (uchar)buffer[19] << 24 | (uchar)buffer[18] << 16 |
 
650
                                           (uchar)buffer[17] << 8 | (uchar)buffer[16];
 
651
 
 
652
                        // uncompressed file size
 
653
                        uint ucsize = (uchar)buffer[27] << 24 | (uchar)buffer[26] << 16 |
 
654
                                (uchar)buffer[25] << 8 | (uchar)buffer[24];
 
655
                        // compressed file size
 
656
                        uint csize = (uchar)buffer[23] << 24 | (uchar)buffer[22] << 16 |
 
657
                                (uchar)buffer[21] << 8 | (uchar)buffer[20];
 
658
 
 
659
                        // offset of local header
 
660
                        uint localheaderoffset = (uchar)buffer[45] << 24 | (uchar)buffer[44] << 16 |
661
661
                                (uchar)buffer[43] << 8 | (uchar)buffer[42];
662
662
 
663
 
            // some clever people use different extra field lengths
664
 
            // in the central header and in the local header... funny.
665
 
            // so we need to get the localextralen to calculate the offset
666
 
            // from localheaderstart to dataoffset
667
 
            int localextralen = pfi.extralen; // FIXME: this will not work if
668
 
                                                // no local header exists
669
 
 
670
 
            //qDebug() << "localextralen: " << localextralen;
671
 
 
672
 
            // offset, where the real data for uncompression starts
673
 
            uint dataoffset = localheaderoffset + 30 + localextralen + namelen; //comment only in central header
674
 
 
675
 
            //qDebug() << "esize: " << esize;
676
 
            //qDebug() << "eoffset: " << eoffset;
677
 
            //qDebug() << "csize: " << csize;
678
 
 
679
 
            int os_madeby = (uchar)buffer[5];
680
 
            bool isdir = false;
681
 
            int access = 0100644;
682
 
 
683
 
            if (os_madeby == 3) {       // good ole unix
684
 
                access = (uchar)buffer[40] | (uchar)buffer[41] << 8;
685
 
            }
686
 
 
687
 
            QString entryName;
688
 
 
689
 
            if ( name.endsWith( '/' ) ) // Entries with a trailing slash are directories
690
 
            {
691
 
                isdir = true;
692
 
                name = name.left( name.length() - 1 );
693
 
                if (os_madeby != 3) access = S_IFDIR | 0755;
 
663
                        // some clever people use different extra field lengths
 
664
                        // in the central header and in the local header... funny.
 
665
                        // so we need to get the localextralen to calculate the offset
 
666
                        // from localheaderstart to dataoffset
 
667
                        int localextralen = pfi.extralen; // FIXME: this will not work if
 
668
                                                        // no local header exists
 
669
 
 
670
                        //qDebug() << "localextralen: " << localextralen;
 
671
 
 
672
                        // offset, where the real data for uncompression starts
 
673
                        uint dataoffset = localheaderoffset + 30 + localextralen + namelen; //comment only in central header
 
674
 
 
675
                        //qDebug() << "esize: " << esize;
 
676
                        //qDebug() << "eoffset: " << eoffset;
 
677
                        //qDebug() << "csize: " << csize;
 
678
 
 
679
                int os_madeby = (uchar)buffer[5];
 
680
                        bool isdir = false;
 
681
                        int access = 0100644;
 
682
 
 
683
                if (os_madeby == 3) {   // good ole unix
 
684
                        access = (uchar)buffer[40] | (uchar)buffer[41] << 8;
 
685
                }
 
686
 
 
687
                        QString entryName;
 
688
 
 
689
                        if ( name.endsWith( '/' ) ) // Entries with a trailing slash are directories
 
690
                        {
 
691
                                isdir = true;
 
692
                                name = name.left( name.length() - 1 );
 
693
                                if (os_madeby != 3) access = S_IFDIR | 0755;
694
694
                else Q_ASSERT(access & S_IFDIR);
695
 
            }
696
 
 
697
 
            int pos = name.lastIndexOf( '/' );
698
 
            if ( pos == -1 )
699
 
                entryName = name;
700
 
            else
701
 
                entryName = name.mid( pos + 1 );
702
 
            Q_ASSERT( !entryName.isEmpty() );
703
 
 
704
 
            KArchiveEntry* entry;
705
 
            if ( isdir )
706
 
            {
707
 
                QString path = QDir::cleanPath( name );
708
 
                const KArchiveEntry* ent = rootDir()->entry( path );
709
 
                if ( ent && ent->isDirectory() )
710
 
                {
711
 
                    //qDebug() << "Directory already exists, NOT going to add it again";
712
 
                    entry = 0;
713
 
                }
714
 
                else
715
 
                {
716
 
                    entry = new KArchiveDirectory( this, entryName, access, (int)pfi.mtime, rootDir()->user(), rootDir()->group(), QString() );
717
 
                    //qDebug() << "KArchiveDirectory created, entryName= " << entryName << ", name=" << name;
718
 
                }
719
 
            }
720
 
            else
721
 
            {
722
 
                QString symlink;
 
695
                        }
 
696
 
 
697
                        int pos = name.lastIndexOf( '/' );
 
698
                        if ( pos == -1 )
 
699
                                entryName = name;
 
700
                        else
 
701
                                entryName = name.mid( pos + 1 );
 
702
                        Q_ASSERT( !entryName.isEmpty() );
 
703
 
 
704
                        KArchiveEntry* entry;
 
705
                        if ( isdir )
 
706
                        {
 
707
                                QString path = QDir::cleanPath( name );
 
708
                                const KArchiveEntry* ent = rootDir()->entry( path );
 
709
                                if ( ent && ent->isDirectory() )
 
710
                                {
 
711
                                        //qDebug() << "Directory already exists, NOT going to add it again";
 
712
                                        entry = 0;
 
713
                                }
 
714
                                else
 
715
                                {
 
716
                                        entry = new KArchiveDirectory( this, entryName, access, (int)pfi.mtime, rootDir()->user(), rootDir()->group(), QString() );
 
717
                                        //qDebug() << "KArchiveDirectory created, entryName= " << entryName << ", name=" << name;
 
718
                                }
 
719
                }
 
720
                        else
 
721
                        {
 
722
                        QString symlink;
723
723
                if (S_ISLNK(access)) {
724
 
                    symlink = QFile::decodeName(pfi.guessed_symlink);
 
724
                        symlink = QFile::decodeName(pfi.guessed_symlink);
725
725
                }
726
 
                entry = new KZipFileEntry( this, entryName, access, pfi.mtime,
 
726
                                entry = new KZipFileEntry( this, entryName, access, pfi.mtime,
727
727
                                        rootDir()->user(), rootDir()->group(),
728
728
                                        symlink, name, dataoffset,
729
729
                                        ucsize, cmethod, csize );
730
 
                static_cast<KZipFileEntry *>(entry)->setHeaderStart( localheaderoffset );
731
 
                static_cast<KZipFileEntry*>(entry)->setCRC32(crc32);
732
 
                //qDebug() << "KZipFileEntry created, entryName= " << entryName << ", name=" << name;
733
 
                d->m_fileList.append( static_cast<KZipFileEntry *>( entry ) );
734
 
            }
735
 
 
736
 
            if ( entry )
737
 
            {
738
 
                if ( pos == -1 )
739
 
                {
740
 
                    rootDir()->addEntry(entry);
741
 
                }
742
 
                else
743
 
                {
744
 
                    // In some tar files we can find dir/./file => call cleanPath
745
 
                    QString path = QDir::cleanPath( name.left( pos ) );
746
 
                    // Ensure container directory exists, create otherwise
747
 
                    KArchiveDirectory * tdir = findOrCreate( path );
748
 
                    tdir->addEntry(entry);
749
 
                }
750
 
            }
751
 
 
752
 
            //calculate offset to next entry
753
 
            offset += 46 + commlen + extralen + namelen;
754
 
            bool b = dev->seek(offset);
755
 
            Q_ASSERT( b );
756
 
            if ( !b )
757
 
              return false;
758
 
        }
759
 
        else if ( startOfFile )
760
 
        {
761
 
            // The file does not start with any ZIP header (e.g. self-extractable ZIP files)
762
 
            // Therefore we need to find the first PK\003\004 (local header)
763
 
            qDebug() << "Try to skip start of file";
764
 
            startOfFile = false;
765
 
            bool foundSignature = false;
766
 
 
767
 
            while (!foundSignature)
768
 
            {
769
 
                n = dev->read( buffer, 1 );
770
 
                if (n < 1)
771
 
                {
772
 
                    qWarning() << "Invalid ZIP file. Unexpected end of file. " ;
773
 
                    return false;
774
 
                }
775
 
 
776
 
                if ( buffer[0] != 'P' )
777
 
                    continue;
778
 
 
779
 
                n = dev->read( buffer, 3 );
780
 
                if (n < 3)
781
 
                {
782
 
                    qWarning() << "Invalid ZIP file. Unexpected end of file. " ;
783
 
                    return false;
784
 
                }
785
 
 
786
 
                // We have to detect the magic token for a local header: PK\003\004
787
 
                /*
788
 
                 * Note: we do not need to check the other magics, if the ZIP file has no
789
 
                 * local header, then it has not any files!
790
 
                 */
791
 
                if ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 )
792
 
                {
793
 
                    foundSignature = true;
794
 
                    dev->seek( dev->pos() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
795
 
                }
796
 
                else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
797
 
                {
798
 
                        // We have another P character so we must go back a little to check if it is a magic
799
 
                    dev->seek( dev->pos() - 3 );
800
 
                }
801
 
            }
802
 
        }
803
 
        else
804
 
        {
805
 
            qWarning() << "Invalid ZIP file. Unrecognized header at offset " << offset;
806
 
 
807
 
            return false;
808
 
        }
809
 
    }
810
 
    //qDebug() << "*** done *** ";
811
 
    return true;
 
730
                                static_cast<KZipFileEntry *>(entry)->setHeaderStart( localheaderoffset );
 
731
                                static_cast<KZipFileEntry*>(entry)->setCRC32(crc32);
 
732
                                //qDebug() << "KZipFileEntry created, entryName= " << entryName << ", name=" << name;
 
733
                                d->m_fileList.append( static_cast<KZipFileEntry *>( entry ) );
 
734
                        }
 
735
 
 
736
                        if ( entry )
 
737
                        {
 
738
                                if ( pos == -1 )
 
739
                                {
 
740
                                        rootDir()->addEntry(entry);
 
741
                                }
 
742
                                else
 
743
                                {
 
744
                                        // In some tar files we can find dir/./file => call cleanPath
 
745
                                        QString path = QDir::cleanPath( name.left( pos ) );
 
746
                                        // Ensure container directory exists, create otherwise
 
747
                                        KArchiveDirectory * tdir = findOrCreate( path );
 
748
                                        tdir->addEntry(entry);
 
749
                                }
 
750
                        }
 
751
 
 
752
                        //calculate offset to next entry
 
753
                        offset += 46 + commlen + extralen + namelen;
 
754
                        bool b = dev->seek(offset);
 
755
                        Q_ASSERT( b );
 
756
                        if ( !b )
 
757
                          return false;
 
758
                }
 
759
                else if ( startOfFile )
 
760
                {
 
761
                        // The file does not start with any ZIP header (e.g. self-extractable ZIP files)
 
762
                        // Therefore we need to find the first PK\003\004 (local header)
 
763
                        qDebug() << "Try to skip start of file";
 
764
                        startOfFile = false;
 
765
                        bool foundSignature = false;
 
766
 
 
767
                        while (!foundSignature)
 
768
                        {
 
769
                                n = dev->read( buffer, 1 );
 
770
                                if (n < 1)
 
771
                                {
 
772
                                        qWarning() << "Invalid ZIP file. Unexpected end of file. " ;
 
773
                                        return false;
 
774
                                }
 
775
 
 
776
                                if ( buffer[0] != 'P' )
 
777
                                        continue;
 
778
 
 
779
                                n = dev->read( buffer, 3 );
 
780
                                if (n < 3)
 
781
                                {
 
782
                                        qWarning() << "Invalid ZIP file. Unexpected end of file. " ;
 
783
                                        return false;
 
784
                                }
 
785
 
 
786
                                // We have to detect the magic token for a local header: PK\003\004
 
787
                                /*
 
788
                                 * Note: we do not need to check the other magics, if the ZIP file has no
 
789
                                 * local header, then it has not any files!
 
790
                                 */
 
791
                                if ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 )
 
792
                                {
 
793
                                        foundSignature = true;
 
794
                                        dev->seek( dev->pos() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
 
795
                                }
 
796
                                else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
 
797
                                {
 
798
                                                // We have another P character so we must go back a little to check if it is a magic
 
799
                                        dev->seek( dev->pos() - 3 );
 
800
                                }
 
801
                        }
 
802
                }
 
803
                else
 
804
                {
 
805
                        qWarning() << "Invalid ZIP file. Unrecognized header at offset " << offset;
 
806
 
 
807
                        return false;
 
808
                }
 
809
        }
 
810
        //qDebug() << "*** done *** ";
 
811
        return true;
812
812
}
813
813
 
814
814
bool KZip::closeArchive()
815
815
{
816
 
    if ( ! ( mode() & QIODevice::WriteOnly ) )
817
 
    {
818
 
        //qDebug() << "readonly";
819
 
        return true;
820
 
    }
821
 
 
822
 
    //ReadWrite or WriteOnly
823
 
    //write all central dir file entries
824
 
 
825
 
    // to be written at the end of the file...
826
 
    char buffer[ 22 ]; // first used for 12, then for 22 at the end
827
 
    uLong crc = crc32(0L, Z_NULL, 0);
828
 
 
829
 
    qint64 centraldiroffset = device()->pos();
830
 
    //qDebug() << "closearchive: centraldiroffset: " << centraldiroffset;
831
 
    qint64 atbackup = centraldiroffset;
832
 
    QMutableListIterator<KZipFileEntry*> it( d->m_fileList );
833
 
 
834
 
    while(it.hasNext())
835
 
    {   //set crc and compressed size in each local file header
836
 
            it.next();
837
 
        if ( !device()->seek( it.value()->headerStart() + 14 ) )
838
 
            return false;
 
816
        if ( ! ( mode() & QIODevice::WriteOnly ) )
 
817
        {
 
818
                //qDebug() << "readonly";
 
819
                return true;
 
820
        }
 
821
 
 
822
        //ReadWrite or WriteOnly
 
823
        //write all central dir file entries
 
824
 
 
825
        // to be written at the end of the file...
 
826
        char buffer[ 22 ]; // first used for 12, then for 22 at the end
 
827
        uLong crc = crc32(0L, Z_NULL, 0);
 
828
 
 
829
        qint64 centraldiroffset = device()->pos();
 
830
        //qDebug() << "closearchive: centraldiroffset: " << centraldiroffset;
 
831
        qint64 atbackup = centraldiroffset;
 
832
        QMutableListIterator<KZipFileEntry*> it( d->m_fileList );
 
833
 
 
834
        while(it.hasNext())
 
835
        {       //set crc and compressed size in each local file header
 
836
                it.next();
 
837
                if ( !device()->seek( it.value()->headerStart() + 14 ) )
 
838
                        return false;
839
839
        //qDebug() << "closearchive setcrcandcsize: fileName:"
840
840
        //    << it.current()->path()
841
841
        //    << "encoding:" << it.current()->encoding();
842
842
 
843
 
        uLong mycrc = it.value()->crc32();
844
 
        buffer[0] = char(mycrc); // crc checksum, at headerStart+14
845
 
        buffer[1] = char(mycrc >> 8);
846
 
        buffer[2] = char(mycrc >> 16);
847
 
        buffer[3] = char(mycrc >> 24);
848
 
 
849
 
        int mysize1 = it.value()->compressedSize();
850
 
        buffer[4] = char(mysize1); // compressed file size, at headerStart+18
851
 
        buffer[5] = char(mysize1 >> 8);
852
 
        buffer[6] = char(mysize1 >> 16);
853
 
        buffer[7] = char(mysize1 >> 24);
854
 
 
855
 
        int myusize = it.value()->size();
856
 
        buffer[8] = char(myusize); // uncompressed file size, at headerStart+22
857
 
        buffer[9] = char(myusize >> 8);
858
 
        buffer[10] = char(myusize >> 16);
859
 
        buffer[11] = char(myusize >> 24);
860
 
 
861
 
        if ( device()->write( buffer, 12 ) != 12 )
862
 
            return false;
863
 
    }
864
 
    device()->seek( atbackup );
865
 
 
866
 
    it.toFront();
867
 
    while (it.hasNext())
868
 
    {
 
843
                uLong mycrc = it.value()->crc32();
 
844
                buffer[0] = char(mycrc); // crc checksum, at headerStart+14
 
845
                buffer[1] = char(mycrc >> 8);
 
846
                buffer[2] = char(mycrc >> 16);
 
847
                buffer[3] = char(mycrc >> 24);
 
848
 
 
849
                int mysize1 = it.value()->compressedSize();
 
850
                buffer[4] = char(mysize1); // compressed file size, at headerStart+18
 
851
                buffer[5] = char(mysize1 >> 8);
 
852
                buffer[6] = char(mysize1 >> 16);
 
853
                buffer[7] = char(mysize1 >> 24);
 
854
 
 
855
                int myusize = it.value()->size();
 
856
                buffer[8] = char(myusize); // uncompressed file size, at headerStart+22
 
857
                buffer[9] = char(myusize >> 8);
 
858
                buffer[10] = char(myusize >> 16);
 
859
                buffer[11] = char(myusize >> 24);
 
860
 
 
861
                if ( device()->write( buffer, 12 ) != 12 )
 
862
                        return false;
 
863
        }
 
864
        device()->seek( atbackup );
 
865
 
 
866
        it.toFront();
 
867
        while (it.hasNext())
 
868
        {
869
869
        it.next();
870
 
        //qDebug() << "fileName:" << it.current()->path()
871
 
        //              << "encoding:" << it.current()->encoding();
 
870
                //qDebug() << "fileName:" << it.current()->path()
 
871
                //              << "encoding:" << it.current()->encoding();
872
872
 
873
 
        QByteArray path = QFile::encodeName(it.value()->path());
 
873
                QByteArray path = QFile::encodeName(it.value()->path());
874
874
 
875
875
        const int extra_field_len = 9;
876
 
        int bufferSize = extra_field_len + path.length() + 46;
877
 
        char* buffer = new char[ bufferSize ];
878
 
 
879
 
        memset(buffer, 0, 46); // zero is a nice default for most header fields
880
 
 
881
 
        const char head[] =
882
 
        {
883
 
            'P', 'K', 1, 2, // central file header signature
884
 
            0x14, 3,        // version made by (3 == UNIX)
885
 
            0x14, 0         // version needed to extract
886
 
        };
 
876
                int bufferSize = extra_field_len + path.length() + 46;
 
877
                char* buffer = new char[ bufferSize ];
 
878
 
 
879
                memset(buffer, 0, 46); // zero is a nice default for most header fields
 
880
 
 
881
                const char head[] =
 
882
                {
 
883
                        'P', 'K', 1, 2, // central file header signature
 
884
                        0x14, 3,        // version made by (3 == UNIX)
 
885
                        0x14, 0         // version needed to extract
 
886
                };
887
887
 
888
888
        // I do not know why memcpy is not working here
889
 
        //memcpy(buffer, head, sizeof(head));
890
 
        memmove(buffer, head, sizeof(head));
891
 
 
892
 
        buffer[ 10 ] = char(it.value()->encoding()); // compression method
893
 
        buffer[ 11 ] = char(it.value()->encoding() >> 8);
894
 
 
895
 
        transformToMsDos( it.value()->datetime(), &buffer[ 12 ] );
896
 
 
897
 
        uLong mycrc = it.value()->crc32();
898
 
        buffer[ 16 ] = char(mycrc); // crc checksum
899
 
        buffer[ 17 ] = char(mycrc >> 8);
900
 
        buffer[ 18 ] = char(mycrc >> 16);
901
 
        buffer[ 19 ] = char(mycrc >> 24);
902
 
 
903
 
        int mysize1 = it.value()->compressedSize();
904
 
        buffer[ 20 ] = char(mysize1); // compressed file size
905
 
        buffer[ 21 ] = char(mysize1 >> 8);
906
 
        buffer[ 22 ] = char(mysize1 >> 16);
907
 
        buffer[ 23 ] = char(mysize1 >> 24);
908
 
 
909
 
        int mysize = it.value()->size();
910
 
        buffer[ 24 ] = char(mysize); // uncompressed file size
911
 
        buffer[ 25 ] = char(mysize >> 8);
912
 
        buffer[ 26 ] = char(mysize >> 16);
913
 
        buffer[ 27 ] = char(mysize >> 24);
914
 
 
915
 
        buffer[ 28 ] = char(it.value()->path().length()); // fileName length
916
 
        buffer[ 29 ] = char(it.value()->path().length() >> 8);
 
889
                //memcpy(buffer, head, sizeof(head));
 
890
                memmove(buffer, head, sizeof(head));
 
891
 
 
892
                buffer[ 10 ] = char(it.value()->encoding()); // compression method
 
893
                buffer[ 11 ] = char(it.value()->encoding() >> 8);
 
894
 
 
895
                transformToMsDos( it.value()->datetime(), &buffer[ 12 ] );
 
896
 
 
897
                uLong mycrc = it.value()->crc32();
 
898
                buffer[ 16 ] = char(mycrc); // crc checksum
 
899
                buffer[ 17 ] = char(mycrc >> 8);
 
900
                buffer[ 18 ] = char(mycrc >> 16);
 
901
                buffer[ 19 ] = char(mycrc >> 24);
 
902
 
 
903
                int mysize1 = it.value()->compressedSize();
 
904
                buffer[ 20 ] = char(mysize1); // compressed file size
 
905
                buffer[ 21 ] = char(mysize1 >> 8);
 
906
                buffer[ 22 ] = char(mysize1 >> 16);
 
907
                buffer[ 23 ] = char(mysize1 >> 24);
 
908
 
 
909
                int mysize = it.value()->size();
 
910
                buffer[ 24 ] = char(mysize); // uncompressed file size
 
911
                buffer[ 25 ] = char(mysize >> 8);
 
912
                buffer[ 26 ] = char(mysize >> 16);
 
913
                buffer[ 27 ] = char(mysize >> 24);
 
914
 
 
915
                buffer[ 28 ] = char(it.value()->path().length()); // fileName length
 
916
                buffer[ 29 ] = char(it.value()->path().length() >> 8);
917
917
 
918
918
        buffer[ 30 ] = char(extra_field_len);
919
919
        buffer[ 31 ] = char(extra_field_len >> 8);
921
921
        buffer[ 40 ] = char(it.value()->permissions());
922
922
        buffer[ 41 ] = char(it.value()->permissions() >> 8);
923
923
 
924
 
        int myhst = it.value()->headerStart();
925
 
        buffer[ 42 ] = char(myhst); //relative offset of local header
926
 
        buffer[ 43 ] = char(myhst >> 8);
927
 
        buffer[ 44 ] = char(myhst >> 16);
928
 
        buffer[ 45 ] = char(myhst >> 24);
 
924
                int myhst = it.value()->headerStart();
 
925
                buffer[ 42 ] = char(myhst); //relative offset of local header
 
926
                buffer[ 43 ] = char(myhst >> 8);
 
927
                buffer[ 44 ] = char(myhst >> 16);
 
928
                buffer[ 45 ] = char(myhst >> 24);
929
929
 
930
 
        // file name
931
 
        strncpy( buffer + 46, path, path.length() );
 
930
                // file name
 
931
                strncpy( buffer + 46, path, path.length() );
932
932
        //qDebug() << "closearchive length to write: " << bufferSize;
933
933
 
934
934
        // extra field
946
946
        extfield[7] = char(time >> 16);
947
947
        extfield[8] = char(time >> 24);
948
948
 
949
 
        crc = crc32(crc, (Bytef *)buffer, bufferSize );
950
 
        bool ok = ( device()->write( buffer, bufferSize ) == bufferSize );
951
 
        delete[] buffer;
952
 
        if ( !ok )
953
 
            return false;
954
 
    }
955
 
    qint64 centraldirendoffset = device()->pos();
956
 
    //qDebug() << "closearchive: centraldirendoffset: " << centraldirendoffset;
957
 
    //qDebug() << "closearchive: device()->pos(): " << device()->pos();
958
 
 
959
 
    //write end of central dir record.
960
 
    buffer[ 0 ] = 'P'; //end of central dir signature
961
 
    buffer[ 1 ] = 'K';
962
 
    buffer[ 2 ] = 5;
963
 
    buffer[ 3 ] = 6;
964
 
 
965
 
    buffer[ 4 ] = 0; // number of this disk
966
 
    buffer[ 5 ] = 0;
967
 
 
968
 
    buffer[ 6 ] = 0; // number of disk with start of central dir
969
 
    buffer[ 7 ] = 0;
970
 
 
971
 
    int count = d->m_fileList.count();
972
 
    //qDebug() << "number of files (count): " << count;
973
 
 
974
 
 
975
 
    buffer[ 8 ] = char(count); // total number of entries in central dir of
976
 
    buffer[ 9 ] = char(count >> 8); // this disk
977
 
 
978
 
    buffer[ 10 ] = buffer[ 8 ]; // total number of entries in the central dir
979
 
    buffer[ 11 ] = buffer[ 9 ];
980
 
 
981
 
    int cdsize = centraldirendoffset - centraldiroffset;
982
 
    buffer[ 12 ] = char(cdsize); // size of the central dir
983
 
    buffer[ 13 ] = char(cdsize >> 8);
984
 
    buffer[ 14 ] = char(cdsize >> 16);
985
 
    buffer[ 15 ] = char(cdsize >> 24);
986
 
 
987
 
    //qDebug() << "end : centraldiroffset: " << centraldiroffset;
988
 
    //qDebug() << "end : centraldirsize: " << cdsize;
989
 
 
990
 
    buffer[ 16 ] = char(centraldiroffset); // central dir offset
991
 
    buffer[ 17 ] = char(centraldiroffset >> 8);
992
 
    buffer[ 18 ] = char(centraldiroffset >> 16);
993
 
    buffer[ 19 ] = char(centraldiroffset >> 24);
994
 
 
995
 
    buffer[ 20 ] = 0; //zipfile comment length
996
 
    buffer[ 21 ] = 0;
997
 
 
998
 
    if ( device()->write( buffer, 22 ) != 22 )
999
 
        return false;
1000
 
 
1001
 
    return true;
 
949
                crc = crc32(crc, (Bytef *)buffer, bufferSize );
 
950
                bool ok = ( device()->write( buffer, bufferSize ) == bufferSize );
 
951
                delete[] buffer;
 
952
                if ( !ok )
 
953
                        return false;
 
954
        }
 
955
        qint64 centraldirendoffset = device()->pos();
 
956
        //qDebug() << "closearchive: centraldirendoffset: " << centraldirendoffset;
 
957
        //qDebug() << "closearchive: device()->pos(): " << device()->pos();
 
958
 
 
959
        //write end of central dir record.
 
960
        buffer[ 0 ] = 'P'; //end of central dir signature
 
961
        buffer[ 1 ] = 'K';
 
962
        buffer[ 2 ] = 5;
 
963
        buffer[ 3 ] = 6;
 
964
 
 
965
        buffer[ 4 ] = 0; // number of this disk
 
966
        buffer[ 5 ] = 0;
 
967
 
 
968
        buffer[ 6 ] = 0; // number of disk with start of central dir
 
969
        buffer[ 7 ] = 0;
 
970
 
 
971
        int count = d->m_fileList.count();
 
972
        //qDebug() << "number of files (count): " << count;
 
973
 
 
974
 
 
975
        buffer[ 8 ] = char(count); // total number of entries in central dir of
 
976
        buffer[ 9 ] = char(count >> 8); // this disk
 
977
 
 
978
        buffer[ 10 ] = buffer[ 8 ]; // total number of entries in the central dir
 
979
        buffer[ 11 ] = buffer[ 9 ];
 
980
 
 
981
        int cdsize = centraldirendoffset - centraldiroffset;
 
982
        buffer[ 12 ] = char(cdsize); // size of the central dir
 
983
        buffer[ 13 ] = char(cdsize >> 8);
 
984
        buffer[ 14 ] = char(cdsize >> 16);
 
985
        buffer[ 15 ] = char(cdsize >> 24);
 
986
 
 
987
        //qDebug() << "end : centraldiroffset: " << centraldiroffset;
 
988
        //qDebug() << "end : centraldirsize: " << cdsize;
 
989
 
 
990
        buffer[ 16 ] = char(centraldiroffset); // central dir offset
 
991
        buffer[ 17 ] = char(centraldiroffset >> 8);
 
992
        buffer[ 18 ] = char(centraldiroffset >> 16);
 
993
        buffer[ 19 ] = char(centraldiroffset >> 24);
 
994
 
 
995
        buffer[ 20 ] = 0; //zipfile comment length
 
996
        buffer[ 21 ] = 0;
 
997
 
 
998
        if ( device()->write( buffer, 22 ) != 22 )
 
999
                return false;
 
1000
 
 
1001
        return true;
1002
1002
}
1003
1003
 
1004
1004
bool KZip::doWriteDir( const QString&, const QString&, const QString&,
1005
 
                       mode_t, time_t, time_t, time_t ) {
1006
 
        return true;
 
1005
                                           mode_t, time_t, time_t, time_t ) {
 
1006
                return true;
1007
1007
}
1008
1008
 
1009
1009
bool KZip::doPrepareWriting(const QString &name, const QString &user,
1010
 
                               const QString &group, qint64 /*size*/, mode_t perm,
1011
 
                               time_t atime, time_t mtime, time_t ctime) {
1012
 
    //qDebug();
1013
 
    if ( !isOpen() )
1014
 
    {
1015
 
        qWarning( "KZip::writeFile: You must open the zip file before writing to it\n");
1016
 
        return false;
1017
 
    }
1018
 
 
1019
 
    if ( ! ( mode() & QIODevice::WriteOnly ) ) // accept WriteOnly and ReadWrite
1020
 
    {
1021
 
        qWarning( "KZip::writeFile: You must open the zip file for writing\n");
1022
 
        return false;
1023
 
    }
1024
 
 
1025
 
    Q_ASSERT( device() );
1026
 
 
1027
 
    // set right offset in zip.
1028
 
    if ( !device()->seek( d->m_offset ) ) {
1029
 
        qWarning() << "doPrepareWriting: cannot seek in ZIP file. Disk full?";
1030
 
        return false;
1031
 
    }
1032
 
 
1033
 
    // delete entries in the filelist with the same fileName as the one we want
1034
 
    // to save, so that we don't have duplicate file entries when viewing the zip
1035
 
    // with konqi...
1036
 
    // CAUTION: the old file itself is still in the zip and won't be removed !!!
1037
 
    QMutableListIterator<KZipFileEntry*> it( d->m_fileList );
 
1010
                                                           const QString &group, qint64 /*size*/, mode_t perm,
 
1011
                                                           time_t atime, time_t mtime, time_t ctime) {
 
1012
        //qDebug();
 
1013
        if ( !isOpen() )
 
1014
        {
 
1015
                qWarning( "KZip::writeFile: You must open the zip file before writing to it\n");
 
1016
                return false;
 
1017
        }
 
1018
 
 
1019
        if ( ! ( mode() & QIODevice::WriteOnly ) ) // accept WriteOnly and ReadWrite
 
1020
        {
 
1021
                qWarning( "KZip::writeFile: You must open the zip file for writing\n");
 
1022
                return false;
 
1023
        }
 
1024
 
 
1025
        Q_ASSERT( device() );
 
1026
 
 
1027
        // set right offset in zip.
 
1028
        if ( !device()->seek( d->m_offset ) ) {
 
1029
                qWarning() << "doPrepareWriting: cannot seek in ZIP file. Disk full?";
 
1030
                return false;
 
1031
        }
 
1032
 
 
1033
        // delete entries in the filelist with the same fileName as the one we want
 
1034
        // to save, so that we don't have duplicate file entries when viewing the zip
 
1035
        // with konqi...
 
1036
        // CAUTION: the old file itself is still in the zip and won't be removed !!!
 
1037
        QMutableListIterator<KZipFileEntry*> it( d->m_fileList );
1038
1038
        //qDebug() << "fileName to write: " << name;
1039
 
    while(it.hasNext())
1040
 
    {
1041
 
            it.next();
1042
 
        //qDebug() << "prepfileName: " << it.current()->path();
 
1039
        while(it.hasNext())
 
1040
        {
 
1041
                it.next();
 
1042
                //qDebug() << "prepfileName: " << it.current()->path();
1043
1043
                if (name == it.value()->path() )
1044
 
        {
1045
 
                //qDebug() << "removing following entry: " << it.current()->path();
 
1044
                {
 
1045
                        //qDebug() << "removing following entry: " << it.current()->path();
1046
1046
                delete it.value();
1047
 
                it.remove();
1048
 
        }
1049
 
 
1050
 
    }
1051
 
    // Find or create parent dir
1052
 
    KArchiveDirectory* parentDir = rootDir();
1053
 
    QString fileName( name );
1054
 
    int i = name.lastIndexOf( '/' );
1055
 
    if ( i != -1 )
1056
 
    {
1057
 
        QString dir = name.left( i );
1058
 
        fileName = name.mid( i + 1 );
1059
 
        //qDebug() << "ensuring" << dir << "exists. fileName=" << fileName;
1060
 
        parentDir = findOrCreate( dir );
1061
 
    }
1062
 
 
1063
 
    // construct a KZipFileEntry and add it to list
1064
 
    KZipFileEntry * e = new KZipFileEntry( this, fileName, perm, mtime, user, group, QString(),
1065
 
                                           name, device()->pos() + 30 + name.length(), // start
1066
 
                                           0 /*size unknown yet*/, d->m_compression, 0 /*csize unknown yet*/ );
1067
 
    e->setHeaderStart( device()->pos() );
1068
 
    //qDebug() << "wrote file start: " << e->position() << " name: " << name;
1069
 
    parentDir->addEntry( e );
1070
 
 
1071
 
    d->m_currentFile = e;
1072
 
    d->m_fileList.append( e );
1073
 
 
1074
 
    int extra_field_len = 0;
1075
 
    if ( d->m_extraField == ModificationTime )
1076
 
        extra_field_len = 17;   // value also used in finishWriting()
1077
 
 
1078
 
    // write out zip header
1079
 
    QByteArray encodedName = QFile::encodeName(name);
1080
 
    int bufferSize = extra_field_len + encodedName.length() + 30;
1081
 
    //qDebug() << "bufferSize=" << bufferSize;
1082
 
    char* buffer = new char[ bufferSize ];
1083
 
 
1084
 
    buffer[ 0 ] = 'P'; //local file header signature
1085
 
    buffer[ 1 ] = 'K';
1086
 
    buffer[ 2 ] = 3;
1087
 
    buffer[ 3 ] = 4;
1088
 
 
1089
 
    buffer[ 4 ] = 0x14; // version needed to extract
1090
 
    buffer[ 5 ] = 0;
1091
 
 
1092
 
    buffer[ 6 ] = 0; // general purpose bit flag
1093
 
    buffer[ 7 ] = 0;
1094
 
 
1095
 
    buffer[ 8 ] = char(e->encoding()); // compression method
1096
 
    buffer[ 9 ] = char(e->encoding() >> 8);
1097
 
 
1098
 
    transformToMsDos( e->datetime(), &buffer[ 10 ] );
1099
 
 
1100
 
    buffer[ 14 ] = 'C'; //dummy crc
1101
 
    buffer[ 15 ] = 'R';
1102
 
    buffer[ 16 ] = 'C';
1103
 
    buffer[ 17 ] = 'q';
1104
 
 
1105
 
    buffer[ 18 ] = 'C'; //compressed file size
1106
 
    buffer[ 19 ] = 'S';
1107
 
    buffer[ 20 ] = 'I';
1108
 
    buffer[ 21 ] = 'Z';
1109
 
 
1110
 
    buffer[ 22 ] = 'U'; //uncompressed file size
1111
 
    buffer[ 23 ] = 'S';
1112
 
    buffer[ 24 ] = 'I';
1113
 
    buffer[ 25 ] = 'Z';
1114
 
 
1115
 
    buffer[ 26 ] = (uchar)(encodedName.length()); //fileName length
1116
 
    buffer[ 27 ] = (uchar)(encodedName.length() >> 8);
1117
 
 
1118
 
    buffer[ 28 ] = (uchar)(extra_field_len); // extra field length
1119
 
    buffer[ 29 ] = (uchar)(extra_field_len >> 8);
1120
 
 
1121
 
    // file name
1122
 
    strncpy( buffer + 30, encodedName, encodedName.length() );
1123
 
 
1124
 
    // extra field
1125
 
    if ( d->m_extraField == ModificationTime )
1126
 
    {
1127
 
        char *extfield = buffer + 30 + encodedName.length();
1128
 
        // "Extended timestamp" header (0x5455)
1129
 
        extfield[0] = 'U';
1130
 
        extfield[1] = 'T';
1131
 
        extfield[2] = 13; // data size
1132
 
        extfield[3] = 0;
1133
 
        extfield[4] = 1 | 2 | 4;        // contains mtime, atime, ctime
1134
 
 
1135
 
        extfield[5] = char(mtime);
1136
 
        extfield[6] = char(mtime >> 8);
1137
 
        extfield[7] = char(mtime >> 16);
1138
 
        extfield[8] = char(mtime >> 24);
1139
 
 
1140
 
        extfield[9] = char(atime);
1141
 
        extfield[10] = char(atime >> 8);
1142
 
        extfield[11] = char(atime >> 16);
1143
 
        extfield[12] = char(atime >> 24);
1144
 
 
1145
 
        extfield[13] = char(ctime);
1146
 
        extfield[14] = char(ctime >> 8);
1147
 
        extfield[15] = char(ctime >> 16);
1148
 
        extfield[16] = char(ctime >> 24);
1149
 
    }
1150
 
 
1151
 
    // Write header
1152
 
    bool b = (device()->write( buffer, bufferSize ) == bufferSize );
1153
 
    d->m_crc = 0L;
1154
 
    delete[] buffer;
1155
 
 
1156
 
    Q_ASSERT( b );
1157
 
    if (!b) {
1158
 
        return false;
1159
 
    }
1160
 
 
1161
 
    // Prepare device for writing the data
1162
 
    // Either device() if no compression, or a KFilterDev to compress
1163
 
    if ( d->m_compression == 0 ) {
1164
 
        d->m_currentDev = device();
1165
 
        return true;
1166
 
    }
1167
 
 
1168
 
    d->m_currentDev = KFilterDev::device( device(), "application/x-gzip", false );
1169
 
    Q_ASSERT( d->m_currentDev );
1170
 
    if ( !d->m_currentDev ) {
1171
 
        return false; // ouch
1172
 
    }
1173
 
    static_cast<KFilterDev *>(d->m_currentDev)->setSkipHeaders(); // Just zlib, not gzip
1174
 
 
1175
 
    b = d->m_currentDev->open( QIODevice::WriteOnly );
1176
 
    Q_ASSERT( b );
1177
 
    return b;
 
1047
                        it.remove();
 
1048
                }
 
1049
 
 
1050
        }
 
1051
        // Find or create parent dir
 
1052
        KArchiveDirectory* parentDir = rootDir();
 
1053
        QString fileName( name );
 
1054
        int i = name.lastIndexOf( '/' );
 
1055
        if ( i != -1 )
 
1056
        {
 
1057
                QString dir = name.left( i );
 
1058
                fileName = name.mid( i + 1 );
 
1059
                //qDebug() << "ensuring" << dir << "exists. fileName=" << fileName;
 
1060
                parentDir = findOrCreate( dir );
 
1061
        }
 
1062
 
 
1063
        // construct a KZipFileEntry and add it to list
 
1064
        KZipFileEntry * e = new KZipFileEntry( this, fileName, perm, mtime, user, group, QString(),
 
1065
                                                                                   name, device()->pos() + 30 + name.length(), // start
 
1066
                                                                                   0 /*size unknown yet*/, d->m_compression, 0 /*csize unknown yet*/ );
 
1067
        e->setHeaderStart( device()->pos() );
 
1068
        //qDebug() << "wrote file start: " << e->position() << " name: " << name;
 
1069
        parentDir->addEntry( e );
 
1070
 
 
1071
        d->m_currentFile = e;
 
1072
        d->m_fileList.append( e );
 
1073
 
 
1074
        int extra_field_len = 0;
 
1075
        if ( d->m_extraField == ModificationTime )
 
1076
                extra_field_len = 17;   // value also used in finishWriting()
 
1077
 
 
1078
        // write out zip header
 
1079
        QByteArray encodedName = QFile::encodeName(name);
 
1080
        int bufferSize = extra_field_len + encodedName.length() + 30;
 
1081
        //qDebug() << "bufferSize=" << bufferSize;
 
1082
        char* buffer = new char[ bufferSize ];
 
1083
 
 
1084
        buffer[ 0 ] = 'P'; //local file header signature
 
1085
        buffer[ 1 ] = 'K';
 
1086
        buffer[ 2 ] = 3;
 
1087
        buffer[ 3 ] = 4;
 
1088
 
 
1089
        buffer[ 4 ] = 0x14; // version needed to extract
 
1090
        buffer[ 5 ] = 0;
 
1091
 
 
1092
        buffer[ 6 ] = 0; // general purpose bit flag
 
1093
        buffer[ 7 ] = 0;
 
1094
 
 
1095
        buffer[ 8 ] = char(e->encoding()); // compression method
 
1096
        buffer[ 9 ] = char(e->encoding() >> 8);
 
1097
 
 
1098
        transformToMsDos( e->datetime(), &buffer[ 10 ] );
 
1099
 
 
1100
        buffer[ 14 ] = 'C'; //dummy crc
 
1101
        buffer[ 15 ] = 'R';
 
1102
        buffer[ 16 ] = 'C';
 
1103
        buffer[ 17 ] = 'q';
 
1104
 
 
1105
        buffer[ 18 ] = 'C'; //compressed file size
 
1106
        buffer[ 19 ] = 'S';
 
1107
        buffer[ 20 ] = 'I';
 
1108
        buffer[ 21 ] = 'Z';
 
1109
 
 
1110
        buffer[ 22 ] = 'U'; //uncompressed file size
 
1111
        buffer[ 23 ] = 'S';
 
1112
        buffer[ 24 ] = 'I';
 
1113
        buffer[ 25 ] = 'Z';
 
1114
 
 
1115
        buffer[ 26 ] = (uchar)(encodedName.length()); //fileName length
 
1116
        buffer[ 27 ] = (uchar)(encodedName.length() >> 8);
 
1117
 
 
1118
        buffer[ 28 ] = (uchar)(extra_field_len); // extra field length
 
1119
        buffer[ 29 ] = (uchar)(extra_field_len >> 8);
 
1120
 
 
1121
        // file name
 
1122
        strncpy( buffer + 30, encodedName, encodedName.length() );
 
1123
 
 
1124
        // extra field
 
1125
        if ( d->m_extraField == ModificationTime )
 
1126
        {
 
1127
                char *extfield = buffer + 30 + encodedName.length();
 
1128
                // "Extended timestamp" header (0x5455)
 
1129
                extfield[0] = 'U';
 
1130
                extfield[1] = 'T';
 
1131
                extfield[2] = 13; // data size
 
1132
                extfield[3] = 0;
 
1133
                extfield[4] = 1 | 2 | 4;        // contains mtime, atime, ctime
 
1134
 
 
1135
                extfield[5] = char(mtime);
 
1136
                extfield[6] = char(mtime >> 8);
 
1137
                extfield[7] = char(mtime >> 16);
 
1138
                extfield[8] = char(mtime >> 24);
 
1139
 
 
1140
                extfield[9] = char(atime);
 
1141
                extfield[10] = char(atime >> 8);
 
1142
                extfield[11] = char(atime >> 16);
 
1143
                extfield[12] = char(atime >> 24);
 
1144
 
 
1145
                extfield[13] = char(ctime);
 
1146
                extfield[14] = char(ctime >> 8);
 
1147
                extfield[15] = char(ctime >> 16);
 
1148
                extfield[16] = char(ctime >> 24);
 
1149
        }
 
1150
 
 
1151
        // Write header
 
1152
        bool b = (device()->write( buffer, bufferSize ) == bufferSize );
 
1153
        d->m_crc = 0L;
 
1154
        delete[] buffer;
 
1155
 
 
1156
        Q_ASSERT( b );
 
1157
        if (!b) {
 
1158
                return false;
 
1159
        }
 
1160
 
 
1161
        // Prepare device for writing the data
 
1162
        // Either device() if no compression, or a KFilterDev to compress
 
1163
        if ( d->m_compression == 0 ) {
 
1164
                d->m_currentDev = device();
 
1165
                return true;
 
1166
        }
 
1167
 
 
1168
        d->m_currentDev = KFilterDev::device( device(), "application/x-gzip", false );
 
1169
        Q_ASSERT( d->m_currentDev );
 
1170
        if ( !d->m_currentDev ) {
 
1171
                return false; // ouch
 
1172
        }
 
1173
        static_cast<KFilterDev *>(d->m_currentDev)->setSkipHeaders(); // Just zlib, not gzip
 
1174
 
 
1175
        b = d->m_currentDev->open( QIODevice::WriteOnly );
 
1176
        Q_ASSERT( b );
 
1177
        return b;
1178
1178
}
1179
1179
 
1180
1180
bool KZip::doFinishWriting( qint64 size )
1181
1181
{
1182
 
    if ( d->m_currentFile->encoding() == 8 ) {
1183
 
        // Finish
1184
 
        (void)d->m_currentDev->write( 0, 0 );
1185
 
        delete d->m_currentDev;
1186
 
    }
1187
 
    // If 0, d->m_currentDev was device() - don't delete ;)
1188
 
    d->m_currentDev = 0L;
1189
 
 
1190
 
    Q_ASSERT( d->m_currentFile );
1191
 
    //qDebug() << "fileName: " << d->m_currentFile->path();
1192
 
    //qDebug() << "getpos (at): " << device()->pos();
1193
 
    d->m_currentFile->setSize(size);
1194
 
    int extra_field_len = 0;
1195
 
    if ( d->m_extraField == ModificationTime )
1196
 
        extra_field_len = 17;   // value also used in finishWriting()
1197
 
 
1198
 
    int csize = device()->pos() -
1199
 
        d->m_currentFile->headerStart() - 30 -
 
1182
        if ( d->m_currentFile->encoding() == 8 ) {
 
1183
                // Finish
 
1184
                (void)d->m_currentDev->write( 0, 0 );
 
1185
                delete d->m_currentDev;
 
1186
        }
 
1187
        // If 0, d->m_currentDev was device() - don't delete ;)
 
1188
        d->m_currentDev = 0L;
 
1189
 
 
1190
        Q_ASSERT( d->m_currentFile );
 
1191
        //qDebug() << "fileName: " << d->m_currentFile->path();
 
1192
        //qDebug() << "getpos (at): " << device()->pos();
 
1193
        d->m_currentFile->setSize(size);
 
1194
        int extra_field_len = 0;
 
1195
        if ( d->m_extraField == ModificationTime )
 
1196
                extra_field_len = 17;   // value also used in finishWriting()
 
1197
 
 
1198
        int csize = device()->pos() -
 
1199
                d->m_currentFile->headerStart() - 30 -
1200
1200
                d->m_currentFile->path().length() - extra_field_len;
1201
 
    d->m_currentFile->setCompressedSize(csize);
1202
 
    //qDebug() << "usize: " << d->m_currentFile->size();
1203
 
    //qDebug() << "csize: " << d->m_currentFile->compressedSize();
1204
 
    //qDebug() << "headerstart: " << d->m_currentFile->headerStart();
1205
 
 
1206
 
    //qDebug() << "crc: " << d->m_crc;
1207
 
    d->m_currentFile->setCRC32( d->m_crc );
1208
 
 
1209
 
    d->m_currentFile = 0L;
1210
 
 
1211
 
    // update saved offset for appending new files
1212
 
    d->m_offset = device()->pos();
1213
 
    return true;
 
1201
        d->m_currentFile->setCompressedSize(csize);
 
1202
        //qDebug() << "usize: " << d->m_currentFile->size();
 
1203
        //qDebug() << "csize: " << d->m_currentFile->compressedSize();
 
1204
        //qDebug() << "headerstart: " << d->m_currentFile->headerStart();
 
1205
 
 
1206
        //qDebug() << "crc: " << d->m_crc;
 
1207
        d->m_currentFile->setCRC32( d->m_crc );
 
1208
 
 
1209
        d->m_currentFile = 0L;
 
1210
 
 
1211
        // update saved offset for appending new files
 
1212
        d->m_offset = device()->pos();
 
1213
        return true;
1214
1214
}
1215
1215
 
1216
1216
bool KZip::doWriteSymLink(const QString &name, const QString &target,
1217
 
                          const QString &user, const QString &group,
1218
 
                          mode_t perm, time_t atime, time_t mtime, time_t ctime) {
 
1217
                                                  const QString &user, const QString &group,
 
1218
                                                  mode_t perm, time_t atime, time_t mtime, time_t ctime) {
1219
1219
  // reassure that symlink flag is set, otherwise strange things happen on
1220
1220
  // extraction
1221
1221
  perm |= S_IFLNK;
1223
1223
  setCompression(NoCompression);        // link targets are never compressed
1224
1224
 
1225
1225
  if (!doPrepareWriting(name, user, group, 0, perm, atime, mtime, ctime)) {
1226
 
    qWarning() << "prepareWriting failed";
1227
 
    setCompression(c);
1228
 
    return false;
 
1226
        qWarning() << "prepareWriting failed";
 
1227
        setCompression(c);
 
1228
        return false;
1229
1229
  }
1230
1230
 
1231
1231
  QByteArray symlink_target = QFile::encodeName(target);
1232
1232
  if (!writeData(symlink_target, symlink_target.length())) {
1233
 
    qWarning() << "writeData failed";
1234
 
    setCompression(c);
1235
 
    return false;
 
1233
        qWarning() << "writeData failed";
 
1234
        setCompression(c);
 
1235
        return false;
1236
1236
  }
1237
1237
 
1238
1238
  if (!finishWriting(symlink_target.length())) {
1239
 
    qWarning() << "finishWriting failed";
1240
 
    setCompression(c);
1241
 
    return false;
 
1239
        qWarning() << "finishWriting failed";
 
1240
        setCompression(c);
 
1241
        return false;
1242
1242
  }
1243
1243
 
1244
1244
  setCompression(c);
1247
1247
 
1248
1248
void KZip::virtual_hook( int id, void* data )
1249
1249
{
1250
 
    KArchive::virtual_hook( id, data );
 
1250
        KArchive::virtual_hook( id, data );
1251
1251
}
1252
1252
 
1253
1253
bool KZip::writeData(const char * data, qint64 size)
1254
1254
{
1255
 
    Q_ASSERT( d->m_currentFile );
1256
 
    Q_ASSERT( d->m_currentDev );
1257
 
    if (!d->m_currentFile || !d->m_currentDev) {
1258
 
        return false;
1259
 
    }
1260
 
 
1261
 
    // crc to be calculated over uncompressed stuff...
1262
 
    // and they didn't mention it in their docs...
1263
 
    d->m_crc = crc32(d->m_crc, (const Bytef *) data , size);
1264
 
 
1265
 
    qint64 written = d->m_currentDev->write( data, size );
1266
 
    //qDebug() << "wrote" << size << "bytes.";
1267
 
    return written == size;
 
1255
        Q_ASSERT( d->m_currentFile );
 
1256
        Q_ASSERT( d->m_currentDev );
 
1257
        if (!d->m_currentFile || !d->m_currentDev) {
 
1258
                return false;
 
1259
        }
 
1260
 
 
1261
        // crc to be calculated over uncompressed stuff...
 
1262
        // and they didn't mention it in their docs...
 
1263
        d->m_crc = crc32(d->m_crc, (const Bytef *) data , size);
 
1264
 
 
1265
        qint64 written = d->m_currentDev->write( data, size );
 
1266
        //qDebug() << "wrote" << size << "bytes.";
 
1267
        return written == size;
1268
1268
}
1269
1269
 
1270
1270
void KZip::setCompression( Compression c )
1271
1271
{
1272
 
    d->m_compression = ( c == NoCompression ) ? 0 : 8;
 
1272
        d->m_compression = ( c == NoCompression ) ? 0 : 8;
1273
1273
}
1274
1274
 
1275
1275
KZip::Compression KZip::compression() const
1279
1279
 
1280
1280
void KZip::setExtraField( ExtraField ef )
1281
1281
{
1282
 
    d->m_extraField = ef;
 
1282
        d->m_extraField = ef;
1283
1283
}
1284
1284
 
1285
1285
KZip::ExtraField KZip::extraField() const
1286
1286
{
1287
 
    return d->m_extraField;
 
1287
        return d->m_extraField;
1288
1288
}
1289
1289
 
1290
1290
////////////////////////////////////////////////////////////////////////
1293
1293
class KZipFileEntry::KZipFileEntryPrivate
1294
1294
{
1295
1295
public:
1296
 
    KZipFileEntryPrivate()
1297
 
    : crc(0),
1298
 
      compressedSize(0),
1299
 
      headerStart(0),
1300
 
      encoding(0)
1301
 
    {}
1302
 
    unsigned long crc;
1303
 
    qint64        compressedSize;
1304
 
    qint64        headerStart;
1305
 
    int           encoding;
1306
 
    QString       path;
 
1296
        KZipFileEntryPrivate()
 
1297
        : crc(0),
 
1298
          compressedSize(0),
 
1299
          headerStart(0),
 
1300
          encoding(0)
 
1301
        {}
 
1302
        unsigned long crc;
 
1303
        qint64        compressedSize;
 
1304
        qint64        headerStart;
 
1305
        int           encoding;
 
1306
        QString       path;
1307
1307
};
1308
1308
 
1309
1309
KZipFileEntry::KZipFileEntry(KZip* zip, const QString& name, int access, int date,
1310
 
                             const QString& user, const QString& group, const QString& symlink,
1311
 
                             const QString& path, qint64 start, qint64 uncompressedSize,
1312
 
                             int encoding, qint64 compressedSize)
 
1310
                                                         const QString& user, const QString& group, const QString& symlink,
 
1311
                                                         const QString& path, qint64 start, qint64 uncompressedSize,
 
1312
                                                         int encoding, qint64 compressedSize)
1313
1313
 : KArchiveFile(zip, name, access, date, user, group, symlink, start, uncompressedSize ),
1314
1314
   d(new KZipFileEntryPrivate)
1315
1315
{
1316
 
    d->path = path;
1317
 
    d->encoding = encoding;
1318
 
    d->compressedSize = compressedSize;
 
1316
        d->path = path;
 
1317
        d->encoding = encoding;
 
1318
        d->compressedSize = compressedSize;
1319
1319
}
1320
1320
 
1321
1321
KZipFileEntry::~KZipFileEntry()
1322
1322
{
1323
 
    delete d;
 
1323
        delete d;
1324
1324
}
1325
1325
 
1326
1326
int KZipFileEntry::encoding() const
1327
1327
{
1328
 
    return d->encoding;
 
1328
        return d->encoding;
1329
1329
}
1330
1330
 
1331
1331
qint64 KZipFileEntry::compressedSize() const
1332
1332
{
1333
 
    return d->compressedSize;
 
1333
        return d->compressedSize;
1334
1334
}
1335
1335
 
1336
1336
void KZipFileEntry::setCompressedSize(qint64 compressedSize)
1337
1337
{
1338
 
    d->compressedSize = compressedSize;
 
1338
        d->compressedSize = compressedSize;
1339
1339
}
1340
1340
 
1341
1341
void KZipFileEntry::setHeaderStart(qint64 headerstart)
1342
1342
{
1343
 
    d->headerStart = headerstart;
 
1343
        d->headerStart = headerstart;
1344
1344
}
1345
1345
 
1346
1346
qint64 KZipFileEntry::headerStart() const
1347
1347
{
1348
 
    return d->headerStart;
 
1348
        return d->headerStart;
1349
1349
}
1350
1350
 
1351
1351
unsigned long KZipFileEntry::crc32() const
1352
1352
{
1353
 
    return d->crc;
 
1353
        return d->crc;
1354
1354
}
1355
1355
 
1356
1356
void KZipFileEntry::setCRC32(unsigned long crc32)
1357
1357
{
1358
 
    d->crc=crc32;
 
1358
        d->crc=crc32;
1359
1359
}
1360
1360
 
1361
1361
const QString &KZipFileEntry::path() const
1362
1362
{
1363
 
    return d->path;
 
1363
        return d->path;
1364
1364
}
1365
1365
 
1366
1366
QByteArray KZipFileEntry::data() const
1367
1367
{
1368
 
    QIODevice* dev = createDevice();
1369
 
    QByteArray arr;
1370
 
    if ( dev ) {
1371
 
        arr = dev->readAll();
1372
 
        delete dev;
1373
 
    }
1374
 
    return arr;
 
1368
        QIODevice* dev = createDevice();
 
1369
        QByteArray arr;
 
1370
        if ( dev ) {
 
1371
                arr = dev->readAll();
 
1372
                delete dev;
 
1373
        }
 
1374
        return arr;
1375
1375
}
1376
1376
 
1377
1377
QIODevice* KZipFileEntry::createDevice() const
1378
1378
{
1379
 
    //qDebug() << "creating iodevice limited to pos=" << position() << ", csize=" << compressedSize();
1380
 
    // Limit the reading to the appropriate part of the underlying device (e.g. file)
1381
 
    KLimitedIODevice* limitedDev = new KLimitedIODevice( archive()->device(), position(), compressedSize() );
1382
 
    if ( encoding() == 0 || compressedSize() == 0 ) // no compression (or even no data)
1383
 
        return limitedDev;
 
1379
        //qDebug() << "creating iodevice limited to pos=" << position() << ", csize=" << compressedSize();
 
1380
        // Limit the reading to the appropriate part of the underlying device (e.g. file)
 
1381
        KLimitedIODevice* limitedDev = new KLimitedIODevice( archive()->device(), position(), compressedSize() );
 
1382
        if ( encoding() == 0 || compressedSize() == 0 ) // no compression (or even no data)
 
1383
                return limitedDev;
1384
1384
 
1385
 
    if ( encoding() == 8 )
1386
 
    {
1387
 
        // On top of that, create a device that uncompresses the zlib data
1388
 
        QIODevice* filterDev = KFilterDev::device( limitedDev, "application/x-gzip" );
1389
 
        if ( !filterDev )
1390
 
            return 0L; // ouch
1391
 
        static_cast<KFilterDev *>(filterDev)->setSkipHeaders(); // Just zlib, not gzip
1392
 
        bool b = filterDev->open( QIODevice::ReadOnly );
 
1385
        if ( encoding() == 8 )
 
1386
        {
 
1387
                // On top of that, create a device that uncompresses the zlib data
 
1388
                QIODevice* filterDev = KFilterDev::device( limitedDev, "application/x-gzip" );
 
1389
                if ( !filterDev )
 
1390
                        return 0L; // ouch
 
1391
                static_cast<KFilterDev *>(filterDev)->setSkipHeaders(); // Just zlib, not gzip
 
1392
                bool b = filterDev->open( QIODevice::ReadOnly );
1393
1393
        b = b; // annoying unused variable warning
1394
 
        Q_ASSERT( b );
1395
 
        return filterDev;
1396
 
    }
 
1394
                Q_ASSERT( b );
 
1395
                return filterDev;
 
1396
        }
1397
1397
 
1398
 
    qWarning() << "This zip file contains files compressed with method"
1399
 
              << encoding() << ", this method is currently not supported by KZip,"
1400
 
              << "please use a command-line tool to handle this file.";
1401
 
    return 0L;
 
1398
        qWarning() << "This zip file contains files compressed with method"
 
1399
                          << encoding() << ", this method is currently not supported by KZip,"
 
1400
                          << "please use a command-line tool to handle this file.";
 
1401
        return 0L;
1402
1402
}