@zip.js/zip.js 2.8.53 → 2.8.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/deno.json +2 -1
- package/dist/zip-core-external.js +691 -482
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +698 -481
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +729 -511
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +691 -496
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +729 -511
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +743 -512
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +742 -511
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +700 -483
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +700 -483
- package/dist/zip-native.min.js +1 -1
- package/dist/zip-web-worker-native.js +1 -1
- package/dist/zip-web-worker.js +1 -1
- package/dist/zip.js +699 -482
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +1 -0
- package/index-native.cjs +743 -512
- package/index-native.min.js +1 -1
- package/index.cjs +742 -511
- package/index.d.cts +398 -42
- package/index.d.ts +398 -42
- package/index.min.js +1 -1
- package/lib/core/configuration.js +62 -21
- package/lib/core/constants.js +11 -1
- package/lib/core/io.js +33 -27
- package/lib/core/options.js +44 -2
- package/lib/core/streams/aes-crypto-stream.js +12 -12
- package/lib/core/util/decode-text.js +11 -2
- package/lib/core/web-worker-base.js +3 -2
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/zip-fs.js +38 -27
- package/lib/core/zip-reader.js +58 -26
- package/lib/core/zip-writer.js +293 -177
- package/lib/zip-core-base.js +6 -1
- package/lib/zip-core-reader.js +1 -0
- package/lib/zip-core-writer.js +4 -0
- package/package.json +8 -2
package/lib/core/zip-reader.js
CHANGED
|
@@ -37,6 +37,8 @@ import {
|
|
|
37
37
|
COMPRESSION_METHOD_STORE,
|
|
38
38
|
COMPRESSION_METHOD_AES,
|
|
39
39
|
SPLIT_ZIP_FILE_SIGNATURE,
|
|
40
|
+
TEMPORARY_SPLIT_ZIP_FILE_SIGNATURE,
|
|
41
|
+
SPLIT_ZIP_FILE_SIGNATURE_LENGTH,
|
|
40
42
|
DATA_DESCRIPTOR_RECORD_SIGNATURE,
|
|
41
43
|
DATA_DESCRIPTOR_RECORD_LENGTH,
|
|
42
44
|
DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH,
|
|
@@ -90,7 +92,6 @@ import {
|
|
|
90
92
|
FILE_ATTR_UNIX_SETGID_MASK,
|
|
91
93
|
FILE_ATTR_UNIX_STICKY_MASK,
|
|
92
94
|
NUMBER_TYPE,
|
|
93
|
-
STRING_TYPE,
|
|
94
95
|
EMPTY_UINT8_ARRAY
|
|
95
96
|
} from "./constants.js";
|
|
96
97
|
import { getConfiguration } from "./configuration.js";
|
|
@@ -167,7 +168,11 @@ import {
|
|
|
167
168
|
OPTION_USE_WEB_WORKERS,
|
|
168
169
|
OPTION_USE_COMPRESSION_STREAM,
|
|
169
170
|
OPTION_TRANSFER_STREAMS,
|
|
170
|
-
OPTION_PREVENT_CLOSE
|
|
171
|
+
OPTION_PREVENT_CLOSE,
|
|
172
|
+
checkFunctionOption,
|
|
173
|
+
checkSignalOption,
|
|
174
|
+
checkPasswordOption,
|
|
175
|
+
toNumber
|
|
171
176
|
} from "./options.js";
|
|
172
177
|
|
|
173
178
|
const ERR_BAD_FORMAT = "File format is not recognized";
|
|
@@ -181,6 +186,7 @@ const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
|
|
|
181
186
|
const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
|
|
182
187
|
const ERR_SPLIT_ZIP_FILE = "Split zip file";
|
|
183
188
|
const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
|
|
189
|
+
const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
|
|
184
190
|
const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
|
|
185
191
|
const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
|
|
186
192
|
const ERR_UNSAFE_FILENAME = "Unsafe filename";
|
|
@@ -210,6 +216,7 @@ const ZIP64_EXTRACTION = {
|
|
|
210
216
|
}
|
|
211
217
|
};
|
|
212
218
|
const MAX_END_OF_CENTRAL_DIR_PROBES = 64;
|
|
219
|
+
const MAX_DEFLATE_EXPANSION_RATIO = 1032;
|
|
213
220
|
const CENTRAL_DIRECTORY_UNREACHABLE = 0;
|
|
214
221
|
const CENTRAL_DIRECTORY_PLAUSIBLE = 1;
|
|
215
222
|
const CENTRAL_DIRECTORY_REACHABLE = 2;
|
|
@@ -220,7 +227,6 @@ class ZipReader {
|
|
|
220
227
|
Object.assign(this, {
|
|
221
228
|
reader: new GenericReader(reader),
|
|
222
229
|
options,
|
|
223
|
-
config: getConfiguration(),
|
|
224
230
|
readRanges: new Map()
|
|
225
231
|
});
|
|
226
232
|
}
|
|
@@ -228,7 +234,6 @@ class ZipReader {
|
|
|
228
234
|
async* getEntriesGenerator(options = {}) {
|
|
229
235
|
const zipReader = this;
|
|
230
236
|
let { reader } = zipReader;
|
|
231
|
-
const { config } = zipReader;
|
|
232
237
|
await initStream(reader);
|
|
233
238
|
if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
|
|
234
239
|
reader = new BlobReader(await streamToBlob(reader.readable));
|
|
@@ -245,9 +250,7 @@ class ZipReader {
|
|
|
245
250
|
const normalizeFilename = getOptionValue(zipReader, options, OPTION_NORMALIZE_FILENAME);
|
|
246
251
|
const { endOfDirectoryInfo, endOfDirectoryReachingEndCount } = await findEndOfCentralDirectory(reader, rejectAmbiguousEndOfDirectory, maxAppendedDataSize);
|
|
247
252
|
if (!endOfDirectoryInfo) {
|
|
248
|
-
|
|
249
|
-
const signatureView = getDataView(signatureArray);
|
|
250
|
-
if (getUint32(signatureView) == SPLIT_ZIP_FILE_SIGNATURE) {
|
|
253
|
+
if (await startsWithSplitZipSignature(reader)) {
|
|
251
254
|
throw new Error(ERR_SPLIT_ZIP_FILE);
|
|
252
255
|
} else {
|
|
253
256
|
throw new Error(ERR_EOCDR_NOT_FOUND);
|
|
@@ -386,7 +389,7 @@ class ZipReader {
|
|
|
386
389
|
}
|
|
387
390
|
zipReader.directoryOffset = directoryDataOffset;
|
|
388
391
|
zipReader.directoryLength = declaredDirectoryDataLength;
|
|
389
|
-
const decryptCentralDirectory =
|
|
392
|
+
const decryptCentralDirectory = getFunctionOptionValue(zipReader, options, OPTION_DECRYPT_CENTRAL_DIRECTORY);
|
|
390
393
|
let decryptedDirectory;
|
|
391
394
|
if (decryptCentralDirectory && filesLength && directoryArray.length >= 4 &&
|
|
392
395
|
getUint32(directoryView, 0) != CENTRAL_FILE_HEADER_SIGNATURE &&
|
|
@@ -402,7 +405,7 @@ class ZipReader {
|
|
|
402
405
|
const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
|
|
403
406
|
let duplicateFilename;
|
|
404
407
|
for (let indexFile = 0; indexFile < filesLength; indexFile++) {
|
|
405
|
-
const fileEntry = new ZipEntry(reader,
|
|
408
|
+
const fileEntry = new ZipEntry(reader, zipReader.options);
|
|
406
409
|
if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
|
|
407
410
|
if (indexFile == 0 && !decryptedDirectory && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
|
|
408
411
|
throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
|
|
@@ -433,7 +436,7 @@ class ZipReader {
|
|
|
433
436
|
archive: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_ARCHIVE_MASK)
|
|
434
437
|
};
|
|
435
438
|
const offsetFileEntry = getUint32(directoryView, offset + 42);
|
|
436
|
-
const decode =
|
|
439
|
+
const decode = getFunctionOptionValue(zipReader, options, OPTION_DECODE_TEXT) || decodeText;
|
|
437
440
|
const rawFilenameEncoding = filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437;
|
|
438
441
|
const rawCommentEncoding = commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437;
|
|
439
442
|
let filename = decode(rawFilename, rawFilenameEncoding, TEXT_TYPE_FILENAME);
|
|
@@ -546,13 +549,17 @@ class ZipReader {
|
|
|
546
549
|
if (duplicateFilename) {
|
|
547
550
|
throwAmbiguousArchive("duplicate filename");
|
|
548
551
|
}
|
|
549
|
-
if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > 0))) {
|
|
550
|
-
throwAmbiguousArchive("prepended data");
|
|
551
|
-
}
|
|
552
552
|
const extractPrependedData = getOptionValue(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
|
|
553
553
|
const extractAppendedData = getOptionValue(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
|
|
554
|
+
const splitZipSignatureLength = (checkAmbiguity || extractPrependedData) && filesLength &&
|
|
555
|
+
startOffset == SPLIT_ZIP_FILE_SIGNATURE_LENGTH && await startsWithSplitZipMarker(reader) ? SPLIT_ZIP_FILE_SIGNATURE_LENGTH : 0;
|
|
556
|
+
if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > splitZipSignatureLength))) {
|
|
557
|
+
throwAmbiguousArchive("prepended data");
|
|
558
|
+
}
|
|
554
559
|
if (extractPrependedData) {
|
|
555
|
-
zipReader.prependedData = startOffset >
|
|
560
|
+
zipReader.prependedData = startOffset > splitZipSignatureLength ?
|
|
561
|
+
await readUint8Array(reader, splitZipSignatureLength, startOffset - splitZipSignatureLength) :
|
|
562
|
+
EMPTY_UINT8_ARRAY;
|
|
556
563
|
}
|
|
557
564
|
zipReader.comment = commentLength ? await readUint8Array(reader, commentOffset + END_OF_CENTRAL_DIR_LENGTH, commentLength) : EMPTY_UINT8_ARRAY;
|
|
558
565
|
if (extractAppendedData) {
|
|
@@ -637,6 +644,7 @@ export {
|
|
|
637
644
|
ERR_INVALID_COMPRESSED_DATA,
|
|
638
645
|
ERR_SPLIT_ZIP_FILE,
|
|
639
646
|
ERR_OVERLAPPING_ENTRY,
|
|
647
|
+
ERR_ENTRY_DATA_OUT_OF_BOUNDS,
|
|
640
648
|
ERR_AMBIGUOUS_ARCHIVE,
|
|
641
649
|
ERR_ENCRYPTED_CENTRAL_DIRECTORY,
|
|
642
650
|
ERR_UNSAFE_FILENAME,
|
|
@@ -648,16 +656,16 @@ export {
|
|
|
648
656
|
|
|
649
657
|
class ZipEntry {
|
|
650
658
|
|
|
651
|
-
constructor(reader,
|
|
659
|
+
constructor(reader, options) {
|
|
652
660
|
Object.assign(this, {
|
|
653
661
|
reader,
|
|
654
|
-
config,
|
|
655
662
|
options
|
|
656
663
|
});
|
|
657
664
|
}
|
|
658
665
|
|
|
659
666
|
async getData(writer, fileEntry, readRanges, options = {}) {
|
|
660
667
|
const zipEntry = this;
|
|
668
|
+
const config = getConfiguration();
|
|
661
669
|
const {
|
|
662
670
|
reader,
|
|
663
671
|
index,
|
|
@@ -666,7 +674,6 @@ class ZipEntry {
|
|
|
666
674
|
extraFieldAES,
|
|
667
675
|
extraFieldZip64,
|
|
668
676
|
compressionMethod,
|
|
669
|
-
config,
|
|
670
677
|
bitFlag,
|
|
671
678
|
rawBitFlag,
|
|
672
679
|
crc32,
|
|
@@ -684,6 +691,7 @@ class ZipEntry {
|
|
|
684
691
|
let password = getOptionValue(zipEntry, options, OPTION_PASSWORD);
|
|
685
692
|
let rawPassword = getOptionValue(zipEntry, options, OPTION_RAW_PASSWORD);
|
|
686
693
|
const passThrough = getOptionValue(zipEntry, options, OPTION_PASS_THROUGH);
|
|
694
|
+
checkPasswordOption(password, rawPassword);
|
|
687
695
|
password = password && password.length && password;
|
|
688
696
|
rawPassword = rawPassword && rawPassword.length && rawPassword;
|
|
689
697
|
if (extraFieldAES) {
|
|
@@ -753,9 +761,12 @@ class ZipEntry {
|
|
|
753
761
|
}
|
|
754
762
|
}
|
|
755
763
|
const dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
|
|
764
|
+
if (dataOffset + compressedSize > reader.size) {
|
|
765
|
+
throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
|
|
766
|
+
}
|
|
756
767
|
const size = compressedSize;
|
|
757
768
|
const readable = toCompatibleReadable(reader.createReadable({ offset: dataOffset, size }));
|
|
758
|
-
const signal = getOptionValue(zipEntry, options, OPTION_SIGNAL);
|
|
769
|
+
const signal = checkSignalOption(getOptionValue(zipEntry, options, OPTION_SIGNAL));
|
|
759
770
|
const checkPasswordOnly = getOptionValue(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
|
|
760
771
|
let checkOverlappingEntry = getOptionValue(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
|
|
761
772
|
const checkOverlappingEntryOnly = getOptionValue(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY_ONLY);
|
|
@@ -763,6 +774,8 @@ class ZipEntry {
|
|
|
763
774
|
checkOverlappingEntry = true;
|
|
764
775
|
}
|
|
765
776
|
const { onstart, onprogress, onend } = options;
|
|
777
|
+
const compressed = compressionMethod != COMPRESSION_METHOD_STORE && !passThrough;
|
|
778
|
+
const outputSize = passThrough ? compressedSize : uncompressedSize;
|
|
766
779
|
const deflate64 = compressionMethod == COMPRESSION_METHOD_DEFLATE_64;
|
|
767
780
|
let useCompressionStream = getOptionValue(zipEntry, options, OPTION_USE_COMPRESSION_STREAM);
|
|
768
781
|
if (deflate64) {
|
|
@@ -783,9 +796,9 @@ class ZipEntry {
|
|
|
783
796
|
checkCrc32,
|
|
784
797
|
checkAuthenticationCode: getOptionValue(zipEntry, options, OPTION_CHECK_AUTHENTICATION_CODE),
|
|
785
798
|
passwordVerification: zipCrypto && (dataDescriptor ? ((rawLastModDate >>> 8) & MAX_8_BITS) : ((crc32 >>> 24) & MAX_8_BITS)),
|
|
786
|
-
outputSize
|
|
799
|
+
outputSize,
|
|
787
800
|
crc32,
|
|
788
|
-
compressed
|
|
801
|
+
compressed,
|
|
789
802
|
encrypted,
|
|
790
803
|
useWebWorkers: getOptionValue(zipEntry, options, OPTION_USE_WEB_WORKERS),
|
|
791
804
|
useCompressionStream,
|
|
@@ -822,11 +835,11 @@ class ZipEntry {
|
|
|
822
835
|
writer = new WritableStream();
|
|
823
836
|
}
|
|
824
837
|
writer = new GenericWriter(writer);
|
|
825
|
-
await initStream(writer,
|
|
838
|
+
await initStream(writer, getDecodableOutputSize(outputSize, compressedSize, compressed));
|
|
826
839
|
({ writable } = writer);
|
|
827
|
-
const { outputSize } = await runWorker({ readable, writable }, workerOptions);
|
|
828
|
-
writer.size +=
|
|
829
|
-
if (
|
|
840
|
+
const { outputSize: writtenSize } = await runWorker({ readable, writable }, workerOptions);
|
|
841
|
+
writer.size += writtenSize;
|
|
842
|
+
if (writtenSize != outputSize) {
|
|
830
843
|
throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
831
844
|
}
|
|
832
845
|
}
|
|
@@ -1246,10 +1259,28 @@ function getDiskOffset(reader, diskNumber) {
|
|
|
1246
1259
|
return reader.getDiskOffset ? reader.getDiskOffset(diskNumber) : 0;
|
|
1247
1260
|
}
|
|
1248
1261
|
|
|
1262
|
+
async function startsWithSplitZipSignature(reader) {
|
|
1263
|
+
return await getFirstSignature(reader) == SPLIT_ZIP_FILE_SIGNATURE;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
async function startsWithSplitZipMarker(reader) {
|
|
1267
|
+
const signature = await getFirstSignature(reader);
|
|
1268
|
+
return signature == SPLIT_ZIP_FILE_SIGNATURE || signature == TEMPORARY_SPLIT_ZIP_FILE_SIGNATURE;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
async function getFirstSignature(reader) {
|
|
1272
|
+
const signatureArray = await readUint8Array(reader, 0, SPLIT_ZIP_FILE_SIGNATURE_LENGTH);
|
|
1273
|
+
return getUint32(getDataView(signatureArray));
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1249
1276
|
function isStrictnessValue(value) {
|
|
1250
1277
|
return value === STRICTNESS_STRICT || value === STRICTNESS_BALANCED || value === STRICTNESS_TOLERANT;
|
|
1251
1278
|
}
|
|
1252
1279
|
|
|
1280
|
+
function getDecodableOutputSize(outputSize, compressedSize, compressed) {
|
|
1281
|
+
return Math.min(outputSize, compressed ? compressedSize * MAX_DEFLATE_EXPANSION_RATIO : compressedSize);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1253
1284
|
function getStrictness(options, inheritedOptions) {
|
|
1254
1285
|
return resolveStrictness(options, resolveStrictness(inheritedOptions, STRICTNESS_BALANCED));
|
|
1255
1286
|
}
|
|
@@ -1463,10 +1494,11 @@ function getOptionValue(zipReader, options, name) {
|
|
|
1463
1494
|
return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
|
|
1464
1495
|
}
|
|
1465
1496
|
|
|
1466
|
-
function
|
|
1467
|
-
return
|
|
1497
|
+
function getFunctionOptionValue(zipReader, options, name) {
|
|
1498
|
+
return checkFunctionOption(getOptionValue(zipReader, options, name));
|
|
1468
1499
|
}
|
|
1469
1500
|
|
|
1501
|
+
|
|
1470
1502
|
function getDate(timeRaw) {
|
|
1471
1503
|
const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
|
|
1472
1504
|
return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
|