• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdeio/tdeio
 

tdeio/tdeio

  • tdeio
  • tdeio
kzip.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 David Faure <faure@kde.org>
3  Copyright (C) 2002 Holger Schroeder <holger-kde@holgis.net>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 /*
21  This class implements a tdeioslave to access ZIP files from KDE.
22  you can use it in IO_ReadOnly or in IO_WriteOnly mode, and it
23  behaves just as expected (i hope ;-) ).
24  It can also be used in IO_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 IO_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 
38 */
39 
40 #include "kzip.h"
41 #include "kfilterdev.h"
42 #include "klimitediodevice.h"
43 #include <kmimetype.h>
44 #include <ksavefile.h>
45 #include <kdebug.h>
46 
47 #include <tqasciidict.h>
48 #include <tqfile.h>
49 #include <tqdir.h>
50 #include <tqdatetime.h>
51 #include <tqptrlist.h>
52 
53 #include <zlib.h>
54 #include <time.h>
55 #include <string.h>
56 
57 const int max_path_len = 4095; // maximum number of character a path may contain
58 
59 static void transformToMsDos(const TQDateTime& dt, char* buffer)
60 {
61  if ( dt.isValid() )
62  {
63  const TQ_UINT16 time =
64  ( dt.time().hour() << 11 ) // 5 bit hour
65  | ( dt.time().minute() << 5 ) // 6 bit minute
66  | ( dt.time().second() >> 1 ); // 5 bit double seconds
67 
68  buffer[0] = char(time);
69  buffer[1] = char(time >> 8);
70 
71  const TQ_UINT16 date =
72  ( ( dt.date().year() - 1980 ) << 9 ) // 7 bit year 1980-based
73  | ( dt.date().month() << 5 ) // 4 bit month
74  | ( dt.date().day() ); // 5 bit day
75 
76  buffer[2] = char(date);
77  buffer[3] = char(date >> 8);
78  }
79  else // !dt.isValid(), assume 1980-01-01 midnight
80  {
81  buffer[0] = 0;
82  buffer[1] = 0;
83  buffer[2] = 33;
84  buffer[3] = 0;
85  }
86 }
87 
88 static time_t transformFromMsDos(const char* buffer)
89 {
90  TQ_UINT16 time = (uchar)buffer[0] | ( (uchar)buffer[1] << 8 );
91  int h = time >> 11;
92  int m = ( time & 0x7ff ) >> 5;
93  int s = ( time & 0x1f ) * 2 ;
94  TQTime qt(h, m, s);
95 
96  TQ_UINT16 date = (uchar)buffer[2] | ( (uchar)buffer[3] << 8 );
97  int y = ( date >> 9 ) + 1980;
98  int o = ( date & 0x1ff ) >> 5;
99  int d = ( date & 0x1f );
100  TQDate qd(y, o, d);
101 
102  TQDateTime dt( qd, qt );
103  return dt.toTime_t();
104 }
105 
106 // == parsing routines for zip headers
107 
109 struct ParseFileInfo {
110  // file related info
111 // TQCString name; // filename
112  mode_t perm; // permissions of this file
113  time_t atime; // last access time (UNIX format)
114  time_t mtime; // modification time (UNIX format)
115  time_t ctime; // creation time (UNIX format)
116  int uid; // user id (-1 if not specified)
117  int gid; // group id (-1 if not specified)
118  TQCString guessed_symlink; // guessed symlink target
119  int extralen; // length of extra field
120 
121  // parsing related info
122  bool exttimestamp_seen; // true if extended timestamp extra field
123  // has been parsed
124  bool newinfounix_seen; // true if Info-ZIP Unix New extra field has
125  // been parsed
126 
127  ParseFileInfo() : perm(0100644), uid(-1), gid(-1), extralen(0),
128  exttimestamp_seen(false), newinfounix_seen(false) {
129  ctime = mtime = atime = time(0);
130  }
131 };
132 
141 static bool parseExtTimestamp(const char *buffer, int size, bool islocal,
142  ParseFileInfo &pfi) {
143  if (size < 1) {
144  kdDebug(7040) << "premature end of extended timestamp (#1)" << endl;
145  return false;
146  }/*end if*/
147  int flags = *buffer; // read flags
148  buffer += 1;
149  size -= 1;
150 
151  if (flags & 1) { // contains modification time
152  if (size < 4) {
153  kdDebug(7040) << "premature end of extended timestamp (#2)" << endl;
154  return false;
155  }/*end if*/
156  pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
157  | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
158  buffer += 4;
159  size -= 4;
160  }/*end if*/
161  // central extended field cannot contain more than the modification time
162  // even if other flags are set
163  if (!islocal) {
164  pfi.exttimestamp_seen = true;
165  return true;
166  }/*end if*/
167 
168  if (flags & 2) { // contains last access time
169  if (size < 4) {
170  kdDebug(7040) << "premature end of extended timestamp (#3)" << endl;
171  return true;
172  }/*end if*/
173  pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
174  | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
175  buffer += 4;
176  size -= 4;
177  }/*end if*/
178 
179  if (flags & 4) { // contains creation time
180  if (size < 4) {
181  kdDebug(7040) << "premature end of extended timestamp (#4)" << endl;
182  return true;
183  }/*end if*/
184  pfi.ctime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
185  | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
186  buffer += 4;
187  }/*end if*/
188 
189  pfi.exttimestamp_seen = true;
190  return true;
191 }
192 
201 static bool parseInfoZipUnixOld(const char *buffer, int size, bool islocal,
202  ParseFileInfo &pfi) {
203  // spec mandates to omit this field if one of the newer fields are available
204  if (pfi.exttimestamp_seen || pfi.newinfounix_seen) return true;
205 
206  if (size < 8) {
207  kdDebug(7040) << "premature end of Info-ZIP unix extra field old" << endl;
208  return false;
209  }/*end if*/
210 
211  pfi.atime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
212  | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
213  buffer += 4;
214  pfi.mtime = time_t((uchar)buffer[0] | (uchar)buffer[1] << 8
215  | (uchar)buffer[2] << 16 | (uchar)buffer[3] << 24);
216  buffer += 4;
217  if (islocal && size >= 12) {
218  pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
219  buffer += 2;
220  pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
221  buffer += 2;
222  }/*end if*/
223  return true;
224 }
225 
226 #if 0 // not needed yet
235 static bool parseInfoZipUnixNew(const char *buffer, int size, bool islocal,
236  ParseFileInfo &pfi) {
237  if (!islocal) { // contains nothing in central field
238  pfi.newinfounix = true;
239  return true;
240  }/*end if*/
241 
242  if (size < 4) {
243  kdDebug(7040) << "premature end of Info-ZIP unix extra field new" << endl;
244  return false;
245  }/*end if*/
246 
247  pfi.uid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
248  buffer += 2;
249  pfi.gid = (uchar)buffer[0] | (uchar)buffer[1] << 8;
250  buffer += 2;
251 
252  pfi.newinfounix = true;
253  return true;
254 }
255 #endif
256 
265 static bool parseExtraField(const char *buffer, int size, bool islocal,
266  ParseFileInfo &pfi) {
267  // extra field in central directory doesn't contain useful data, so we
268  // don't bother parsing it
269  if (!islocal) return true;
270 
271  while (size >= 4) { // as long as a potential extra field can be read
272  int magic = (uchar)buffer[0] | (uchar)buffer[1] << 8;
273  buffer += 2;
274  int fieldsize = (uchar)buffer[0] | (uchar)buffer[1] << 8;
275  buffer += 2;
276  size -= 4;
277 
278  if (fieldsize > size) {
279  //kdDebug(7040) << "fieldsize: " << fieldsize << " size: " << size << endl;
280  kdDebug(7040) << "premature end of extra fields reached" << endl;
281  break;
282  }/*end if*/
283 
284  switch (magic) {
285  case 0x5455: // extended timestamp
286  if (!parseExtTimestamp(buffer, fieldsize, islocal, pfi)) return false;
287  break;
288  case 0x5855: // old Info-ZIP unix extra field
289  if (!parseInfoZipUnixOld(buffer, fieldsize, islocal, pfi)) return false;
290  break;
291 #if 0 // not needed yet
292  case 0x7855: // new Info-ZIP unix extra field
293  if (!parseInfoZipUnixNew(buffer, fieldsize, islocal, pfi)) return false;
294  break;
295 #endif
296  default:
297  /* ignore everything else */;
298  }/*end switch*/
299 
300  buffer += fieldsize;
301  size -= fieldsize;
302  }/*wend*/
303  return true;
304 }
305 
309 
310 class KZip::KZipPrivate
311 {
312 public:
313  KZipPrivate()
314  : m_crc( 0 ),
315  m_currentFile( 0L ),
316  m_currentDev( 0L ),
317  m_compression( 8 ),
318  m_extraField( KZip::NoExtraField ),
319  m_offset( 0L ),
320  m_saveFile( 0 ) {}
321 
322  unsigned long m_crc; // checksum
323  KZipFileEntry* m_currentFile; // file currently being written
324  TQIODevice* m_currentDev; // filterdev used to write to the above file
325  TQPtrList<KZipFileEntry> m_fileList; // flat list of all files, for the index (saves a recursive method ;)
326  int m_compression;
327  KZip::ExtraField m_extraField;
328  unsigned int m_offset; // holds the offset of the place in the zip,
329  // where new data can be appended. after openarchive it points to 0, when in
330  // writeonly mode, or it points to the beginning of the central directory.
331  // each call to writefile updates this value.
332  KSaveFile* m_saveFile;
333 };
334 
335 KZip::KZip( const TQString& filename )
336  : KArchive( 0L )
337 {
338  //kdDebug(7040) << "KZip(filename) reached." << endl;
339  Q_ASSERT( !filename.isEmpty() );
340  m_filename = filename;
341  d = new KZipPrivate;
342  // unusual: this ctor leaves the device set to 0.
343  // This is for the use of KSaveFile, see openArchive.
344  // KDE4: move KSaveFile support to base class, KArchive.
345 }
346 
347 KZip::KZip( TQIODevice * dev )
348  : KArchive( dev )
349 {
350  //kdDebug(7040) << "KZip::KZip( TQIODevice * dev) reached." << endl;
351  d = new KZipPrivate;
352 }
353 
354 KZip::~KZip()
355 {
356  // mjarrett: Closes to prevent ~KArchive from aborting w/o device
357  //kdDebug(7040) << "~KZip reached." << endl;
358  if( isOpened() )
359  close();
360  if ( !m_filename.isEmpty() ) { // we created the device ourselves
361  if ( d->m_saveFile ) // writing mode
362  delete d->m_saveFile;
363  else // reading mode
364  delete device(); // (the TQFile)
365  }
366  delete d;
367 }
368 
369 bool KZip::openArchive( int mode )
370 {
371  //kdDebug(7040) << "openarchive reached." << endl;
372  d->m_fileList.clear();
373 
374  switch ( mode ) {
375  case IO_WriteOnly:
376  // The use of KSaveFile can't be done in the ctor (no mode known yet)
377  // Ideally we would reimplement open() and do it there (BIC)
378  if ( !m_filename.isEmpty() ) {
379  kdDebug(7040) << "Writing to a file using KSaveFile" << endl;
380  d->m_saveFile = new KSaveFile( m_filename );
381  if ( d->m_saveFile->status() != 0 ) {
382  kdWarning(7040) << "KSaveFile creation for " << m_filename << " failed, " << strerror( d->m_saveFile->status() ) << endl;
383  delete d->m_saveFile;
384  d->m_saveFile = 0;
385  return false;
386  }
387  Q_ASSERT( d->m_saveFile->file() );
388  setDevice( d->m_saveFile->file() );
389  }
390  return true;
391  case IO_ReadOnly:
392  case IO_ReadWrite:
393  {
394  // ReadWrite mode still uses TQFile for now; we'd need to copy to the tempfile, in fact.
395  if ( !m_filename.isEmpty() ) {
396  setDevice( new TQFile( m_filename ) );
397  if ( !device()->open( mode ) )
398  return false;
399  }
400  break; // continued below
401  }
402  default:
403  kdWarning(7040) << "Unsupported mode " << mode << endl;
404  return false;
405  }
406 
407  char buffer[47];
408 
409  // Check that it's a valid ZIP file
410  // the above code opened the underlying device already.
411  TQIODevice* dev = device();
412 
413  if (!dev) {
414  return false;
415  }
416 
417  uint offset = 0; // holds offset, where we read
418  int n;
419 
420  // contains information gathered from the local file headers
421  TQAsciiDict<ParseFileInfo> pfi_map(1009, true /*case sensitive */, true /*copy keys*/);
422  pfi_map.setAutoDelete(true);
423 
424  // We set a bool for knowing if we are allowed to skip the start of the file
425  bool startOfFile = true;
426 
427  for (;;) // repeat until 'end of entries' signature is reached
428  {
429 kdDebug(7040) << "loop starts" << endl;
430 kdDebug(7040) << "dev->at() now : " << dev->at() << endl;
431  n = dev->readBlock( buffer, 4 );
432 
433  if (n < 4)
434  {
435  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#1)" << endl;
436 
437  return false;
438  }
439 
440  if ( !memcmp( buffer, "PK\5\6", 4 ) ) // 'end of entries'
441  {
442  kdDebug(7040) << "PK56 found end of archive" << endl;
443  startOfFile = false;
444  break;
445  }
446 
447  if ( !memcmp( buffer, "PK\3\4", 4 ) ) // local file header
448  {
449  kdDebug(7040) << "PK34 found local file header" << endl;
450  startOfFile = false;
451  // can this fail ???
452  dev->at( dev->at() + 2 ); // skip 'version needed to extract'
453 
454  // read static header stuff
455  n = dev->readBlock( buffer, 24 );
456  if (n < 24) {
457  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#4)" << endl;
458  return false;
459  }
460 
461  int gpf = (uchar)buffer[0]; // "general purpose flag" not "general protection fault" ;-)
462  int compression_mode = (uchar)buffer[2] | (uchar)buffer[3] << 8;
463  time_t mtime = transformFromMsDos( buffer+4 );
464 
465  TQ_LONG compr_size = (uchar)buffer[12] | (uchar)buffer[13] << 8
466  | (uchar)buffer[14] << 16 | (uchar)buffer[15] << 24;
467  TQ_LONG uncomp_size = (uchar)buffer[16] | (uchar)buffer[17] << 8
468  | (uchar)buffer[18] << 16 | (uchar)buffer[19] << 24;
469  int namelen = (uchar)buffer[20] | (uchar)buffer[21] << 8;
470  int extralen = (uchar)buffer[22] | (uchar)buffer[23] << 8;
471 
472  kdDebug(7040) << "general purpose bit flag: " << gpf << endl;
473  kdDebug(7040) << "compressed size: " << compr_size << endl;
474  kdDebug(7040) << "uncompressed size: " << uncomp_size << endl;
475  kdDebug(7040) << "namelen: " << namelen << endl;
476  kdDebug(7040) << "extralen: " << extralen << endl;
477  kdDebug(7040) << "archive size: " << dev->size() << endl;
478 
479  // read filename
480  TQCString filename(namelen + 1);
481  n = dev->readBlock(filename.data(), namelen);
482  if ( n < namelen ) {
483  kdWarning(7040) << "Invalid ZIP file. Name not completely read (#2)" << endl;
484  return false;
485  }
486 
487  ParseFileInfo *pfi = new ParseFileInfo();
488  pfi->mtime = mtime;
489  pfi_map.insert(filename.data(), pfi);
490 
491  // read and parse the beginning of the extra field,
492  // skip rest of extra field in case it is too long
493  unsigned int extraFieldEnd = dev->at() + extralen;
494  pfi->extralen = extralen;
495  int handledextralen = TQMIN(extralen, (int)sizeof buffer);
496 
497  kdDebug(7040) << "handledextralen: " << handledextralen << endl;
498 
499  n = dev->readBlock(buffer, handledextralen);
500  // no error msg necessary as we deliberately truncate the extra field
501  if (!parseExtraField(buffer, handledextralen, true, *pfi))
502  {
503  kdWarning(7040) << "Invalid ZIP File. Broken ExtraField." << endl;
504  return false;
505  }
506 
507  // jump to end of extra field
508  dev->at( extraFieldEnd );
509 
510  // we have to take care of the 'general purpose bit flag'.
511  // if bit 3 is set, the header doesn't contain the length of
512  // the file and we look for the signature 'PK\7\8'.
513  if ( gpf & 8 )
514  {
515  // here we have to read through the compressed data to find
516  // the next PKxx
517  kdDebug(7040) << "trying to seek for next PK78" << endl;
518  bool foundSignature = false;
519 
520  while (!foundSignature)
521  {
522  n = dev->readBlock( buffer, 1 );
523  if (n < 1)
524  {
525  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#2)" << endl;
526  return false;
527  }
528 
529  if ( buffer[0] != 'P' )
530  continue;
531 
532  n = dev->readBlock( buffer, 3 );
533  if (n < 3)
534  {
535  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#3)" << endl;
536  return false;
537  }
538 
539  // we have to detect three magic tokens here:
540  // PK34 for the next local header in case there is no data descriptor
541  // PK12 for the central header in case there is no data descriptor
542  // PK78 for the data descriptor in case it is following the compressed data
543 
544  if ( buffer[0] == 'K' && buffer[1] == 7 && buffer[2] == 8 )
545  {
546  foundSignature = true;
547  dev->at( dev->at() + 12 ); // skip the 'data_descriptor'
548  }
549  else if ( ( buffer[0] == 'K' && buffer[1] == 1 && buffer[2] == 2 )
550  || ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 ) )
551  {
552  foundSignature = true;
553  dev->at( dev->at() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
554  }
555  else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
556  {
557  // We have another P character so we must go back a little to check if it is a magic
558  dev->at( dev->at() - 3 );
559  }
560 
561  }
562  }
563  else
564  {
565  // here we skip the compressed data and jump to the next header
566  kdDebug(7040) << "general purpose bit flag indicates, that local file header contains valid size" << endl;
567  // check if this could be a symbolic link
568  if (compression_mode == NoCompression
569  && uncomp_size <= max_path_len
570  && uncomp_size > 0) {
571  // read content and store it
572  pfi->guessed_symlink.resize(uncomp_size + 1);
573  kdDebug(7040) << "guessed symlink size: " << uncomp_size << endl;
574  n = dev->readBlock(pfi->guessed_symlink.data(), uncomp_size);
575  if (n < uncomp_size) {
576  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#5)" << endl;
577  return false;
578  }
579  } else {
580 
581  if ( compr_size > (TQ_LONG)dev->size() )
582  {
583  // here we cannot trust the compressed size, so scan through the compressed
584  // data to find the next header
585  bool foundSignature = false;
586 
587  while (!foundSignature)
588  {
589  n = dev->readBlock( buffer, 1 );
590  if (n < 1)
591  {
592  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#2)" << endl;
593  return false;
594  }
595 
596  if ( buffer[0] != 'P' )
597  continue;
598 
599  n = dev->readBlock( buffer, 3 );
600  if (n < 3)
601  {
602  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. (#3)" << endl;
603  return false;
604  }
605 
606  // we have to detect three magic tokens here:
607  // PK34 for the next local header in case there is no data descriptor
608  // PK12 for the central header in case there is no data descriptor
609  // PK78 for the data descriptor in case it is following the compressed data
610 
611  if ( buffer[0] == 'K' && buffer[1] == 7 && buffer[2] == 8 )
612  {
613  foundSignature = true;
614  dev->at( dev->at() + 12 ); // skip the 'data_descriptor'
615  }
616 
617  if ( ( buffer[0] == 'K' && buffer[1] == 1 && buffer[2] == 2 )
618  || ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 ) )
619  {
620  foundSignature = true;
621  dev->at( dev->at() - 4 );
622  // go back 4 bytes, so that the magic bytes can be found
623  // in the next cycle...
624  }
625  }
626  }
627  else
628  {
629 // kdDebug(7040) << "before interesting dev->at(): " << dev->at() << endl;
630  bool success;
631  success = dev->at( dev->at() + compr_size ); // can this fail ???
632 /* kdDebug(7040) << "after interesting dev->at(): " << dev->at() << endl;
633  if ( success )
634  kdDebug(7040) << "dev->at was successful... " << endl;
635  else
636  kdDebug(7040) << "dev->at failed... " << endl;*/
637  }
638 
639  }
640 
641 // not needed any more
642 /* // here we calculate the length of the file in the zip
643  // with headers and jump to the next header.
644  uint skip = compr_size + namelen + extralen;
645  offset += 30 + skip;*/
646  }
647  }
648  else if ( !memcmp( buffer, "PK\1\2", 4 ) ) // central block
649  {
650  kdDebug(7040) << "PK12 found central block" << endl;
651  startOfFile = false;
652 
653  // so we reached the central header at the end of the zip file
654  // here we get all interesting data out of the central header
655  // of a file
656  offset = dev->at() - 4;
657 
658  //set offset for appending new files
659  if ( d->m_offset == 0L ) d->m_offset = offset;
660 
661  n = dev->readBlock( buffer + 4, 42 );
662  if (n < 42) {
663  kdWarning(7040) << "Invalid ZIP file, central entry too short" << endl; // not long enough for valid entry
664  return false;
665  }
666 
667  //int gpf = (uchar)buffer[9] << 8 | (uchar)buffer[10];
668  //kdDebug() << "general purpose flag=" << gpf << endl;
669  // length of the filename (well, pathname indeed)
670  int namelen = (uchar)buffer[29] << 8 | (uchar)buffer[28];
671  TQCString bufferName( namelen + 1 );
672  n = dev->readBlock( bufferName.data(), namelen );
673  if ( n < namelen )
674  kdWarning(7040) << "Invalid ZIP file. Name not completely read" << endl;
675 
676  ParseFileInfo *pfi = pfi_map[bufferName];
677  if (!pfi) { // can that happen?
678  pfi_map.insert(bufferName.data(), pfi = new ParseFileInfo());
679  }
680  TQString name( TQFile::decodeName(bufferName) );
681 
682  //kdDebug(7040) << "name: " << name << endl;
683  // only in central header ! see below.
684  // length of extra attributes
685  int extralen = (uchar)buffer[31] << 8 | (uchar)buffer[30];
686  // length of comment for this file
687  int commlen = (uchar)buffer[33] << 8 | (uchar)buffer[32];
688  // compression method of this file
689  int cmethod = (uchar)buffer[11] << 8 | (uchar)buffer[10];
690 
691  //kdDebug(7040) << "cmethod: " << cmethod << endl;
692  //kdDebug(7040) << "extralen: " << extralen << endl;
693 
694  // uncompressed file size
695  uint ucsize = (uchar)buffer[27] << 24 | (uchar)buffer[26] << 16 |
696  (uchar)buffer[25] << 8 | (uchar)buffer[24];
697  // compressed file size
698  uint csize = (uchar)buffer[23] << 24 | (uchar)buffer[22] << 16 |
699  (uchar)buffer[21] << 8 | (uchar)buffer[20];
700 
701  // offset of local header
702  uint localheaderoffset = (uchar)buffer[45] << 24 | (uchar)buffer[44] << 16 |
703  (uchar)buffer[43] << 8 | (uchar)buffer[42];
704 
705  // some clever people use different extra field lengths
706  // in the central header and in the local header... funny.
707  // so we need to get the localextralen to calculate the offset
708  // from localheaderstart to dataoffset
709  int localextralen = pfi->extralen; // FIXME: this will not work if
710  // no local header exists
711 
712  //kdDebug(7040) << "localextralen: " << localextralen << endl;
713 
714  // offset, where the real data for uncompression starts
715  uint dataoffset = localheaderoffset + 30 + localextralen + namelen; //comment only in central header
716 
717  //kdDebug(7040) << "esize: " << esize << endl;
718  //kdDebug(7040) << "eoffset: " << eoffset << endl;
719  //kdDebug(7040) << "csize: " << csize << endl;
720 
721  int os_madeby = (uchar)buffer[5];
722  bool isdir = false;
723  int access = 0100644;
724 
725  if (os_madeby == 3) { // good ole unix
726  access = (uchar)buffer[40] | (uchar)buffer[41] << 8;
727  }
728 
729  TQString entryName;
730 
731  if ( name.endsWith( "/" ) ) // Entries with a trailing slash are directories
732  {
733  isdir = true;
734  name = name.left( name.length() - 1 );
735  if (os_madeby != 3) access = S_IFDIR | 0755;
736  else Q_ASSERT(access & S_IFDIR);
737  }
738 
739  int pos = name.findRev( '/' );
740  if ( pos == -1 )
741  entryName = name;
742  else
743  entryName = name.mid( pos + 1 );
744  Q_ASSERT( !entryName.isEmpty() );
745 
746  KArchiveEntry* entry;
747  if ( isdir )
748  {
749  TQString path = TQDir::cleanDirPath( name );
750  KArchiveEntry* ent = rootDir()->entry( path );
751  if ( ent && ent->isDirectory() )
752  {
753  //kdDebug(7040) << "Directory already exists, NOT going to add it again" << endl;
754  entry = 0L;
755  }
756  else
757  {
758  entry = new KArchiveDirectory( this, entryName, access, (int)pfi->mtime, rootDir()->user(), rootDir()->group(), TQString::null );
759  //kdDebug(7040) << "KArchiveDirectory created, entryName= " << entryName << ", name=" << name << endl;
760  }
761  }
762  else
763  {
764  TQString symlink;
765  if (S_ISLNK(access)) {
766  symlink = TQFile::decodeName(pfi->guessed_symlink);
767  }
768  entry = new KZipFileEntry( this, entryName, access, pfi->mtime,
769  rootDir()->user(), rootDir()->group(),
770  symlink, name, dataoffset,
771  ucsize, cmethod, csize );
772  static_cast<KZipFileEntry *>(entry)->setHeaderStart( localheaderoffset );
773  //kdDebug(7040) << "KZipFileEntry created, entryName= " << entryName << ", name=" << name << endl;
774  d->m_fileList.append( static_cast<KZipFileEntry *>( entry ) );
775  }
776 
777  if ( entry )
778  {
779  if ( pos == -1 )
780  {
781  rootDir()->addEntry(entry);
782  }
783  else
784  {
785  // In some tar files we can find dir/./file => call cleanDirPath
786  TQString path = TQDir::cleanDirPath( name.left( pos ) );
787  // Ensure container directory exists, create otherwise
788  KArchiveDirectory * tdir = findOrCreate( path );
789  tdir->addEntry(entry);
790  }
791  }
792 
793  //calculate offset to next entry
794  offset += 46 + commlen + extralen + namelen;
795  bool b = dev->at(offset);
796  Q_ASSERT( b );
797  if ( !b )
798  return false;
799  }
800  else if ( startOfFile )
801  {
802  // The file does not start with any ZIP header (e.g. self-extractable ZIP files)
803  // Therefore we need to find the first PK\003\004 (local header)
804  kdDebug(7040) << "Try to skip start of file" << endl;
805  startOfFile = false;
806  bool foundSignature = false;
807 
808  while (!foundSignature)
809  {
810  n = dev->readBlock( buffer, 1 );
811  if (n < 1)
812  {
813  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. " << k_funcinfo << endl;
814  return false;
815  }
816 
817  if ( buffer[0] != 'P' )
818  continue;
819 
820  n = dev->readBlock( buffer, 3 );
821  if (n < 3)
822  {
823  kdWarning(7040) << "Invalid ZIP file. Unexpected end of file. " << k_funcinfo << endl;
824  return false;
825  }
826 
827  // We have to detect the magic token for a local header: PK\003\004
828  /*
829  * Note: we do not need to check the other magics, if the ZIP file has no
830  * local header, then it has not any files!
831  */
832  if ( buffer[0] == 'K' && buffer[1] == 3 && buffer[2] == 4 )
833  {
834  foundSignature = true;
835  dev->at( dev->at() - 4 ); // go back 4 bytes, so that the magic bytes can be found...
836  }
837  else if ( buffer[0] == 'P' || buffer[1] == 'P' || buffer[2] == 'P' )
838  {
839  // We have another P character so we must go back a little to check if it is a magic
840  dev->at( dev->at() - 3 );
841  }
842  }
843  }
844  else
845  {
846  kdWarning(7040) << "Invalid ZIP file. Unrecognized header at offset " << offset << endl;
847 
848  return false;
849  }
850  }
851  //kdDebug(7040) << "*** done *** " << endl;
852  return true;
853 }
854 
855 bool KZip::closeArchive()
856 {
857  if ( ! ( mode() & IO_WriteOnly ) )
858  {
859  //kdDebug(7040) << "closearchive readonly reached." << endl;
860  return true;
861  }
862 
863  kdDebug() << k_funcinfo << "device=" << device() << endl;
864  //ReadWrite or WriteOnly
865  //write all central dir file entries
866 
867  if ( !device() ) // saving aborted
868  return false;
869 
870  // to be written at the end of the file...
871  char buffer[ 22 ]; // first used for 12, then for 22 at the end
872  uLong crc = crc32(0L, Z_NULL, 0);
873 
874  TQ_LONG centraldiroffset = device()->at();
875  //kdDebug(7040) << "closearchive: centraldiroffset: " << centraldiroffset << endl;
876  TQ_LONG atbackup = centraldiroffset;
877  TQPtrListIterator<KZipFileEntry> it( d->m_fileList );
878 
879  for ( ; it.current() ; ++it )
880  { //set crc and compressed size in each local file header
881  if ( !device()->at( it.current()->headerStart() + 14 ) )
882  return false;
883  //kdDebug(7040) << "closearchive setcrcandcsize: filename: "
884  // << it.current()->path()
885  // << " encoding: "<< it.current()->encoding() << endl;
886 
887  uLong mycrc = it.current()->crc32();
888  buffer[0] = char(mycrc); // crc checksum, at headerStart+14
889  buffer[1] = char(mycrc >> 8);
890  buffer[2] = char(mycrc >> 16);
891  buffer[3] = char(mycrc >> 24);
892 
893  int mysize1 = it.current()->compressedSize();
894  buffer[4] = char(mysize1); // compressed file size, at headerStart+18
895  buffer[5] = char(mysize1 >> 8);
896  buffer[6] = char(mysize1 >> 16);
897  buffer[7] = char(mysize1 >> 24);
898 
899  int myusize = it.current()->size();
900  buffer[8] = char(myusize); // uncompressed file size, at headerStart+22
901  buffer[9] = char(myusize >> 8);
902  buffer[10] = char(myusize >> 16);
903  buffer[11] = char(myusize >> 24);
904 
905  if ( device()->writeBlock( buffer, 12 ) != 12 )
906  return false;
907  }
908  device()->at( atbackup );
909 
910  for ( it.toFirst(); it.current() ; ++it )
911  {
912  //kdDebug(7040) << "closearchive: filename: " << it.current()->path()
913  // << " encoding: "<< it.current()->encoding() << endl;
914 
915  TQCString path = TQFile::encodeName(it.current()->path());
916 
917  const int extra_field_len = 9;
918  int bufferSize = extra_field_len + path.length() + 46;
919  char* buffer = new char[ bufferSize ];
920 
921  memset(buffer, 0, 46); // zero is a nice default for most header fields
922 
923  const char head[] =
924  {
925  'P', 'K', 1, 2, // central file header signature
926  0x14, 3, // version made by (3 == UNIX)
927  0x14, 0 // version needed to extract
928  };
929 
930  // I do not know why memcpy is not working here
931  //memcpy(buffer, head, sizeof(head));
932  tqmemmove(buffer, head, sizeof(head));
933 
934  buffer[ 10 ] = char(it.current()->encoding()); // compression method
935  buffer[ 11 ] = char(it.current()->encoding() >> 8);
936 
937  transformToMsDos( it.current()->datetime(), &buffer[ 12 ] );
938 
939  uLong mycrc = it.current()->crc32();
940  buffer[ 16 ] = char(mycrc); // crc checksum
941  buffer[ 17 ] = char(mycrc >> 8);
942  buffer[ 18 ] = char(mycrc >> 16);
943  buffer[ 19 ] = char(mycrc >> 24);
944 
945  int mysize1 = it.current()->compressedSize();
946  buffer[ 20 ] = char(mysize1); // compressed file size
947  buffer[ 21 ] = char(mysize1 >> 8);
948  buffer[ 22 ] = char(mysize1 >> 16);
949  buffer[ 23 ] = char(mysize1 >> 24);
950 
951  int mysize = it.current()->size();
952  buffer[ 24 ] = char(mysize); // uncompressed file size
953  buffer[ 25 ] = char(mysize >> 8);
954  buffer[ 26 ] = char(mysize >> 16);
955  buffer[ 27 ] = char(mysize >> 24);
956 
957  buffer[ 28 ] = char(it.current()->path().length()); // filename length
958  buffer[ 29 ] = char(it.current()->path().length() >> 8);
959 
960  buffer[ 30 ] = char(extra_field_len);
961  buffer[ 31 ] = char(extra_field_len >> 8);
962 
963  buffer[ 40 ] = char(it.current()->permissions());
964  buffer[ 41 ] = char(it.current()->permissions() >> 8);
965 
966  int myhst = it.current()->headerStart();
967  buffer[ 42 ] = char(myhst); //relative offset of local header
968  buffer[ 43 ] = char(myhst >> 8);
969  buffer[ 44 ] = char(myhst >> 16);
970  buffer[ 45 ] = char(myhst >> 24);
971 
972  // file name
973  strncpy( buffer + 46, path, path.length() );
974  //kdDebug(7040) << "closearchive length to write: " << bufferSize << endl;
975 
976  // extra field
977  char *extfield = buffer + 46 + path.length();
978  extfield[0] = 'U';
979  extfield[1] = 'T';
980  extfield[2] = 5;
981  extfield[3] = 0;
982  extfield[4] = 1 | 2 | 4; // specify flags from local field
983  // (unless I misread the spec)
984  // provide only modification time
985  unsigned long time = (unsigned long)it.current()->date();
986  extfield[5] = char(time);
987  extfield[6] = char(time >> 8);
988  extfield[7] = char(time >> 16);
989  extfield[8] = char(time >> 24);
990 
991  crc = crc32(crc, (Bytef *)buffer, bufferSize );
992  bool ok = ( device()->writeBlock( buffer, bufferSize ) == bufferSize );
993  delete[] buffer;
994  if ( !ok )
995  return false;
996  }
997  TQ_LONG centraldirendoffset = device()->at();
998  //kdDebug(7040) << "closearchive: centraldirendoffset: " << centraldirendoffset << endl;
999  //kdDebug(7040) << "closearchive: device()->at(): " << device()->at() << endl;
1000 
1001  //write end of central dir record.
1002  buffer[ 0 ] = 'P'; //end of central dir signature
1003  buffer[ 1 ] = 'K';
1004  buffer[ 2 ] = 5;
1005  buffer[ 3 ] = 6;
1006 
1007  buffer[ 4 ] = 0; // number of this disk
1008  buffer[ 5 ] = 0;
1009 
1010  buffer[ 6 ] = 0; // number of disk with start of central dir
1011  buffer[ 7 ] = 0;
1012 
1013  int count = d->m_fileList.count();
1014  //kdDebug(7040) << "number of files (count): " << count << endl;
1015 
1016 
1017  buffer[ 8 ] = char(count); // total number of entries in central dir of
1018  buffer[ 9 ] = char(count >> 8); // this disk
1019 
1020  buffer[ 10 ] = buffer[ 8 ]; // total number of entries in the central dir
1021  buffer[ 11 ] = buffer[ 9 ];
1022 
1023  int cdsize = centraldirendoffset - centraldiroffset;
1024  buffer[ 12 ] = char(cdsize); // size of the central dir
1025  buffer[ 13 ] = char(cdsize >> 8);
1026  buffer[ 14 ] = char(cdsize >> 16);
1027  buffer[ 15 ] = char(cdsize >> 24);
1028 
1029  //kdDebug(7040) << "end : centraldiroffset: " << centraldiroffset << endl;
1030  //kdDebug(7040) << "end : centraldirsize: " << cdsize << endl;
1031 
1032  buffer[ 16 ] = char(centraldiroffset); // central dir offset
1033  buffer[ 17 ] = char(centraldiroffset >> 8);
1034  buffer[ 18 ] = char(centraldiroffset >> 16);
1035  buffer[ 19 ] = char(centraldiroffset >> 24);
1036 
1037  buffer[ 20 ] = 0; //zipfile comment length
1038  buffer[ 21 ] = 0;
1039 
1040  if ( device()->writeBlock( buffer, 22 ) != 22 )
1041  return false;
1042 
1043  if ( d->m_saveFile ) {
1044  d->m_saveFile->close();
1045  setDevice( 0 );
1046  delete d->m_saveFile;
1047  d->m_saveFile = 0;
1048  }
1049 
1050  //kdDebug(7040) << __FILE__" reached." << endl;
1051  return true;
1052 }
1053 
1054 bool KZip::writeDir(const TQString& name, const TQString& user, const TQString& group)
1055 {
1056  // Zip files have no explicit directories, they are implicitly created during extraction time
1057  // when file entries have paths in them.
1058  // However, to support empty directories, we must create a dummy file entry which ends with '/'.
1059  TQString dirName = name;
1060  if (!name.endsWith("/")) {
1061  dirName = dirName.append('/');
1062  }
1063 
1064  mode_t perm = 040755;
1065  time_t the_time = time(0);
1066  return writeFile(dirName, user, group, 0, perm, the_time, the_time, the_time, 0);
1067 }
1068 
1069 // Doesn't need to be reimplemented anymore. Remove for KDE-4.0
1070 bool KZip::writeFile( const TQString& name, const TQString& user, const TQString& group, uint size, const char* data )
1071 {
1072  mode_t mode = 0100644;
1073  time_t the_time = time(0);
1074  return KArchive::writeFile( name, user, group, size, mode, the_time,
1075  the_time, the_time, data );
1076 }
1077 
1078 // Doesn't need to be reimplemented anymore. Remove for KDE-4.0
1079 bool KZip::writeFile( const TQString& name, const TQString& user,
1080  const TQString& group, uint size, mode_t perm,
1081  time_t atime, time_t mtime, time_t ctime,
1082  const char* data ) {
1083  return KArchive::writeFile(name, user, group, size, perm, atime, mtime,
1084  ctime, data);
1085 }
1086 
1087 // Doesn't need to be reimplemented anymore. Remove for KDE-4.0
1088 bool KZip::prepareWriting( const TQString& name, const TQString& user, const TQString& group, uint size )
1089 {
1090  mode_t dflt_perm = 0100644;
1091  time_t the_time = time(0);
1092  return prepareWriting(name,user,group,size,dflt_perm,
1093  the_time,the_time,the_time);
1094 }
1095 
1096 // Doesn't need to be reimplemented anymore. Remove for KDE-4.0
1097 bool KZip::prepareWriting(const TQString& name, const TQString& user,
1098  const TQString& group, uint size, mode_t perm,
1099  time_t atime, time_t mtime, time_t ctime) {
1100  return KArchive::prepareWriting(name,user,group,size,perm,atime,mtime,ctime);
1101 }
1102 
1103 bool KZip::prepareWriting_impl(const TQString &name, const TQString &user,
1104  const TQString &group, uint /*size*/, mode_t perm,
1105  time_t atime, time_t mtime, time_t ctime) {
1106  //kdDebug(7040) << "prepareWriting reached." << endl;
1107  if ( !isOpened() )
1108  {
1109  tqWarning( "KZip::writeFile: You must open the zip file before writing to it\n");
1110  return false;
1111  }
1112 
1113  if ( ! ( mode() & IO_WriteOnly ) ) // accept WriteOnly and ReadWrite
1114  {
1115  tqWarning( "KZip::writeFile: You must open the zip file for writing\n");
1116  return false;
1117  }
1118 
1119  if ( !device() ) { // aborted
1120  //kdWarning(7040) << "prepareWriting_impl: no device" << endl;
1121  return false;
1122  }
1123 
1124  // set right offset in zip.
1125  if ( !device()->at( d->m_offset ) ) {
1126  kdWarning(7040) << "prepareWriting_impl: cannot seek in ZIP file. Disk full?" << endl;
1127  abort();
1128  return false;
1129  }
1130 
1131  // delete entries in the filelist with the same filename as the one we want
1132  // to save, so that we don�t have duplicate file entries when viewing the zip
1133  // with konqi...
1134  // CAUTION: the old file itself is still in the zip and won't be removed !!!
1135  TQPtrListIterator<KZipFileEntry> it( d->m_fileList );
1136 
1137  //kdDebug(7040) << "filename to write: " << name <<endl;
1138  for ( ; it.current() ; ++it )
1139  {
1140  //kdDebug(7040) << "prepfilename: " << it.current()->path() <<endl;
1141  if (name == it.current()->path() )
1142  {
1143  //kdDebug(7040) << "removing following entry: " << it.current()->path() <<endl;
1144  d->m_fileList.remove();
1145  }
1146 
1147  }
1148  // Find or create parent dir
1149  KArchiveDirectory* parentDir = rootDir();
1150  TQString fileName( name );
1151  int i = name.findRev( '/' );
1152  if ( i != -1 )
1153  {
1154  TQString dir = name.left( i );
1155  fileName = name.mid( i + 1 );
1156  //kdDebug(7040) << "KZip::prepareWriting ensuring " << dir << " exists. fileName=" << fileName << endl;
1157  parentDir = findOrCreate( dir );
1158  }
1159 
1160  // construct a KZipFileEntry and add it to list
1161  KZipFileEntry * e = new KZipFileEntry( this, fileName, perm, mtime, user, group, TQString::null,
1162  name, device()->at() + 30 + name.length(), // start
1163  0 /*size unknown yet*/, d->m_compression, 0 /*csize unknown yet*/ );
1164  e->setHeaderStart( device()->at() );
1165  //kdDebug(7040) << "wrote file start: " << e->position() << " name: " << name << endl;
1166  parentDir->addEntry( e );
1167 
1168  d->m_currentFile = e;
1169  d->m_fileList.append( e );
1170 
1171  int extra_field_len = 0;
1172  if ( d->m_extraField == ModificationTime )
1173  extra_field_len = 17; // value also used in doneWriting()
1174 
1175  // write out zip header
1176  TQCString encodedName = TQFile::encodeName(name);
1177  int bufferSize = extra_field_len + encodedName.length() + 30;
1178  //kdDebug(7040) << "KZip::prepareWriting bufferSize=" << bufferSize << endl;
1179  char* buffer = new char[ bufferSize ];
1180 
1181  buffer[ 0 ] = 'P'; //local file header signature
1182  buffer[ 1 ] = 'K';
1183  buffer[ 2 ] = 3;
1184  buffer[ 3 ] = 4;
1185 
1186  buffer[ 4 ] = 0x14; // version needed to extract
1187  buffer[ 5 ] = 0;
1188 
1189  buffer[ 6 ] = 0; // general purpose bit flag
1190  buffer[ 7 ] = 0;
1191 
1192  buffer[ 8 ] = char(e->encoding()); // compression method
1193  buffer[ 9 ] = char(e->encoding() >> 8);
1194 
1195  transformToMsDos( e->datetime(), &buffer[ 10 ] );
1196 
1197  buffer[ 14 ] = 'C'; //dummy crc
1198  buffer[ 15 ] = 'R';
1199  buffer[ 16 ] = 'C';
1200  buffer[ 17 ] = 'q';
1201 
1202  buffer[ 18 ] = 'C'; //compressed file size
1203  buffer[ 19 ] = 'S';
1204  buffer[ 20 ] = 'I';
1205  buffer[ 21 ] = 'Z';
1206 
1207  buffer[ 22 ] = 'U'; //uncompressed file size
1208  buffer[ 23 ] = 'S';
1209  buffer[ 24 ] = 'I';
1210  buffer[ 25 ] = 'Z';
1211 
1212  buffer[ 26 ] = (uchar)(encodedName.length()); //filename length
1213  buffer[ 27 ] = (uchar)(encodedName.length() >> 8);
1214 
1215  buffer[ 28 ] = (uchar)(extra_field_len); // extra field length
1216  buffer[ 29 ] = (uchar)(extra_field_len >> 8);
1217 
1218  // file name
1219  strncpy( buffer + 30, encodedName, encodedName.length() );
1220 
1221  // extra field
1222  if ( d->m_extraField == ModificationTime )
1223  {
1224  char *extfield = buffer + 30 + encodedName.length();
1225  // "Extended timestamp" header (0x5455)
1226  extfield[0] = 'U';
1227  extfield[1] = 'T';
1228  extfield[2] = 13; // data size
1229  extfield[3] = 0;
1230  extfield[4] = 1 | 2 | 4; // contains mtime, atime, ctime
1231 
1232  extfield[5] = char(mtime);
1233  extfield[6] = char(mtime >> 8);
1234  extfield[7] = char(mtime >> 16);
1235  extfield[8] = char(mtime >> 24);
1236 
1237  extfield[9] = char(atime);
1238  extfield[10] = char(atime >> 8);
1239  extfield[11] = char(atime >> 16);
1240  extfield[12] = char(atime >> 24);
1241 
1242  extfield[13] = char(ctime);
1243  extfield[14] = char(ctime >> 8);
1244  extfield[15] = char(ctime >> 16);
1245  extfield[16] = char(ctime >> 24);
1246  }
1247 
1248  // Write header
1249  bool b = (device()->writeBlock( buffer, bufferSize ) == bufferSize );
1250  d->m_crc = 0L;
1251  delete[] buffer;
1252 
1253  Q_ASSERT( b );
1254  if (!b) {
1255  abort();
1256  return false;
1257  }
1258 
1259  // Prepare device for writing the data
1260  // Either device() if no compression, or a KFilterDev to compress
1261  if ( d->m_compression == 0 ) {
1262  d->m_currentDev = device();
1263  return true;
1264  }
1265 
1266  d->m_currentDev = KFilterDev::device( device(), "application/x-gzip", false );
1267  Q_ASSERT( d->m_currentDev );
1268  if ( !d->m_currentDev ) {
1269  abort();
1270  return false; // ouch
1271  }
1272  static_cast<KFilterDev *>(d->m_currentDev)->setSkipHeaders(); // Just zlib, not gzip
1273 
1274  b = d->m_currentDev->open( IO_WriteOnly );
1275  Q_ASSERT( b );
1276  return b;
1277 }
1278 
1279 bool KZip::doneWriting( uint size )
1280 {
1281  if ( d->m_currentFile->encoding() == 8 ) {
1282  // Finish
1283  (void)d->m_currentDev->writeBlock( 0, 0 );
1284  delete d->m_currentDev;
1285  }
1286  // If 0, d->m_currentDev was device() - don't delete ;)
1287  d->m_currentDev = 0L;
1288 
1289  Q_ASSERT( d->m_currentFile );
1290  //kdDebug(7040) << "donewriting reached." << endl;
1291  //kdDebug(7040) << "filename: " << d->m_currentFile->path() << endl;
1292  //kdDebug(7040) << "getpos (at): " << device()->at() << endl;
1293  d->m_currentFile->setSize(size);
1294  int extra_field_len = 0;
1295  if ( d->m_extraField == ModificationTime )
1296  extra_field_len = 17; // value also used in doneWriting()
1297 
1298  int csize = device()->at() -
1299  d->m_currentFile->headerStart() - 30 -
1300  d->m_currentFile->path().length() - extra_field_len;
1301  d->m_currentFile->setCompressedSize(csize);
1302  //kdDebug(7040) << "usize: " << d->m_currentFile->size() << endl;
1303  //kdDebug(7040) << "csize: " << d->m_currentFile->compressedSize() << endl;
1304  //kdDebug(7040) << "headerstart: " << d->m_currentFile->headerStart() << endl;
1305 
1306  //kdDebug(7040) << "crc: " << d->m_crc << endl;
1307  d->m_currentFile->setCRC32( d->m_crc );
1308 
1309  d->m_currentFile = 0L;
1310 
1311  // update saved offset for appending new files
1312  d->m_offset = device()->at();
1313  return true;
1314 }
1315 
1316 bool KZip::writeSymLink(const TQString &name, const TQString &target,
1317  const TQString &user, const TQString &group,
1318  mode_t perm, time_t atime, time_t mtime, time_t ctime) {
1319  return KArchive::writeSymLink(name,target,user,group,perm,atime,mtime,ctime);
1320 }
1321 
1322 bool KZip::writeSymLink_impl(const TQString &name, const TQString &target,
1323  const TQString &user, const TQString &group,
1324  mode_t perm, time_t atime, time_t mtime, time_t ctime) {
1325 
1326  // reassure that symlink flag is set, otherwise strange things happen on
1327  // extraction
1328  perm |= S_IFLNK;
1329  Compression c = compression();
1330  setCompression(NoCompression); // link targets are never compressed
1331 
1332  if (!prepareWriting(name, user, group, 0, perm, atime, mtime, ctime)) {
1333  kdWarning() << "KZip::writeFile prepareWriting failed" << endl;
1334  setCompression(c);
1335  return false;
1336  }
1337 
1338  TQCString symlink_target = TQFile::encodeName(target);
1339  if (!writeData(symlink_target, symlink_target.length())) {
1340  kdWarning() << "KZip::writeFile writeData failed" << endl;
1341  setCompression(c);
1342  return false;
1343  }
1344 
1345  if (!doneWriting(symlink_target.length())) {
1346  kdWarning() << "KZip::writeFile doneWriting failed" << endl;
1347  setCompression(c);
1348  return false;
1349  }
1350 
1351  setCompression(c);
1352  return true;
1353 }
1354 
1355 void KZip::virtual_hook( int id, void* data )
1356 {
1357  switch (id) {
1358  case VIRTUAL_WRITE_DATA: {
1359  WriteDataParams* params = reinterpret_cast<WriteDataParams *>(data);
1360  params->retval = writeData_impl( params->data, params->size );
1361  break;
1362  }
1363  case VIRTUAL_WRITE_SYMLINK: {
1364  WriteSymlinkParams *params = reinterpret_cast<WriteSymlinkParams *>(data);
1365  params->retval = writeSymLink_impl(*params->name,*params->target,
1366  *params->user,*params->group,params->perm,
1367  params->atime,params->mtime,params->ctime);
1368  break;
1369  }
1370  case VIRTUAL_PREPARE_WRITING: {
1371  PrepareWritingParams *params = reinterpret_cast<PrepareWritingParams *>(data);
1372  params->retval = prepareWriting_impl(*params->name,*params->user,
1373  *params->group,params->size,params->perm,
1374  params->atime,params->mtime,params->ctime);
1375  break;
1376  }
1377  default:
1378  KArchive::virtual_hook( id, data );
1379  }/*end switch*/
1380 }
1381 
1382 // made virtual using virtual_hook
1383 bool KZip::writeData(const char * c, uint i)
1384 {
1385  return KArchive::writeData( c, i );
1386 }
1387 
1388 bool KZip::writeData_impl(const char * c, uint i)
1389 {
1390  Q_ASSERT( d->m_currentFile );
1391  Q_ASSERT( d->m_currentDev );
1392  if (!d->m_currentFile || !d->m_currentDev) {
1393  abort();
1394  return false;
1395  }
1396 
1397  // crc to be calculated over uncompressed stuff...
1398  // and they didn't mention it in their docs...
1399  d->m_crc = crc32(d->m_crc, (const Bytef *) c , i);
1400 
1401  TQ_LONG written = d->m_currentDev->writeBlock( c, i );
1402  //kdDebug(7040) << "KZip::writeData wrote " << i << " bytes." << endl;
1403  bool ok = written == (TQ_LONG)i;
1404  if ( !ok )
1405  abort();
1406  return ok;
1407 }
1408 
1409 void KZip::setCompression( Compression c )
1410 {
1411  d->m_compression = ( c == NoCompression ) ? 0 : 8;
1412 }
1413 
1414 KZip::Compression KZip::compression() const
1415 {
1416  return ( d->m_compression == 8 ) ? DeflateCompression : NoCompression;
1417 }
1418 
1419 void KZip::setExtraField( ExtraField ef )
1420 {
1421  d->m_extraField = ef;
1422 }
1423 
1424 KZip::ExtraField KZip::extraField() const
1425 {
1426  return d->m_extraField;
1427 }
1428 
1429 void KZip::abort()
1430 {
1431  if ( d->m_saveFile ) {
1432  d->m_saveFile->abort();
1433  setDevice( 0 );
1434  }
1435 }
1436 
1437 
1439 
1440 TQByteArray KZipFileEntry::data() const
1441 {
1442  TQIODevice* dev = device();
1443  TQByteArray arr;
1444  if ( dev ) {
1445  arr = dev->readAll();
1446  delete dev;
1447  }
1448  return arr;
1449 }
1450 
1451 TQIODevice* KZipFileEntry::device() const
1452 {
1453  //kdDebug(7040) << "KZipFileEntry::device creating iodevice limited to pos=" << position() << ", csize=" << compressedSize() << endl;
1454  // Limit the reading to the appropriate part of the underlying device (e.g. file)
1455  KLimitedIODevice* limitedDev = new KLimitedIODevice( archive()->device(), position(), compressedSize() );
1456  if ( encoding() == 0 || compressedSize() == 0 ) // no compression (or even no data)
1457  return limitedDev;
1458 
1459  if ( encoding() == 8 )
1460  {
1461  // On top of that, create a device that uncompresses the zlib data
1462  TQIODevice* filterDev = KFilterDev::device( limitedDev, "application/x-gzip" );
1463  if ( !filterDev )
1464  return 0L; // ouch
1465  static_cast<KFilterDev *>(filterDev)->setSkipHeaders(); // Just zlib, not gzip
1466  bool b = filterDev->open( IO_ReadOnly );
1467  Q_ASSERT( b );
1468  return filterDev;
1469  }
1470 
1471  kdError() << "This zip file contains files compressed with method "
1472  << encoding() <<", this method is currently not supported by KZip,"
1473  <<" please use a command-line tool to handle this file." << endl;
1474  return 0L;
1475 }
KArchiveDirectory
Represents a directory entry in a KArchive.
Definition: karchive.h:574
KArchiveDirectory::entry
KArchiveEntry * entry(TQString name)
Returns the entry with the given name.
Definition: karchive.cpp:547
KArchiveEntry
A base class for entries in an KArchive.
Definition: karchive.h:396
KArchiveEntry::isDirectory
virtual bool isDirectory() const
Checks whether the entry is a directory.
Definition: karchive.h:464
KArchive
KArchive is a base class for reading and writing archives.
Definition: karchive.h:43
KArchive::rootDir
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
Definition: karchive.cpp:368
KArchive::open
virtual bool open(int mode)
Opens the archive for reading or writing.
Definition: karchive.cpp:91
KArchive::findOrCreate
KArchiveDirectory * findOrCreate(const TQString &path)
Ensures that path exists, create otherwise.
Definition: karchive.cpp:383
KArchive::close
virtual void close()
Closes the archive.
Definition: karchive.cpp:108
KArchive::mode
int mode() const
Returns the mode in which the archive was opened.
Definition: karchive.h:90
KArchive::isOpened
bool isOpened() const
Checks whether the archive is open.
Definition: karchive.h:83
KArchive::writeData
bool writeData(const char *data, uint size)
Write data into the current file - to be called after calling prepareWriting.
Definition: karchive.cpp:353
KArchive::device
TQIODevice * device() const
The underlying device.
Definition: karchive.h:96
KArchive::writeSymLink
bool writeSymLink(const TQString &name, const TQString &target, const TQString &user, const TQString &group, mode_t perm, time_t atime, time_t mtime, time_t ctime)
Writes a symbolic link to the archive if the archive must be opened for writing.
Definition: karchive.cpp:327
KArchive::prepareWriting
virtual bool prepareWriting(const TQString &name, const TQString &user, const TQString &group, uint size)=0
Here's another way of writing a file into an archive: Call prepareWriting, then call writeData() as m...
KArchive::writeFile
virtual bool writeFile(const TQString &name, const TQString &user, const TQString &group, uint size, const char *data)
If an archive is opened for writing then you can add a new file using this function.
Definition: karchive.cpp:228
KFilterDev
A class for reading and writing compressed data onto a device (e.g.
Definition: kfilterdev.h:37
KFilterDev::open
virtual bool open(int mode)
Open for reading or writing.
Definition: kfilterdev.cpp:119
KFilterDev::device
static TQIODevice * device(TQIODevice *inDevice, const TQString &mimetype)
Creates an i/o device that is able to read from the TQIODevice inDevice, whether the data is compress...
Definition: kfilterdev.cpp:101
KLimitedIODevice
A readonly device that reads from an underlying device from a given point to another (e....
Definition: klimitediodevice.h:32
KZip
This class implements a tdeioslave to access zip files from KDE.
Definition: kzip.h:54
KZip::writeDir
virtual bool writeDir(const TQString &name, const TQString &user, const TQString &group)
If an archive is opened for writing then you can add new directories using this function.
Definition: kzip.cpp:1054
KZip::fileName
TQString fileName()
The name of the zip file, as passed to the constructor.
Definition: kzip.h:84
KZip::setCompression
void setCompression(Compression c)
Call this before writeFile or prepareWriting, to define whether the next files to be written should b...
Definition: kzip.cpp:1409
KZip::ExtraField
ExtraField
Describes the contents of the "extra field" for a given file in the Zip archive.
Definition: kzip.h:89
KZip::ModificationTime
@ ModificationTime
Modification time ("extended timestamp" header)
Definition: kzip.h:90
KZip::NoExtraField
@ NoExtraField
No extra field.
Definition: kzip.h:89
KZip::writeData
bool writeData(const char *data, uint size)
Write data to a file that has been created using prepareWriting().
Definition: kzip.cpp:1383
KZip::closeArchive
virtual bool closeArchive()
Closes the archive.
Definition: kzip.cpp:855
KZip::prepareWriting
virtual bool prepareWriting(const TQString &name, const TQString &user, const TQString &group, uint size)
Alternative method for writing: call prepareWriting(), then feed the data in small chunks using write...
Definition: kzip.cpp:1088
KZip::setExtraField
void setExtraField(ExtraField ef)
Call this before writeFile or prepareWriting, to define what the next file to be written should have ...
Definition: kzip.cpp:1419
KZip::writeFile
virtual bool writeFile(const TQString &name, const TQString &user, const TQString &group, uint size, const char *data)
If an archive is opened for writing then you can add a new file using this function.
Definition: kzip.cpp:1070
KZip::~KZip
virtual ~KZip()
If the zip file is still opened, then it will be closed automatically by the destructor.
Definition: kzip.cpp:354
KZip::openArchive
virtual bool openArchive(int mode)
Opens the archive for reading.
Definition: kzip.cpp:369
KZip::Compression
Compression
Describes the compression type for a given file in the Zip archive.
Definition: kzip.h:112
KZip::DeflateCompression
@ DeflateCompression
Deflate compression method.
Definition: kzip.h:113
KZip::NoCompression
@ NoCompression
Uncompressed.
Definition: kzip.h:112
KZip::compression
Compression compression() const
The current compression mode that will be used for new files.
Definition: kzip.cpp:1414
KZip::KZip
KZip(const TQString &filename)
Creates an instance that operates on the given filename.
Definition: kzip.cpp:335
KZip::doneWriting
virtual bool doneWriting(uint size)
Write data to a file that has been created using prepareWriting().
Definition: kzip.cpp:1279
KZip::extraField
ExtraField extraField() const
The current type of "extra field" that will be used for new files.
Definition: kzip.cpp:1424

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdeio/tdeio

Skip menu "tdeio/tdeio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdeio/tdeio by doxygen 1.9.1
This website is maintained by Timothy Pearson.