9#include "loggingcategory.h"
16#include <qplatformdefs.h>
18#include "kcompressiondevice.h"
19#include "klimitediodevice_p.h"
20#include <kfilterbase.h>
28#define QT_STAT_LNK 0120000
35#define BUFFER_SIZE 8 * 1024
37static const unsigned char k7zip_signature[6] = {
'7',
'z', 0xBC, 0xAF, 0x27, 0x1C};
41static QChar GetUi16(
const char *p)
43 return QChar(
static_cast<unsigned char>(p[0])
44 | (
static_cast<unsigned char>(p[1]) << 8));
47static quint32 GetUi32(
const char *p)
49 return (
static_cast<unsigned char>(p[0])
50 | (
static_cast<unsigned char>(p[1]) << 8)
51 | (
static_cast<unsigned char>(p[2]) << 16)
52 | (
static_cast<unsigned char>(p[3]) << 24));
55static quint64 GetUi64(
const char *p)
58 | (
static_cast<quint64
>(GetUi32(p + 4)) << 32));
61static quint32 lzma2_dic_size_from_prop(
int p)
63 return ((
static_cast<quint32
>(2) | (p & 1)) << ((p / 2) + 11));
68#define FILE_ATTRIBUTE_READONLY 1
69#define FILE_ATTRIBUTE_HIDDEN 2
70#define FILE_ATTRIBUTE_SYSTEM 4
71#define FILE_ATTRIBUTE_DIRECTORY 16
72#define FILE_ATTRIBUTE_ARCHIVE 32
73#define FILE_ATTRIBUTE_DEVICE 64
74#define FILE_ATTRIBUTE_NORMAL 128
75#define FILE_ATTRIBUTE_TEMPORARY 256
76#define FILE_ATTRIBUTE_SPARSE_FILE 512
77#define FILE_ATTRIBUTE_REPARSE_POINT 1024
78#define FILE_ATTRIBUTE_COMPRESSED 2048
79#define FILE_ATTRIBUTE_OFFLINE 0x1000
80#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
81#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000
90 kAdditionalStreamsInfo,
132static const quint64 k_LZMA2 = 0x21;
135static const quint64 k_LZMA = 0x030101;
136static const quint64 k_BCJ = 0x03030103;
137static const quint64 k_BCJ2 = 0x0303011B;
145static const quint64 k_PPMD = 0x030401;
156static const quint64 k_BZip2 = 0x040202;
167static const quint64 k_AES = 0x06F10701;
175 K7ZipFileEntry(K7Zip *zip,
178 const QDateTime &
date,
180 const QString &
group,
181 const QString &symlink,
184 const QByteArray &data);
186 ~K7ZipFileEntry()
override;
192 QByteArray data()
const override;
204 QIODevice *createDevice()
const override;
207 const QByteArray m_data;
211K7ZipFileEntry::K7ZipFileEntry(
K7Zip *zip,
225 m_buffer->setData(m_data);
229K7ZipFileEntry::~K7ZipFileEntry()
239QIODevice *K7ZipFileEntry::createDevice()
const
241 return new KLimitedIODevice(m_buffer,
position(),
size());
251 , attribDefined(false)
281 bool isSimpleCoder()
const
283 return (numInStreams == 1) && (numOutStreams == 1);
288 QList<unsigned char> properties;
293 : unpackCRCDefined(false)
300 qDeleteAll(folderInfos);
303 Q_DISABLE_COPY(Folder)
305 quint64 getUnpackSize()
const
307 if (unpackSizes.isEmpty()) {
310 for (
int i = unpackSizes.size() - 1; i >= 0; i--) {
311 if (findBindPairForOutStream(i) < 0) {
312 return unpackSizes.at(i);
318 int getNumOutStreams()
const
321 for (
int i = 0; i < folderInfos.size(); i++) {
322 result += folderInfos.at(i)->numOutStreams;
327 quint32 getCoderInStreamIndex(quint32 coderIndex)
const
329 quint32 streamIndex = 0;
330 for (quint32 i = 0; i < coderIndex; i++) {
331 streamIndex += folderInfos.at(i)->numInStreams;
336 quint32 getCoderOutStreamIndex(quint32 coderIndex)
const
338 quint32 streamIndex = 0;
339 for (quint32 i = 0; i < coderIndex; i++) {
340 streamIndex += folderInfos.at(i)->numOutStreams;
345 int findBindPairForInStream(
size_t inStreamIndex)
const
347 for (
int i = 0; i < inIndexes.size(); i++) {
348 if (inIndexes[i] == inStreamIndex) {
355 int findBindPairForOutStream(
size_t outStreamIndex)
const
357 for (
int i = 0; i < outIndexes.size(); i++) {
358 if (outIndexes[i] == outStreamIndex) {
365 int findPackStreamArrayIndex(
size_t inStreamIndex)
const
367 for (
int i = 0; i < packedStreams.size(); i++) {
368 if (packedStreams[i] == inStreamIndex) {
375 void findInStream(quint32 streamIndex, quint32 &coderIndex, quint32 &coderStreamIndex)
const
377 for (coderIndex = 0; coderIndex < (quint32)folderInfos.size(); coderIndex++) {
378 quint32 curSize = folderInfos[coderIndex]->numInStreams;
379 if (streamIndex < curSize) {
380 coderStreamIndex = streamIndex;
383 streamIndex -= curSize;
387 void findOutStream(quint32 streamIndex, quint32 &coderIndex, quint32 &coderStreamIndex)
const
389 for (coderIndex = 0; coderIndex < (quint32)folderInfos.size(); coderIndex++) {
390 quint32 curSize = folderInfos[coderIndex]->numOutStreams;
391 if (streamIndex < curSize) {
392 coderStreamIndex = streamIndex;
395 streamIndex -= curSize;
399 bool isEncrypted()
const
401 for (
int i = folderInfos.size() - 1; i >= 0; i--) {
402 if (folderInfos.at(i)->methodID == k_AES) {
411 bool unpackCRCDefined;
413 QList<FolderInfo *> folderInfos;
414 QList<quint64> inIndexes;
415 QList<quint64> outIndexes;
416 QList<quint64> packedStreams;
417 QList<quint64> unpackSizes;
420class Q_DECL_HIDDEN
K7Zip::K7ZipPrivate
423 K7ZipPrivate(K7Zip *parent)
432 , m_currentFile(nullptr)
439 qDeleteAll(fileInfos);
444 QList<bool> packCRCsDefined;
445 QList<quint32> packCRCs;
446 QList<quint64> numUnpackStreamsInFolders;
448 QList<Folder *> folders;
449 QList<FileInfo *> fileInfos;
451 QList<bool> cTimesDefined;
452 QList<quint64> cTimes;
453 QList<bool> aTimesDefined;
454 QList<quint64> aTimes;
455 QList<bool> mTimesDefined;
456 QList<quint64> mTimes;
457 QList<bool> startPositionsDefined;
458 QList<quint64> startPositions;
459 QList<int> fileInfoPopIDs;
462 quint64 numPackStreams;
463 QList<quint64> packSizes;
464 QList<quint64> unpackSizes;
465 QList<bool> digestsDefined;
466 QList<quint32> digests;
479 K7ZipFileEntry *m_currentFile;
480 QList<KArchiveEntry *> m_entryList;
484 packCRCsDefined.
clear();
486 numUnpackStreamsInFolders.
clear();
489 qDeleteAll(fileInfos);
491 cTimesDefined.
clear();
493 aTimesDefined.
clear();
495 mTimesDefined.
clear();
497 startPositionsDefined.
clear();
498 startPositions.
clear();
499 fileInfoPopIDs.
clear();
502 digestsDefined.
clear();
515 quint32 readUInt32();
516 quint64 readUInt64();
517 quint64 readNumber();
518 QString readString();
519 void readHashDigests(
int numItems, QList<bool> &digestsDefined, QList<quint32> &digests);
520 void readBoolVector(
int numItems, QList<bool> &v);
521 void readBoolVector2(
int numItems, QList<bool> &v);
522 void skipData(
int size);
523 bool findAttribute(
int attribute);
524 bool readUInt64DefVector(
int numFiles, QList<quint64> &values, QList<bool> &defined);
527 bool readMainStreamsInfo();
529 bool readUnpackInfo();
530 bool readSubStreamsInfo();
531 QByteArray readAndDecodePackedStreams(
bool readMainStreamInfo =
true);
534 void createItemsFromEntities(
const KArchiveDirectory *,
const QString &, QByteArray &);
535 void writeByte(
unsigned char b);
536 void writeNumber(quint64 value);
537 void writeBoolVector(
const QList<bool> &boolVector);
538 void writeUInt32(quint32 value);
539 void writeUInt64(quint64 value);
540 void writeHashDigests(
const QList<bool> &digestsDefined,
const QList<quint32> &digests);
541 void writeAlignedBoolHeader(
const QList<bool> &v,
int numDefined,
int type,
unsigned itemSize);
542 void writeUInt64DefVector(
const QList<quint64> &v,
const QList<bool> &defined,
int type);
543 void writeFolder(
const Folder *folder);
544 void writePackInfo(quint64 dataOffset, QList<quint64> &packedSizes, QList<bool> &packedCRCsDefined, QList<quint32> &packedCRCs);
545 void writeUnpackInfo(
const QList<Folder *> &folderItems);
546 void writeSubStreamsInfo(
const QList<quint64> &unpackSizes,
const QList<bool> &digestsDefined,
const QList<quint32> &digests);
547 void writeHeader(quint64 &headerOffset);
548 void writeSignature();
549 void writeStartHeader(
const quint64 nextHeaderSize,
const quint32 nextHeaderCRC,
const quint64 nextHeaderOffset);
550 QByteArray encodeStream(QList<quint64> &packSizes, QList<Folder *> &folds);
555 , d(new K7ZipPrivate(this))
561 , d(new K7ZipPrivate(this))
575int K7Zip::K7ZipPrivate::readByte()
577 if (!buffer || pos + 1 > end) {
580 return buffer[pos++];
583quint32 K7Zip::K7ZipPrivate::readUInt32()
585 if (!buffer || (quint64)(pos + 4) > end) {
586 qCDebug(KArchiveLog) <<
"error size";
590 quint32 res = GetUi32(buffer + pos);
595quint64 K7Zip::K7ZipPrivate::readUInt64()
597 if (!buffer || (quint64)(pos + 8) > end) {
598 qCDebug(KArchiveLog) <<
"error size";
602 quint64 res = GetUi64(buffer + pos);
607quint64 K7Zip::K7ZipPrivate::readNumber()
609 if (!buffer || (quint64)(pos + 8) > end) {
613 unsigned char firstByte = buffer[pos++];
614 unsigned char mask = 0x80;
616 for (
int i = 0; i < 8; i++) {
617 if ((firstByte & mask) == 0) {
618 quint64 highPart = firstByte & (mask - 1);
619 value += (highPart << (i * 8));
622 value |= ((
unsigned char)buffer[pos++] << (8 * i));
628QString K7Zip::K7ZipPrivate::readString()
634 const char *buf = buffer + pos;
635 size_t rem = (
end - pos) / 2 * 2;
638 for (i = 0; i < rem; i += 2) {
639 if (buf[i] == 0 && buf[i + 1] == 0) {
644 qCDebug(KArchiveLog) <<
"read string error";
650 int len = (int)(rem / 2);
651 if (len < 0 || (
size_t)len * 2 != rem) {
652 qCDebug(KArchiveLog) <<
"read string unsupported";
657 for (
int i = 0; i < len; i++, buf += 2) {
665void K7Zip::K7ZipPrivate::skipData(
int size)
667 if (!buffer || pos + size > end) {
673bool K7Zip::K7ZipPrivate::findAttribute(
int attribute)
680 int type = readByte();
681 if (type == attribute) {
687 skipData(readNumber());
691void K7Zip::K7ZipPrivate::readBoolVector(
int numItems, QList<bool> &v)
698 unsigned char mask = 0;
699 for (
int i = 0; i < numItems; i++) {
704 v.
append((b & mask) != 0);
709void K7Zip::K7ZipPrivate::readBoolVector2(
int numItems, QList<bool> &v)
715 int allAreDefined = readByte();
716 if (allAreDefined == 0) {
717 readBoolVector(numItems, v);
721 for (
int i = 0; i < numItems; i++) {
726void K7Zip::K7ZipPrivate::readHashDigests(
int numItems, QList<bool> &digestsDefined, QList<quint32> &digests)
732 readBoolVector2(numItems, digestsDefined);
733 for (
int i = 0; i < numItems; i++) {
735 if (digestsDefined[i]) {
736 crc = GetUi32(buffer + pos);
743Folder *K7Zip::K7ZipPrivate::folderItem()
750 int numCoders = readNumber();
752 quint64 numInStreamsTotal = 0;
753 quint64 numOutStreamsTotal = 0;
754 for (
int i = 0; i < numCoders; ++i) {
764 unsigned char coderInfo = readByte();
765 int codecIdSize = (coderInfo & 0xF);
766 if (codecIdSize > 8) {
767 qCDebug(KArchiveLog) <<
"unsupported codec id size";
771 Folder::FolderInfo *info =
new Folder::FolderInfo();
772 std::unique_ptr<unsigned char[]> codecID(
new unsigned char[codecIdSize]);
773 for (
int i = 0; i < codecIdSize; ++i) {
774 codecID[i] = readByte();
778 for (
int j = 0; j < codecIdSize; j++) {
779 id |= codecID[codecIdSize - 1 - j] << (8 * j);
784 if ((coderInfo & 0x10) != 0) {
785 info->numInStreams = readNumber();
786 info->numOutStreams = readNumber();
788 info->numInStreams = 1;
789 info->numOutStreams = 1;
793 if ((coderInfo & 0x20) != 0) {
794 int propertiesSize = readNumber();
795 for (
int i = 0; i < propertiesSize; ++i) {
796 info->properties.
append(readByte());
800 if ((coderInfo & 0x80) != 0) {
801 qCDebug(KArchiveLog) <<
"unsupported";
807 numInStreamsTotal += info->numInStreams;
808 numOutStreamsTotal += info->numOutStreams;
809 folder->folderInfos.
append(info);
812 int numBindPairs = numOutStreamsTotal - 1;
813 for (
int i = 0; i < numBindPairs; i++) {
814 folder->inIndexes.
append(readNumber());
815 folder->outIndexes.
append(readNumber());
818 int numPackedStreams = numInStreamsTotal - numBindPairs;
819 if (numPackedStreams > 1) {
820 for (
int i = 0; i < numPackedStreams; ++i) {
821 folder->packedStreams.
append(readNumber());
824 if (numPackedStreams == 1) {
825 for (quint64 i = 0; i < numInStreamsTotal; i++) {
826 if (folder->findBindPairForInStream(i) < 0) {
827 folder->packedStreams.
append(i);
831 if (folder->packedStreams.
size() != 1) {
840bool K7Zip::K7ZipPrivate::readUInt64DefVector(
int numFiles, QList<quint64> &values, QList<bool> &defined)
846 readBoolVector2(numFiles, defined);
848 int external = readByte();
850 int dataIndex = readNumber();
851 if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
852 qCDebug(KArchiveLog) <<
"wrong data index";
859 for (
int i = 0; i < numFiles; i++) {
869bool K7Zip::K7ZipPrivate::readPackInfo()
875 packPos = readNumber();
876 numPackStreams = readNumber();
879 packCRCsDefined.
clear();
882 if (!findAttribute(kSize)) {
883 qCDebug(KArchiveLog) <<
"kSize not found";
887 for (quint64 i = 0; i < numPackStreams; ++i) {
888 packSizes.
append(readNumber());
892 int type = readByte();
897 readHashDigests(numPackStreams, packCRCsDefined, packCRCs);
900 skipData(readNumber());
904 for (quint64 i = 0; i < numPackStreams; ++i) {
905 packCRCsDefined.
append(
false);
912bool K7Zip::K7ZipPrivate::readUnpackInfo()
918 if (!findAttribute(kFolder)) {
919 qCDebug(KArchiveLog) <<
"kFolder not found";
923 int numFolders = readNumber();
926 int external = readByte();
929 for (
int i = 0; i < numFolders; ++i) {
930 folders.
append(folderItem());
935 int dataIndex = readNumber();
936 if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
937 qCDebug(KArchiveLog) <<
"wrong data index";
943 qCDebug(KArchiveLog) <<
"external error";
947 if (!findAttribute(kCodersUnpackSize)) {
948 qCDebug(KArchiveLog) <<
"kCodersUnpackSize not found";
952 for (
int i = 0; i < numFolders; ++i) {
954 int numOutStreams = folder->getNumOutStreams();
955 for (
int j = 0; j < numOutStreams; ++j) {
956 folder->unpackSizes.
append(readNumber());
961 int type = readByte();
966 QList<bool> crcsDefined;
968 readHashDigests(numFolders, crcsDefined, crcs);
969 for (
int i = 0; i < numFolders; i++) {
971 folder->unpackCRCDefined = crcsDefined[i];
972 folder->unpackCRC = crcs[i];
976 skipData(readNumber());
981bool K7Zip::K7ZipPrivate::readSubStreamsInfo()
987 numUnpackStreamsInFolders.
clear();
992 if (type == kNumUnpackStream) {
993 for (
int i = 0; i < folders.
size(); i++) {
994 numUnpackStreamsInFolders.
append(readNumber());
998 if (type == kCRC || type == kSize) {
1004 skipData(readNumber());
1007 if (numUnpackStreamsInFolders.
isEmpty()) {
1008 for (
int i = 0; i < folders.
size(); i++) {
1009 numUnpackStreamsInFolders.
append(1);
1013 for (
int i = 0; i < numUnpackStreamsInFolders.
size(); i++) {
1014 quint64 numSubstreams = numUnpackStreamsInFolders.
at(i);
1015 if (numSubstreams == 0) {
1019 for (quint64 j = 1; j < numSubstreams; j++) {
1020 if (type == kSize) {
1021 int size = readNumber();
1022 unpackSizes.
append(size);
1026 unpackSizes.
append(folders.
at(i)->getUnpackSize() - sum);
1029 if (type == kSize) {
1034 int numDigestsTotal = 0;
1035 for (
int i = 0; i < folders.
size(); i++) {
1036 quint64 numSubstreams = numUnpackStreamsInFolders.
at(i);
1037 if (numSubstreams != 1 || !folders.
at(i)->unpackCRCDefined) {
1038 numDigests += numSubstreams;
1040 numDigestsTotal += numSubstreams;
1045 QList<bool> digestsDefined2;
1046 QList<quint32> digests2;
1047 readHashDigests(numDigests, digestsDefined2, digests2);
1048 int digestIndex = 0;
1049 for (
int i = 0; i < folders.
size(); i++) {
1050 quint64 numSubstreams = numUnpackStreamsInFolders.
at(i);
1051 const Folder *folder = folders.
at(i);
1052 if (numSubstreams == 1 && folder->unpackCRCDefined) {
1053 digestsDefined.
append(
true);
1054 digests.
append(folder->unpackCRC);
1056 for (quint64 j = 0; j < numSubstreams; j++, digestIndex++) {
1057 digestsDefined.
append(digestsDefined2[digestIndex]);
1058 digests.
append(digests2[digestIndex]);
1062 }
else if (type == kEnd) {
1063 if (digestsDefined.
isEmpty()) {
1064 for (
int i = 0; i < numDigestsTotal; i++) {
1065 digestsDefined.
append(
false);
1072 skipData(readNumber());
1080#define TICKSPERSEC 10000000
1081#define TICKSPERMSEC 10000
1082#define SECSPERDAY 86400
1083#define SECSPERHOUR 3600
1084#define SECSPERMIN 60
1085#define EPOCHWEEKDAY 1
1086#define DAYSPERWEEK 7
1087#define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
1088#define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
1089#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKSPERSEC)
1090#define SECS_1601_TO_1970 ((369 * 365 + 89) * (unsigned long long)SECSPERDAY)
1092static uint toTimeT(
const long long liTime)
1094 long long time = liTime / TICKSPERSEC;
1100 long int days = time / SECSPERDAY;
1101 int secondsInDay = time % SECSPERDAY;
1104 short hour = (short)(secondsInDay / SECSPERHOUR);
1105 secondsInDay = secondsInDay % SECSPERHOUR;
1106 short minute = (short)(secondsInDay / SECSPERMIN);
1107 short second = (short)(secondsInDay % SECSPERMIN);
1110 long int cleaps = (3 * ((4 * days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
1111 days += 28188 + cleaps;
1112 long int years = (20 * days - 2442) / (5 * DAYSPERNORMALQUADRENNIUM);
1113 long int yearday = days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
1114 long int months = (64 * yearday) / 1959;
1122 month = (short)(months - 1);
1123 year = (short)(years + 1524);
1125 month = (short)(months - 13);
1126 year = (short)(years + 1525);
1131 short day = (short)(yearday - (1959 * months) / 64);
1133 QDateTime t(QDate(year, month, day), QTime(hour, minute, second));
1135 return t.toSecsSinceEpoch();
1138long long rtlSecondsSince1970ToSpecTime(quint32 seconds)
1140 long long secs = seconds * (
long long)TICKSPERSEC + TICKS_1601_TO_1970;
1144bool K7Zip::K7ZipPrivate::readMainStreamsInfo()
1153 if (type > ((quint32)1 << 30)) {
1154 qCDebug(KArchiveLog) <<
"type error";
1161 if (!readPackInfo()) {
1162 qCDebug(KArchiveLog) <<
"error during read pack information";
1168 if (!readUnpackInfo()) {
1169 qCDebug(KArchiveLog) <<
"error during read pack information";
1174 case kSubStreamsInfo: {
1175 if (!readSubStreamsInfo()) {
1176 qCDebug(KArchiveLog) <<
"error during read substreams information";
1182 qCDebug(KArchiveLog) <<
"Wrong type";
1187 qCDebug(KArchiveLog) <<
"should not reach";
1191static bool getInStream(
const Folder *folder, quint32 streamIndex,
int &seqInStream, quint32 &coderIndex)
1193 for (
int i = 0; i < folder->packedStreams.
size(); i++) {
1194 if (folder->packedStreams[i] == streamIndex) {
1200 int binderIndex = folder->findBindPairForInStream(streamIndex);
1201 if (binderIndex < 0) {
1205 quint32 coderStreamIndex;
1206 folder->findOutStream(folder->outIndexes[binderIndex], coderIndex, coderStreamIndex);
1208 quint32 startIndex = folder->getCoderInStreamIndex(coderIndex);
1210 if (folder->folderInfos[coderIndex]->numInStreams > 1) {
1214 for (
int i = 0; i < (int)folder->folderInfos[coderIndex]->numInStreams; i++) {
1215 getInStream(folder, startIndex + i, seqInStream, coderIndex);
1221static bool getOutStream(
const Folder *folder, quint32 streamIndex,
int &seqOutStream)
1223 QList<quint32> outStreams;
1224 quint32 outStreamIndex = 0;
1225 for (
int i = 0; i < folder->folderInfos.
size(); i++) {
1226 const Folder::FolderInfo *coderInfo = folder->folderInfos.
at(i);
1228 for (
int j = 0; j < coderInfo->numOutStreams; j++, outStreamIndex++) {
1229 if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
1230 outStreams.
append(outStreamIndex);
1235 for (
int i = 0; i < outStreams.
size(); i++) {
1236 if (outStreams[i] == streamIndex) {
1242 int binderIndex = folder->findBindPairForOutStream(streamIndex);
1243 if (binderIndex < 0) {
1248 quint32 coderStreamIndex;
1249 folder->findInStream(folder->inIndexes[binderIndex], coderIndex, coderStreamIndex);
1251 quint32 startIndex = folder->getCoderOutStreamIndex(coderIndex);
1253 if (folder->folderInfos[coderIndex]->numOutStreams > 1) {
1257 for (
int i = 0; i < (int)folder->folderInfos[coderIndex]->numOutStreams; i++) {
1258 getOutStream(folder, startIndex + i, seqOutStream);
1264const int kNumTopBits = 24;
1265const quint32 kTopValue = (1 << kNumTopBits);
1276 RangeDecoder(
const QByteArray &s)
1282 for (
int i = 0; i < 5; i++) {
1283 code = (code << 8) | readByte();
1287 unsigned char readByte()
1289 if (pos >= stream.
size()) {
1292 return stream[pos++];
1297 while (range < kTopValue) {
1298 code = (code << 8) | readByte();
1303 quint32 getThreshold(quint32 total)
1305 return (code) / (range /= total);
1308 void decode(quint32
start, quint32 size)
1310 code -=
start * range;
1315 quint32 decodeDirectBits(
int numTotalBits)
1320 for (
int i = numTotalBits; i != 0; i--) {
1322 quint32 t = (c - r) >> 31;
1324 result = (result << 1) | (1 - t);
1326 if (r < kTopValue) {
1327 c = (c << 8) | readByte();
1336 quint32 DecodeBit(quint32 size0, quint32 numTotalBits)
1338 quint32 newBound = (range >> numTotalBits) * size0;
1340 if (code < newBound) {
1353const int kNumBitModelTotalBits = 11;
1354const quint32 kBitModelTotal = (1 << kNumBitModelTotalBits);
1356template<
int numMoveBits>
1361 void updateModel(quint32 symbol)
1364 prob += (kBitModelTotal - prob) >> numMoveBits;
1366 prob -= (prob) >> numMoveBits;
1372 prob = kBitModelTotal / 2;
1376template<
int numMoveBits>
1377class CBitDecoder :
public CBitModel<numMoveBits>
1380 quint32 decode(RangeDecoder *decoder)
1382 quint32 newBound = (decoder->range >> kNumBitModelTotalBits) * this->prob;
1383 if (decoder->code < newBound) {
1384 decoder->range = newBound;
1385 this->prob += (kBitModelTotal - this->prob) >> numMoveBits;
1386 if (decoder->range < kTopValue) {
1387 decoder->code = (decoder->code << 8) | decoder->readByte();
1388 decoder->range <<= 8;
1392 decoder->range -= newBound;
1393 decoder->code -= newBound;
1394 this->prob -= (this->prob) >> numMoveBits;
1395 if (decoder->range < kTopValue) {
1396 decoder->code = (decoder->code << 8) | decoder->readByte();
1397 decoder->range <<= 8;
1404inline bool isJcc(
unsigned char b0,
unsigned char b1)
1406 return (b0 == 0x0F && (b1 & 0xF0) == 0x80);
1408inline bool isJ(
unsigned char b0,
unsigned char b1)
1410 return ((b1 & 0xFE) == 0xE8 || isJcc(b0, b1));
1412inline unsigned getIndex(
unsigned char b0,
unsigned char b1)
1414 return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257));
1417const int kNumMoveBits = 5;
1419static QByteArray decodeBCJ2(
const QByteArray &mainStream,
const QByteArray &callStream,
const QByteArray &jumpStream,
const QByteArray &rangeBuffer)
1421 unsigned char prevByte = 0;
1422 QByteArray outStream;
1423 int mainStreamPos = 0;
1424 int callStreamPos = 0;
1425 int jumpStreamPos = 0;
1427 RangeDecoder rangeDecoder(rangeBuffer);
1429 QList<CBitDecoder<kNumMoveBits>> statusDecoder(256 + 2);
1431 for (
int i = 0; i < 256 + 2; i++) {
1432 statusDecoder[i].init();
1437 unsigned char b = 0;
1438 const quint32 kBurstSize = (1 << 18);
1439 for (i = 0; i < kBurstSize; i++) {
1440 if (mainStreamPos == mainStream.
size()) {
1444 b = mainStream[mainStreamPos++];
1447 if (isJ(prevByte, b)) {
1453 if (i == kBurstSize) {
1457 unsigned index = getIndex(prevByte, b);
1458 if (statusDecoder[index].decode(&rangeDecoder) == 1) {
1460 if (callStreamPos + 4 > callStream.
size()) {
1461 return QByteArray();
1464 if (jumpStreamPos + 4 > jumpStream.
size()) {
1465 return QByteArray();
1469 for (
int i = 0; i < 4; i++) {
1472 b0 = callStream[callStreamPos++];
1474 b0 = jumpStream[jumpStreamPos++];
1477 src |= ((quint32)b0);
1480 quint32 dest = src - (quint32(outStream.
size()) + 4);
1481 outStream.
append((
unsigned char)(dest));
1482 outStream.
append((
unsigned char)(dest >> 8));
1483 outStream.
append((
unsigned char)(dest >> 16));
1484 outStream.
append((
unsigned char)(dest >> 24));
1485 prevByte = (
unsigned char)(dest >> 24);
1492QByteArray K7Zip::K7ZipPrivate::readAndDecodePackedStreams(
bool readMainStreamInfo)
1495 return QByteArray();
1498 if (readMainStreamInfo) {
1499 readMainStreamsInfo();
1502 QByteArray inflatedData;
1504 quint64 startPos = 32 + packPos;
1505 for (
int i = 0; i < folders.
size(); i++) {
1506 const Folder *folder = folders.
at(i);
1507 quint64 unpackSize64 = folder->getUnpackSize();
1508 size_t unpackSize = (size_t)unpackSize64;
1509 if (unpackSize != unpackSize64) {
1510 qCDebug(KArchiveLog) <<
"unsupported";
1511 return inflatedData;
1515 quint32 mainCoderIndex = 0;
1516 QList<int> outStreamIndexed;
1517 int outStreamIndex = 0;
1518 for (
int j = 0; j < folder->folderInfos.
size(); j++) {
1519 const Folder::FolderInfo *info = folder->folderInfos[j];
1520 for (
int k = 0; k < info->numOutStreams; k++, outStreamIndex++) {
1521 if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
1522 outStreamIndexed.
append(outStreamIndex);
1529 if (!outStreamIndexed.
isEmpty()) {
1530 folder->findOutStream(outStreamIndexed[0], mainCoderIndex, temp);
1533 quint32 startInIndex = folder->getCoderInStreamIndex(mainCoderIndex);
1534 quint32 startOutIndex = folder->getCoderOutStreamIndex(mainCoderIndex);
1536 Folder::FolderInfo *mainCoder = folder->folderInfos[mainCoderIndex];
1538 QList<int> seqInStreams;
1539 QList<quint32> coderIndexes;
1540 seqInStreams.
reserve(mainCoder->numInStreams);
1541 coderIndexes.
reserve(mainCoder->numInStreams);
1542 for (
int j = 0; j < (int)mainCoder->numInStreams; j++) {
1545 getInStream(folder, startInIndex + j, seqInStream, coderIndex);
1546 seqInStreams.
append(seqInStream);
1547 coderIndexes.
append(coderIndex);
1550 QList<int> seqOutStreams;
1551 seqOutStreams.
reserve(mainCoder->numOutStreams);
1552 for (
int j = 0; j < (int)mainCoder->numOutStreams; j++) {
1554 getOutStream(folder, startOutIndex + j, seqOutStream);
1555 seqOutStreams.
append(seqOutStream);
1558 QList<QByteArray> datas;
1559 for (
int j = 0; j < (int)mainCoder->numInStreams; j++) {
1560 quint64 size = packSizes[j + i];
1561 std::unique_ptr<char[]> encodedBuffer(
new char[size]);
1562 QIODevice *dev = q->
device();
1563 dev->
seek(startPos);
1564 quint64 n = dev->
read(encodedBuffer.get(), size);
1566 qCDebug(KArchiveLog) <<
"Failed read next size, should read " << size <<
", read " << n;
1567 return inflatedData;
1569 QByteArray deflatedData(encodedBuffer.get(), size);
1570 datas.
append(deflatedData);
1576 QList<QByteArray> inflatedDatas;
1577 QByteArray deflatedData;
1578 for (
int j = 0; j < seqInStreams.
size(); ++j) {
1579 Folder::FolderInfo *coder =
nullptr;
1580 if ((quint32)j != mainCoderIndex) {
1581 coder = folder->folderInfos[coderIndexes[j]];
1583 coder = folder->folderInfos[mainCoderIndex];
1586 deflatedData = datas[seqInStreams[j]];
1588 KFilterBase *
filter =
nullptr;
1590 switch (coder->methodID) {
1594 qCDebug(KArchiveLog) <<
"filter not found";
1595 return QByteArray();
1602 qCDebug(KArchiveLog) <<
"filter not found";
1603 return QByteArray();
1618 if (coder->properties.
size() >= 1) {
1627 qCDebug(KArchiveLog) <<
"filter not found";
1628 return QByteArray();
1633 QByteArray bcj2 = decodeBCJ2(inflatedDatas[0], inflatedDatas[1], inflatedDatas[2], deflatedData);
1634 inflatedDatas.
clear();
1635 inflatedDatas.
append(bcj2);
1641 qCDebug(KArchiveLog) <<
"filter not found";
1642 return QByteArray();
1648 if (coder->methodID == k_BCJ2) {
1653 return QByteArray();
1658 QByteArray outBuffer;
1660 outBuffer.
resize(unpackSize);
1663 QByteArray inflatedDataTmp;
1664 while (result != KFilterBase::End && result != KFilterBase::Error && !
filter->inBufferEmpty()) {
1666 result =
filter->uncompress();
1667 if (result == KFilterBase::Error) {
1668 qCDebug(KArchiveLog) <<
" decode error";
1671 return QByteArray();
1673 int uncompressedBytes = outBuffer.
size() -
filter->outBufferAvailable();
1676 inflatedDataTmp.
append(outBuffer.
data(), uncompressedBytes);
1678 if (result == KFilterBase::End) {
1684 if (result != KFilterBase::End && !
filter->inBufferEmpty()) {
1685 qCDebug(KArchiveLog) <<
"decode failed result" << result;
1688 return QByteArray();
1694 inflatedDatas.
append(inflatedDataTmp);
1697 QByteArray inflated;
1698 for (
const QByteArray &data : std::as_const(inflatedDatas)) {
1702 inflatedDatas.
clear();
1704 if (folder->unpackCRCDefined) {
1705 if ((
size_t)inflated.
size() < unpackSize) {
1706 qCDebug(KArchiveLog) <<
"wrong crc size data";
1707 return QByteArray();
1709 quint32 crc = crc32(0, (Bytef *)(inflated.
data()), unpackSize);
1710 if (crc != folder->unpackCRC) {
1711 qCDebug(KArchiveLog) <<
"wrong crc";
1712 return QByteArray();
1716 inflatedData.
append(inflated);
1719 return inflatedData;
1724void K7Zip::K7ZipPrivate::createItemsFromEntities(
const KArchiveDirectory *dir,
const QString &path, QByteArray &data)
1726 const QStringList l =
dir->entries();
1728 for (; it != l.
end(); ++it) {
1729 const KArchiveEntry *entry =
dir->entry((*it));
1731 FileInfo *fileInfo =
new FileInfo;
1732 fileInfo->attribDefined =
true;
1734 fileInfo->path =
path + entry->
name();
1735 mTimesDefined.
append(
true);
1739 const K7ZipFileEntry *fileEntry =
static_cast<const K7ZipFileEntry *
>(entry);
1741 fileInfo->attributes = FILE_ATTRIBUTE_ARCHIVE;
1742 fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->
permissions() & 0xFFFF) << 16);
1743 fileInfo->size = fileEntry->
size();
1745 if (fileInfo->size > 0) {
1746 fileInfo->hasStream =
true;
1748 unpackSizes.
append(fileInfo->size);
1749 }
else if (!symLink.
isEmpty()) {
1750 fileInfo->hasStream =
true;
1754 fileInfos.
append(fileInfo);
1756 fileInfo->attributes = FILE_ATTRIBUTE_DIRECTORY;
1757 fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->
permissions() & 0xFFFF) << 16);
1758 fileInfo->isDir =
true;
1759 fileInfos.
append(fileInfo);
1760 createItemsFromEntities((KArchiveDirectory *)entry, path + (*it) + QLatin1Char(
'/'), data);
1765void K7Zip::K7ZipPrivate::writeByte(
unsigned char b)
1771void K7Zip::K7ZipPrivate::writeNumber(quint64 value)
1776 for (i = 0; i < 8; i++) {
1777 if (value < ((quint64(1) << (7 * (i + 1))))) {
1778 firstByte |= (int)(value >> (8 * i));
1784 writeByte(firstByte);
1785 for (; i > 0; i--) {
1786 writeByte((
int)value);
1791void K7Zip::K7ZipPrivate::writeBoolVector(
const QList<bool> &boolVector)
1795 for (
int i = 0; i < boolVector.
size(); i++) {
1796 if (boolVector[i]) {
1811void K7Zip::K7ZipPrivate::writeUInt32(quint32 value)
1813 for (
int i = 0; i < 4; i++) {
1814 writeByte((
unsigned char)value);
1819void K7Zip::K7ZipPrivate::writeUInt64(quint64 value)
1821 for (
int i = 0; i < 8; i++) {
1822 writeByte((
unsigned char)value);
1827void K7Zip::K7ZipPrivate::writeAlignedBoolHeader(
const QList<bool> &v,
int numDefined,
int type,
unsigned itemSize)
1829 const unsigned bvSize = (numDefined == v.
size()) ? 0 : ((unsigned)v.
size() + 7) / 8;
1830 const quint64 dataSize = (quint64)numDefined * itemSize + bvSize + 2;
1834 writeNumber(dataSize);
1835 if (numDefined == v.
size()) {
1844void K7Zip::K7ZipPrivate::writeUInt64DefVector(
const QList<quint64> &v,
const QList<bool> &defined,
int type)
1848 for (
int i = 0; i < defined.
size(); i++) {
1854 if (numDefined == 0) {
1858 writeAlignedBoolHeader(defined, numDefined, type, 8);
1860 for (
int i = 0; i < defined.
size(); i++) {
1867void K7Zip::K7ZipPrivate::writeHashDigests(
const QList<bool> &digestsDefined,
const QList<quint32> &digests)
1871 for (i = 0; i < digestsDefined.
size(); i++) {
1872 if (digestsDefined[i]) {
1877 if (numDefined == 0) {
1882 if (numDefined == digestsDefined.
size()) {
1886 writeBoolVector(digestsDefined);
1889 for (i = 0; i < digests.
size(); i++) {
1890 if (digestsDefined[i]) {
1891 writeUInt32(digests[i]);
1896void K7Zip::K7ZipPrivate::writePackInfo(quint64 dataOffset, QList<quint64> &packedSizes, QList<bool> &packedCRCsDefined, QList<quint32> &packedCRCs)
1901 writeByte(kPackInfo);
1902 writeNumber(dataOffset);
1903 writeNumber(packedSizes.
size());
1906 for (
int i = 0; i < packedSizes.
size(); i++) {
1907 writeNumber(packedSizes[i]);
1910 writeHashDigests(packedCRCsDefined, packedCRCs);
1915void K7Zip::K7ZipPrivate::writeFolder(
const Folder *folder)
1917 writeNumber(folder->folderInfos.
size());
1918 for (
int i = 0; i < folder->folderInfos.
size(); i++) {
1919 const Folder::FolderInfo *info = folder->folderInfos.
at(i);
1921 size_t propsSize = info->properties.
size();
1923 quint64
id = info->methodID;
1925 for (idSize = 1; idSize <
sizeof(id); idSize++) {
1926 if ((
id >> (8 * idSize)) == 0) {
1932 for (
int t = idSize - 1; t >= 0; t--,
id >>= 8) {
1933 longID[t] = (int)(
id & 0xFF);
1937 b = (int)(idSize & 0xF);
1938 bool isComplex = !info->isSimpleCoder();
1939 b |= (isComplex ? 0x10 : 0);
1940 b |= ((propsSize != 0) ? 0x20 : 0);
1943 for (
size_t j = 0; j < idSize; ++j) {
1944 writeByte(longID[j]);
1948 writeNumber(info->numInStreams);
1949 writeNumber(info->numOutStreams);
1952 if (propsSize == 0) {
1956 writeNumber(propsSize);
1957 for (
size_t j = 0; j < propsSize; ++j) {
1958 writeByte(info->properties[j]);
1963 for (
int i = 0; i < folder->inIndexes.
size(); i++) {
1964 writeNumber(folder->inIndexes[i]);
1965 writeNumber(folder->outIndexes[i]);
1968 if (folder->packedStreams.
size() > 1) {
1969 for (
int i = 0; i < folder->packedStreams.
size(); i++) {
1970 writeNumber(folder->packedStreams[i]);
1975void K7Zip::K7ZipPrivate::writeUnpackInfo(
const QList<Folder *> &folderItems)
1981 writeByte(kUnpackInfo);
1984 writeNumber(folderItems.
size());
1987 for (
int i = 0; i < folderItems.
size(); i++) {
1988 writeFolder(folderItems[i]);
1992 writeByte(kCodersUnpackSize);
1994 for (i = 0; i < folderItems.
size(); i++) {
1995 const Folder *folder = folderItems[i];
1996 for (
int j = 0; j < folder->unpackSizes.
size(); j++) {
1997 writeNumber(folder->unpackSizes.
at(j));
2001 QList<bool> unpackCRCsDefined;
2002 QList<quint32> unpackCRCs;
2005 for (i = 0; i < folderItems.
size(); i++) {
2006 const Folder *folder = folderItems[i];
2007 unpackCRCsDefined.
append(folder->unpackCRCDefined);
2008 unpackCRCs.
append(folder->unpackCRC);
2010 writeHashDigests(unpackCRCsDefined, unpackCRCs);
2015void K7Zip::K7ZipPrivate::writeSubStreamsInfo(
const QList<quint64> &unpackSizes,
const QList<bool> &digestsDefined,
const QList<quint32> &digests)
2017 writeByte(kSubStreamsInfo);
2019 for (
int i = 0; i < numUnpackStreamsInFolders.
size(); i++) {
2020 if (numUnpackStreamsInFolders.
at(i) != 1) {
2021 writeByte(kNumUnpackStream);
2022 for (
int j = 0; j < numUnpackStreamsInFolders.
size(); j++) {
2023 writeNumber(numUnpackStreamsInFolders.
at(j));
2029 bool needFlag =
true;
2031 for (
int i = 0; i < numUnpackStreamsInFolders.
size(); i++) {
2032 for (quint32 j = 0; j < numUnpackStreamsInFolders.
at(i); j++) {
2033 if (j + 1 != numUnpackStreamsInFolders.
at(i)) {
2038 writeNumber(unpackSizes[index]);
2044 QList<bool> digestsDefined2;
2045 QList<quint32> digests2;
2047 int digestIndex = 0;
2048 for (
int i = 0; i < folders.
size(); i++) {
2049 int numSubStreams = (int)numUnpackStreamsInFolders.
at(i);
2050 if (numSubStreams == 1 && folders.
at(i)->unpackCRCDefined) {
2053 for (
int j = 0; j < numSubStreams; j++, digestIndex++) {
2054 digestsDefined2.
append(digestsDefined[digestIndex]);
2055 digests2.
append(digests[digestIndex]);
2059 writeHashDigests(digestsDefined2, digests2);
2063QByteArray K7Zip::K7ZipPrivate::encodeStream(QList<quint64> &packSizes, QList<Folder *> &folds)
2066 folder->unpackCRCDefined =
true;
2067 folder->unpackCRC = crc32(0, (Bytef *)(header.
data()), header.
size());
2070 Folder::FolderInfo *info =
new Folder::FolderInfo();
2071 info->numInStreams = 1;
2072 info->numOutStreams = 1;
2073 info->methodID = k_LZMA2;
2075 quint32 dictSize = header.
size();
2076 const quint32 kMinReduceSize = (1 << 16);
2077 if (dictSize < kMinReduceSize) {
2078 dictSize = kMinReduceSize;
2082 for (dict = 0; dict < 40; dict++) {
2083 if (dictSize <= lzma2_dic_size_from_prop(dict)) {
2088 info->properties.
append(dict);
2089 folder->folderInfos.
append(info);
2094 QByteArray encodedData;
2097 QBuffer inBuffer(&enc);
2099 KCompressionDevice flt(&inBuffer,
false, KCompressionDevice::Xz);
2102 KFilterBase *
filter = flt.filterBase();
2106 const int ret = flt.write(header);
2107 if (ret != header.
size()) {
2108 qCDebug(KArchiveLog) <<
"write error write " << ret <<
"expected" << header.
size();
2113 encodedData = inBuffer.
data();
2120void K7Zip::K7ZipPrivate::writeHeader(quint64 &headerOffset)
2122 quint64 packedSize = 0;
2123 for (
int i = 0; i < packSizes.
size(); ++i) {
2124 packedSize += packSizes[i];
2127 headerOffset = packedSize;
2134 writeByte(kMainStreamsInfo);
2135 writePackInfo(0, packSizes, packCRCsDefined, packCRCs);
2137 writeUnpackInfo(folders);
2139 QList<quint64> unpackFileSizes;
2140 QList<bool> digestsDefined;
2141 QList<quint32> digests;
2142 for (
int i = 0; i < fileInfos.
size(); i++) {
2143 const FileInfo *file = fileInfos.
at(i);
2144 if (!file->hasStream) {
2147 unpackFileSizes.
append(file->size);
2148 digestsDefined.
append(file->crcDefined);
2149 digests.
append(file->crc);
2152 writeSubStreamsInfo(unpackSizes, digestsDefined, digests);
2161 writeByte(kFilesInfo);
2162 writeNumber(fileInfos.
size());
2166 QList<bool> emptyStreamVector;
2167 int numEmptyStreams = 0;
2168 for (
int i = 0; i < fileInfos.
size(); i++) {
2169 if (fileInfos.
at(i)->hasStream) {
2170 emptyStreamVector.
append(
false);
2172 emptyStreamVector.
append(
true);
2177 if (numEmptyStreams > 0) {
2178 writeByte(kEmptyStream);
2179 writeNumber(((
unsigned)emptyStreamVector.
size() + 7) / 8);
2180 writeBoolVector(emptyStreamVector);
2182 QList<bool> emptyFileVector;
2183 QList<bool> antiVector;
2184 int numEmptyFiles = 0;
2185 int numAntiItems = 0;
2186 for (
int i = 0; i < fileInfos.
size(); i++) {
2187 const FileInfo *file = fileInfos.
at(i);
2188 if (!file->hasStream) {
2189 emptyFileVector.
append(!file->isDir);
2192 bool isAnti = (i < this->isAnti.size() && this->isAnti[i]);
2193 antiVector.
append(isAnti);
2201 if (numEmptyFiles > 0) {
2202 writeByte(kEmptyFile);
2203 writeNumber(((
unsigned)emptyFileVector.
size() + 7) / 8);
2204 writeBoolVector(emptyFileVector);
2207 if (numAntiItems > 0) {
2209 writeNumber(((
unsigned)antiVector.
size() + 7) / 8);
2210 writeBoolVector(antiVector);
2219 size_t namesDataSize = 0;
2220 for (
int i = 0; i < fileInfos.
size(); i++) {
2221 const QString &
name = fileInfos.
at(i)->path;
2226 if (numDefined > 0) {
2231 writeNumber(namesDataSize);
2233 for (
int i = 0; i < fileInfos.
size(); i++) {
2234 const QString &
name = fileInfos.
at(i)->path;
2237 writeByte((
unsigned char)c);
2238 writeByte((
unsigned char)(c >> 8));
2247 writeUInt64DefVector(mTimes, mTimesDefined, kMTime);
2249 writeUInt64DefVector(startPositions, startPositionsDefined, kStartPos);
2253 QList<bool> boolVector;
2256 for (
int i = 0; i < fileInfos.
size(); i++) {
2257 bool defined = fileInfos.
at(i)->attribDefined;
2258 boolVector.
append(defined);
2264 if (numDefined > 0) {
2265 writeAlignedBoolHeader(boolVector, numDefined, kAttributes, 4);
2266 for (
int i = 0; i < fileInfos.
size(); i++) {
2267 const FileInfo *file = fileInfos.
at(i);
2268 if (file->attribDefined) {
2269 writeUInt32(file->attributes);
2279static void setUInt32(
unsigned char *p, quint32 d)
2281 for (
int i = 0; i < 4; i++, d >>= 8) {
2286static void setUInt64(
unsigned char *p, quint64 d)
2288 for (
int i = 0; i < 8; i++, d >>= 8) {
2289 p[i] = (
unsigned char)d;
2293void K7Zip::K7ZipPrivate::writeStartHeader(
const quint64 nextHeaderSize,
const quint32 nextHeaderCRC,
const quint64 nextHeaderOffset)
2295 unsigned char buf[24];
2296 setUInt64(buf + 4, nextHeaderOffset);
2297 setUInt64(buf + 12, nextHeaderSize);
2298 setUInt32(buf + 20, nextHeaderCRC);
2299 setUInt32(buf, crc32(0, (Bytef *)(buf + 4), 20));
2303void K7Zip::K7ZipPrivate::writeSignature()
2305 unsigned char buf[8];
2306 memcpy(buf, k7zip_signature, 6);
2327 qint64 n = dev->
read(header, 32);
2333 for (
int i = 0; i < 6; ++i) {
2334 if ((
unsigned char)header[i] != k7zip_signature[i]) {
2341 int major = header[6];
2342 int minor = header[7];
2350 quint32 startHeaderCRC = GetUi32(header + 8);
2351 quint64 nextHeaderOffset = GetUi64(header + 12);
2352 quint64 nextHeaderSize = GetUi64(header + 20);
2353 quint32 nextHeaderCRC = GetUi32(header + 28);
2355 quint32 crc = crc32(0, (Bytef *)(header + 0xC), 20);
2357 if (crc != startHeaderCRC) {
2362 if (nextHeaderSize == 0) {
2366 if (nextHeaderSize > (quint64)0xFFFFFFFF) {
2371 if ((qint64)nextHeaderOffset < 0) {
2376 dev->
seek(nextHeaderOffset + 32);
2379 inBuffer.
resize(nextHeaderSize);
2382 if (n != (qint64)nextHeaderSize) {
2383 setErrorString(tr(
"Failed read next header size; should read %1, read %2").arg(nextHeaderSize).arg(n));
2386 d->buffer = inBuffer.
data();
2387 d->end = nextHeaderSize;
2389 d->headerSize = 32 + nextHeaderSize;
2392 crc = crc32(0, (Bytef *)(d->buffer), (quint32)nextHeaderSize);
2394 if (crc != nextHeaderCRC) {
2399 int type = d->readByte();
2401 if (type != kHeader) {
2402 if (type != kEncodedHeader) {
2407 decodedData = d->readAndDecodePackedStreams();
2409 int external = d->readByte();
2410 if (external != 0) {
2411 int dataIndex = (int)d->readNumber();
2412 if (dataIndex < 0) {
2417 d->end = decodedData.
size();
2420 type = d->readByte();
2421 if (type != kHeader) {
2428 type = d->readByte();
2430 if (type == kArchiveProperties) {
2436 if (type == kAdditionalStreamsInfo) {
2442 if (type == kMainStreamsInfo) {
2443 if (!d->readMainStreamsInfo()) {
2444 setErrorString(tr(
"Error while reading main streams information"));
2447 type = d->readByte();
2449 for (
int i = 0; i < d->folders.size(); ++i) {
2450 Folder *folder = d->folders.at(i);
2451 d->unpackSizes.
append(folder->getUnpackSize());
2452 d->digestsDefined.append(folder->unpackCRCDefined);
2453 d->digests.append(folder->unpackCRC);
2461 if (type != kFilesInfo) {
2467 int numFiles = d->readNumber();
2468 for (
int i = 0; i < numFiles; ++i) {
2469 d->fileInfos.append(
new FileInfo);
2475 int numEmptyStreams = 0;
2478 quint64 type = d->readByte();
2483 quint64 size = d->readNumber();
2485 size_t ppp = d->pos;
2487 bool addPropIdToList =
true;
2488 bool isKnownType =
true;
2490 if (type > ((quint32)1 << 30)) {
2491 isKnownType =
false;
2494 case kEmptyStream: {
2495 d->readBoolVector(numFiles, emptyStreamVector);
2496 for (
int i = 0; i < emptyStreamVector.
size(); ++i) {
2497 if (emptyStreamVector[i]) {
2505 d->readBoolVector(numEmptyStreams, emptyFileVector);
2508 d->readBoolVector(numEmptyStreams, antiFileVector);
2511 if (!d->readUInt64DefVector(numFiles, d->cTimes, d->cTimesDefined)) {
2516 if (!d->readUInt64DefVector(numFiles, d->aTimes, d->aTimesDefined)) {
2521 if (!d->readUInt64DefVector(numFiles, d->mTimes, d->mTimesDefined)) {
2527 int external = d->readByte();
2528 if (external != 0) {
2529 int dataIndex = d->readNumber();
2530 if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
2531 qCDebug(KArchiveLog) <<
"wrong data index";
2538 for (
int i = 0; i < numFiles; i++) {
2539 name = d->readString();
2540 d->fileInfos.
at(i)->path = name;
2546 d->readBoolVector2(numFiles, attributesAreDefined);
2547 int external = d->readByte();
2548 if (external != 0) {
2549 int dataIndex = d->readNumber();
2550 if (dataIndex < 0) {
2551 qCDebug(KArchiveLog) <<
"wrong data index";
2557 for (
int i = 0; i < numFiles; i++) {
2558 FileInfo *fileInfo = d->fileInfos.at(i);
2559 fileInfo->attribDefined = attributesAreDefined[i];
2560 if (fileInfo->attribDefined) {
2561 fileInfo->attributes = d->readUInt32();
2567 if (!d->readUInt64DefVector(numFiles, d->startPositions, d->startPositionsDefined)) {
2573 for (quint64 i = 0; i < size; i++) {
2574 if (d->readByte() != 0) {
2579 addPropIdToList =
false;
2583 addPropIdToList = isKnownType =
false;
2588 if (addPropIdToList) {
2589 d->fileInfoPopIDs.append(type);
2592 d->skipData(d->readNumber());
2595 bool checkRecordsSize = (major > 0 || minor > 2);
2596 if (checkRecordsSize && d->pos - ppp != size) {
2598 "(checkRecordsSize: %1, d->pos - ppp: %2, size: %3)")
2599 .arg(checkRecordsSize)
2606 int emptyFileIndex = 0;
2609 int numAntiItems = 0;
2611 if (emptyStreamVector.
isEmpty()) {
2612 emptyStreamVector.
fill(
false, numFiles);
2615 if (antiFileVector.
isEmpty()) {
2616 antiFileVector.
fill(
false, numEmptyStreams);
2618 if (emptyFileVector.
isEmpty()) {
2619 emptyFileVector.
fill(
false, numEmptyStreams);
2622 for (
int i = 0; i < numEmptyStreams; i++) {
2623 if (antiFileVector[i]) {
2628 d->outData = d->readAndDecodePackedStreams(
false);
2631 int filesWithoutNames = 0;
2639 for (
int i = 0; i < numFiles; i++) {
2640 FileInfo *fileInfo = d->fileInfos.at(i);
2644 if (fileInfo->path.
isEmpty()) {
2646 filesWithoutNames++;
2647 fileInfo->path = QStringLiteral(
"%1_%2").
arg(defaultBaseName).
arg(filesWithoutNames);
2649 fileInfo->path = defaultBaseName;
2654 fileInfo->hasStream = !emptyStreamVector[i];
2655 if (fileInfo->hasStream) {
2656 fileInfo->isDir =
false;
2658 fileInfo->size = d->unpackSizes[sizeIndex];
2659 fileInfo->crc = d->digests[sizeIndex];
2660 fileInfo->crcDefined = d->digestsDefined[sizeIndex];
2663 fileInfo->isDir = !emptyFileVector[emptyFileIndex];
2664 isAnti = antiFileVector[emptyFileIndex];
2667 fileInfo->crcDefined =
false;
2669 if (numAntiItems != 0) {
2670 d->isAnti.append(isAnti);
2674 bool symlink =
false;
2675 if (fileInfo->attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {
2676 access = fileInfo->attributes >> 16;
2677 if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
2681 if (fileInfo->isDir) {
2682 access = S_IFDIR | 0755;
2689 if (!fileInfo->isDir) {
2691 oldPos += fileInfo->size;
2698 entryName = fileInfo->path;
2700 entryName = fileInfo->path.
mid(index + 1);
2702 Q_ASSERT(!entryName.
isEmpty());
2705 if (d->mTimesDefined.size() > i && d->mTimesDefined[i]) {
2706 mTime = KArchivePrivate::time_tToDateTime(toTimeT(d->mTimes[i]));
2708 mTime = KArchivePrivate::time_tToDateTime(time(
nullptr));
2711 if (fileInfo->isDir) {
2721 e =
new K7ZipFileEntry(
this,
2733 e =
new K7ZipFileEntry(
this, entryName, access, mTime,
rootDir()->user(),
rootDir()->group(), target, 0, 0,
nullptr);
2765 Folder *folder =
new Folder();
2767 folder->unpackSizes.
clear();
2768 folder->unpackSizes.
append(d->outData.size());
2770 Folder::FolderInfo *info =
new Folder::FolderInfo();
2772 info->numInStreams = 1;
2773 info->numOutStreams = 1;
2774 info->methodID = k_LZMA2;
2776 quint32 dictSize = d->outData.size();
2778 const quint32 kMinReduceSize = (1 << 16);
2779 if (dictSize < kMinReduceSize) {
2780 dictSize = kMinReduceSize;
2785 for (dict = 0; dict < 40; dict++) {
2786 if (dictSize <= lzma2_dic_size_from_prop(dict)) {
2790 info->properties.
append(dict);
2792 folder->folderInfos.
append(info);
2793 d->folders.append(folder);
2797 d->createItemsFromEntities(dir,
QString(), data);
2800 folder->unpackCRCDefined =
true;
2801 folder->unpackCRC = crc32(0, (Bytef *)(d->outData.data()), d->outData.size());
2805 if (!d->outData.isEmpty()) {
2816 static_cast<KXzFilter *
>(filter)->init(
QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
2818 const int ret = flt.
write(d->outData);
2819 if (ret != d->outData.size()) {
2825 encodedData = inBuffer.
data();
2830 int numUnpackStream = 0;
2831 for (
int i = 0; i < d->fileInfos.size(); ++i) {
2832 if (d->fileInfos.at(i)->hasStream) {
2836 d->numUnpackStreamsInFolders.
append(numUnpackStream);
2838 quint64 headerOffset;
2839 d->writeHeader(headerOffset);
2846 encodedStream = d->encodeStream(packSizes, folders);
2856 d->writeByte(kEncodedHeader);
2859 d->writePackInfo(headerOffset, packSizes, emptyDefined, emptyCrcs);
2860 d->writeUnpackInfo(folders);
2862 for (
int i = 0; i < packSizes.
size(); i++) {
2863 headerOffset += packSizes.
at(i);
2865 qDeleteAll(folders);
2869 quint64 nextHeaderSize = d->header.size();
2870 quint32 nextHeaderCRC = crc32(0, (Bytef *)(d->header.data()), d->header.size());
2871 quint64 nextHeaderOffset = headerOffset;
2874 d->writeSignature();
2875 d->writeStartHeader(nextHeaderSize, nextHeaderCRC, nextHeaderOffset);
2878 device()->
write(d->header.data(), d->header.size());
2885 d->m_currentFile->setSize(size);
2886 d->m_currentFile =
nullptr;
2893 if (!d->m_currentFile) {
2898 if (d->m_currentFile->position() == d->outData.size()) {
2899 d->outData.append(data, size);
2901 d->outData.remove(d->m_currentFile->position(), d->m_currentFile->size());
2902 d->outData.insert(d->m_currentFile->position(), data, size);
2918 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2919 qCWarning(KArchiveLog) <<
"doPrepareWriting failed: !isOpen()";
2924 setErrorString(tr(
"Application error: attempted to write into non-writable 7-Zip file"));
2925 qCWarning(KArchiveLog) <<
"doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
2945 new K7ZipFileEntry(
this,
fileName, perm, mtime, user, group,
QString() , d->outData.
size(), 0 , d->outData);
2949 d->m_entryList << e;
2950 d->m_currentFile = e;
2968 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2969 qCWarning(KArchiveLog) <<
"doWriteDir failed: !isOpen()";
2990 dirName = name.
mid(i + 1);
3010 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
3011 qCWarning(KArchiveLog) <<
"doWriteSymLink failed: !isOpen()";
3016 setErrorString(tr(
"Application error: attempted to write into non-writable 7-Zip file"));
3017 qCWarning(KArchiveLog) <<
"doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
3033 K7ZipFileEntry *e =
new K7ZipFileEntry(
this,
fileName, perm, mtime, user, group, target, 0, 0,
nullptr);
3034 d->outData.append(encodedTarget);
3040 d->m_entryList << e;
3045void K7Zip::virtual_hook(
int id,
void *data)
3047 KArchive::virtual_hook(
id, data);
A class for reading / writing p7zip archives.
bool doWriteDir(const QString &name, const QString &user, const QString &group, mode_t perm, const QDateTime &atime, const QDateTime &mtime, const QDateTime &ctime) override
Reimplemented from KArchive.
bool doWriteData(const char *data, qint64 size) override
Reimplemented from KArchive.
bool doFinishWriting(qint64 size) override
Reimplemented from KArchive.
bool openArchive(QIODevice::OpenMode mode) override
Opens the archive for reading.
bool closeArchive() override
Closes the archive.
bool doWriteSymLink(const QString &name, const QString &target, const QString &user, const QString &group, mode_t perm, const QDateTime &atime, const QDateTime &mtime, const QDateTime &ctime) override
Reimplemented from KArchive.
~K7Zip() override
If the archive is still opened, then it will be closed automatically by the destructor.
K7Zip(const QString &filename)
Creates an instance that operates on the given filename using the compression filter associated to gi...
bool doPrepareWriting(const QString &name, const QString &user, const QString &group, qint64 size, mode_t perm, const QDateTime &atime, const QDateTime &mtime, const QDateTime &ctime) override
Reimplemented from KArchive.
Represents a directory entry in a KArchive.
void addEntry(KArchiveEntry *)
bool addEntryV2(KArchiveEntry *)
const KArchiveEntry * entry(const QString &name) const
Returns the entry in the archive with the given name.
A base class for entries in an KArchive.
mode_t permissions() const
The permissions and mode flags as returned by the stat() function in st_mode.
QString user() const
User who created the file.
virtual bool isDirectory() const
Checks whether the entry is a directory.
QDateTime date() const
Creation date of the file.
QString group() const
Group of the user who created the file.
QString name() const
Name of the file without path.
QString symLinkTarget() const
Symlink if there is one.
virtual bool isFile() const
Checks whether the entry is a file.
Represents a file entry in a KArchive.
qint64 size() const
Size of the data.
qint64 position() const
Position of the data in the [uncompressed] archive.
QIODevice * device() const
The underlying device.
virtual bool close()
Closes the archive.
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
KArchive(const QString &fileName)
Base constructor (protected since this is a pure virtual class).
const KArchiveDirectory * directory() const
If an archive is opened for reading, then the contents of the archive can be accessed via this functi...
KArchiveDirectory * findOrCreate(const QString &path)
Ensures that path exists, create otherwise.
QIODevice::OpenMode mode() const
Returns the mode in which the archive was opened.
QString fileName() const
The name of the archive file, as passed to the constructor that takes a fileName, or an empty string ...
bool isOpen() const
Checks whether the archive is open.
void setErrorString(const QString &errorStr)
Sets error description.
A class for reading and writing compressed data onto a device (e.g.
static KFilterBase * filterForCompressionType(CompressionType type)
Call this to create the appropriate filter for the CompressionType named type.
void close() override
Close after reading or writing.
bool open(QIODevice::OpenMode mode) override
Open for reading or writing.
This is the base class for compression filters such as gzip and bzip2.
Q_SCRIPTABLE Q_NOREPLY void start()
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
KIOCORE_EXPORT SimpleJob * symlink(const QString &target, const QUrl &dest, JobFlags flags=DefaultFlags)
QString normalize(QStringView str)
QString path(const QString &relativePath)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QString dir(const QString &fileClass)
QString name(StandardAction id)
const QList< QKeySequence > & end()
const QByteArray & data() const const
QByteArray & append(QByteArrayView data)
const char * constData() const const
bool isEmpty() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
void resize(qsizetype newSize, char c)
qsizetype size() const const
qint64 toSecsSinceEpoch() const const
QString cleanPath(const QString &path)
QString decodeName(const QByteArray &localFileName)
QByteArray encodeName(const QString &fileName)
QString completeBaseName() const const
QByteArray read(qint64 maxSize)
virtual bool seek(qint64 pos)
qint64 write(const QByteArray &data)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
QList< T > & fill(parameter_type value, qsizetype size)
bool isEmpty() const const
void reserve(qsizetype size)
qsizetype size() const const
QString arg(Args &&... args) const const
const QChar at(qsizetype position) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
QString left(qsizetype n) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
qsizetype size() const const
QByteArray toLatin1() const const
QByteArray toUtf8() const const
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)