00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "zip.h"
00029 #include "zip_p.h"
00030 #include "zipentry_p.h"
00031
00032
00033 #include <time.h>
00034
00035 #include <QMap>
00036 #include <QString>
00037 #include <QStringList>
00038 #include <QDir>
00039 #include <QFile>
00040 #include <QDateTime>
00041 #include <QCoreApplication>
00042
00043
00044 #include <QtDebug>
00045
00047 #define ZIP_LOCAL_HEADER_SIZE 30
00049 #define ZIP_LOCAL_ENC_HEADER_SIZE 12
00051 #define ZIP_DD_SIZE_WS 16
00053 #define ZIP_CD_SIZE 46
00055 #define ZIP_EOCD_SIZE 22
00056
00057
00058 #define ZIP_LH_OFF_VERS 4
00059 #define ZIP_LH_OFF_GPFLAG 6
00060 #define ZIP_LH_OFF_CMET 8
00061 #define ZIP_LH_OFF_MODT 10
00062 #define ZIP_LH_OFF_MODD 12
00063 #define ZIP_LH_OFF_CRC 14
00064 #define ZIP_LH_OFF_CSIZE 18
00065 #define ZIP_LH_OFF_USIZE 22
00066 #define ZIP_LH_OFF_NAMELEN 26
00067 #define ZIP_LH_OFF_XLEN 28
00068
00069
00070 #define ZIP_DD_OFF_CRC32 4
00071 #define ZIP_DD_OFF_CSIZE 8
00072 #define ZIP_DD_OFF_USIZE 12
00073
00074
00075 #define ZIP_CD_OFF_MADEBY 4
00076 #define ZIP_CD_OFF_VERSION 6
00077 #define ZIP_CD_OFF_GPFLAG 8
00078 #define ZIP_CD_OFF_CMET 10
00079 #define ZIP_CD_OFF_MODT 12
00080 #define ZIP_CD_OFF_MODD 14
00081 #define ZIP_CD_OFF_CRC 16
00082 #define ZIP_CD_OFF_CSIZE 20
00083 #define ZIP_CD_OFF_USIZE 24
00084 #define ZIP_CD_OFF_NAMELEN 28
00085 #define ZIP_CD_OFF_XLEN 30
00086 #define ZIP_CD_OFF_COMMLEN 32
00087 #define ZIP_CD_OFF_DISKSTART 34
00088 #define ZIP_CD_OFF_IATTR 36
00089 #define ZIP_CD_OFF_EATTR 38
00090 #define ZIP_CD_OFF_LHOFF 42
00091
00092
00093 #define ZIP_EOCD_OFF_DISKNUM 4
00094 #define ZIP_EOCD_OFF_CDDISKNUM 6
00095 #define ZIP_EOCD_OFF_ENTRIES 8
00096 #define ZIP_EOCD_OFF_CDENTRIES 10
00097 #define ZIP_EOCD_OFF_CDSIZE 12
00098 #define ZIP_EOCD_OFF_CDOFF 16
00099 #define ZIP_EOCD_OFF_COMMLEN 20
00100
00102 #define ZIP_VERSION 0x14
00103
00105 #define ZIP_COMPRESSION_THRESHOLD 60
00106
00108 #define CRC32(c, b) crcTable[((int)c^b) & 0xff] ^ (c >> 8)
00109
00211
00212
00213
00214
00218 Zip::Zip()
00219 {
00220 d = new ZipPrivate;
00221 }
00222
00226 Zip::~Zip()
00227 {
00228 closeArchive();
00229 delete d;
00230 }
00231
00235 bool Zip::isOpen() const
00236 {
00237 return d->device != 0;
00238 }
00239
00246 void Zip::setPassword(const QString& pwd)
00247 {
00248 d->password = pwd;
00249 }
00250
00252 void Zip::clearPassword()
00253 {
00254 d->password.clear();
00255 }
00256
00258 QString Zip::password() const
00259 {
00260 return d->password;
00261 }
00262
00268 Zip::ErrorCode Zip::createArchive(const QString& filename, bool overwrite)
00269 {
00270 QFile* file = new QFile(filename);
00271
00272 if (file->exists() && !overwrite) {
00273 delete file;
00274 return Zip::FileExists;
00275 }
00276
00277 if (!file->open(QIODevice::WriteOnly)) {
00278 delete file;
00279 return Zip::OpenFailed;
00280 }
00281
00282 Zip::ErrorCode ec = createArchive(file);
00283 if (ec != Zip::Ok) {
00284 file->remove();
00285 }
00286
00287 return ec;
00288 }
00289
00294 Zip::ErrorCode Zip::createArchive(QIODevice* device)
00295 {
00296 if (device == 0)
00297 {
00298 qDebug() << "Invalid device.";
00299 return Zip::OpenFailed;
00300 }
00301
00302 return d->createArchive(device);
00303 }
00304
00308 QString Zip::archiveComment() const
00309 {
00310 return d->comment;
00311 }
00312
00317 void Zip::setArchiveComment(const QString& comment)
00318 {
00319 if (d->device != 0)
00320 d->comment = comment;
00321 }
00322
00333 Zip::ErrorCode Zip::addDirectory(const QString& path, CompressionOptions options, CompressionLevel level)
00334 {
00335 return addDirectory(path, QString(), options, level);
00336 }
00337
00342 Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionLevel level)
00343 {
00344 return addDirectory(path, root, Zip::RelativePaths, level);
00345 }
00346
00351 Zip::ErrorCode Zip::addDirectoryContents(const QString& path, CompressionLevel level)
00352 {
00353 return addDirectory(path, QString(), IgnorePaths, level);
00354 }
00355
00360 Zip::ErrorCode Zip::addDirectoryContents(const QString& path, const QString& root, CompressionLevel level)
00361 {
00362 return addDirectory(path, root, IgnorePaths, level);
00363 }
00364
00376 Zip::ErrorCode Zip::addDirectory(const QString& path, const QString& root, CompressionOptions options, CompressionLevel level)
00377 {
00378
00379
00380
00381 if (d->device == 0)
00382 return Zip::NoOpenArchive;
00383
00384 QDir dir(path);
00385 if (!dir.exists())
00386 return Zip::FileNotFound;
00387
00388
00389 QString actualRoot = root.trimmed();
00390
00391
00392 if (actualRoot != "/")
00393 {
00394 while (actualRoot.endsWith("/") || actualRoot.endsWith("\\"))
00395 actualRoot.truncate(actualRoot.length() - 1);
00396 }
00397
00398
00399 QFileInfo current(QDir::cleanPath(path));
00400
00401 if (!actualRoot.isEmpty() && actualRoot != "/")
00402 actualRoot.append("/");
00403
00404
00405
00406 if (options.testFlag(AbsolutePaths) && !options.testFlag(IgnorePaths))
00407 {
00408 QString absolutePath = d->extractRoot(path);
00409 if (!absolutePath.isEmpty() && absolutePath != "/")
00410 absolutePath.append("/");
00411 actualRoot.append(absolutePath);
00412 }
00413
00414 if (!options.testFlag(IgnorePaths))
00415 {
00416 actualRoot = actualRoot.append(QDir(current.absoluteFilePath()).dirName());
00417 actualRoot.append("/");
00418 }
00419
00420
00421
00422
00423 QFileInfoList list = dir.entryInfoList(
00424 QDir::Files |
00425 QDir::Dirs |
00426 QDir::NoDotAndDotDot |
00427 QDir::NoSymLinks);
00428
00429 ErrorCode ec = Zip::Ok;
00430 bool filesAdded = false;
00431
00432 CompressionOptions recursionOptions;
00433 if (options.testFlag(IgnorePaths))
00434 recursionOptions |= IgnorePaths;
00435 else recursionOptions |= RelativePaths;
00436
00437 for (int i = 0; i < list.size() && ec == Zip::Ok; ++i)
00438 {
00439 QFileInfo info = list.at(i);
00440
00441 if (info.isDir())
00442 {
00443
00444 ec = addDirectory(info.absoluteFilePath(), actualRoot, recursionOptions, level);
00445 }
00446 else
00447 {
00448 ec = d->createEntry(info, actualRoot, level);
00449 filesAdded = true;
00450 }
00451 }
00452
00453
00454
00455
00456 if (!filesAdded && !options.testFlag(IgnorePaths))
00457 ec = d->createEntry(current, actualRoot, level);
00458
00459 return ec;
00460 }
00461
00465 Zip::ErrorCode Zip::closeArchive()
00466 {
00467 Zip::ErrorCode ec = d->closeArchive();
00468 d->reset();
00469 return ec;
00470 }
00471
00475 QString Zip::formatError(Zip::ErrorCode c) const
00476 {
00477 switch (c)
00478 {
00479 case Ok: return QCoreApplication::translate("Zip", "ZIP operation completed successfully."); break;
00480 case ZlibInit: return QCoreApplication::translate("Zip", "Failed to initialize or load zlib library."); break;
00481 case ZlibError: return QCoreApplication::translate("Zip", "zlib library error."); break;
00482 case OpenFailed: return QCoreApplication::translate("Zip", "Unable to create or open file."); break;
00483 case NoOpenArchive: return QCoreApplication::translate("Zip", "No archive has been created yet."); break;
00484 case FileNotFound: return QCoreApplication::translate("Zip", "File or directory does not exist."); break;
00485 case ReadFailed: return QCoreApplication::translate("Zip", "File read error."); break;
00486 case WriteFailed: return QCoreApplication::translate("Zip", "File write error."); break;
00487 case SeekFailed: return QCoreApplication::translate("Zip", "File seek error."); break;
00488 default: ;
00489 }
00490
00491 return QCoreApplication::translate("Zip", "Unknown error.");
00492 }
00493
00494
00495
00496
00497
00498
00500 ZipPrivate::ZipPrivate()
00501 {
00502 headers = 0;
00503 device = 0;
00504
00505
00506 uBuffer = (unsigned char*) buffer1;
00507 crcTable = (quint32*) get_crc_table();
00508 }
00509
00511 ZipPrivate::~ZipPrivate()
00512 {
00513 closeArchive();
00514 }
00515
00517 Zip::ErrorCode ZipPrivate::createArchive(QIODevice* dev)
00518 {
00519 Q_ASSERT(dev != 0);
00520
00521 if (device != 0)
00522 closeArchive();
00523
00524 device = dev;
00525
00526 if (!device->isOpen())
00527 {
00528 if (!device->open(QIODevice::ReadOnly)) {
00529 delete device;
00530 device = 0;
00531 qDebug() << "Unable to open device for writing.";
00532 return Zip::OpenFailed;
00533 }
00534 }
00535
00536 headers = new QMap<QString,ZipEntryP*>;
00537 return Zip::Ok;
00538 }
00539
00541 Zip::ErrorCode ZipPrivate::createEntry(const QFileInfo& file, const QString& root, Zip::CompressionLevel level)
00542 {
00544
00545
00546
00547
00548
00549 bool isPNGFile = false;
00550 bool dirOnly = file.isDir();
00551
00552 QString entryName = root;
00553
00554
00555 if (dirOnly)
00556 level = Zip::Store;
00557 else
00558 {
00559 entryName.append(file.fileName());
00560
00561 QString ext = file.completeSuffix().toLower();
00562 isPNGFile = ext == "png";
00563
00564 if (file.size() < ZIP_COMPRESSION_THRESHOLD)
00565 level = Zip::Store;
00566 else
00567 switch (level)
00568 {
00569 case Zip::AutoCPU:
00570 level = Zip::Deflate5;
00571 break;
00572 case Zip::AutoMIME:
00573 level = detectCompressionByMime(ext);
00574 break;
00575 case Zip::AutoFull:
00576 level = detectCompressionByMime(ext);
00577 break;
00578 default:
00579 ;
00580 }
00581 }
00582
00583
00584
00585
00586
00587
00588 ZipEntryP* h = new ZipEntryP;
00589
00590 h->compMethod = (level == Zip::Store) ? 0 : 0x0008;
00591
00592
00593
00594 bool encrypt = !dirOnly && !password.isEmpty();
00595 if (encrypt)
00596 h->gpFlag[0] |= 9;
00597
00598 QDateTime dt = file.lastModified();
00599 QDate d = dt.date();
00600 h->modDate[1] = ((d.year() - 1980) << 1) & 254;
00601 h->modDate[1] |= ((d.month() >> 3) & 1);
00602 h->modDate[0] = ((d.month() & 7) << 5) & 224;
00603 h->modDate[0] |= d.day();
00604
00605 QTime t = dt.time();
00606 h->modTime[1] = (t.hour() << 3) & 248;
00607 h->modTime[1] |= ((t.minute() >> 3) & 7);
00608 h->modTime[0] = ((t.minute() & 7) << 5) & 224;
00609 h->modTime[0] |= t.second() / 2;
00610
00611 h->szUncomp = dirOnly ? 0 : file.size();
00612
00613
00614
00615
00616 buffer1[0] = 'P'; buffer1[1] = 'K';
00617 buffer1[2] = 0x3; buffer1[3] = 0x4;
00618
00619
00620 buffer1[ZIP_LH_OFF_VERS] = ZIP_VERSION;
00621 buffer1[ZIP_LH_OFF_VERS + 1] = 0;
00622
00623
00624 buffer1[ZIP_LH_OFF_GPFLAG] = h->gpFlag[0];
00625 buffer1[ZIP_LH_OFF_GPFLAG + 1] = h->gpFlag[1];
00626
00627
00628 buffer1[ZIP_LH_OFF_CMET] = h->compMethod & 0xFF;
00629 buffer1[ZIP_LH_OFF_CMET + 1] = (h->compMethod>>8) & 0xFF;
00630
00631
00632 buffer1[ZIP_LH_OFF_MODT] = h->modTime[0];
00633 buffer1[ZIP_LH_OFF_MODT + 1] = h->modTime[1];
00634
00635
00636 buffer1[ZIP_LH_OFF_MODD] = h->modDate[0];
00637 buffer1[ZIP_LH_OFF_MODD + 1] = h->modDate[1];
00638
00639
00640
00641
00642 buffer1[ZIP_LH_OFF_CSIZE] =
00643 buffer1[ZIP_LH_OFF_CSIZE + 1] =
00644 buffer1[ZIP_LH_OFF_CSIZE + 2] =
00645 buffer1[ZIP_LH_OFF_CSIZE + 3] = 0;
00646
00647 h->szComp = encrypt ? ZIP_LOCAL_ENC_HEADER_SIZE : 0;
00648
00649
00650 setULong(h->szUncomp, buffer1, ZIP_LH_OFF_USIZE);
00651
00652
00653 QByteArray entryNameBytes = entryName.toAscii();
00654 int sz = entryNameBytes.size();
00655
00656 buffer1[ZIP_LH_OFF_NAMELEN] = sz & 0xFF;
00657 buffer1[ZIP_LH_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF;
00658
00659
00660 buffer1[ZIP_LH_OFF_XLEN] = buffer1[ZIP_LH_OFF_XLEN + 1] = 0;
00661
00662
00663 h->lhOffset = device->pos();
00664 quint32 crcOffset = h->lhOffset + ZIP_LH_OFF_CRC;
00665
00666 if (device->write(buffer1, ZIP_LOCAL_HEADER_SIZE) != ZIP_LOCAL_HEADER_SIZE)
00667 {
00668 delete h;
00669 return Zip::WriteFailed;
00670 }
00671
00672
00673 if (device->write(entryNameBytes) != sz)
00674 {
00675 delete h;
00676 return Zip::WriteFailed;
00677 }
00678
00679
00680 quint32 keys[3] = { 0, 0, 0 };
00681
00682 if (encrypt)
00683 {
00684
00685
00686
00687
00688 srand(time(NULL) ^ 3141592654UL);
00689 int randByte;
00690
00691 initKeys(keys);
00692 for (int i=0; i<10; ++i)
00693 {
00694 randByte = (rand() >> 7) & 0xff;
00695 buffer1[i] = decryptByte(keys[2]) ^ randByte;
00696 updateKeys(keys, randByte);
00697 }
00698
00699
00700 initKeys(keys);
00701 for (int i=0; i<10; ++i)
00702 {
00703 randByte = decryptByte(keys[2]);
00704 updateKeys(keys, buffer1[i]);
00705 buffer1[i] ^= randByte;
00706 }
00707
00708
00709
00710 randByte = decryptByte(keys[2]);
00711 updateKeys(keys, h->modTime[0]);
00712 buffer1[10] ^= randByte;
00713
00714 randByte = decryptByte(keys[2]);
00715 updateKeys(keys, h->modTime[1]);
00716 buffer1[11] ^= randByte;
00717
00718
00719 if (device->write(buffer1, ZIP_LOCAL_ENC_HEADER_SIZE) != ZIP_LOCAL_ENC_HEADER_SIZE)
00720 {
00721 delete h;
00722 return Zip::WriteFailed;
00723 }
00724 }
00725
00726 qint64 written = 0;
00727 quint32 crc = crc32(0L, Z_NULL, 0);
00728
00729 if (!dirOnly)
00730 {
00731 QFile actualFile(file.absoluteFilePath());
00732 if (!actualFile.open(QIODevice::ReadOnly))
00733 {
00734 qDebug() << QString("An error occurred while opening %1").arg(file.absoluteFilePath());
00735 return Zip::OpenFailed;
00736 }
00737
00738
00739 qint64 read = 0;
00740 qint64 totRead = 0;
00741 qint64 toRead = actualFile.size();
00742
00743 if (level == Zip::Store)
00744 {
00745 while ( (read = actualFile.read(buffer1, ZIP_READ_BUFFER)) > 0 )
00746 {
00747 crc = crc32(crc, uBuffer, read);
00748
00749 if (password != 0)
00750 encryptBytes(keys, buffer1, read);
00751
00752 if ( (written = device->write(buffer1, read)) != read )
00753 {
00754 actualFile.close();
00755 delete h;
00756 return Zip::WriteFailed;
00757 }
00758 }
00759 }
00760 else
00761 {
00762 z_stream zstr;
00763
00764
00765 zstr.zalloc = Z_NULL;
00766 zstr.zfree = Z_NULL;
00767 zstr.opaque = Z_NULL;
00768
00769 int zret;
00770
00771
00772 if ((zret = deflateInit2_(
00773 &zstr,
00774 (int)level,
00775 Z_DEFLATED,
00776 -MAX_WBITS,
00777 8,
00778 isPNGFile ? Z_RLE : Z_DEFAULT_STRATEGY,
00779 ZLIB_VERSION,
00780 sizeof(z_stream)
00781 )) != Z_OK )
00782 {
00783 actualFile.close();
00784 qDebug() << "Could not initialize zlib for compression";
00785 delete h;
00786 return Zip::ZlibError;
00787 }
00788
00789 qint64 compressed;
00790
00791 int flush = Z_NO_FLUSH;
00792
00793 do
00794 {
00795 read = actualFile.read(buffer1, ZIP_READ_BUFFER);
00796 totRead += read;
00797
00798 if (read == 0)
00799 break;
00800 if (read < 0)
00801 {
00802 actualFile.close();
00803 deflateEnd(&zstr);
00804 qDebug() << QString("Error while reading %1").arg(file.absoluteFilePath());
00805 delete h;
00806 return Zip::ReadFailed;
00807 }
00808
00809 crc = crc32(crc, uBuffer, read);
00810
00811 zstr.next_in = (Bytef*) buffer1;
00812 zstr.avail_in = (uInt)read;
00813
00814
00815
00816 flush = (totRead == toRead) ? Z_FINISH : Z_NO_FLUSH;
00817
00818
00819
00820 do
00821 {
00822 zstr.next_out = (Bytef*) buffer2;
00823 zstr.avail_out = ZIP_READ_BUFFER;
00824
00825 zret = deflate(&zstr, flush);
00826
00827 Q_ASSERT(zret != Z_STREAM_ERROR);
00828
00829
00830 compressed = ZIP_READ_BUFFER - zstr.avail_out;
00831
00832 if (password != 0)
00833 encryptBytes(keys, buffer2, compressed);
00834
00835 if (device->write(buffer2, compressed) != compressed)
00836 {
00837 deflateEnd(&zstr);
00838 actualFile.close();
00839 qDebug() << QString("Error while writing %1").arg(file.absoluteFilePath());
00840 delete h;
00841 return Zip::WriteFailed;
00842 }
00843
00844 written += compressed;
00845
00846 } while (zstr.avail_out == 0);
00847
00848
00849 Q_ASSERT(zstr.avail_in == 0);
00850
00851 } while (flush != Z_FINISH);
00852
00853
00854 Q_ASSERT(zret == Z_STREAM_END);
00855
00856 deflateEnd(&zstr);
00857
00858 }
00859
00860 actualFile.close();
00861 }
00862
00863
00864 quint32 current = device->pos();
00865
00866
00867 if (!device->seek(crcOffset))
00868 {
00869 delete h;
00870 return Zip::SeekFailed;
00871 }
00872
00873 h->crc = dirOnly ? 0 : crc;
00874 h->szComp += written;
00875
00876 setULong(h->crc, buffer1, 0);
00877 setULong(h->szComp, buffer1, 4);
00878 if ( device->write(buffer1, 8) != 8)
00879 {
00880 delete h;
00881 return Zip::WriteFailed;
00882 }
00883
00884
00885 if (!device->seek(current))
00886 {
00887 delete h;
00888 return Zip::SeekFailed;
00889 }
00890
00891 if ((h->gpFlag[0] & 8) == 8)
00892 {
00893
00894
00895
00896 buffer1[0] = 'P';
00897 buffer1[1] = 'K';
00898 buffer1[2] = 0x07;
00899 buffer1[3] = 0x08;
00900
00901
00902 setULong(h->crc, buffer1, ZIP_DD_OFF_CRC32);
00903
00904
00905 setULong(h->szComp, buffer1, ZIP_DD_OFF_CSIZE);
00906
00907
00908 setULong(h->szUncomp, buffer1, ZIP_DD_OFF_USIZE);
00909
00910 if (device->write(buffer1, ZIP_DD_SIZE_WS) != ZIP_DD_SIZE_WS)
00911 {
00912 delete h;
00913 return Zip::WriteFailed;
00914 }
00915 }
00916
00917 headers->insert(entryName, h);
00918 return Zip::Ok;
00919 }
00920
00922 int ZipPrivate::decryptByte(quint32 key2) const
00923 {
00924 quint16 temp = ((quint16)(key2) & 0xffff) | 2;
00925 return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
00926 }
00927
00929 void ZipPrivate::setULong(quint32 v, char* buffer, unsigned int offset)
00930 {
00931 buffer[offset+3] = ((v >> 24) & 0xFF);
00932 buffer[offset+2] = ((v >> 16) & 0xFF);
00933 buffer[offset+1] = ((v >> 8) & 0xFF);
00934 buffer[offset] = (v & 0xFF);
00935 }
00936
00938 void ZipPrivate::initKeys(quint32* keys) const
00939 {
00940
00941
00942 keys[0] = 305419896L;
00943 keys[1] = 591751049L;
00944 keys[2] = 878082192L;
00945
00946 QByteArray pwdBytes = password.toAscii();
00947 int sz = pwdBytes.size();
00948 const char* ascii = pwdBytes.data();
00949
00950 for (int i=0; i<sz; ++i)
00951 updateKeys(keys, (int)ascii[i]);
00952 }
00953
00955 void ZipPrivate::updateKeys(quint32* keys, int c) const
00956 {
00957 keys[0] = CRC32(keys[0], c);
00958 keys[1] += keys[0] & 0xff;
00959 keys[1] = keys[1] * 134775813L + 1;
00960 keys[2] = CRC32(keys[2], ((int)keys[1]) >> 24);
00961 }
00962
00964 void ZipPrivate::encryptBytes(quint32* keys, char* buffer, qint64 read)
00965 {
00966 char t;
00967
00968 for (int i=0; i<(int)read; ++i)
00969 {
00970 t = buffer[i];
00971 buffer[i] ^= decryptByte(keys[2]);
00972 updateKeys(keys, t);
00973 }
00974 }
00975
00977 Zip::CompressionLevel ZipPrivate::detectCompressionByMime(const QString& ext)
00978 {
00979
00980 if ((ext == "png") ||
00981 (ext == "jpg") ||
00982 (ext == "jpeg") ||
00983 (ext == "mp3") ||
00984 (ext == "ogg") ||
00985 (ext == "ogm") ||
00986 (ext == "avi") ||
00987 (ext == "mov") ||
00988 (ext == "rm") ||
00989 (ext == "ra") ||
00990 (ext == "zip") ||
00991 (ext == "rar") ||
00992 (ext == "bz2") ||
00993 (ext == "gz") ||
00994 (ext == "7z") ||
00995 (ext == "z") ||
00996 (ext == "jar")
00997 ) return Zip::Store;
00998
00999
01000 if ((ext == "exe") ||
01001 (ext == "bin") ||
01002 (ext == "rpm") ||
01003 (ext == "deb")
01004 ) return Zip::Deflate2;
01005
01006 return Zip::Deflate9;
01007 }
01008
01012 Zip::ErrorCode ZipPrivate::closeArchive()
01013 {
01014
01015
01016
01017 if (device == 0)
01018 return Zip::Ok;
01019
01020 if (headers == 0)
01021 return Zip::Ok;
01022
01023 const ZipEntryP* h;
01024
01025 unsigned int sz;
01026 quint32 szCentralDir = 0;
01027 quint32 offCentralDir = device->pos();
01028
01029 for (QMap<QString,ZipEntryP*>::ConstIterator itr = headers->constBegin(); itr != headers->constEnd(); ++itr)
01030 {
01031 h = itr.value();
01032
01033
01034 buffer1[0] = 'P';
01035 buffer1[1] = 'K';
01036 buffer1[2] = 0x01;
01037 buffer1[3] = 0x02;
01038
01039
01040 buffer1[ZIP_CD_OFF_MADEBY] = buffer1[ZIP_CD_OFF_MADEBY + 1] = 0;
01041
01042
01043 buffer1[ZIP_CD_OFF_VERSION] = ZIP_VERSION;
01044 buffer1[ZIP_CD_OFF_VERSION + 1] = 0;
01045
01046
01047 buffer1[ZIP_CD_OFF_GPFLAG] = h->gpFlag[0];
01048 buffer1[ZIP_CD_OFF_GPFLAG + 1] = h->gpFlag[1];
01049
01050
01051 buffer1[ZIP_CD_OFF_CMET] = h->compMethod & 0xFF;
01052 buffer1[ZIP_CD_OFF_CMET + 1] = (h->compMethod >> 8) & 0xFF;
01053
01054
01055 buffer1[ZIP_CD_OFF_MODT] = h->modTime[0];
01056 buffer1[ZIP_CD_OFF_MODT + 1] = h->modTime[1];
01057
01058
01059 buffer1[ZIP_CD_OFF_MODD] = h->modDate[0];
01060 buffer1[ZIP_CD_OFF_MODD + 1] = h->modDate[1];
01061
01062
01063 setULong(h->crc, buffer1, ZIP_CD_OFF_CRC);
01064
01065
01066 setULong(h->szComp, buffer1, ZIP_CD_OFF_CSIZE);
01067
01068
01069 setULong(h->szUncomp, buffer1, ZIP_CD_OFF_USIZE);
01070
01071
01072 QByteArray fileNameBytes = itr.key().toAscii();
01073 sz = fileNameBytes.size();
01074 buffer1[ZIP_CD_OFF_NAMELEN] = sz & 0xFF;
01075 buffer1[ZIP_CD_OFF_NAMELEN + 1] = (sz >> 8) & 0xFF;
01076
01077
01078 buffer1[ZIP_CD_OFF_XLEN] = buffer1[ZIP_CD_OFF_XLEN + 1] = 0;
01079
01080
01081 buffer1[ZIP_CD_OFF_COMMLEN] = buffer1[ZIP_CD_OFF_COMMLEN + 1] = 0;
01082
01083
01084 buffer1[ZIP_CD_OFF_DISKSTART] = buffer1[ZIP_CD_OFF_DISKSTART + 1] = 0;
01085
01086
01087 buffer1[ZIP_CD_OFF_IATTR] = buffer1[ZIP_CD_OFF_IATTR + 1] = 0;
01088
01089
01090 buffer1[ZIP_CD_OFF_EATTR] =
01091 buffer1[ZIP_CD_OFF_EATTR + 1] =
01092 buffer1[ZIP_CD_OFF_EATTR + 2] =
01093 buffer1[ZIP_CD_OFF_EATTR + 3] = 0;
01094
01095
01096 setULong(h->lhOffset, buffer1, ZIP_CD_OFF_LHOFF);
01097
01098 if (device->write(buffer1, ZIP_CD_SIZE) != ZIP_CD_SIZE)
01099 {
01101
01102
01103
01104
01105 return Zip::WriteFailed;
01106 }
01107
01108
01109 if ((unsigned int)device->write(fileNameBytes) != sz)
01110 {
01112
01113
01114
01115
01116 return Zip::WriteFailed;
01117 }
01118
01119 szCentralDir += (ZIP_CD_SIZE + sz);
01120
01121 }
01122
01123
01124
01125
01126
01127 buffer1[0] = 'P';
01128 buffer1[1] = 'K';
01129 buffer1[2] = 0x05;
01130 buffer1[3] = 0x06;
01131
01132
01133 buffer1[ZIP_EOCD_OFF_DISKNUM] = buffer1[ZIP_EOCD_OFF_DISKNUM + 1] = 0;
01134
01135
01136 buffer1[ZIP_EOCD_OFF_CDDISKNUM] = buffer1[ZIP_EOCD_OFF_CDDISKNUM + 1] = 0;
01137
01138
01139 sz = headers->count();
01140 buffer1[ZIP_EOCD_OFF_ENTRIES] = sz & 0xFF;
01141 buffer1[ZIP_EOCD_OFF_ENTRIES + 1] = (sz >> 8) & 0xFF;
01142
01143
01144 buffer1[ZIP_EOCD_OFF_CDENTRIES] = buffer1[ZIP_EOCD_OFF_ENTRIES];
01145 buffer1[ZIP_EOCD_OFF_CDENTRIES + 1] = buffer1[ZIP_EOCD_OFF_ENTRIES + 1];
01146
01147
01148 setULong(szCentralDir, buffer1, ZIP_EOCD_OFF_CDSIZE);
01149
01150
01151 setULong(offCentralDir, buffer1, ZIP_EOCD_OFF_CDOFF);
01152
01153
01154 QByteArray commentBytes = comment.toAscii();
01155 quint16 commentLength = commentBytes.size();
01156
01157 if (commentLength == 0)
01158 {
01159 buffer1[ZIP_EOCD_OFF_COMMLEN] = buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = 0;
01160 }
01161 else
01162 {
01163 buffer1[ZIP_EOCD_OFF_COMMLEN] = commentLength & 0xFF;
01164 buffer1[ZIP_EOCD_OFF_COMMLEN + 1] = (commentLength >> 8) & 0xFF;
01165 }
01166
01167 if (device->write(buffer1, ZIP_EOCD_SIZE) != ZIP_EOCD_SIZE)
01168 {
01170
01171
01172
01173
01174 return Zip::WriteFailed;
01175 }
01176
01177 if (commentLength != 0)
01178 {
01179 if ((unsigned int)device->write(commentBytes) != commentLength)
01180 {
01182
01183
01184
01185
01186 return Zip::WriteFailed;
01187 }
01188 }
01189
01190 return Zip::Ok;
01191 }
01192
01194 void ZipPrivate::reset()
01195 {
01196 comment.clear();
01197
01198 if (headers != 0)
01199 {
01200 qDeleteAll(*headers);
01201 delete headers;
01202 headers = 0;
01203 }
01204
01205 delete device; device = 0;
01206 }
01207
01209 QString ZipPrivate::extractRoot(const QString& p)
01210 {
01211 QDir d(QDir::cleanPath(p));
01212 if (!d.exists())
01213 return QString();
01214
01215 if (!d.cdUp())
01216 return QString();
01217
01218 return d.absolutePath();
01219 }