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, quint64 offset)
43 return QChar(
static_cast<unsigned char>(p[offset + 0])
44 | (
static_cast<unsigned char>(p[1]) << 8));
47static quint32 GetUi32(
const char *p, quint64 offset)
49 return (
static_cast<unsigned char>(p[offset + 0])
50 | (
static_cast<unsigned char>(p[offset + 1]) << 8)
51 | (
static_cast<unsigned char>(p[offset + 2]) << 16)
52 | (
static_cast<unsigned char>(p[offset + 3]) << 24));
55static quint64 GetUi64(
const char *p, quint64 offset)
57 return (GetUi32(p, offset)
58 | (
static_cast<quint64
>(GetUi32(p, offset + 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,
186 ~K7ZipFileEntry()
override;
204 QIODevice *createDevice()
const override;
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);
293 : unpackCRCDefined(false)
300 qDeleteAll(folderInfos);
303 Q_DISABLE_COPY(Folder)
305 quint64 getUnpackSize()
const
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;
420class Q_DECL_HIDDEN
K7Zip::K7ZipPrivate
423 K7ZipPrivate(
K7Zip *parent)
432 , m_currentFile(nullptr)
439 qDeleteAll(fileInfos);
462 quint64 numPackStreams;
479 K7ZipFileEntry *m_currentFile;
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();
521 void readBoolVector2(
int numItems,
QList<bool> &v);
522 void skipData(
int size);
523 bool findAttribute(
int attribute);
526 Folder *folderItem();
527 bool readMainStreamsInfo();
529 bool readUnpackInfo();
530 bool readSubStreamsInfo();
531 QByteArray readAndDecodePackedStreams(
bool readMainStreamInfo =
true);
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);
541 void writeAlignedBoolHeader(
const QList<bool> &v,
int numDefined,
int type,
unsigned itemSize);
543 void writeFolder(
const Folder *folder);
547 void writeHeader(quint64 &headerOffset);
548 void writeSignature();
549 void writeStartHeader(
const quint64 nextHeaderSize,
const quint32 nextHeaderCRC,
const quint64 nextHeaderOffset);
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) {
658 p += GetUi16(buf, 0);
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++) {
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()
749 Folder *folder =
new Folder;
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) {
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) {
953 Folder *folder = folders.
at(i);
954 int numOutStreams = folder->getNumOutStreams();
955 for (
int j = 0; j < numOutStreams; ++j) {
956 folder->unpackSizes.
append(readNumber());
961 int type = readByte();
968 readHashDigests(numFolders, crcsDefined, crcs);
969 for (
int i = 0; i < numFolders; i++) {
970 Folder *folder = folders.
at(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;
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);
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)
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);
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;
1421 unsigned char prevByte = 0;
1423 int mainStreamPos = 0;
1424 int callStreamPos = 0;
1425 int jumpStreamPos = 0;
1427 RangeDecoder rangeDecoder(rangeBuffer);
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()) {
1464 if (jumpStreamPos + 4 > jumpStream.
size()) {
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)
1498 if (readMainStreamInfo) {
1499 readMainStreamsInfo();
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;
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];
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);
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);
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]);
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);
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]];
1590 switch (coder->methodID) {
1594 qCDebug(KArchiveLog) <<
"filter not found";
1602 qCDebug(KArchiveLog) <<
"filter not found";
1618 if (coder->properties.
size() >= 1) {
1627 qCDebug(KArchiveLog) <<
"filter not found";
1633 QByteArray bcj2 = decodeBCJ2(inflatedDatas[0], inflatedDatas[1], inflatedDatas[2], deflatedData);
1634 inflatedDatas.
clear();
1635 inflatedDatas.
append(bcj2);
1641 qCDebug(KArchiveLog) <<
"filter not found";
1648 if (coder->methodID == k_BCJ2) {
1660 outBuffer.
resize(unpackSize);
1664 while (result != KFilterBase::End && result != KFilterBase::Error && !
filter->inBufferEmpty()) {
1666 result =
filter->uncompress();
1667 if (result == KFilterBase::Error) {
1668 qCDebug(KArchiveLog) <<
" decode error";
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;
1694 inflatedDatas.
append(inflatedDataTmp);
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";
1709 quint32 crc = crc32(0, (Bytef *)(inflated.
data()), unpackSize);
1710 if (crc != folder->unpackCRC) {
1711 qCDebug(KArchiveLog) <<
"wrong crc";
1716 inflatedData.
append(inflated);
1719 return inflatedData;
1728 for (; it != l.
end(); ++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);
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()) {
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++) {
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]);
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));
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);
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]);
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);
2065 Folder *folder =
new Folder;
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);
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);
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());
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);
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++) {
2228 if (numDefined > 0) {
2233 writeNumber(namesDataSize);
2235 for (
int i = 0; i < fileInfos.
size(); i++) {
2239 writeByte((
unsigned char)c);
2240 writeByte((
unsigned char)(c >> 8));
2249 writeUInt64DefVector(mTimes, mTimesDefined, kMTime);
2251 writeUInt64DefVector(startPositions, startPositionsDefined, kStartPos);
2258 for (
int i = 0; i < fileInfos.
size(); i++) {
2259 bool defined = fileInfos.
at(i)->attribDefined;
2260 boolVector.
append(defined);
2266 if (numDefined > 0) {
2267 writeAlignedBoolHeader(boolVector, numDefined, kAttributes, 4);
2268 for (
int i = 0; i < fileInfos.
size(); i++) {
2269 const FileInfo *file = fileInfos.
at(i);
2270 if (file->attribDefined) {
2271 writeUInt32(file->attributes);
2281static void setUInt32(
unsigned char *p, quint32 d)
2283 for (
int i = 0; i < 4; i++, d >>= 8) {
2288static void setUInt64(
unsigned char *p, quint64 d)
2290 for (
int i = 0; i < 8; i++, d >>= 8) {
2291 p[i] = (
unsigned char)d;
2295void K7Zip::K7ZipPrivate::writeStartHeader(
const quint64 nextHeaderSize,
const quint32 nextHeaderCRC,
const quint64 nextHeaderOffset)
2297 unsigned char buf[24];
2298 setUInt64(buf + 4, nextHeaderOffset);
2299 setUInt64(buf + 12, nextHeaderSize);
2300 setUInt32(buf + 20, nextHeaderCRC);
2301 setUInt32(buf, crc32(0, (Bytef *)(buf + 4), 20));
2305void K7Zip::K7ZipPrivate::writeSignature()
2307 unsigned char buf[8];
2308 memcpy(buf, k7zip_signature, 6);
2329 qint64 n = dev->
read(header, 32);
2335 for (
int i = 0; i < 6; ++i) {
2336 if ((
unsigned char)header[i] != k7zip_signature[i]) {
2343 int major = header[6];
2344 int minor = header[7];
2352 quint32 startHeaderCRC = GetUi32(header, 8);
2353 quint64 nextHeaderOffset = GetUi64(header, 12);
2354 quint64 nextHeaderSize = GetUi64(header, 20);
2355 quint32 nextHeaderCRC = GetUi32(header, 28);
2357 quint32 crc = crc32(0, (Bytef *)(header + 0xC), 20);
2359 if (crc != startHeaderCRC) {
2364 if (nextHeaderSize == 0) {
2368 if (nextHeaderSize > (quint64)0xFFFFFFFF) {
2373 if ((qint64)nextHeaderOffset < 0) {
2378 dev->
seek(nextHeaderOffset + 32);
2381 inBuffer.
resize(nextHeaderSize);
2384 if (n != (qint64)nextHeaderSize) {
2385 setErrorString(tr(
"Failed read next header size; should read %1, read %2").arg(nextHeaderSize).arg(n));
2388 d->buffer = inBuffer.
data();
2389 d->end = nextHeaderSize;
2391 d->headerSize = 32 + nextHeaderSize;
2394 crc = crc32(0, (Bytef *)(d->buffer), (quint32)nextHeaderSize);
2396 if (crc != nextHeaderCRC) {
2401 int type = d->readByte();
2403 if (type != kHeader) {
2404 if (type != kEncodedHeader) {
2409 decodedData = d->readAndDecodePackedStreams();
2411 int external = d->readByte();
2412 if (external != 0) {
2413 int dataIndex = (int)d->readNumber();
2414 if (dataIndex < 0) {
2419 d->end = decodedData.
size();
2422 type = d->readByte();
2423 if (type != kHeader) {
2430 type = d->readByte();
2432 if (type == kArchiveProperties) {
2438 if (type == kAdditionalStreamsInfo) {
2444 if (type == kMainStreamsInfo) {
2445 if (!d->readMainStreamsInfo()) {
2446 setErrorString(tr(
"Error while reading main streams information"));
2449 type = d->readByte();
2451 for (
int i = 0; i < d->folders.size(); ++i) {
2452 Folder *folder = d->folders.at(i);
2453 d->unpackSizes.append(folder->getUnpackSize());
2454 d->digestsDefined.append(folder->unpackCRCDefined);
2455 d->digests.append(folder->unpackCRC);
2463 if (type != kFilesInfo) {
2469 int numFiles = d->readNumber();
2470 for (
int i = 0; i < numFiles; ++i) {
2471 d->fileInfos.append(
new FileInfo);
2477 int numEmptyStreams = 0;
2480 quint64 type = d->readByte();
2485 quint64 size = d->readNumber();
2487 size_t ppp = d->pos;
2489 bool addPropIdToList =
true;
2490 bool isKnownType =
true;
2492 if (type > ((quint32)1 << 30)) {
2493 isKnownType =
false;
2496 case kEmptyStream: {
2497 d->readBoolVector(numFiles, emptyStreamVector);
2498 for (
int i = 0; i < emptyStreamVector.
size(); ++i) {
2499 if (emptyStreamVector[i]) {
2507 d->readBoolVector(numEmptyStreams, emptyFileVector);
2510 d->readBoolVector(numEmptyStreams, antiFileVector);
2513 if (!d->readUInt64DefVector(numFiles, d->cTimes, d->cTimesDefined)) {
2518 if (!d->readUInt64DefVector(numFiles, d->aTimes, d->aTimesDefined)) {
2523 if (!d->readUInt64DefVector(numFiles, d->mTimes, d->mTimesDefined)) {
2529 int external = d->readByte();
2530 if (external != 0) {
2531 int dataIndex = d->readNumber();
2532 if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
2533 qCDebug(KArchiveLog) <<
"wrong data index";
2540 for (
int i = 0; i < numFiles; i++) {
2541 name = d->readString();
2542 d->fileInfos.at(i)->path = name;
2548 d->readBoolVector2(numFiles, attributesAreDefined);
2549 int external = d->readByte();
2550 if (external != 0) {
2551 int dataIndex = d->readNumber();
2552 if (dataIndex < 0) {
2553 qCDebug(KArchiveLog) <<
"wrong data index";
2559 for (
int i = 0; i < numFiles; i++) {
2560 FileInfo *fileInfo = d->fileInfos.at(i);
2561 fileInfo->attribDefined = attributesAreDefined[i];
2562 if (fileInfo->attribDefined) {
2563 fileInfo->attributes = d->readUInt32();
2569 if (!d->readUInt64DefVector(numFiles, d->startPositions, d->startPositionsDefined)) {
2575 for (quint64 i = 0; i < size; i++) {
2576 if (d->readByte() != 0) {
2581 addPropIdToList =
false;
2585 addPropIdToList = isKnownType =
false;
2590 if (addPropIdToList) {
2591 d->fileInfoPopIDs.append(type);
2594 d->skipData(d->readNumber());
2597 bool checkRecordsSize = (major > 0 || minor > 2);
2598 if (checkRecordsSize && d->pos - ppp != size) {
2600 "(checkRecordsSize: %1, d->pos - ppp: %2, size: %3)")
2601 .arg(checkRecordsSize)
2608 int emptyFileIndex = 0;
2611 int numAntiItems = 0;
2613 if (emptyStreamVector.
isEmpty()) {
2614 emptyStreamVector.
fill(
false, numFiles);
2617 if (antiFileVector.
isEmpty()) {
2618 antiFileVector.
fill(
false, numEmptyStreams);
2620 if (emptyFileVector.
isEmpty()) {
2621 emptyFileVector.
fill(
false, numEmptyStreams);
2624 for (
int i = 0; i < numEmptyStreams; i++) {
2625 if (antiFileVector[i]) {
2630 d->outData = d->readAndDecodePackedStreams(
false);
2633 for (
int i = 0; i < numFiles; i++) {
2634 FileInfo *fileInfo = d->fileInfos.at(i);
2636 fileInfo->hasStream = !emptyStreamVector[i];
2637 if (fileInfo->hasStream) {
2638 fileInfo->isDir =
false;
2640 fileInfo->size = d->unpackSizes[sizeIndex];
2641 fileInfo->crc = d->digests[sizeIndex];
2642 fileInfo->crcDefined = d->digestsDefined[sizeIndex];
2645 fileInfo->isDir = !emptyFileVector[emptyFileIndex];
2646 isAnti = antiFileVector[emptyFileIndex];
2649 fileInfo->crcDefined =
false;
2651 if (numAntiItems != 0) {
2652 d->isAnti.append(isAnti);
2656 bool symlink =
false;
2657 if (fileInfo->attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {
2658 access = fileInfo->attributes >> 16;
2659 if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
2663 if (fileInfo->isDir) {
2664 access = S_IFDIR | 0755;
2671 if (!fileInfo->isDir) {
2673 oldPos += fileInfo->size;
2680 entryName = fileInfo->path;
2682 entryName = fileInfo->path.
mid(index + 1);
2684 Q_ASSERT(!entryName.
isEmpty());
2687 if (d->mTimesDefined.size() > i && d->mTimesDefined[i]) {
2688 mTime = KArchivePrivate::time_tToDateTime(toTimeT(d->mTimes[i]));
2690 mTime = KArchivePrivate::time_tToDateTime(time(
nullptr));
2693 if (fileInfo->isDir) {
2703 e =
new K7ZipFileEntry(
this,
2715 e =
new K7ZipFileEntry(
this, entryName, access, mTime,
rootDir()->user(),
rootDir()->group(), target, 0, 0,
nullptr);
2747 Folder *folder =
new Folder();
2749 folder->unpackSizes.
clear();
2750 folder->unpackSizes.
append(d->outData.size());
2752 Folder::FolderInfo *info =
new Folder::FolderInfo();
2754 info->numInStreams = 1;
2755 info->numOutStreams = 1;
2756 info->methodID = k_LZMA2;
2758 quint32 dictSize = d->outData.size();
2760 const quint32 kMinReduceSize = (1 << 16);
2761 if (dictSize < kMinReduceSize) {
2762 dictSize = kMinReduceSize;
2767 for (dict = 0; dict < 40; dict++) {
2768 if (dictSize <= lzma2_dic_size_from_prop(dict)) {
2772 info->properties.
append(dict);
2774 folder->folderInfos.
append(info);
2775 d->folders.append(folder);
2779 d->createItemsFromEntities(dir,
QString(), data);
2782 folder->unpackCRCDefined =
true;
2783 folder->unpackCRC = crc32(0, (Bytef *)(d->outData.data()), d->outData.size());
2787 if (!d->outData.isEmpty()) {
2798 static_cast<KXzFilter *
>(filter)->init(
QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
2800 const int ret = flt.
write(d->outData);
2801 if (ret != d->outData.size()) {
2807 encodedData = inBuffer.
data();
2810 d->packSizes.append(encodedData.
size());
2812 int numUnpackStream = 0;
2813 for (
int i = 0; i < d->fileInfos.size(); ++i) {
2814 if (d->fileInfos.at(i)->hasStream) {
2818 d->numUnpackStreamsInFolders.append(numUnpackStream);
2820 quint64 headerOffset;
2821 d->writeHeader(headerOffset);
2828 encodedStream = d->encodeStream(packSizes, folders);
2838 d->writeByte(kEncodedHeader);
2841 d->writePackInfo(headerOffset, packSizes, emptyDefined, emptyCrcs);
2842 d->writeUnpackInfo(folders);
2844 for (
int i = 0; i < packSizes.
size(); i++) {
2845 headerOffset += packSizes.
at(i);
2847 qDeleteAll(folders);
2851 quint64 nextHeaderSize = d->header.size();
2852 quint32 nextHeaderCRC = crc32(0, (Bytef *)(d->header.data()), d->header.size());
2853 quint64 nextHeaderOffset = headerOffset;
2856 d->writeSignature();
2857 d->writeStartHeader(nextHeaderSize, nextHeaderCRC, nextHeaderOffset);
2860 device()->
write(d->header.data(), d->header.size());
2867 d->m_currentFile->setSize(size);
2868 d->m_currentFile =
nullptr;
2875 if (!d->m_currentFile) {
2880 if (d->m_currentFile->position() == d->outData.size()) {
2881 d->outData.append(data, size);
2883 d->outData.remove(d->m_currentFile->position(), d->m_currentFile->size());
2884 d->outData.insert(d->m_currentFile->position(), data, size);
2900 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2901 qCWarning(KArchiveLog) <<
"doPrepareWriting failed: !isOpen()";
2906 setErrorString(tr(
"Application error: attempted to write into non-writable 7-Zip file"));
2907 qCWarning(KArchiveLog) <<
"doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
2927 new K7ZipFileEntry(
this,
fileName, perm, mtime, user, group,
QString() , d->outData.size(), 0 , d->outData);
2931 d->m_entryList << e;
2932 d->m_currentFile = e;
2950 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2951 qCWarning(KArchiveLog) <<
"doWriteDir failed: !isOpen()";
2972 dirName = name.
mid(i + 1);
2992 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2993 qCWarning(KArchiveLog) <<
"doWriteSymLink failed: !isOpen()";
2998 setErrorString(tr(
"Application error: attempted to write into non-writable 7-Zip file"));
2999 qCWarning(KArchiveLog) <<
"doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
3015 K7ZipFileEntry *e =
new K7ZipFileEntry(
this,
fileName, perm, mtime, user, group, target, 0, 0,
nullptr);
3016 d->outData.append(encodedTarget);
3022 d->m_entryList << e;
3027void K7Zip::virtual_hook(
int id,
void *data)
3029 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.
KArchive is a base class for reading and writing archives.
QIODevice * device() const
The underlying device.
virtual bool close()
Closes the archive.
virtual KArchiveDirectory * rootDir()
Retrieves or create the root directory.
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()
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT SimpleJob * symlink(const QString &target, const QUrl &dest, JobFlags flags=DefaultFlags)
QString normalize(QStringView str)
QString path(const QString &relativePath)
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)
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
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)