@zip.js/zip.js 2.8.57 → 2.8.59
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/deno.json +1 -1
- package/dist/zip-core-external.js +458 -200
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +472 -199
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +481 -201
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +497 -193
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +481 -201
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +498 -202
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +499 -203
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +474 -201
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +474 -201
- 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 +475 -202
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +498 -202
- package/index-native.min.js +1 -1
- package/index.cjs +499 -203
- package/index.d.cts +297 -10
- package/index.d.ts +297 -10
- package/index.min.js +1 -1
- package/lib/core/constants.js +4 -0
- package/lib/core/options.js +2 -0
- 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 +27 -1
- package/lib/core/zip-reader.js +168 -38
- package/lib/core/zip-writer.js +290 -161
- package/lib/core/zlib-streams-inline.js +1 -1
- package/lib/zip-core-reader.js +16 -1
- package/package.json +1 -1
package/lib/core/zip-reader.js
CHANGED
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
ZIP64_END_OF_CENTRAL_DIR_LENGTH,
|
|
69
69
|
BITFLAG_ENCRYPTED,
|
|
70
70
|
BITFLAG_STRONG_ENCRYPTION,
|
|
71
|
+
BITFLAG_COMPRESSED_PATCHED_DATA,
|
|
71
72
|
BITFLAG_MASKED_LOCAL_HEADERS,
|
|
72
73
|
BITFLAG_LEVEL,
|
|
73
74
|
BITFLAG_DATA_DESCRIPTOR,
|
|
@@ -93,7 +94,8 @@ import {
|
|
|
93
94
|
FILE_ATTR_UNIX_SETGID_MASK,
|
|
94
95
|
FILE_ATTR_UNIX_STICKY_MASK,
|
|
95
96
|
NUMBER_TYPE,
|
|
96
|
-
EMPTY_UINT8_ARRAY
|
|
97
|
+
EMPTY_UINT8_ARRAY,
|
|
98
|
+
MIN_DATE
|
|
97
99
|
} from "./constants.js";
|
|
98
100
|
import { getConfiguration } from "./configuration.js";
|
|
99
101
|
import { getRegisteredCodec } from "./codec-registry.js";
|
|
@@ -195,6 +197,21 @@ const ERR_INVALID_STRICTNESS = "Invalid strictness (must be 'strict', 'balanced'
|
|
|
195
197
|
const ERR_INVALID_FILENAME_VALIDATION = "Invalid filenameValidation (must be 'strict', 'balanced' or 'tolerant')";
|
|
196
198
|
const ERR_INVALID_MAX_APPENDED_DATA_SIZE = "Invalid maxAppendedDataSize (must be a number greater than or equal to 0)";
|
|
197
199
|
const ERR_UNSUPPORTED_UINT64 = "64-bit value exceeds Number.MAX_SAFE_INTEGER";
|
|
200
|
+
const WARNING_UNSORTED_CENTRAL_DIRECTORY = "unsorted central directory";
|
|
201
|
+
const WARNING_UNKNOWN_VERSION = "unknown version needed to extract";
|
|
202
|
+
const WARNING_COMPRESSED_PATCHED_DATA = "compressed patched data";
|
|
203
|
+
const WARNING_MALFORMED_EXTRA_FIELD = "malformed extra field";
|
|
204
|
+
const WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA = "unknown zip64 extensible data";
|
|
205
|
+
const WARNING_WRAPPED_ENTRIES_COUNT = "wrapped entries count";
|
|
206
|
+
const WARNING_APPENDED_DATA = "appended data";
|
|
207
|
+
const WARNING_PREPENDED_DATA = "prepended data";
|
|
208
|
+
const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
|
|
209
|
+
const WARNING_DUPLICATE_FILENAME = "duplicate filename";
|
|
210
|
+
const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
|
|
211
|
+
const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
|
|
212
|
+
const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
|
|
213
|
+
const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
|
|
214
|
+
const MAX_KNOWN_VERSION = 63;
|
|
198
215
|
const DRIVE_LETTER_REGEXP = /^[a-zA-Z]:/;
|
|
199
216
|
const CHARSET_UTF8 = "utf-8";
|
|
200
217
|
const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
|
|
@@ -245,6 +262,7 @@ class ZipReader {
|
|
|
245
262
|
if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
|
|
246
263
|
throw new Error(ERR_BAD_FORMAT);
|
|
247
264
|
}
|
|
265
|
+
const warnings = zipReader.warnings = [];
|
|
248
266
|
const strictness = getStrictness(options, zipReader.options);
|
|
249
267
|
const checkAmbiguity = strictness == STRICTNESS_STRICT;
|
|
250
268
|
const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
|
|
@@ -268,8 +286,12 @@ class ZipReader {
|
|
|
268
286
|
const commentOffset = endOfDirectoryInfo.offset;
|
|
269
287
|
const commentLength = getUint16(endOfDirectoryView, 20);
|
|
270
288
|
const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
|
|
271
|
-
|
|
272
|
-
|
|
289
|
+
const appendedDataLength = reader.size - appendedDataOffset;
|
|
290
|
+
if (appendedDataLength > maxAppendedDataSize) {
|
|
291
|
+
throwAmbiguousArchive(WARNING_APPENDED_DATA);
|
|
292
|
+
}
|
|
293
|
+
if (appendedDataLength > 0) {
|
|
294
|
+
addWarning(warnings, WARNING_APPENDED_DATA);
|
|
273
295
|
}
|
|
274
296
|
let lastDiskNumber = getUint16(endOfDirectoryView, 4);
|
|
275
297
|
const expectedLastDiskNumber = reader.lastDiskNumber || 0;
|
|
@@ -323,23 +345,23 @@ class ZipReader {
|
|
|
323
345
|
}
|
|
324
346
|
if (lastDiskNumber == MAX_16_BITS) {
|
|
325
347
|
lastDiskNumber = getUint32(endOfDirectoryView, 16);
|
|
326
|
-
} else if (
|
|
327
|
-
|
|
348
|
+
} else if (lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
|
|
349
|
+
reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
|
|
328
350
|
}
|
|
329
351
|
if (diskNumber == MAX_16_BITS) {
|
|
330
352
|
diskNumber = getUint32(endOfDirectoryView, 20);
|
|
331
|
-
} else if (
|
|
332
|
-
|
|
353
|
+
} else if (diskNumber != getUint32(endOfDirectoryView, 20)) {
|
|
354
|
+
reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
|
|
333
355
|
}
|
|
334
356
|
if (filesLength == MAX_16_BITS) {
|
|
335
357
|
filesLength = getBigUint64(endOfDirectoryView, 32);
|
|
336
|
-
} else if (
|
|
337
|
-
|
|
358
|
+
} else if (filesLength != getBigUint64(endOfDirectoryView, 32)) {
|
|
359
|
+
reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
|
|
338
360
|
}
|
|
339
361
|
if (directoryDataLength == MAX_32_BITS) {
|
|
340
362
|
directoryDataLength = getBigUint64(endOfDirectoryView, 40);
|
|
341
|
-
} else if (
|
|
342
|
-
|
|
363
|
+
} else if (directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
|
|
364
|
+
reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
|
|
343
365
|
}
|
|
344
366
|
directoryDataOffset = getDiskOffset(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
|
|
345
367
|
}
|
|
@@ -408,11 +430,23 @@ class ZipReader {
|
|
|
408
430
|
declaredDirectoryDataLength = directoryArray.length;
|
|
409
431
|
decryptedDirectory = true;
|
|
410
432
|
}
|
|
433
|
+
if (directoryEncryptionInfo && !decryptedDirectory &&
|
|
434
|
+
(directoryArray.length < 4 || getUint32(directoryView, 0) == CENTRAL_FILE_HEADER_SIGNATURE)) {
|
|
435
|
+
addWarning(warnings, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA);
|
|
436
|
+
}
|
|
411
437
|
startOffset = directoryDataOffset;
|
|
412
438
|
const filenameEncoding = getOptionValue(zipReader, options, OPTION_FILENAME_ENCODING);
|
|
413
439
|
const commentEncoding = getOptionValue(zipReader, options, OPTION_COMMENT_ENCODING);
|
|
414
|
-
const filenames =
|
|
440
|
+
const filenames = new Set();
|
|
415
441
|
let duplicateFilename;
|
|
442
|
+
let previousEntryPosition = -1;
|
|
443
|
+
const recoverWrappedFilesLength = !checkAmbiguity && !zip64EndOfDirectory;
|
|
444
|
+
if (!filesLength && recoverWrappedFilesLength) {
|
|
445
|
+
filesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
|
|
446
|
+
if (filesLength) {
|
|
447
|
+
addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
416
450
|
for (let indexFile = 0; indexFile < filesLength; indexFile++) {
|
|
417
451
|
const fileEntry = new ZipEntry(reader, zipReader.options);
|
|
418
452
|
if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
|
|
@@ -490,15 +524,26 @@ class ZipReader {
|
|
|
490
524
|
filename,
|
|
491
525
|
comment
|
|
492
526
|
});
|
|
493
|
-
readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6)
|
|
527
|
+
if (readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6)) {
|
|
528
|
+
addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
|
|
529
|
+
}
|
|
494
530
|
fileEntry.offset += prependedDataLength;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
531
|
+
const entryPosition = getDiskOffset(reader, fileEntry.diskNumberStart) + fileEntry.offset;
|
|
532
|
+
startOffset = Math.min(entryPosition, startOffset);
|
|
533
|
+
if (entryPosition < previousEntryPosition) {
|
|
534
|
+
addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
|
|
535
|
+
}
|
|
536
|
+
previousEntryPosition = entryPosition;
|
|
537
|
+
if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
|
|
538
|
+
addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
|
|
539
|
+
}
|
|
540
|
+
if ((fileEntry.rawBitFlag & BITFLAG_COMPRESSED_PATCHED_DATA) == BITFLAG_COMPRESSED_PATCHED_DATA) {
|
|
541
|
+
addWarning(warnings, WARNING_COMPRESSED_PATCHED_DATA, filename);
|
|
542
|
+
}
|
|
543
|
+
if (filenames.has(fileEntry.filename)) {
|
|
544
|
+
duplicateFilename = true;
|
|
501
545
|
}
|
|
546
|
+
filenames.add(fileEntry.filename);
|
|
502
547
|
const unixExternalUpper = (fileEntry.externalFileAttributes >> 16) & MAX_16_BITS;
|
|
503
548
|
if (fileEntry.unixMode === UNDEFINED_VALUE && (unixExternalUpper & (FILE_ATTR_UNIX_DEFAULT_MASK | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_TYPE_DIR)) != 0) {
|
|
504
549
|
fileEntry.unixMode = unixExternalUpper;
|
|
@@ -522,7 +567,7 @@ class ZipReader {
|
|
|
522
567
|
internalFileAttribute: fileEntry.internalFileAttributes,
|
|
523
568
|
externalFileAttribute: fileEntry.externalFileAttributes,
|
|
524
569
|
executable,
|
|
525
|
-
directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) ||
|
|
570
|
+
directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
|
|
526
571
|
zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
|
|
527
572
|
});
|
|
528
573
|
const entry = new Entry(fileEntry);
|
|
@@ -535,6 +580,13 @@ class ZipReader {
|
|
|
535
580
|
return arrayBufferPromise;
|
|
536
581
|
};
|
|
537
582
|
offset = endOffset;
|
|
583
|
+
if (indexFile == filesLength - 1 && recoverWrappedFilesLength) {
|
|
584
|
+
const wrappedFilesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
|
|
585
|
+
if (wrappedFilesLength) {
|
|
586
|
+
filesLength += wrappedFilesLength;
|
|
587
|
+
addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
538
590
|
const { onprogress } = options;
|
|
539
591
|
if (onprogress) {
|
|
540
592
|
try {
|
|
@@ -559,18 +611,22 @@ class ZipReader {
|
|
|
559
611
|
zipReader.digitalSignature = digitalSignature;
|
|
560
612
|
offsetAfterSignature = offset + 6 + digitalSignature.length;
|
|
561
613
|
}
|
|
562
|
-
if (
|
|
563
|
-
|
|
614
|
+
if ((offset != declaredDirectoryDataLength && offsetAfterSignature != declaredDirectoryDataLength) ||
|
|
615
|
+
(!decryptedDirectory && offset != directoryDataLength && offsetAfterSignature != directoryDataLength)) {
|
|
616
|
+
reportAmbiguity(checkAmbiguity, warnings, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA);
|
|
564
617
|
}
|
|
565
618
|
if (duplicateFilename) {
|
|
566
|
-
|
|
619
|
+
reportAmbiguity(checkAmbiguity, warnings, WARNING_DUPLICATE_FILENAME);
|
|
567
620
|
}
|
|
568
621
|
const extractPrependedData = getOptionValue(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
|
|
569
622
|
const extractAppendedData = getOptionValue(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
|
|
570
623
|
const splitZipSignatureLength = (checkAmbiguity || extractPrependedData) && filesLength &&
|
|
571
624
|
startOffset == SPLIT_ZIP_FILE_SIGNATURE_LENGTH && await startsWithSplitZipMarker(reader) ? SPLIT_ZIP_FILE_SIGNATURE_LENGTH : 0;
|
|
572
625
|
if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > splitZipSignatureLength))) {
|
|
573
|
-
throwAmbiguousArchive(
|
|
626
|
+
throwAmbiguousArchive(WARNING_PREPENDED_DATA);
|
|
627
|
+
}
|
|
628
|
+
if (prependedDataLength || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
|
|
629
|
+
addWarning(warnings, WARNING_PREPENDED_DATA);
|
|
574
630
|
}
|
|
575
631
|
if (extractPrependedData) {
|
|
576
632
|
zipReader.prependedData = startOffset > splitZipSignatureLength ?
|
|
@@ -640,8 +696,31 @@ class ZipReaderStream {
|
|
|
640
696
|
}
|
|
641
697
|
}
|
|
642
698
|
|
|
699
|
+
async function isZipFile(reader, options = {}) {
|
|
700
|
+
reader = new GenericReader(reader);
|
|
701
|
+
await initStream(reader);
|
|
702
|
+
if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
|
|
703
|
+
reader = new BlobReader(await streamToBlob(reader.readable));
|
|
704
|
+
await initStream(reader);
|
|
705
|
+
}
|
|
706
|
+
if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
const strictness = getStrictness(options, {});
|
|
710
|
+
const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
|
|
711
|
+
const maxAppendedDataSize = getMaxAppendedDataSize(options[OPTION_MAX_APPENDED_DATA_SIZE], strictness);
|
|
712
|
+
const { endOfDirectoryInfo, endOfDirectoryReachingEndCount } = await findEndOfCentralDirectory(reader, rejectAmbiguousEndOfDirectory, maxAppendedDataSize);
|
|
713
|
+
if (!endOfDirectoryInfo || (strictness == STRICTNESS_STRICT && endOfDirectoryReachingEndCount > 1)) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
const commentLength = getUint16(getDataView(endOfDirectoryInfo), 20);
|
|
717
|
+
const appendedDataOffset = endOfDirectoryInfo.offset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
|
|
718
|
+
return reader.size - appendedDataOffset <= maxAppendedDataSize;
|
|
719
|
+
}
|
|
720
|
+
|
|
643
721
|
export {
|
|
644
722
|
ZipReader,
|
|
723
|
+
isZipFile,
|
|
645
724
|
ZipReaderStream,
|
|
646
725
|
ERR_BAD_FORMAT,
|
|
647
726
|
ERR_EOCDR_NOT_FOUND,
|
|
@@ -668,7 +747,21 @@ export {
|
|
|
668
747
|
ERR_INVALID_FILENAME_VALIDATION,
|
|
669
748
|
ERR_INVALID_MAX_APPENDED_DATA_SIZE,
|
|
670
749
|
ERR_UNSUPPORTED_UINT64,
|
|
671
|
-
ERR_WORKER_STARTUP_TIMEOUT
|
|
750
|
+
ERR_WORKER_STARTUP_TIMEOUT,
|
|
751
|
+
WARNING_UNSORTED_CENTRAL_DIRECTORY,
|
|
752
|
+
WARNING_UNKNOWN_VERSION,
|
|
753
|
+
WARNING_COMPRESSED_PATCHED_DATA,
|
|
754
|
+
WARNING_MALFORMED_EXTRA_FIELD,
|
|
755
|
+
WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA,
|
|
756
|
+
WARNING_WRAPPED_ENTRIES_COUNT,
|
|
757
|
+
WARNING_APPENDED_DATA,
|
|
758
|
+
WARNING_PREPENDED_DATA,
|
|
759
|
+
WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
|
|
760
|
+
WARNING_DUPLICATE_FILENAME,
|
|
761
|
+
WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
|
|
762
|
+
WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
|
|
763
|
+
WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
|
|
764
|
+
WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES
|
|
672
765
|
};
|
|
673
766
|
|
|
674
767
|
class ZipEntry {
|
|
@@ -702,6 +795,7 @@ class ZipEntry {
|
|
|
702
795
|
dataDescriptor
|
|
703
796
|
} = bitFlag;
|
|
704
797
|
const localDirectory = fileEntry.localDirectory = {};
|
|
798
|
+
const warnings = fileEntry.warnings = [];
|
|
705
799
|
const localHeaderOffset = getDiskOffset(reader, diskNumberStart) + offset;
|
|
706
800
|
const dataArray = await readUint8Array(reader, localHeaderOffset, HEADER_SIZE);
|
|
707
801
|
const dataView = getDataView(dataArray);
|
|
@@ -724,6 +818,7 @@ class ZipEntry {
|
|
|
724
818
|
extraFieldLength,
|
|
725
819
|
filenameLength
|
|
726
820
|
} = localDirectory;
|
|
821
|
+
const dataOffset = localDirectory.dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
|
|
727
822
|
const checkLocalDirectoryOption = getOptionValue(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
|
|
728
823
|
const entryStrictness = getStrictness(options, zipEntry.options);
|
|
729
824
|
const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
|
|
@@ -741,10 +836,10 @@ class ZipEntry {
|
|
|
741
836
|
if (checkLocalFilename) {
|
|
742
837
|
localDirectory.rawFilename = rawLocalFilename;
|
|
743
838
|
}
|
|
744
|
-
readCommonFooter(zipEntry, localDirectory, dataView, 4, true)
|
|
745
|
-
|
|
746
|
-
validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
|
|
839
|
+
if (readCommonFooter(zipEntry, localDirectory, dataView, 4, true)) {
|
|
840
|
+
addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD);
|
|
747
841
|
}
|
|
842
|
+
validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
|
|
748
843
|
const { lastAccessDate, creationDate, uid, gid } = localDirectory;
|
|
749
844
|
if (lastAccessDate) {
|
|
750
845
|
fileEntry.lastAccessDate = lastAccessDate;
|
|
@@ -777,7 +872,6 @@ class ZipEntry {
|
|
|
777
872
|
throw new Error(ERR_ENCRYPTED);
|
|
778
873
|
}
|
|
779
874
|
}
|
|
780
|
-
const dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
|
|
781
875
|
if (dataOffset + compressedSize > reader.size) {
|
|
782
876
|
throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
|
|
783
877
|
}
|
|
@@ -897,6 +991,16 @@ function detectEncryptedCentralDirectory(directoryView) {
|
|
|
897
991
|
return false;
|
|
898
992
|
}
|
|
899
993
|
|
|
994
|
+
function getWrappedFilesLength(directoryView, directoryArray, offset) {
|
|
995
|
+
let wrappedFilesLength = 0;
|
|
996
|
+
while (offset + CENTRAL_FILE_HEADER_LENGTH <= directoryArray.length && getUint32(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE) {
|
|
997
|
+
offset += CENTRAL_FILE_HEADER_LENGTH +
|
|
998
|
+
getUint16(directoryView, offset + 28) + getUint16(directoryView, offset + 30) + getUint16(directoryView, offset + 32);
|
|
999
|
+
wrappedFilesLength++;
|
|
1000
|
+
}
|
|
1001
|
+
return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
900
1004
|
function readDigitalSignature(signatureRecordArray) {
|
|
901
1005
|
if (signatureRecordArray.length >= 6) {
|
|
902
1006
|
const signatureRecordView = getDataView(signatureRecordArray);
|
|
@@ -961,6 +1065,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
|
|
|
961
1065
|
const extraField = directory.extraField = new Map();
|
|
962
1066
|
const rawExtraFieldView = getDataView(rawExtraField);
|
|
963
1067
|
let offsetExtraField = 0;
|
|
1068
|
+
let malformedExtraField = false;
|
|
964
1069
|
try {
|
|
965
1070
|
while (offsetExtraField < rawExtraField.length) {
|
|
966
1071
|
const type = getUint16(rawExtraFieldView, offsetExtraField);
|
|
@@ -972,7 +1077,10 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
|
|
|
972
1077
|
offsetExtraField += 4 + size;
|
|
973
1078
|
}
|
|
974
1079
|
} catch {
|
|
975
|
-
|
|
1080
|
+
malformedExtraField = true;
|
|
1081
|
+
}
|
|
1082
|
+
if (offsetExtraField > rawExtraField.length) {
|
|
1083
|
+
malformedExtraField = true;
|
|
976
1084
|
}
|
|
977
1085
|
const compressionMethod = getUint16(dataView, offset + 4);
|
|
978
1086
|
Object.assign(directory, {
|
|
@@ -1040,6 +1148,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
|
|
|
1040
1148
|
if (extraFieldUSDZ) {
|
|
1041
1149
|
directory.extraFieldUSDZ = extraFieldUSDZ;
|
|
1042
1150
|
}
|
|
1151
|
+
return malformedExtraField;
|
|
1043
1152
|
}
|
|
1044
1153
|
|
|
1045
1154
|
function readExtraFieldZip64(extraFieldZip64, directory) {
|
|
@@ -1069,10 +1178,11 @@ function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName,
|
|
|
1069
1178
|
const computedCrc32View = getDataView(new Uint8Array(4));
|
|
1070
1179
|
computedCrc32View.setUint32(0, computedCrc32.get(), true);
|
|
1071
1180
|
const nameCrc32 = getUint32(extraFieldView, 1);
|
|
1181
|
+
const version = getUint8(extraFieldView, 0);
|
|
1072
1182
|
Object.assign(extraFieldUnicode, {
|
|
1073
|
-
version
|
|
1183
|
+
version,
|
|
1074
1184
|
[propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
|
|
1075
|
-
valid: !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32(computedCrc32View, 0)
|
|
1185
|
+
valid: version == 1 && !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32(computedCrc32View, 0)
|
|
1076
1186
|
});
|
|
1077
1187
|
if (extraFieldUnicode.valid) {
|
|
1078
1188
|
directory[propertyName] = extraFieldUnicode[propertyName];
|
|
@@ -1500,27 +1610,46 @@ async function readSignature(reader, view, anchoredOffset, signatureOffset, size
|
|
|
1500
1610
|
return UNDEFINED_VALUE;
|
|
1501
1611
|
}
|
|
1502
1612
|
|
|
1503
|
-
function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
|
|
1613
|
+
function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, warnings) {
|
|
1504
1614
|
const { rawFilename } = zipEntry;
|
|
1615
|
+
const reject = !warnings;
|
|
1505
1616
|
const maskedLocalDirectory = zipEntry.decryptedDirectory &&
|
|
1506
1617
|
(localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
|
|
1507
1618
|
if (checkLocalFilename && !maskedLocalDirectory &&
|
|
1508
1619
|
(rawLocalFilename.length != rawFilename.length ||
|
|
1509
1620
|
rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
|
|
1510
|
-
|
|
1621
|
+
reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
|
|
1511
1622
|
}
|
|
1512
1623
|
if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
|
|
1513
|
-
|
|
1624
|
+
reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
|
|
1514
1625
|
}
|
|
1515
1626
|
if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
|
|
1516
|
-
|
|
1627
|
+
reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD);
|
|
1517
1628
|
}
|
|
1518
1629
|
if (!localDirectory.bitFlag.dataDescriptor && !maskedLocalDirectory &&
|
|
1519
1630
|
(localDirectory.crc32 || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
|
|
1520
1631
|
(localDirectory.crc32 != zipEntry.crc32 ||
|
|
1521
1632
|
localDirectory.compressedSize != zipEntry.compressedSize ||
|
|
1522
1633
|
localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
|
|
1523
|
-
|
|
1634
|
+
reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
function reportAmbiguity(reject, warnings, reason) {
|
|
1639
|
+
if (reject) {
|
|
1640
|
+
throwAmbiguousArchive(reason);
|
|
1641
|
+
} else {
|
|
1642
|
+
addWarning(warnings, reason);
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
function addWarning(warnings, reason, filename) {
|
|
1647
|
+
if (!warnings.some(warning => warning.reason == reason)) {
|
|
1648
|
+
const warning = { reason };
|
|
1649
|
+
if (filename !== UNDEFINED_VALUE) {
|
|
1650
|
+
warning.filename = filename;
|
|
1651
|
+
}
|
|
1652
|
+
warnings.push(warning);
|
|
1524
1653
|
}
|
|
1525
1654
|
}
|
|
1526
1655
|
|
|
@@ -1541,7 +1670,8 @@ function getFunctionOptionValue(zipReader, options, name) {
|
|
|
1541
1670
|
|
|
1542
1671
|
function getDate(timeRaw) {
|
|
1543
1672
|
const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
|
|
1544
|
-
|
|
1673
|
+
const result = new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
|
|
1674
|
+
return result < MIN_DATE ? MIN_DATE : result;
|
|
1545
1675
|
}
|
|
1546
1676
|
|
|
1547
1677
|
function getDateNTFS(timeRaw) {
|