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 return stream[pos++];
1294 while (range < kTopValue) {
1295 code = (code << 8) | readByte();
1300 quint32 getThreshold(quint32 total)
1302 return (code) / (range /= total);
1305 void decode(quint32
start, quint32 size)
1307 code -=
start * range;
1312 quint32 decodeDirectBits(
int numTotalBits)
1317 for (
int i = numTotalBits; i != 0; i--) {
1319 quint32 t = (c - r) >> 31;
1321 result = (result << 1) | (1 - t);
1323 if (r < kTopValue) {
1324 c = (c << 8) | readByte();
1333 quint32 DecodeBit(quint32 size0, quint32 numTotalBits)
1335 quint32 newBound = (range >> numTotalBits) * size0;
1337 if (code < newBound) {
1350const int kNumBitModelTotalBits = 11;
1351const quint32 kBitModelTotal = (1 << kNumBitModelTotalBits);
1353template<
int numMoveBits>
1358 void updateModel(quint32 symbol)
1361 prob += (kBitModelTotal - prob) >> numMoveBits;
1363 prob -= (prob) >> numMoveBits;
1369 prob = kBitModelTotal / 2;
1373template<
int numMoveBits>
1374class CBitDecoder :
public CBitModel<numMoveBits>
1377 quint32 decode(RangeDecoder *decoder)
1379 quint32 newBound = (decoder->range >> kNumBitModelTotalBits) * this->prob;
1380 if (decoder->code < newBound) {
1381 decoder->range = newBound;
1382 this->prob += (kBitModelTotal - this->prob) >> numMoveBits;
1383 if (decoder->range < kTopValue) {
1384 decoder->code = (decoder->code << 8) | decoder->readByte();
1385 decoder->range <<= 8;
1389 decoder->range -= newBound;
1390 decoder->code -= newBound;
1391 this->prob -= (this->prob) >> numMoveBits;
1392 if (decoder->range < kTopValue) {
1393 decoder->code = (decoder->code << 8) | decoder->readByte();
1394 decoder->range <<= 8;
1401inline bool isJcc(
unsigned char b0,
unsigned char b1)
1403 return (b0 == 0x0F && (b1 & 0xF0) == 0x80);
1405inline bool isJ(
unsigned char b0,
unsigned char b1)
1407 return ((b1 & 0xFE) == 0xE8 || isJcc(b0, b1));
1409inline unsigned getIndex(
unsigned char b0,
unsigned char b1)
1411 return ((b1 == 0xE8) ? b0 : ((b1 == 0xE9) ? 256 : 257));
1414const int kNumMoveBits = 5;
1418 unsigned char prevByte = 0;
1420 int mainStreamPos = 0;
1421 int callStreamPos = 0;
1422 int jumpStreamPos = 0;
1424 RangeDecoder rangeDecoder(rangeBuffer);
1428 for (
int i = 0; i < 256 + 2; i++) {
1429 statusDecoder[i].init();
1434 unsigned char b = 0;
1435 const quint32 kBurstSize = (1 << 18);
1436 for (i = 0; i < kBurstSize; i++) {
1437 if (mainStreamPos == mainStream.
size()) {
1441 b = mainStream[mainStreamPos++];
1444 if (isJ(prevByte, b)) {
1450 if (i == kBurstSize) {
1454 unsigned index = getIndex(prevByte, b);
1455 if (statusDecoder[index].decode(&rangeDecoder) == 1) {
1457 if (callStreamPos + 4 > callStream.
size()) {
1461 if (jumpStreamPos + 4 > jumpStream.
size()) {
1466 for (
int i = 0; i < 4; i++) {
1469 b0 = callStream[callStreamPos++];
1471 b0 = jumpStream[jumpStreamPos++];
1474 src |= ((quint32)b0);
1477 quint32 dest = src - (quint32(outStream.
size()) + 4);
1478 outStream.
append((
unsigned char)(dest));
1479 outStream.
append((
unsigned char)(dest >> 8));
1480 outStream.
append((
unsigned char)(dest >> 16));
1481 outStream.
append((
unsigned char)(dest >> 24));
1482 prevByte = (
unsigned char)(dest >> 24);
1489QByteArray K7Zip::K7ZipPrivate::readAndDecodePackedStreams(
bool readMainStreamInfo)
1495 if (readMainStreamInfo) {
1496 readMainStreamsInfo();
1501 quint64 startPos = 32 + packPos;
1502 for (
int i = 0; i < folders.
size(); i++) {
1503 const Folder *folder = folders.
at(i);
1504 quint64 unpackSize64 = folder->getUnpackSize();
1505 size_t unpackSize = (size_t)unpackSize64;
1506 if (unpackSize != unpackSize64) {
1507 qCDebug(KArchiveLog) <<
"unsupported";
1508 return inflatedData;
1512 quint32 mainCoderIndex = 0;
1514 int outStreamIndex = 0;
1515 for (
int j = 0; j < folder->folderInfos.
size(); j++) {
1516 const Folder::FolderInfo *info = folder->folderInfos[j];
1517 for (
int k = 0; k < info->numOutStreams; k++, outStreamIndex++) {
1518 if (folder->findBindPairForOutStream(outStreamIndex) < 0) {
1519 outStreamIndexed.
append(outStreamIndex);
1526 if (!outStreamIndexed.
isEmpty()) {
1527 folder->findOutStream(outStreamIndexed[0], mainCoderIndex, temp);
1530 quint32 startInIndex = folder->getCoderInStreamIndex(mainCoderIndex);
1531 quint32 startOutIndex = folder->getCoderOutStreamIndex(mainCoderIndex);
1533 Folder::FolderInfo *mainCoder = folder->folderInfos[mainCoderIndex];
1537 seqInStreams.
reserve(mainCoder->numInStreams);
1538 coderIndexes.
reserve(mainCoder->numInStreams);
1539 for (
int j = 0; j < (int)mainCoder->numInStreams; j++) {
1542 getInStream(folder, startInIndex + j, seqInStream, coderIndex);
1543 seqInStreams.
append(seqInStream);
1544 coderIndexes.
append(coderIndex);
1548 seqOutStreams.
reserve(mainCoder->numOutStreams);
1549 for (
int j = 0; j < (int)mainCoder->numOutStreams; j++) {
1551 getOutStream(folder, startOutIndex + j, seqOutStream);
1552 seqOutStreams.
append(seqOutStream);
1556 for (
int j = 0; j < (int)mainCoder->numInStreams; j++) {
1557 int size = packSizes[j + i];
1558 std::unique_ptr<char[]> encodedBuffer(
new char[size]);
1560 dev->
seek(startPos);
1561 quint64 n = dev->
read(encodedBuffer.get(), size);
1562 if (n != (quint64)size) {
1563 qCDebug(KArchiveLog) <<
"Failed read next size, should read " << size <<
", read " << n;
1564 return inflatedData;
1566 QByteArray deflatedData(encodedBuffer.get(), size);
1567 datas.
append(deflatedData);
1575 for (
int j = 0; j < seqInStreams.
size(); ++j) {
1576 Folder::FolderInfo *coder =
nullptr;
1577 if ((quint32)j != mainCoderIndex) {
1578 coder = folder->folderInfos[coderIndexes[j]];
1580 coder = folder->folderInfos[mainCoderIndex];
1583 deflatedData = datas[seqInStreams[j]];
1587 switch (coder->methodID) {
1591 qCDebug(KArchiveLog) <<
"filter not found";
1599 qCDebug(KArchiveLog) <<
"filter not found";
1615 if (coder->properties.
size() >= 1) {
1624 qCDebug(KArchiveLog) <<
"filter not found";
1630 QByteArray bcj2 = decodeBCJ2(inflatedDatas[0], inflatedDatas[1], inflatedDatas[2], deflatedData);
1631 inflatedDatas.
clear();
1632 inflatedDatas.
append(bcj2);
1638 qCDebug(KArchiveLog) <<
"filter not found";
1645 if (coder->methodID == k_BCJ2) {
1657 outBuffer.
resize(unpackSize);
1661 while (result != KFilterBase::End && result != KFilterBase::Error && !
filter->inBufferEmpty()) {
1663 result =
filter->uncompress();
1664 if (result == KFilterBase::Error) {
1665 qCDebug(KArchiveLog) <<
" decode error";
1670 int uncompressedBytes = outBuffer.
size() -
filter->outBufferAvailable();
1673 inflatedDataTmp.
append(outBuffer.
data(), uncompressedBytes);
1675 if (result == KFilterBase::End) {
1681 if (result != KFilterBase::End && !
filter->inBufferEmpty()) {
1682 qCDebug(KArchiveLog) <<
"decode failed result" << result;
1691 inflatedDatas.
append(inflatedDataTmp);
1695 for (
const QByteArray &data :
std::as_const(inflatedDatas)) {
1699 inflatedDatas.
clear();
1701 if (folder->unpackCRCDefined) {
1702 if ((
size_t)inflated.
size() < unpackSize) {
1703 qCDebug(KArchiveLog) <<
"wrong crc size data";
1706 quint32 crc = crc32(0, (Bytef *)(inflated.
data()), unpackSize);
1707 if (crc != folder->unpackCRC) {
1708 qCDebug(KArchiveLog) <<
"wrong crc";
1713 inflatedData.
append(inflated);
1716 return inflatedData;
1725 for (; it != l.
end(); ++it) {
1728 FileInfo *fileInfo =
new FileInfo;
1729 fileInfo->attribDefined =
true;
1731 fileInfo->path =
path + entry->
name();
1732 mTimesDefined.
append(
true);
1736 const K7ZipFileEntry *fileEntry =
static_cast<const K7ZipFileEntry *
>(entry);
1738 fileInfo->attributes = FILE_ATTRIBUTE_ARCHIVE;
1739 fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->
permissions() & 0xFFFF) << 16);
1740 fileInfo->size = fileEntry->
size();
1742 if (fileInfo->size > 0) {
1743 fileInfo->hasStream =
true;
1745 unpackSizes.
append(fileInfo->size);
1746 }
else if (!symLink.
isEmpty()) {
1747 fileInfo->hasStream =
true;
1751 fileInfos.
append(fileInfo);
1753 fileInfo->attributes = FILE_ATTRIBUTE_DIRECTORY;
1754 fileInfo->attributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((entry->
permissions() & 0xFFFF) << 16);
1755 fileInfo->isDir =
true;
1756 fileInfos.
append(fileInfo);
1762void K7Zip::K7ZipPrivate::writeByte(
unsigned char b)
1768void K7Zip::K7ZipPrivate::writeNumber(quint64 value)
1773 for (i = 0; i < 8; i++) {
1774 if (value < ((quint64(1) << (7 * (i + 1))))) {
1775 firstByte |= (int)(value >> (8 * i));
1781 writeByte(firstByte);
1782 for (; i > 0; i--) {
1783 writeByte((
int)value);
1788void K7Zip::K7ZipPrivate::writeBoolVector(
const QList<bool> &boolVector)
1792 for (
int i = 0; i < boolVector.
size(); i++) {
1793 if (boolVector[i]) {
1808void K7Zip::K7ZipPrivate::writeUInt32(quint32 value)
1810 for (
int i = 0; i < 4; i++) {
1811 writeByte((
unsigned char)value);
1816void K7Zip::K7ZipPrivate::writeUInt64(quint64 value)
1818 for (
int i = 0; i < 8; i++) {
1819 writeByte((
unsigned char)value);
1824void K7Zip::K7ZipPrivate::writeAlignedBoolHeader(
const QList<bool> &v,
int numDefined,
int type,
unsigned itemSize)
1826 const unsigned bvSize = (numDefined == v.
size()) ? 0 : ((unsigned)v.size() + 7) / 8;
1827 const quint64 dataSize = (quint64)numDefined * itemSize + bvSize + 2;
1831 writeNumber(dataSize);
1832 if (numDefined == v.
size()) {
1845 for (
int i = 0; i < defined.
size(); i++) {
1851 if (numDefined == 0) {
1855 writeAlignedBoolHeader(defined, numDefined, type, 8);
1857 for (
int i = 0; i < defined.
size(); i++) {
1868 for (i = 0; i < digestsDefined.
size(); i++) {
1869 if (digestsDefined[i]) {
1874 if (numDefined == 0) {
1879 if (numDefined == digestsDefined.
size()) {
1883 writeBoolVector(digestsDefined);
1886 for (i = 0; i < digests.
size(); i++) {
1887 if (digestsDefined[i]) {
1888 writeUInt32(digests[i]);
1898 writeByte(kPackInfo);
1899 writeNumber(dataOffset);
1900 writeNumber(packedSizes.
size());
1903 for (
int i = 0; i < packedSizes.
size(); i++) {
1904 writeNumber(packedSizes[i]);
1907 writeHashDigests(packedCRCsDefined, packedCRCs);
1912void K7Zip::K7ZipPrivate::writeFolder(
const Folder *folder)
1914 writeNumber(folder->folderInfos.
size());
1915 for (
int i = 0; i < folder->folderInfos.
size(); i++) {
1916 const Folder::FolderInfo *info = folder->folderInfos.
at(i);
1918 size_t propsSize = info->properties.
size();
1920 quint64
id = info->methodID;
1922 for (idSize = 1; idSize <
sizeof(id); idSize++) {
1923 if ((
id >> (8 * idSize)) == 0) {
1929 for (
int t = idSize - 1; t >= 0; t--,
id >>= 8) {
1930 longID[t] = (int)(
id & 0xFF);
1934 b = (int)(idSize & 0xF);
1935 bool isComplex = !info->isSimpleCoder();
1936 b |= (isComplex ? 0x10 : 0);
1937 b |= ((propsSize != 0) ? 0x20 : 0);
1940 for (
size_t j = 0; j < idSize; ++j) {
1941 writeByte(longID[j]);
1945 writeNumber(info->numInStreams);
1946 writeNumber(info->numOutStreams);
1949 if (propsSize == 0) {
1953 writeNumber(propsSize);
1954 for (
size_t j = 0; j < propsSize; ++j) {
1955 writeByte(info->properties[j]);
1960 for (
int i = 0; i < folder->inIndexes.
size(); i++) {
1961 writeNumber(folder->inIndexes[i]);
1962 writeNumber(folder->outIndexes[i]);
1965 if (folder->packedStreams.
size() > 1) {
1966 for (
int i = 0; i < folder->packedStreams.
size(); i++) {
1967 writeNumber(folder->packedStreams[i]);
1972void K7Zip::K7ZipPrivate::writeUnpackInfo(
const QList<Folder *> &folderItems)
1978 writeByte(kUnpackInfo);
1981 writeNumber(folderItems.
size());
1984 for (
int i = 0; i < folderItems.
size(); i++) {
1985 writeFolder(folderItems[i]);
1989 writeByte(kCodersUnpackSize);
1991 for (i = 0; i < folderItems.
size(); i++) {
1992 const Folder *folder = folderItems[i];
1993 for (
int j = 0; j < folder->unpackSizes.
size(); j++) {
1994 writeNumber(folder->unpackSizes.
at(j));
2002 for (i = 0; i < folderItems.
size(); i++) {
2003 const Folder *folder = folderItems[i];
2004 unpackCRCsDefined.
append(folder->unpackCRCDefined);
2005 unpackCRCs.
append(folder->unpackCRC);
2007 writeHashDigests(unpackCRCsDefined, unpackCRCs);
2014 writeByte(kSubStreamsInfo);
2016 for (
int i = 0; i < numUnpackStreamsInFolders.
size(); i++) {
2017 if (numUnpackStreamsInFolders.
at(i) != 1) {
2018 writeByte(kNumUnpackStream);
2019 for (
int j = 0; j < numUnpackStreamsInFolders.
size(); j++) {
2020 writeNumber(numUnpackStreamsInFolders.
at(j));
2026 bool needFlag =
true;
2028 for (
int i = 0; i < numUnpackStreamsInFolders.
size(); i++) {
2029 for (quint32 j = 0; j < numUnpackStreamsInFolders.
at(i); j++) {
2030 if (j + 1 != numUnpackStreamsInFolders.
at(i)) {
2035 writeNumber(unpackSizes[index]);
2044 int digestIndex = 0;
2045 for (
int i = 0; i < folders.
size(); i++) {
2046 int numSubStreams = (int)numUnpackStreamsInFolders.
at(i);
2047 if (numSubStreams == 1 && folders.
at(i)->unpackCRCDefined) {
2050 for (
int j = 0; j < numSubStreams; j++, digestIndex++) {
2051 digestsDefined2.
append(digestsDefined[digestIndex]);
2052 digests2.
append(digests[digestIndex]);
2056 writeHashDigests(digestsDefined2, digests2);
2062 Folder *folder =
new Folder;
2063 folder->unpackCRCDefined =
true;
2064 folder->unpackCRC = crc32(0, (Bytef *)(header.
data()), header.
size());
2067 Folder::FolderInfo *info =
new Folder::FolderInfo();
2068 info->numInStreams = 1;
2069 info->numOutStreams = 1;
2070 info->methodID = k_LZMA2;
2072 quint32 dictSize = header.
size();
2073 const quint32 kMinReduceSize = (1 << 16);
2074 if (dictSize < kMinReduceSize) {
2075 dictSize = kMinReduceSize;
2079 for (dict = 0; dict < 40; dict++) {
2080 if (dictSize <= lzma2_dic_size_from_prop(dict)) {
2085 info->properties.
append(dict);
2086 folder->folderInfos.
append(info);
2103 const int ret = flt.write(header);
2104 if (ret != header.
size()) {
2105 qCDebug(KArchiveLog) <<
"write error write " << ret <<
"expected" << header.
size();
2110 encodedData = inBuffer.
data();
2117void K7Zip::K7ZipPrivate::writeHeader(quint64 &headerOffset)
2119 quint64 packedSize = 0;
2120 for (
int i = 0; i < packSizes.
size(); ++i) {
2121 packedSize += packSizes[i];
2124 headerOffset = packedSize;
2131 writeByte(kMainStreamsInfo);
2132 writePackInfo(0, packSizes, packCRCsDefined, packCRCs);
2134 writeUnpackInfo(folders);
2139 for (
int i = 0; i < fileInfos.
size(); i++) {
2140 const FileInfo *file = fileInfos.
at(i);
2141 if (!file->hasStream) {
2144 unpackFileSizes.
append(file->size);
2145 digestsDefined.
append(file->crcDefined);
2146 digests.
append(file->crc);
2149 writeSubStreamsInfo(unpackSizes, digestsDefined, digests);
2158 writeByte(kFilesInfo);
2159 writeNumber(fileInfos.
size());
2164 int numEmptyStreams = 0;
2165 for (
int i = 0; i < fileInfos.
size(); i++) {
2166 if (fileInfos.
at(i)->hasStream) {
2167 emptyStreamVector.
append(
false);
2169 emptyStreamVector.
append(
true);
2174 if (numEmptyStreams > 0) {
2175 writeByte(kEmptyStream);
2176 writeNumber(((
unsigned)emptyStreamVector.
size() + 7) / 8);
2177 writeBoolVector(emptyStreamVector);
2181 int numEmptyFiles = 0;
2182 int numAntiItems = 0;
2183 for (
int i = 0; i < fileInfos.
size(); i++) {
2184 const FileInfo *file = fileInfos.
at(i);
2185 if (!file->hasStream) {
2186 emptyFileVector.
append(!file->isDir);
2189 bool isAnti = (i < this->isAnti.size() && this->isAnti[i]);
2190 antiVector.
append(isAnti);
2198 if (numEmptyFiles > 0) {
2199 writeByte(kEmptyFile);
2200 writeNumber(((
unsigned)emptyFileVector.
size() + 7) / 8);
2201 writeBoolVector(emptyFileVector);
2204 if (numAntiItems > 0) {
2206 writeNumber(((
unsigned)antiVector.
size() + 7) / 8);
2207 writeBoolVector(antiVector);
2216 size_t namesDataSize = 0;
2217 for (
int i = 0; i < fileInfos.
size(); i++) {
2225 if (numDefined > 0) {
2230 writeNumber(namesDataSize);
2232 for (
int i = 0; i < fileInfos.
size(); i++) {
2236 writeByte((
unsigned char)c);
2237 writeByte((
unsigned char)(c >> 8));
2246 writeUInt64DefVector(mTimes, mTimesDefined, kMTime);
2248 writeUInt64DefVector(startPositions, startPositionsDefined, kStartPos);
2255 for (
int i = 0; i < fileInfos.
size(); i++) {
2256 bool defined = fileInfos.
at(i)->attribDefined;
2257 boolVector.
append(defined);
2263 if (numDefined > 0) {
2264 writeAlignedBoolHeader(boolVector, numDefined, kAttributes, 4);
2265 for (
int i = 0; i < fileInfos.
size(); i++) {
2266 const FileInfo *file = fileInfos.
at(i);
2267 if (file->attribDefined) {
2268 writeUInt32(file->attributes);
2278static void setUInt32(
unsigned char *p, quint32 d)
2280 for (
int i = 0; i < 4; i++, d >>= 8) {
2285static void setUInt64(
unsigned char *p, quint64 d)
2287 for (
int i = 0; i < 8; i++, d >>= 8) {
2288 p[i] = (
unsigned char)d;
2292void K7Zip::K7ZipPrivate::writeStartHeader(
const quint64 nextHeaderSize,
const quint32 nextHeaderCRC,
const quint64 nextHeaderOffset)
2294 unsigned char buf[24];
2295 setUInt64(buf + 4, nextHeaderOffset);
2296 setUInt64(buf + 12, nextHeaderSize);
2297 setUInt32(buf + 20, nextHeaderCRC);
2298 setUInt32(buf, crc32(0, (Bytef *)(buf + 4), 20));
2302void K7Zip::K7ZipPrivate::writeSignature()
2304 unsigned char buf[8];
2305 memcpy(buf, k7zip_signature, 6);
2326 qint64 n = dev->
read(header, 32);
2332 for (
int i = 0; i < 6; ++i) {
2333 if ((
unsigned char)header[i] != k7zip_signature[i]) {
2340 int major = header[6];
2341 int minor = header[7];
2349 quint32 startHeaderCRC = GetUi32(header, 8);
2350 quint64 nextHeaderOffset = GetUi64(header, 12);
2351 quint64 nextHeaderSize = GetUi64(header, 20);
2352 quint32 nextHeaderCRC = GetUi32(header, 28);
2354 quint32 crc = crc32(0, (Bytef *)(header + 0xC), 20);
2356 if (crc != startHeaderCRC) {
2361 if (nextHeaderSize == 0) {
2365 if (nextHeaderSize > (quint64)0xFFFFFFFF) {
2370 if ((qint64)nextHeaderOffset < 0) {
2375 dev->
seek(nextHeaderOffset + 32);
2378 inBuffer.
resize(nextHeaderSize);
2381 if (n != (qint64)nextHeaderSize) {
2382 setErrorString(tr(
"Failed read next header size; should read %1, read %2").arg(nextHeaderSize).arg(n));
2385 d->buffer = inBuffer.
data();
2386 d->end = nextHeaderSize;
2388 d->headerSize = 32 + nextHeaderSize;
2391 crc = crc32(0, (Bytef *)(d->buffer), (quint32)nextHeaderSize);
2393 if (crc != nextHeaderCRC) {
2398 int type = d->readByte();
2400 if (type != kHeader) {
2401 if (type != kEncodedHeader) {
2406 decodedData = d->readAndDecodePackedStreams();
2408 int external = d->readByte();
2409 if (external != 0) {
2410 int dataIndex = (int)d->readNumber();
2411 if (dataIndex < 0) {
2416 d->end = decodedData.
size();
2419 type = d->readByte();
2420 if (type != kHeader) {
2427 type = d->readByte();
2429 if (type == kArchiveProperties) {
2435 if (type == kAdditionalStreamsInfo) {
2441 if (type == kMainStreamsInfo) {
2442 if (!d->readMainStreamsInfo()) {
2443 setErrorString(tr(
"Error while reading main streams information"));
2446 type = d->readByte();
2448 for (
int i = 0; i < d->folders.size(); ++i) {
2449 Folder *folder = d->folders.at(i);
2450 d->unpackSizes.append(folder->getUnpackSize());
2451 d->digestsDefined.append(folder->unpackCRCDefined);
2452 d->digests.append(folder->unpackCRC);
2460 if (type != kFilesInfo) {
2466 int numFiles = d->readNumber();
2467 for (
int i = 0; i < numFiles; ++i) {
2468 d->fileInfos.append(
new FileInfo);
2474 int numEmptyStreams = 0;
2477 quint64 type = d->readByte();
2482 quint64 size = d->readNumber();
2484 size_t ppp = d->pos;
2486 bool addPropIdToList =
true;
2487 bool isKnownType =
true;
2489 if (type > ((quint32)1 << 30)) {
2490 isKnownType =
false;
2493 case kEmptyStream: {
2494 d->readBoolVector(numFiles, emptyStreamVector);
2495 for (
int i = 0; i < emptyStreamVector.
size(); ++i) {
2496 if (emptyStreamVector[i]) {
2504 d->readBoolVector(numEmptyStreams, emptyFileVector);
2507 d->readBoolVector(numEmptyStreams, antiFileVector);
2510 if (!d->readUInt64DefVector(numFiles, d->cTimes, d->cTimesDefined)) {
2515 if (!d->readUInt64DefVector(numFiles, d->aTimes, d->aTimesDefined)) {
2520 if (!d->readUInt64DefVector(numFiles, d->mTimes, d->mTimesDefined)) {
2526 int external = d->readByte();
2527 if (external != 0) {
2528 int dataIndex = d->readNumber();
2529 if (dataIndex < 0 /*|| dataIndex >= dataVector->Size()*/) {
2530 qCDebug(KArchiveLog) <<
"wrong data index";
2537 for (
int i = 0; i < numFiles; i++) {
2538 name = d->readString();
2539 d->fileInfos.at(i)->path = name;
2545 d->readBoolVector2(numFiles, attributesAreDefined);
2546 int external = d->readByte();
2547 if (external != 0) {
2548 int dataIndex = d->readNumber();
2549 if (dataIndex < 0) {
2550 qCDebug(KArchiveLog) <<
"wrong data index";
2556 for (
int i = 0; i < numFiles; i++) {
2557 FileInfo *fileInfo = d->fileInfos.at(i);
2558 fileInfo->attribDefined = attributesAreDefined[i];
2559 if (fileInfo->attribDefined) {
2560 fileInfo->attributes = d->readUInt32();
2566 if (!d->readUInt64DefVector(numFiles, d->startPositions, d->startPositionsDefined)) {
2572 for (quint64 i = 0; i < size; i++) {
2573 if (d->readByte() != 0) {
2578 addPropIdToList =
false;
2582 addPropIdToList = isKnownType =
false;
2587 if (addPropIdToList) {
2588 d->fileInfoPopIDs.append(type);
2591 d->skipData(d->readNumber());
2594 bool checkRecordsSize = (major > 0 || minor > 2);
2595 if (checkRecordsSize && d->pos - ppp != size) {
2597 "(checkRecordsSize: %1, d->pos - ppp: %2, size: %3)")
2598 .arg(checkRecordsSize)
2605 int emptyFileIndex = 0;
2608 int numAntiItems = 0;
2610 if (emptyStreamVector.
isEmpty()) {
2611 emptyStreamVector.
fill(
false, numFiles);
2614 if (antiFileVector.
isEmpty()) {
2615 antiFileVector.
fill(
false, numEmptyStreams);
2617 if (emptyFileVector.
isEmpty()) {
2618 emptyFileVector.
fill(
false, numEmptyStreams);
2621 for (
int i = 0; i < numEmptyStreams; i++) {
2622 if (antiFileVector[i]) {
2627 d->outData = d->readAndDecodePackedStreams(
false);
2630 for (
int i = 0; i < numFiles; i++) {
2631 FileInfo *fileInfo = d->fileInfos.at(i);
2633 fileInfo->hasStream = !emptyStreamVector[i];
2634 if (fileInfo->hasStream) {
2635 fileInfo->isDir =
false;
2637 fileInfo->size = d->unpackSizes[sizeIndex];
2638 fileInfo->crc = d->digests[sizeIndex];
2639 fileInfo->crcDefined = d->digestsDefined[sizeIndex];
2642 fileInfo->isDir = !emptyFileVector[emptyFileIndex];
2643 isAnti = antiFileVector[emptyFileIndex];
2646 fileInfo->crcDefined =
false;
2648 if (numAntiItems != 0) {
2649 d->isAnti.append(isAnti);
2653 bool symlink =
false;
2654 if (fileInfo->attributes & FILE_ATTRIBUTE_UNIX_EXTENSION) {
2655 access = fileInfo->attributes >> 16;
2656 if ((access & QT_STAT_MASK) == QT_STAT_LNK) {
2660 if (fileInfo->isDir) {
2661 access = S_IFDIR | 0755;
2668 if (!fileInfo->isDir) {
2670 oldPos += fileInfo->size;
2677 entryName = fileInfo->path;
2679 entryName = fileInfo->path.
mid(index + 1);
2681 Q_ASSERT(!entryName.
isEmpty());
2684 if (d->mTimesDefined[i]) {
2685 mTime = KArchivePrivate::time_tToDateTime(toTimeT(d->mTimes[i]));
2687 mTime = KArchivePrivate::time_tToDateTime(time(
nullptr));
2690 if (fileInfo->isDir) {
2700 e =
new K7ZipFileEntry(
this,
2712 e =
new K7ZipFileEntry(
this, entryName, access, mTime,
rootDir()->user(),
rootDir()->group(), target, 0, 0,
nullptr);
2744 Folder *folder =
new Folder();
2746 folder->unpackSizes.
clear();
2747 folder->unpackSizes.
append(d->outData.size());
2749 Folder::FolderInfo *info =
new Folder::FolderInfo();
2751 info->numInStreams = 1;
2752 info->numOutStreams = 1;
2753 info->methodID = k_LZMA2;
2755 quint32 dictSize = d->outData.size();
2757 const quint32 kMinReduceSize = (1 << 16);
2758 if (dictSize < kMinReduceSize) {
2759 dictSize = kMinReduceSize;
2764 for (dict = 0; dict < 40; dict++) {
2765 if (dictSize <= lzma2_dic_size_from_prop(dict)) {
2769 info->properties.
append(dict);
2771 folder->folderInfos.
append(info);
2772 d->folders.append(folder);
2776 d->createItemsFromEntities(dir,
QString(), data);
2779 folder->unpackCRCDefined =
true;
2780 folder->unpackCRC = crc32(0, (Bytef *)(d->outData.data()), d->outData.size());
2784 if (!d->outData.isEmpty()) {
2793 static_cast<KXzFilter *
>(filter)->init(
QIODevice::WriteOnly, KXzFilter::LZMA2, info->properties);
2795 const int ret = flt.
write(d->outData);
2796 if (ret != d->outData.size()) {
2802 encodedData = inBuffer.
data();
2805 d->packSizes.append(encodedData.
size());
2807 int numUnpackStream = 0;
2808 for (
int i = 0; i < d->fileInfos.size(); ++i) {
2809 if (d->fileInfos.at(i)->hasStream) {
2813 d->numUnpackStreamsInFolders.append(numUnpackStream);
2815 quint64 headerOffset;
2816 d->writeHeader(headerOffset);
2823 encodedStream = d->encodeStream(packSizes, folders);
2833 d->writeByte(kEncodedHeader);
2836 d->writePackInfo(headerOffset, packSizes, emptyDefined, emptyCrcs);
2837 d->writeUnpackInfo(folders);
2839 for (
int i = 0; i < packSizes.
size(); i++) {
2840 headerOffset += packSizes.
at(i);
2842 qDeleteAll(folders);
2846 quint64 nextHeaderSize = d->header.size();
2847 quint32 nextHeaderCRC = crc32(0, (Bytef *)(d->header.data()), d->header.size());
2848 quint64 nextHeaderOffset = headerOffset;
2851 d->writeSignature();
2852 d->writeStartHeader(nextHeaderSize, nextHeaderCRC, nextHeaderOffset);
2855 device()->
write(d->header.data(), d->header.size());
2862 d->m_currentFile->setSize(size);
2863 d->m_currentFile =
nullptr;
2870 if (!d->m_currentFile) {
2875 if (d->m_currentFile->position() == d->outData.size()) {
2876 d->outData.append(data, size);
2878 d->outData.remove(d->m_currentFile->position(), d->m_currentFile->size());
2879 d->outData.insert(d->m_currentFile->position(), data, size);
2895 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2896 qCWarning(KArchiveLog) <<
"doPrepareWriting failed: !isOpen()";
2901 setErrorString(tr(
"Application error: attempted to write into non-writable 7-Zip file"));
2902 qCWarning(KArchiveLog) <<
"doPrepareWriting failed: !(mode() & QIODevice::WriteOnly)";
2922 new K7ZipFileEntry(
this,
fileName, perm, mtime, user, group,
QString() , d->outData.size(), 0 , d->outData);
2926 d->m_entryList << e;
2927 d->m_currentFile = e;
2945 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2946 qCWarning(KArchiveLog) <<
"doWriteDir failed: !isOpen()";
2967 dirName = name.
mid(i + 1);
2987 setErrorString(tr(
"Application error: 7-Zip file must be open before being written into"));
2988 qCWarning(KArchiveLog) <<
"doWriteSymLink failed: !isOpen()";
2993 setErrorString(tr(
"Application error: attempted to write into non-writable 7-Zip file"));
2994 qCWarning(KArchiveLog) <<
"doWriteSymLink failed: !(mode() & QIODevice::WriteOnly)";
3010 K7ZipFileEntry *e =
new K7ZipFileEntry(
this,
fileName, perm, mtime, user, group, target, 0, 0,
nullptr);
3011 d->outData.append(encodedTarget);
3017 d->m_entryList << e;
3022void K7Zip::virtual_hook(
int id,
void *data)
3024 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)
const QList< QKeySequence > & end()
QString name(StandardShortcut id)
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)