@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.
@@ -74,6 +74,7 @@ const BITFLAG_LEVEL_MAX_MASK = 0b010;
74
74
  const BITFLAG_LEVEL_FAST_MASK = 0b100;
75
75
  const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
76
76
  const BITFLAG_DATA_DESCRIPTOR = 0b1000;
77
+ const BITFLAG_COMPRESSED_PATCHED_DATA = 0b100000;
77
78
  const BITFLAG_STRONG_ENCRYPTION = 0b1000000;
78
79
  const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
79
80
  const BITFLAG_MASKED_LOCAL_HEADERS = 0b10000000000000;
@@ -92,6 +93,7 @@ const FILE_ATTR_UNIX_SETUID_MASK = 0o4000;
92
93
  const FILE_ATTR_UNIX_SETGID_MASK = 0o2000;
93
94
  const FILE_ATTR_UNIX_STICKY_MASK = 0o1000;
94
95
 
96
+ const VERSION_STORE = 0x0A;
95
97
  const VERSION_DEFLATE = 0x14;
96
98
  const VERSION_ZIP64 = 0x2D;
97
99
  const VERSION_AES = 0x33;
@@ -190,6 +192,7 @@ const OPTION_OFFSET = "offset";
190
192
  const OPTION_USDZ = "usdz";
191
193
  const OPTION_UNIX_EXTRA_FIELD_TYPE = "unixExtraFieldType";
192
194
  const OPTION_LOCAL_EXTRA_FIELD = "localExtraField";
195
+ const OPTION_CENTRAL_EXTRA_FIELD = "centralExtraField";
193
196
  const OPTION_STRICTNESS = "strictness";
194
197
  const OPTION_FILENAME_VALIDATION = "filenameValidation";
195
198
  const OPTION_NORMALIZE_FILENAME = "normalizeFilename";
@@ -4759,6 +4762,21 @@ const ERR_INVALID_STRICTNESS = "Invalid strictness (must be 'strict', 'balanced'
4759
4762
  const ERR_INVALID_FILENAME_VALIDATION = "Invalid filenameValidation (must be 'strict', 'balanced' or 'tolerant')";
4760
4763
  const ERR_INVALID_MAX_APPENDED_DATA_SIZE = "Invalid maxAppendedDataSize (must be a number greater than or equal to 0)";
4761
4764
  const ERR_UNSUPPORTED_UINT64 = "64-bit value exceeds Number.MAX_SAFE_INTEGER";
4765
+ const WARNING_UNSORTED_CENTRAL_DIRECTORY = "unsorted central directory";
4766
+ const WARNING_UNKNOWN_VERSION = "unknown version needed to extract";
4767
+ const WARNING_COMPRESSED_PATCHED_DATA = "compressed patched data";
4768
+ const WARNING_MALFORMED_EXTRA_FIELD = "malformed extra field";
4769
+ const WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA = "unknown zip64 extensible data";
4770
+ const WARNING_WRAPPED_ENTRIES_COUNT = "wrapped entries count";
4771
+ const WARNING_APPENDED_DATA = "appended data";
4772
+ const WARNING_PREPENDED_DATA = "prepended data";
4773
+ const WARNING_TRAILING_CENTRAL_DIRECTORY_DATA = "trailing central directory data";
4774
+ const WARNING_DUPLICATE_FILENAME = "duplicate filename";
4775
+ const WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY = "mismatched zip64 end of central directory record";
4776
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG = "mismatched local file header (general purpose bit flag)";
4777
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD = "mismatched local file header (compression method)";
4778
+ const WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES = "mismatched local file header (crc32 or sizes)";
4779
+ const MAX_KNOWN_VERSION = 63;
4762
4780
  const DRIVE_LETTER_REGEXP = /^[a-zA-Z]:/;
4763
4781
  const CHARSET_UTF8 = "utf-8";
4764
4782
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
@@ -4809,6 +4827,7 @@ class ZipReader {
4809
4827
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
4810
4828
  throw new Error(ERR_BAD_FORMAT);
4811
4829
  }
4830
+ const warnings = zipReader.warnings = [];
4812
4831
  const strictness = getStrictness(options, zipReader.options);
4813
4832
  const checkAmbiguity = strictness == STRICTNESS_STRICT;
4814
4833
  const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
@@ -4832,8 +4851,12 @@ class ZipReader {
4832
4851
  const commentOffset = endOfDirectoryInfo.offset;
4833
4852
  const commentLength = getUint16$1(endOfDirectoryView, 20);
4834
4853
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
4835
- if (reader.size - appendedDataOffset > maxAppendedDataSize) {
4836
- throwAmbiguousArchive("appended data");
4854
+ const appendedDataLength = reader.size - appendedDataOffset;
4855
+ if (appendedDataLength > maxAppendedDataSize) {
4856
+ throwAmbiguousArchive(WARNING_APPENDED_DATA);
4857
+ }
4858
+ if (appendedDataLength > 0) {
4859
+ addWarning(warnings, WARNING_APPENDED_DATA);
4837
4860
  }
4838
4861
  let lastDiskNumber = getUint16$1(endOfDirectoryView, 4);
4839
4862
  const expectedLastDiskNumber = reader.lastDiskNumber || 0;
@@ -4887,23 +4910,23 @@ class ZipReader {
4887
4910
  }
4888
4911
  if (lastDiskNumber == MAX_16_BITS) {
4889
4912
  lastDiskNumber = getUint32$1(endOfDirectoryView, 16);
4890
- } else if (checkAmbiguity && lastDiskNumber != getUint32$1(endOfDirectoryView, 16)) {
4891
- throwAmbiguousArchive("mismatched zip64 end of central directory record");
4913
+ } else if (lastDiskNumber != getUint32$1(endOfDirectoryView, 16)) {
4914
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4892
4915
  }
4893
4916
  if (diskNumber == MAX_16_BITS) {
4894
4917
  diskNumber = getUint32$1(endOfDirectoryView, 20);
4895
- } else if (checkAmbiguity && diskNumber != getUint32$1(endOfDirectoryView, 20)) {
4896
- throwAmbiguousArchive("mismatched zip64 end of central directory record");
4918
+ } else if (diskNumber != getUint32$1(endOfDirectoryView, 20)) {
4919
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4897
4920
  }
4898
4921
  if (filesLength == MAX_16_BITS) {
4899
4922
  filesLength = getBigUint64(endOfDirectoryView, 32);
4900
- } else if (checkAmbiguity && filesLength != getBigUint64(endOfDirectoryView, 32)) {
4901
- throwAmbiguousArchive("mismatched zip64 end of central directory record");
4923
+ } else if (filesLength != getBigUint64(endOfDirectoryView, 32)) {
4924
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4902
4925
  }
4903
4926
  if (directoryDataLength == MAX_32_BITS) {
4904
4927
  directoryDataLength = getBigUint64(endOfDirectoryView, 40);
4905
- } else if (checkAmbiguity && directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
4906
- throwAmbiguousArchive("mismatched zip64 end of central directory record");
4928
+ } else if (directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
4929
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY);
4907
4930
  }
4908
4931
  directoryDataOffset = getDiskOffset$1(reader, diskNumber) + getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
4909
4932
  }
@@ -4972,11 +4995,23 @@ class ZipReader {
4972
4995
  declaredDirectoryDataLength = directoryArray.length;
4973
4996
  decryptedDirectory = true;
4974
4997
  }
4998
+ if (directoryEncryptionInfo && !decryptedDirectory &&
4999
+ (directoryArray.length < 4 || getUint32$1(directoryView, 0) == CENTRAL_FILE_HEADER_SIGNATURE)) {
5000
+ addWarning(warnings, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA);
5001
+ }
4975
5002
  startOffset = directoryDataOffset;
4976
5003
  const filenameEncoding = getOptionValue$1(zipReader, options, OPTION_FILENAME_ENCODING);
4977
5004
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
4978
- const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
5005
+ const filenames = new Set();
4979
5006
  let duplicateFilename;
5007
+ let previousEntryPosition = -1;
5008
+ const recoverWrappedFilesLength = !checkAmbiguity && !zip64EndOfDirectory;
5009
+ if (!filesLength && recoverWrappedFilesLength) {
5010
+ filesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
5011
+ if (filesLength) {
5012
+ addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5013
+ }
5014
+ }
4980
5015
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
4981
5016
  const fileEntry = new ZipEntry$1(reader, zipReader.options);
4982
5017
  if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32$1(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
@@ -5054,15 +5089,26 @@ class ZipReader {
5054
5089
  filename,
5055
5090
  comment
5056
5091
  });
5057
- readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
5092
+ if (readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6)) {
5093
+ addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD, filename);
5094
+ }
5058
5095
  fileEntry.offset += prependedDataLength;
5059
- startOffset = Math.min(getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset, startOffset);
5060
- if (checkAmbiguity) {
5061
- if (filenames.has(fileEntry.filename)) {
5062
- duplicateFilename = true;
5063
- }
5064
- filenames.add(fileEntry.filename);
5096
+ const entryPosition = getDiskOffset$1(reader, fileEntry.diskNumberStart) + fileEntry.offset;
5097
+ startOffset = Math.min(entryPosition, startOffset);
5098
+ if (entryPosition < previousEntryPosition) {
5099
+ addWarning(warnings, WARNING_UNSORTED_CENTRAL_DIRECTORY, filename);
5065
5100
  }
5101
+ previousEntryPosition = entryPosition;
5102
+ if ((fileEntry.version & MAX_8_BITS) > MAX_KNOWN_VERSION) {
5103
+ addWarning(warnings, WARNING_UNKNOWN_VERSION, filename);
5104
+ }
5105
+ if ((fileEntry.rawBitFlag & BITFLAG_COMPRESSED_PATCHED_DATA) == BITFLAG_COMPRESSED_PATCHED_DATA) {
5106
+ addWarning(warnings, WARNING_COMPRESSED_PATCHED_DATA, filename);
5107
+ }
5108
+ if (filenames.has(fileEntry.filename)) {
5109
+ duplicateFilename = true;
5110
+ }
5111
+ filenames.add(fileEntry.filename);
5066
5112
  const unixExternalUpper = (fileEntry.externalFileAttributes >> 16) & MAX_16_BITS;
5067
5113
  if (fileEntry.unixMode === UNDEFINED_VALUE && (unixExternalUpper & (FILE_ATTR_UNIX_DEFAULT_MASK | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_TYPE_DIR)) != 0) {
5068
5114
  fileEntry.unixMode = unixExternalUpper;
@@ -5086,7 +5132,7 @@ class ZipReader {
5086
5132
  internalFileAttribute: fileEntry.internalFileAttributes,
5087
5133
  externalFileAttribute: fileEntry.externalFileAttributes,
5088
5134
  executable,
5089
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
5135
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
5090
5136
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
5091
5137
  });
5092
5138
  const entry = new Entry(fileEntry);
@@ -5099,6 +5145,13 @@ class ZipReader {
5099
5145
  return arrayBufferPromise;
5100
5146
  };
5101
5147
  offset = endOffset;
5148
+ if (indexFile == filesLength - 1 && recoverWrappedFilesLength) {
5149
+ const wrappedFilesLength = getWrappedFilesLength(directoryView, directoryArray, offset);
5150
+ if (wrappedFilesLength) {
5151
+ filesLength += wrappedFilesLength;
5152
+ addWarning(warnings, WARNING_WRAPPED_ENTRIES_COUNT);
5153
+ }
5154
+ }
5102
5155
  const { onprogress } = options;
5103
5156
  if (onprogress) {
5104
5157
  try {
@@ -5123,18 +5176,22 @@ class ZipReader {
5123
5176
  zipReader.digitalSignature = digitalSignature;
5124
5177
  offsetAfterSignature = offset + 6 + digitalSignature.length;
5125
5178
  }
5126
- if (checkAmbiguity && offset != declaredDirectoryDataLength && offsetAfterSignature != declaredDirectoryDataLength) {
5127
- throwAmbiguousArchive("trailing central directory data");
5179
+ if ((offset != declaredDirectoryDataLength && offsetAfterSignature != declaredDirectoryDataLength) ||
5180
+ (!decryptedDirectory && offset != directoryDataLength && offsetAfterSignature != directoryDataLength)) {
5181
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA);
5128
5182
  }
5129
5183
  if (duplicateFilename) {
5130
- throwAmbiguousArchive("duplicate filename");
5184
+ reportAmbiguity(checkAmbiguity, warnings, WARNING_DUPLICATE_FILENAME);
5131
5185
  }
5132
5186
  const extractPrependedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
5133
5187
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
5134
5188
  const splitZipSignatureLength = (checkAmbiguity || extractPrependedData) && filesLength &&
5135
5189
  startOffset == SPLIT_ZIP_FILE_SIGNATURE_LENGTH && await startsWithSplitZipMarker(reader) ? SPLIT_ZIP_FILE_SIGNATURE_LENGTH : 0;
5136
5190
  if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > splitZipSignatureLength))) {
5137
- throwAmbiguousArchive("prepended data");
5191
+ throwAmbiguousArchive(WARNING_PREPENDED_DATA);
5192
+ }
5193
+ if (prependedDataLength || (filesLength && startOffset > SPLIT_ZIP_FILE_SIGNATURE_LENGTH)) {
5194
+ addWarning(warnings, WARNING_PREPENDED_DATA);
5138
5195
  }
5139
5196
  if (extractPrependedData) {
5140
5197
  zipReader.prependedData = startOffset > splitZipSignatureLength ?
@@ -5204,6 +5261,28 @@ class ZipReaderStream {
5204
5261
  }
5205
5262
  }
5206
5263
 
5264
+ async function isZipFile(reader, options = {}) {
5265
+ reader = new GenericReader(reader);
5266
+ await initStream(reader);
5267
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
5268
+ reader = new BlobReader(await streamToBlob(reader.readable));
5269
+ await initStream(reader);
5270
+ }
5271
+ if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
5272
+ return false;
5273
+ }
5274
+ const strictness = getStrictness(options, {});
5275
+ const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
5276
+ const maxAppendedDataSize = getMaxAppendedDataSize(options[OPTION_MAX_APPENDED_DATA_SIZE], strictness);
5277
+ const { endOfDirectoryInfo, endOfDirectoryReachingEndCount } = await findEndOfCentralDirectory(reader, rejectAmbiguousEndOfDirectory, maxAppendedDataSize);
5278
+ if (!endOfDirectoryInfo || (strictness == STRICTNESS_STRICT && endOfDirectoryReachingEndCount > 1)) {
5279
+ return false;
5280
+ }
5281
+ const commentLength = getUint16$1(getDataView(endOfDirectoryInfo), 20);
5282
+ const appendedDataOffset = endOfDirectoryInfo.offset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
5283
+ return reader.size - appendedDataOffset <= maxAppendedDataSize;
5284
+ }
5285
+
5207
5286
  let ZipEntry$1 = class ZipEntry {
5208
5287
 
5209
5288
  constructor(reader, options) {
@@ -5235,6 +5314,7 @@ let ZipEntry$1 = class ZipEntry {
5235
5314
  dataDescriptor
5236
5315
  } = bitFlag;
5237
5316
  const localDirectory = fileEntry.localDirectory = {};
5317
+ const warnings = fileEntry.warnings = [];
5238
5318
  const localHeaderOffset = getDiskOffset$1(reader, diskNumberStart) + offset;
5239
5319
  const dataArray = await readUint8Array(reader, localHeaderOffset, HEADER_SIZE);
5240
5320
  const dataView = getDataView(dataArray);
@@ -5257,6 +5337,7 @@ let ZipEntry$1 = class ZipEntry {
5257
5337
  extraFieldLength,
5258
5338
  filenameLength
5259
5339
  } = localDirectory;
5340
+ const dataOffset = localDirectory.dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
5260
5341
  const checkLocalDirectoryOption = getOptionValue$1(zipEntry, options, OPTION_CHECK_LOCAL_DIRECTORY);
5261
5342
  const entryStrictness = getStrictness(options, zipEntry.options);
5262
5343
  const checkLocalDirectory = getCheckLocalDirectory(checkLocalDirectoryOption, entryStrictness);
@@ -5274,10 +5355,10 @@ let ZipEntry$1 = class ZipEntry {
5274
5355
  if (checkLocalFilename) {
5275
5356
  localDirectory.rawFilename = rawLocalFilename;
5276
5357
  }
5277
- readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
5278
- if (checkLocalDirectory) {
5279
- validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename);
5358
+ if (readCommonFooter(zipEntry, localDirectory, dataView, 4, true)) {
5359
+ addWarning(warnings, WARNING_MALFORMED_EXTRA_FIELD);
5280
5360
  }
5361
+ validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, checkLocalDirectory ? UNDEFINED_VALUE : warnings);
5281
5362
  const { lastAccessDate, creationDate, uid, gid } = localDirectory;
5282
5363
  if (lastAccessDate) {
5283
5364
  fileEntry.lastAccessDate = lastAccessDate;
@@ -5310,7 +5391,6 @@ let ZipEntry$1 = class ZipEntry {
5310
5391
  throw new Error(ERR_ENCRYPTED);
5311
5392
  }
5312
5393
  }
5313
- const dataOffset = localHeaderOffset + HEADER_SIZE + filenameLength + extraFieldLength;
5314
5394
  if (dataOffset + compressedSize > reader.size) {
5315
5395
  throw new Error(ERR_ENTRY_DATA_OUT_OF_BOUNDS);
5316
5396
  }
@@ -5430,6 +5510,16 @@ function detectEncryptedCentralDirectory(directoryView) {
5430
5510
  return false;
5431
5511
  }
5432
5512
 
5513
+ function getWrappedFilesLength(directoryView, directoryArray, offset) {
5514
+ let wrappedFilesLength = 0;
5515
+ while (offset + CENTRAL_FILE_HEADER_LENGTH <= directoryArray.length && getUint32$1(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE) {
5516
+ offset += CENTRAL_FILE_HEADER_LENGTH +
5517
+ getUint16$1(directoryView, offset + 28) + getUint16$1(directoryView, offset + 30) + getUint16$1(directoryView, offset + 32);
5518
+ wrappedFilesLength++;
5519
+ }
5520
+ return wrappedFilesLength % (MAX_16_BITS + 1) ? 0 : wrappedFilesLength;
5521
+ }
5522
+
5433
5523
  function readDigitalSignature(signatureRecordArray) {
5434
5524
  if (signatureRecordArray.length >= 6) {
5435
5525
  const signatureRecordView = getDataView(signatureRecordArray);
@@ -5494,6 +5584,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5494
5584
  const extraField = directory.extraField = new Map();
5495
5585
  const rawExtraFieldView = getDataView(rawExtraField);
5496
5586
  let offsetExtraField = 0;
5587
+ let malformedExtraField = false;
5497
5588
  try {
5498
5589
  while (offsetExtraField < rawExtraField.length) {
5499
5590
  const type = getUint16$1(rawExtraFieldView, offsetExtraField);
@@ -5505,7 +5596,10 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5505
5596
  offsetExtraField += 4 + size;
5506
5597
  }
5507
5598
  } catch {
5508
- // ignored
5599
+ malformedExtraField = true;
5600
+ }
5601
+ if (offsetExtraField > rawExtraField.length) {
5602
+ malformedExtraField = true;
5509
5603
  }
5510
5604
  const compressionMethod = getUint16$1(dataView, offset + 4);
5511
5605
  Object.assign(directory, {
@@ -5573,6 +5667,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
5573
5667
  if (extraFieldUSDZ) {
5574
5668
  directory.extraFieldUSDZ = extraFieldUSDZ;
5575
5669
  }
5670
+ return malformedExtraField;
5576
5671
  }
5577
5672
 
5578
5673
  function readExtraFieldZip64(extraFieldZip64, directory) {
@@ -5602,10 +5697,11 @@ function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName,
5602
5697
  const computedCrc32View = getDataView(new Uint8Array(4));
5603
5698
  computedCrc32View.setUint32(0, computedCrc32.get(), true);
5604
5699
  const nameCrc32 = getUint32$1(extraFieldView, 1);
5700
+ const version = getUint8(extraFieldView, 0);
5605
5701
  Object.assign(extraFieldUnicode, {
5606
- version: getUint8(extraFieldView, 0),
5702
+ version,
5607
5703
  [propertyName]: decodeText(extraFieldUnicode.data.subarray(5)),
5608
- valid: !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
5704
+ valid: version == 1 && !fileEntry.bitFlag.languageEncodingFlag && nameCrc32 == getUint32$1(computedCrc32View, 0)
5609
5705
  });
5610
5706
  if (extraFieldUnicode.valid) {
5611
5707
  directory[propertyName] = extraFieldUnicode[propertyName];
@@ -6033,27 +6129,46 @@ async function readSignature(reader, view, anchoredOffset, signatureOffset, size
6033
6129
  return UNDEFINED_VALUE;
6034
6130
  }
6035
6131
 
6036
- function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename) {
6132
+ function validateLocalDirectory(zipEntry, localDirectory, rawLocalFilename, checkLocalFilename, warnings) {
6037
6133
  const { rawFilename } = zipEntry;
6134
+ const reject = !warnings;
6038
6135
  const maskedLocalDirectory = zipEntry.decryptedDirectory &&
6039
6136
  (localDirectory.rawBitFlag & BITFLAG_MASKED_LOCAL_HEADERS) == BITFLAG_MASKED_LOCAL_HEADERS;
6040
6137
  if (checkLocalFilename && !maskedLocalDirectory &&
6041
6138
  (rawLocalFilename.length != rawFilename.length ||
6042
6139
  rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte]))) {
6043
- throwAmbiguousArchive("mismatched local file header (filename)");
6140
+ reportAmbiguity(reject, warnings, "mismatched local file header (filename)");
6044
6141
  }
6045
6142
  if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
6046
- throwAmbiguousArchive("mismatched local file header (general purpose bit flag)");
6143
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG);
6047
6144
  }
6048
6145
  if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
6049
- throwAmbiguousArchive("mismatched local file header (compression method)");
6146
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD);
6050
6147
  }
6051
6148
  if (!localDirectory.bitFlag.dataDescriptor && !maskedLocalDirectory &&
6052
6149
  (localDirectory.crc32 || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
6053
6150
  (localDirectory.crc32 != zipEntry.crc32 ||
6054
6151
  localDirectory.compressedSize != zipEntry.compressedSize ||
6055
6152
  localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
6056
- throwAmbiguousArchive("mismatched local file header (crc32 or sizes)");
6153
+ reportAmbiguity(reject, warnings, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES);
6154
+ }
6155
+ }
6156
+
6157
+ function reportAmbiguity(reject, warnings, reason) {
6158
+ if (reject) {
6159
+ throwAmbiguousArchive(reason);
6160
+ } else {
6161
+ addWarning(warnings, reason);
6162
+ }
6163
+ }
6164
+
6165
+ function addWarning(warnings, reason, filename) {
6166
+ if (!warnings.some(warning => warning.reason == reason)) {
6167
+ const warning = { reason };
6168
+ if (filename !== UNDEFINED_VALUE) {
6169
+ warning.filename = filename;
6170
+ }
6171
+ warnings.push(warning);
6057
6172
  }
6058
6173
  }
6059
6174
 
@@ -6074,7 +6189,8 @@ function getFunctionOptionValue$1(zipReader, options, name) {
6074
6189
 
6075
6190
  function getDate(timeRaw) {
6076
6191
  const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & MAX_16_BITS;
6077
- return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
6192
+ const result = new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0);
6193
+ return result < MIN_DATE ? MIN_DATE : result;
6078
6194
  }
6079
6195
 
6080
6196
  function getDateNTFS(timeRaw) {
@@ -6129,8 +6245,23 @@ var zipReader = /*#__PURE__*/Object.freeze({
6129
6245
  ERR_UNSUPPORTED_ENCRYPTION: ERR_UNSUPPORTED_ENCRYPTION,
6130
6246
  ERR_UNSUPPORTED_UINT64: ERR_UNSUPPORTED_UINT64,
6131
6247
  ERR_WORKER_STARTUP_TIMEOUT: ERR_WORKER_STARTUP_TIMEOUT,
6248
+ WARNING_APPENDED_DATA: WARNING_APPENDED_DATA,
6249
+ WARNING_COMPRESSED_PATCHED_DATA: WARNING_COMPRESSED_PATCHED_DATA,
6250
+ WARNING_DUPLICATE_FILENAME: WARNING_DUPLICATE_FILENAME,
6251
+ WARNING_MALFORMED_EXTRA_FIELD: WARNING_MALFORMED_EXTRA_FIELD,
6252
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG: WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG,
6253
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD: WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD,
6254
+ WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES: WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES,
6255
+ WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY: WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY,
6256
+ WARNING_PREPENDED_DATA: WARNING_PREPENDED_DATA,
6257
+ WARNING_TRAILING_CENTRAL_DIRECTORY_DATA: WARNING_TRAILING_CENTRAL_DIRECTORY_DATA,
6258
+ WARNING_UNKNOWN_VERSION: WARNING_UNKNOWN_VERSION,
6259
+ WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA: WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA,
6260
+ WARNING_UNSORTED_CENTRAL_DIRECTORY: WARNING_UNSORTED_CENTRAL_DIRECTORY,
6261
+ WARNING_WRAPPED_ENTRIES_COUNT: WARNING_WRAPPED_ENTRIES_COUNT,
6132
6262
  ZipReader: ZipReader,
6133
- ZipReaderStream: ZipReaderStream
6263
+ ZipReaderStream: ZipReaderStream,
6264
+ isZipFile: isZipFile
6134
6265
  });
6135
6266
 
6136
6267
  /*
@@ -6227,153 +6358,151 @@ class ZipWriter {
6227
6358
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
6228
6359
  initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
6229
6360
  pendingAddFileCalls: new Set(),
6361
+ pendingErrors: [],
6230
6362
  bufferedWrites: 0,
6231
6363
  lastFileEntry: UNDEFINED_VALUE
6232
6364
  });
6233
6365
  }
6234
6366
 
6235
- async prependZip(reader) {
6236
- if (this.filenames.size) {
6237
- throw new Error(ERR_ZIP_NOT_EMPTY);
6238
- }
6239
- reader = new GenericReader(reader);
6240
- await initStream(reader);
6241
- if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6242
- reader = new BlobReader(await streamToBlob(reader.readable));
6243
- await initStream(reader);
6244
- }
6245
- const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6246
- const zipReader$1 = new ZipReader(reader);
6247
- const entries = await zipReader$1.getEntries();
6248
- await zipReader$1.close();
6249
- await initStream(this.writer);
6250
- const { directoryOffset } = zipReader$1;
6251
- if (this.addSplitZipSignature) {
6252
- delete this.addSplitZipSignature;
6253
- if (!await startsWithSplitZipSignature(reader)) {
6254
- await writeData(this.writer, getSplitZipSignatureArray());
6255
- this.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6256
- }
6257
- }
6258
- const entryPositions = await copyZipData(this, reader, entries, directoryOffset);
6259
- this.filenames = new Set(entries.map(entry => entry.filename));
6260
- this.fileEntries = new Map(entries.map(entry => {
6261
- const {
6262
- version,
6263
- rawLastModDate,
6264
- lastAccessDate,
6265
- creationDate,
6266
- rawFilename,
6267
- bitFlag,
6268
- encrypted,
6269
- uncompressedSize,
6270
- compressedSize,
6271
- extraFieldZip64
6272
- } = entry;
6273
- let {
6274
- compressionMethod,
6275
- rawExtraFieldZip64,
6276
- rawExtraFieldAES,
6277
- rawExtraFieldExtendedTimestamp,
6278
- rawExtraFieldNTFS,
6279
- rawExtraFieldUnix,
6280
- rawExtraField,
6281
- } = entry;
6282
- const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6283
- rawExtraFieldZip64 = rawExtraFieldZip64 || EMPTY_UINT8_ARRAY;
6284
- rawExtraFieldAES = rawExtraFieldAES || EMPTY_UINT8_ARRAY;
6285
- rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || EMPTY_UINT8_ARRAY;
6286
- rawExtraFieldNTFS = rawExtraFieldNTFS || EMPTY_UINT8_ARRAY;
6287
- rawExtraFieldUnix = rawExtraFieldUnix || EMPTY_UINT8_ARRAY;
6288
- rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6289
- if (entry.extraFieldAES) {
6290
- compressionMethod = COMPRESSION_METHOD_AES;
6291
- }
6292
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
6293
- const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6294
- const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6295
- const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6296
- const {
6297
- headerArray,
6298
- headerView
6299
- } = getHeaderArrayData({
6300
- version,
6301
- bitFlag: bitFlagValue,
6302
- compressionMethod,
6303
- uncompressedSize,
6304
- compressedSize,
6305
- rawLastModDate,
6306
- rawFilename,
6307
- zip64CompressedSize,
6308
- zip64UncompressedSize,
6309
- extraFieldLength
6310
- });
6311
- const { crc32 } = entry;
6312
- if (crc32 !== UNDEFINED_VALUE) {
6313
- setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6314
- }
6315
- const { offset, diskNumberStart } = entryPositions.get(entry);
6316
- Object.assign(entry, {
6317
- zip64UncompressedSize,
6318
- zip64CompressedSize,
6319
- offset,
6320
- diskNumberStart,
6321
- zip64DiskNumberStart: false,
6322
- rawExtraFieldZip64,
6323
- rawExtraFieldAES,
6324
- rawExtraFieldExtendedTimestamp,
6325
- rawExtraFieldNTFS,
6326
- rawExtraFieldUnix,
6327
- rawExtraField,
6328
- extendedTimestamp: rawExtraFieldExtendedTimestamp.length > 0 || rawExtraFieldNTFS.length > 0,
6329
- extraFieldExtendedTimestampFlag: 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0),
6330
- headerArray,
6331
- headerView
6332
- });
6333
- return [entry.filename, entry];
6334
- }));
6367
+ prependZip(reader) {
6368
+ return watchPromiseError(this, prependZipEntries(this, reader));
6335
6369
  }
6336
6370
 
6337
- async add(name = "", reader, options = {}) {
6371
+ appendZip(reader) {
6372
+ return watchPromiseError(this, this.appendZipEntries(reader));
6373
+ }
6374
+
6375
+ async appendZipEntries(reader) {
6338
6376
  const zipWriter = this;
6339
- options = Object.assign({}, options);
6340
- const { pendingAddFileCalls } = zipWriter;
6341
- if (workers < getConfiguration().maxWorkers) {
6342
- workers++;
6343
- } else {
6344
- await new Promise(resolve => pendingEntries.push(resolve));
6377
+ const { pendingAddFileCalls, filenames, fileEntries } = zipWriter;
6378
+ while (pendingAddFileCalls.size) {
6379
+ await Promise.allSettled(Array.from(pendingAddFileCalls));
6345
6380
  }
6346
- let promiseAddFile;
6347
- let nameAdded;
6381
+ let resolveAppendZip;
6382
+ const promiseAppendZip = new Promise(resolve => resolveAppendZip = resolve);
6383
+ pendingAddFileCalls.add(promiseAppendZip);
6384
+ const appendedFilenames = [];
6385
+ let releaseLockWriter;
6348
6386
  try {
6349
- name = name.trim();
6350
- if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6351
- name += DIRECTORY_SIGNATURE;
6352
- }
6353
- if (zipWriter.filenames.has(name)) {
6354
- throw new Error(ERR_DUPLICATED_NAME);
6355
- }
6356
- zipWriter.filenames.add(name);
6357
- nameAdded = true;
6358
- promiseAddFile = addFile(zipWriter, name, reader, options);
6359
- pendingAddFileCalls.add(promiseAddFile);
6360
- return await promiseAddFile;
6361
- } catch (error) {
6362
- if (nameAdded) {
6363
- zipWriter.filenames.delete(name);
6387
+ reader = new GenericReader(reader);
6388
+ await initStream(reader);
6389
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
6390
+ reader = new BlobReader(await streamToBlob(reader.readable));
6391
+ await initStream(reader);
6392
+ }
6393
+ const { ZipReader } = await Promise.resolve().then(function () { return zipReader; });
6394
+ const zipReader$1 = new ZipReader(reader);
6395
+ const entries = await zipReader$1.getEntries();
6396
+ await zipReader$1.close();
6397
+ await initStream(zipWriter.writer);
6398
+ const { directoryOffset } = zipReader$1;
6399
+ entries.forEach(({ filename }) => {
6400
+ if (filenames.has(filename)) {
6401
+ throw new Error(ERR_DUPLICATED_NAME);
6402
+ }
6403
+ filenames.add(filename);
6404
+ appendedFilenames.push(filename);
6405
+ });
6406
+ zipWriter.writerLocked = true;
6407
+ const { lockWriter } = zipWriter;
6408
+ zipWriter.lockWriter = new Promise(resolve => releaseLockWriter = () => {
6409
+ zipWriter.writerLocked = false;
6410
+ resolve();
6411
+ });
6412
+ await lockWriter;
6413
+ if (zipWriter.addSplitZipSignature) {
6414
+ delete zipWriter.addSplitZipSignature;
6415
+ if (!await startsWithSplitZipSignature(reader)) {
6416
+ await writeData(zipWriter.writer, getSplitZipSignatureArray());
6417
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
6418
+ }
6364
6419
  }
6420
+ const entryPositions = await copyZipData(zipWriter, reader, entries, directoryOffset);
6421
+ entries.forEach(entry => {
6422
+ const {
6423
+ version,
6424
+ rawLastModDate,
6425
+ rawFilename,
6426
+ bitFlag,
6427
+ encrypted,
6428
+ uncompressedSize,
6429
+ compressedSize,
6430
+ extraFieldZip64
6431
+ } = entry;
6432
+ let {
6433
+ compressionMethod,
6434
+ rawExtraField,
6435
+ } = entry;
6436
+ const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
6437
+ rawExtraField = removeExtraFieldZip64(rawExtraField || EMPTY_UINT8_ARRAY);
6438
+ if (entry.extraFieldAES) {
6439
+ compressionMethod = COMPRESSION_METHOD_AES;
6440
+ }
6441
+ const extraFieldLength = getLength(rawExtraField);
6442
+ const zip64UncompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.uncompressedSize !== UNDEFINED_VALUE;
6443
+ const zip64CompressedSize = Boolean(extraFieldZip64) && extraFieldZip64.compressedSize !== UNDEFINED_VALUE;
6444
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
6445
+ const {
6446
+ headerArray,
6447
+ headerView
6448
+ } = getHeaderArrayData({
6449
+ version,
6450
+ bitFlag: bitFlagValue,
6451
+ compressionMethod,
6452
+ uncompressedSize,
6453
+ compressedSize,
6454
+ rawLastModDate,
6455
+ rawFilename,
6456
+ zip64CompressedSize,
6457
+ zip64UncompressedSize,
6458
+ extraFieldLength
6459
+ });
6460
+ const { crc32 } = entry;
6461
+ if (crc32 !== UNDEFINED_VALUE) {
6462
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, crc32);
6463
+ }
6464
+ const { offset, diskNumberStart } = entryPositions.get(entry);
6465
+ Object.assign(entry, {
6466
+ zip64UncompressedSize,
6467
+ zip64CompressedSize,
6468
+ offset,
6469
+ diskNumberStart,
6470
+ zip64DiskNumberStart: false,
6471
+ rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
6472
+ rawExtraFieldAES: EMPTY_UINT8_ARRAY,
6473
+ rawExtraFieldExtendedTimestamp: EMPTY_UINT8_ARRAY,
6474
+ rawExtraFieldNTFS: EMPTY_UINT8_ARRAY,
6475
+ rawExtraFieldUnix: EMPTY_UINT8_ARRAY,
6476
+ rawExtraField,
6477
+ rawCentralExtraField: EMPTY_UINT8_ARRAY,
6478
+ extendedTimestamp: false,
6479
+ headerArray,
6480
+ headerView
6481
+ });
6482
+ fileEntries.set(entry.filename, entry);
6483
+ });
6484
+ } catch (error) {
6485
+ appendedFilenames.forEach(filename => filenames.delete(filename));
6365
6486
  throw error;
6366
6487
  } finally {
6367
- pendingAddFileCalls.delete(promiseAddFile);
6368
- const pendingEntry = pendingEntries.shift();
6369
- if (pendingEntry) {
6370
- pendingEntry();
6371
- } else {
6372
- workers--;
6488
+ resolveAppendZip();
6489
+ pendingAddFileCalls.delete(promiseAppendZip);
6490
+ if (releaseLockWriter) {
6491
+ releaseLockWriter();
6373
6492
  }
6374
6493
  }
6375
6494
  }
6376
6495
 
6496
+ add(name = "", reader, options = {}) {
6497
+ const zipWriter = this;
6498
+ const { pendingAddFileCalls } = zipWriter;
6499
+ const promiseAddFile = addFileEntry(zipWriter, name, reader, options);
6500
+ pendingAddFileCalls.add(promiseAddFile);
6501
+ const deletePendingAddFileCall = () => pendingAddFileCalls.delete(promiseAddFile);
6502
+ Promise.prototype.then.call(promiseAddFile, deletePendingAddFileCall, deletePendingAddFileCall);
6503
+ return watchPromiseError(zipWriter, promiseAddFile);
6504
+ }
6505
+
6377
6506
  remove(entry) {
6378
6507
  const { filenames, fileEntries } = this;
6379
6508
  // deno-lint-ignore valid-typeof
@@ -6404,6 +6533,19 @@ class ZipWriter {
6404
6533
  while (pendingAddFileCalls.size) {
6405
6534
  await Promise.allSettled(Array.from(pendingAddFileCalls));
6406
6535
  }
6536
+ await Promise.allSettled(zipWriter.pendingErrors.map(watcher => watcher.recorded));
6537
+ const unobservedWatchers = zipWriter.pendingErrors.filter(watcher => watcher.error && !watcher.observed);
6538
+ if (unobservedWatchers.length) {
6539
+ const unobservedErrors = unobservedWatchers.map(watcher => watcher.error);
6540
+ unobservedWatchers.forEach(watcher => watcher.observed = true);
6541
+ const [error] = unobservedErrors;
6542
+ try {
6543
+ error.entryErrors = unobservedErrors;
6544
+ } catch {
6545
+ // ignored
6546
+ }
6547
+ throw error;
6548
+ }
6407
6549
  await closeFile(zipWriter, comment, options);
6408
6550
  const preventClose = !ownsWritable(writer) && getOptionValue(zipWriter, options, OPTION_PREVENT_CLOSE);
6409
6551
  if (!preventClose) {
@@ -6438,11 +6580,7 @@ class ZipWriterStream {
6438
6580
  try {
6439
6581
  await zipWriter.close();
6440
6582
  } catch (error) {
6441
- try {
6442
- await zipWriter.writer.writable.abort(error);
6443
- } catch {
6444
- // ignored
6445
- }
6583
+ await abortWritable(zipWriter, error);
6446
6584
  }
6447
6585
  }
6448
6586
  }
@@ -6459,8 +6597,89 @@ class ZipWriterStream {
6459
6597
  }
6460
6598
 
6461
6599
  async close(comment = UNDEFINED_VALUE, options = {}) {
6462
- await Promise.all(Array.from(this.pendingAddFileCalls));
6463
- return this.zipWriter.close(comment, options);
6600
+ const { zipWriter } = this;
6601
+ const results = await Promise.allSettled(Array.from(this.pendingAddFileCalls));
6602
+ const entryErrors = results.filter(result => result.status == "rejected").map(result => result.reason);
6603
+ if (entryErrors.length) {
6604
+ const [error] = entryErrors;
6605
+ try {
6606
+ error.entryErrors = entryErrors;
6607
+ } catch {
6608
+ // ignored
6609
+ }
6610
+ await abortWritable(zipWriter, error);
6611
+ throw error;
6612
+ }
6613
+ try {
6614
+ return await zipWriter.close(comment, options);
6615
+ } catch (error) {
6616
+ await abortWritable(zipWriter, error);
6617
+ throw error;
6618
+ }
6619
+ }
6620
+ }
6621
+
6622
+ class WatchedPromise extends Promise {
6623
+
6624
+ then(onFulfilled, onRejected) {
6625
+ const { watcher } = this;
6626
+ if (watcher) {
6627
+ watcher.observed = true;
6628
+ }
6629
+ return super.then(onFulfilled, onRejected);
6630
+ }
6631
+ }
6632
+
6633
+ function watchPromiseError(zipWriter, promise) {
6634
+ const watchedPromise = new WatchedPromise((resolve, reject) => Promise.prototype.then.call(promise, resolve, reject));
6635
+ const watcher = {};
6636
+ watchedPromise.watcher = watcher;
6637
+ watcher.recorded = Promise.prototype.then.call(watchedPromise, UNDEFINED_VALUE, error => watcher.error = error);
6638
+ zipWriter.pendingErrors.push(watcher);
6639
+ return watchedPromise;
6640
+ }
6641
+
6642
+ async function prependZipEntries(zipWriter, reader) {
6643
+ if (zipWriter.filenames.size) {
6644
+ throw new Error(ERR_ZIP_NOT_EMPTY);
6645
+ }
6646
+ await zipWriter.appendZipEntries(reader);
6647
+ }
6648
+
6649
+ async function addFileEntry(zipWriter, name, reader, options) {
6650
+ options = Object.assign({}, options);
6651
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6652
+ name += DIRECTORY_SIGNATURE;
6653
+ }
6654
+ if (zipWriter.filenames.has(name)) {
6655
+ throw new Error(ERR_DUPLICATED_NAME);
6656
+ }
6657
+ zipWriter.filenames.add(name);
6658
+ if (workers < getConfiguration().maxWorkers) {
6659
+ workers++;
6660
+ } else {
6661
+ await new Promise(resolve => pendingEntries.push(resolve));
6662
+ }
6663
+ try {
6664
+ return await addFile(zipWriter, name, reader, options);
6665
+ } catch (error) {
6666
+ zipWriter.filenames.delete(name);
6667
+ throw error;
6668
+ } finally {
6669
+ const pendingEntry = pendingEntries.shift();
6670
+ if (pendingEntry) {
6671
+ pendingEntry();
6672
+ } else {
6673
+ workers--;
6674
+ }
6675
+ }
6676
+ }
6677
+
6678
+ async function abortWritable(zipWriter, error) {
6679
+ try {
6680
+ await zipWriter.writer.writable.abort(error);
6681
+ } catch {
6682
+ // ignored
6464
6683
  }
6465
6684
  }
6466
6685
 
@@ -6519,7 +6738,6 @@ async function addFile(zipWriter, name, reader, options) {
6519
6738
  }
6520
6739
 
6521
6740
  function resolveAttributes(zipWriter, name, options) {
6522
- name = name.trim();
6523
6741
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
6524
6742
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? VERSION_MADE_BY_MSDOS : VERSION_MADE_BY_UNIX);
6525
6743
  const executable = getOptionValue(zipWriter, options, PROPERTY_NAME_EXECUTABLE);
@@ -6663,11 +6881,12 @@ function resolveMetadata(zipWriter, name, options) {
6663
6881
  if (getLength(rawComment) > MAX_16_BITS) {
6664
6882
  throw new Error(ERR_INVALID_ENTRY_COMMENT);
6665
6883
  }
6666
- const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION, VERSION_DEFLATE);
6667
- if (version > MAX_16_BITS) {
6884
+ const version = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION);
6885
+ if (version !== UNDEFINED_VALUE && version > MAX_16_BITS) {
6668
6886
  throw new Error(ERR_INVALID_VERSION);
6669
6887
  }
6670
6888
  const lastModDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_MODIFICATION_DATE, new Date());
6889
+ const rawLastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE);
6671
6890
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6672
6891
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6673
6892
  const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
@@ -6711,7 +6930,7 @@ function resolveMetadata(zipWriter, name, options) {
6711
6930
  if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
6712
6931
  dataDescriptor = false;
6713
6932
  }
6714
- if (dataDescriptor === UNDEFINED_VALUE || zipCrypto) {
6933
+ if (dataDescriptor === UNDEFINED_VALUE || (zipCrypto && !passThrough)) {
6715
6934
  dataDescriptor = true;
6716
6935
  }
6717
6936
  if (level !== UNDEFINED_VALUE && level != 6) {
@@ -6723,6 +6942,7 @@ function resolveMetadata(zipWriter, name, options) {
6723
6942
  }
6724
6943
  const rawExtraField = serializeExtraField(options[PROPERTY_NAME_EXTRA_FIELD]);
6725
6944
  const rawLocalExtraField = serializeExtraField(options[OPTION_LOCAL_EXTRA_FIELD]);
6945
+ const rawCentralExtraField = serializeExtraField(options[OPTION_CENTRAL_EXTRA_FIELD]);
6726
6946
  return {
6727
6947
  comment,
6728
6948
  resolvedOptions: {
@@ -6730,6 +6950,7 @@ function resolveMetadata(zipWriter, name, options) {
6730
6950
  rawComment,
6731
6951
  version,
6732
6952
  lastModDate,
6953
+ rawLastModDate,
6733
6954
  lastAccessDate,
6734
6955
  creationDate,
6735
6956
  internalFileAttributes,
@@ -6757,7 +6978,8 @@ function resolveMetadata(zipWriter, name, options) {
6757
6978
  dataDescriptor,
6758
6979
  zip64,
6759
6980
  rawExtraField,
6760
- rawLocalExtraField
6981
+ rawLocalExtraField,
6982
+ rawCentralExtraField
6761
6983
  }
6762
6984
  };
6763
6985
  }
@@ -6899,7 +7121,6 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
6899
7121
  let { name } = entry;
6900
7122
  const { size } = entry;
6901
7123
  const options = Object.assign({}, entry.options);
6902
- name = name.trim();
6903
7124
  if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
6904
7125
  name += DIRECTORY_SIGNATURE;
6905
7126
  }
@@ -7005,10 +7226,8 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7005
7226
  }
7006
7227
  await initStream(fileWriter);
7007
7228
  const diskOffset = getDiskOffset(writer);
7008
- if (zipWriter.addSplitZipSignature) {
7009
- delete zipWriter.addSplitZipSignature;
7010
- await writeData(writer, getSplitZipSignatureArray());
7011
- zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
7229
+ if (zipWriter.addSplitZipSignature && !bufferedWrite) {
7230
+ await writeSplitZipSignature(zipWriter, writer);
7012
7231
  }
7013
7232
  if (usdz && !bufferedWrite) {
7014
7233
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
@@ -7035,6 +7254,9 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
7035
7254
  if (bufferedWrite) {
7036
7255
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
7037
7256
  await requestLockWriter();
7257
+ if (zipWriter.addSplitZipSignature) {
7258
+ await writeSplitZipSignature(zipWriter, writer);
7259
+ }
7038
7260
  writingBufferedEntryData = true;
7039
7261
  writerSizeBeforeEntry = writer.size;
7040
7262
  await skipDiskIfNeeded();
@@ -7154,6 +7376,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7154
7376
  versionMadeBy,
7155
7377
  rawComment,
7156
7378
  rawExtraField,
7379
+ rawCentralExtraField,
7157
7380
  useWebWorkers,
7158
7381
  transferStreams,
7159
7382
  onstart,
@@ -7197,6 +7420,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lockFileEntry
7197
7420
  rawExtraFieldUnix,
7198
7421
  rawExtraFieldAES,
7199
7422
  rawExtraField,
7423
+ rawCentralExtraField,
7200
7424
  extendedTimestamp,
7201
7425
  msDosCompatible,
7202
7426
  internalFileAttributes,
@@ -7306,6 +7530,7 @@ function getHeaderInfo(options) {
7306
7530
  const {
7307
7531
  rawFilename,
7308
7532
  lastModDate,
7533
+ rawLastModDate: rawLastModDateOption,
7309
7534
  lastAccessDate,
7310
7535
  creationDate,
7311
7536
  level,
@@ -7439,6 +7664,9 @@ function getHeaderInfo(options) {
7439
7664
  if (compressionMethod === UNDEFINED_VALUE) {
7440
7665
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
7441
7666
  }
7667
+ if (version === UNDEFINED_VALUE) {
7668
+ version = compressionMethod == COMPRESSION_METHOD_STORE && !directory && !encrypted ? VERSION_STORE : VERSION_DEFLATE;
7669
+ }
7442
7670
  const { codecVersionNeeded } = options;
7443
7671
  if (compressed && codecVersionNeeded !== UNDEFINED_VALUE) {
7444
7672
  version = version > codecVersionNeeded ? version : codecVersionNeeded;
@@ -7471,6 +7699,7 @@ function getHeaderInfo(options) {
7471
7699
  compressionMethod,
7472
7700
  uncompressedSize,
7473
7701
  lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
7702
+ rawLastModDate: rawLastModDateOption,
7474
7703
  rawFilename,
7475
7704
  zip64CompressedSize,
7476
7705
  zip64UncompressedSize,
@@ -7677,9 +7906,9 @@ function updateLocalHeader({
7677
7906
 
7678
7907
  async function closeFile(zipWriter, comment, options) {
7679
7908
  const directoryDataLength = createDirectoryRecords(zipWriter.fileEntries);
7680
- const { directoryStart, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7909
+ const { directoryStart, directoryEnd, directoryArray } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
7681
7910
  const signatureLength = await writeDigitalSignatureRecord(zipWriter, directoryArray, options);
7682
- await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryDataLength, signatureLength });
7911
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { directoryStart, directoryEnd, directoryDataLength, signatureLength });
7683
7912
  }
7684
7913
 
7685
7914
  function createDirectoryRecords(files) {
@@ -7692,6 +7921,7 @@ function createDirectoryRecords(files) {
7692
7921
  rawExtraFieldNTFS,
7693
7922
  rawExtraFieldUnix,
7694
7923
  rawExtraField,
7924
+ rawCentralExtraField,
7695
7925
  extendedTimestamp,
7696
7926
  extraFieldExtendedTimestampFlag,
7697
7927
  lastModDate,
@@ -7746,7 +7976,8 @@ function createDirectoryRecords(files) {
7746
7976
  rawExtraFieldNTFS,
7747
7977
  rawExtraFieldUnix,
7748
7978
  rawExtraFieldTimestamp,
7749
- rawExtraField);
7979
+ rawExtraField,
7980
+ rawCentralExtraField);
7750
7981
  if (extraFieldLength > MAX_16_BITS) {
7751
7982
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
7752
7983
  }
@@ -7763,6 +7994,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7763
7994
  let directoryDiskOffset = 0;
7764
7995
  let directoryStartDiskNumber = getDiskNumber(writer);
7765
7996
  let directoryStartDiskOffset = getDiskOffset(writer);
7997
+ let directoryEndDiskEntriesLength = 0;
7766
7998
  for (const [indexFileEntry, fileEntry] of Array.from(fileEntries.values()).entries()) {
7767
7999
  const {
7768
8000
  offset: fileEntryOffset,
@@ -7773,6 +8005,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7773
8005
  rawExtraFieldNTFS,
7774
8006
  rawExtraFieldUnix,
7775
8007
  rawExtraField,
8008
+ rawCentralExtraField,
7776
8009
  rawComment,
7777
8010
  versionMadeBy,
7778
8011
  headerArray,
@@ -7787,11 +8020,12 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7787
8020
  uncompressedSize,
7788
8021
  compressedSize
7789
8022
  } = fileEntry;
7790
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
8023
+ const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField, rawCentralExtraField);
7791
8024
  const directoryRecordLength = CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
7792
8025
  if (exceedsAvailableSize(writer, offset + directoryRecordLength - directoryDiskOffset)) {
7793
8026
  await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
7794
8027
  directoryDiskOffset = offset;
8028
+ directoryEndDiskEntriesLength = 0;
7795
8029
  await writer.closeDisk();
7796
8030
  }
7797
8031
  if (indexFileEntry == 0) {
@@ -7824,9 +8058,11 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7824
8058
  directoryRecord.writeBytes(rawExtraFieldNTFS);
7825
8059
  directoryRecord.writeBytes(rawExtraFieldUnix);
7826
8060
  directoryRecord.writeBytes(rawExtraField);
8061
+ directoryRecord.writeBytes(rawCentralExtraField);
7827
8062
  directoryRecord.writeBytes(rawComment);
7828
8063
  arraySet(directoryArray, directoryRecord.array, offset);
7829
8064
  offset += directoryRecordLength;
8065
+ directoryEndDiskEntriesLength++;
7830
8066
  if (options.onprogress) {
7831
8067
  try {
7832
8068
  await options.onprogress(indexFileEntry + 1, fileEntries.size, new Entry(fileEntry));
@@ -7838,6 +8074,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
7838
8074
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
7839
8075
  return {
7840
8076
  directoryStart: { diskNumber: directoryStartDiskNumber, diskOffset: directoryStartDiskOffset },
8077
+ directoryEnd: { diskNumber: getDiskNumber(writer), entriesLength: directoryEndDiskEntriesLength },
7841
8078
  directoryArray
7842
8079
  };
7843
8080
  }
@@ -7866,16 +8103,20 @@ async function writeDigitalSignatureRecord(zipWriter, directoryArray, options) {
7866
8103
 
7867
8104
  async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7868
8105
  const { writer } = zipWriter;
7869
- const { directoryStart, signatureLength } = cdInfo;
8106
+ const { directoryStart, directoryEnd, signatureLength } = cdInfo;
7870
8107
  let { directoryDataLength } = cdInfo;
7871
8108
  let fileEntriesLength = zipWriter.fileEntries.size;
7872
8109
  let diskNumber = directoryStart.diskNumber;
7873
8110
  let directoryOffset = getSegmentOffset(zipWriter, directoryStart);
8111
+ const commentLength = getLength(comment);
8112
+ if (commentLength > MAX_16_BITS) {
8113
+ throw new Error(ERR_INVALID_COMMENT);
8114
+ }
8115
+ let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7874
8116
  let lastDiskNumber = getDiskNumber(writer);
7875
- if (exceedsAvailableSize(writer, END_OF_CENTRAL_DIR_LENGTH)) {
8117
+ if (exceedsAvailableSize(writer, (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH) + commentLength)) {
7876
8118
  lastDiskNumber++;
7877
8119
  }
7878
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
7879
8120
  if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || fileEntriesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
7880
8121
  if (zip64 === false) {
7881
8122
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -7883,15 +8124,12 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7883
8124
  zip64 = true;
7884
8125
  }
7885
8126
  }
7886
- const commentLength = getLength(comment);
7887
- if (commentLength > MAX_16_BITS) {
7888
- throw new Error(ERR_INVALID_COMMENT);
7889
- }
7890
8127
  const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
7891
8128
  if (exceedsAvailableSize(writer, getLength(endOfdirectoryRecord.array) + commentLength)) {
7892
8129
  await writer.closeDisk();
7893
8130
  }
7894
8131
  lastDiskNumber = getDiskNumber(writer);
8132
+ let diskFileEntriesLength = lastDiskNumber == directoryEnd.diskNumber ? directoryEnd.entriesLength : 0;
7895
8133
  if (zip64) {
7896
8134
  endOfdirectoryRecord.writeUint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
7897
8135
  endOfdirectoryRecord.writeUint64(44);
@@ -7899,7 +8137,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7899
8137
  endOfdirectoryRecord.writeUint16(45);
7900
8138
  endOfdirectoryRecord.writeUint32(lastDiskNumber);
7901
8139
  endOfdirectoryRecord.writeUint32(diskNumber);
7902
- endOfdirectoryRecord.writeUint64(fileEntriesLength);
8140
+ endOfdirectoryRecord.writeUint64(diskFileEntriesLength);
7903
8141
  endOfdirectoryRecord.writeUint64(fileEntriesLength);
7904
8142
  endOfdirectoryRecord.writeUint64(directoryDataLength);
7905
8143
  endOfdirectoryRecord.writeUint64(directoryOffset);
@@ -7912,6 +8150,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7912
8150
  lastDiskNumber = MAX_16_BITS;
7913
8151
  diskNumber = MAX_16_BITS;
7914
8152
  }
8153
+ diskFileEntriesLength = MAX_16_BITS;
7915
8154
  fileEntriesLength = MAX_16_BITS;
7916
8155
  directoryOffset = MAX_32_BITS;
7917
8156
  directoryDataLength = MAX_32_BITS;
@@ -7919,7 +8158,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
7919
8158
  endOfdirectoryRecord.writeUint32(END_OF_CENTRAL_DIR_SIGNATURE);
7920
8159
  endOfdirectoryRecord.writeUint16(lastDiskNumber);
7921
8160
  endOfdirectoryRecord.writeUint16(diskNumber);
7922
- endOfdirectoryRecord.writeUint16(fileEntriesLength);
8161
+ endOfdirectoryRecord.writeUint16(diskFileEntriesLength);
7923
8162
  endOfdirectoryRecord.writeUint16(fileEntriesLength);
7924
8163
  endOfdirectoryRecord.writeUint32(directoryDataLength);
7925
8164
  endOfdirectoryRecord.writeUint32(directoryOffset);
@@ -8018,9 +8257,21 @@ async function copyZipData(zipWriter, reader, entries, directoryOffset) {
8018
8257
  async function copyData(zipWriter, reader, offset, size) {
8019
8258
  if (size > 0) {
8020
8259
  const { writer } = zipWriter;
8021
- await createReadable(reader, { offset, size }).pipeTo(writer.writable, { preventClose: true, preventAbort: true });
8022
- writer.size += size;
8023
- zipWriter.offset += size;
8260
+ let copiedLength = 0;
8261
+ try {
8262
+ await flushBufferedData(createReadable(reader, { offset, size }), writer, UNDEFINED_VALUE, chunkLength => copiedLength += chunkLength);
8263
+ } catch (error) {
8264
+ zipWriter.hasCorruptedEntries = true;
8265
+ try {
8266
+ error.corruptedEntry = true;
8267
+ } catch {
8268
+ // ignored
8269
+ }
8270
+ throw error;
8271
+ } finally {
8272
+ writer.size += copiedLength;
8273
+ zipWriter.offset += copiedLength;
8274
+ }
8024
8275
  }
8025
8276
  }
8026
8277
 
@@ -8045,6 +8296,12 @@ function getSplitZipSignatureArray() {
8045
8296
  return signatureArray;
8046
8297
  }
8047
8298
 
8299
+ async function writeSplitZipSignature(zipWriter, writer) {
8300
+ delete zipWriter.addSplitZipSignature;
8301
+ await writeData(writer, getSplitZipSignatureArray());
8302
+ zipWriter.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
8303
+ }
8304
+
8048
8305
  async function writeData(writer, array) {
8049
8306
  const { writable } = writer;
8050
8307
  const streamWriter = writable.getWriter();
@@ -9131,6 +9388,7 @@ const ERR_ENTRY_EXISTS = "Entry filename already exists";
9131
9388
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
9132
9389
  const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
9133
9390
  const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
9391
+ const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
9134
9392
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
9135
9393
  const ERR_ABORTED = "The operation was aborted";
9136
9394
  const ABORT_ERROR_NAME = "AbortError";
@@ -9998,6 +10256,7 @@ function getChildEntryOptions(child, selectedEntry, options) {
9998
10256
  versionMadeBy,
9999
10257
  comment,
10000
10258
  lastModDate,
10259
+ rawLastModDate,
10001
10260
  creationDate,
10002
10261
  lastAccessDate,
10003
10262
  uncompressedSize,
@@ -10008,6 +10267,7 @@ function getChildEntryOptions(child, selectedEntry, options) {
10008
10267
  extraFieldAES,
10009
10268
  internalFileAttributes,
10010
10269
  extraField,
10270
+ bitFlag,
10011
10271
  uid,
10012
10272
  gid
10013
10273
  } = child.data;
@@ -10045,6 +10305,16 @@ function getChildEntryOptions(child, selectedEntry, options) {
10045
10305
  encryptionStrength,
10046
10306
  compressionMethod
10047
10307
  };
10308
+ if (bitFlag) {
10309
+ passThroughOptions.dataDescriptor = bitFlag.dataDescriptor;
10310
+ }
10311
+ const lastModDateOverride = childOptions.lastModDate === UNDEFINED_VALUE ? options.lastModDate : childOptions.lastModDate;
10312
+ if (lastModDateOverride === UNDEFINED_VALUE) {
10313
+ passThroughOptions.rawLastModDate = rawLastModDate;
10314
+ } else if (zipCrypto && (!bitFlag || bitFlag.dataDescriptor) && lastModDateOverride instanceof Date &&
10315
+ getDosTimeHighByte(lastModDateOverride) != ((rawLastModDate >>> 8) & MAX_8_BITS)) {
10316
+ throw new Error(ERR_ZIP_CRYPTO_LAST_MOD_DATE);
10317
+ }
10048
10318
  }
10049
10319
  }
10050
10320
  const entryOptions = Object.assign({ lastModDate: child.defaultLastModDate }, zipEntryMetadata, options, childOptions, passThroughOptions, { directory: child.directory });
@@ -10054,6 +10324,16 @@ function getChildEntryOptions(child, selectedEntry, options) {
10054
10324
  return { name, entryOptions };
10055
10325
  }
10056
10326
 
10327
+ function getDosTimeHighByte(lastModDate) {
10328
+ let dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
10329
+ if (dosLastModDate < MIN_DATE) {
10330
+ dosLastModDate = MIN_DATE;
10331
+ } else if (dosLastModDate > MAX_DATE) {
10332
+ dosLastModDate = MAX_DATE;
10333
+ }
10334
+ return ((dosLastModDate.getHours() << 3) | (dosLastModDate.getMinutes() >> 3)) & MAX_8_BITS;
10335
+ }
10336
+
10057
10337
  function getDeterminedSize(child, passThrough) {
10058
10338
  const { reader } = child;
10059
10339
  if (reader && reader.size !== UNDEFINED_VALUE) {
@@ -10392,4 +10672,4 @@ function addChild(parent, name, params, directory) {
10392
10672
  }
10393
10673
  }
10394
10674
 
10395
- export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_ENTRY_EXISTS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH, ERR_INVALID_READER_OPTIONS, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_READABLE_CONSUMED, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION$1 as ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, Writer, ZipDirectoryEntry, ZipEntry, ZipFS, ZipFileEntry, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, fs, getMimeType, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };
10675
+ export { BlobReader, BlobWriter, Data64URIReader, Data64URIWriter, ERR_ABORTED, ERR_AMBIGUOUS_ARCHIVE, ERR_BAD_FORMAT, ERR_CENTRAL_DIRECTORY_NOT_FOUND, ERR_DUPLICATED_NAME, ERR_ENCRYPTED, ERR_ENCRYPTED_CENTRAL_DIRECTORY, ERR_ENTRY_DATA_OUT_OF_BOUNDS, ERR_ENTRY_EXISTS, ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND, ERR_EOCDR_NOT_FOUND, ERR_EXTRAFIELD_ZIP64_NOT_FOUND, ERR_HTTP_RANGE, ERR_HTTP_RESOURCE_CHANGED, ERR_INVALID_AUTHENTICATION_CODE, ERR_INVALID_CODEC_DEFINITION, ERR_INVALID_CODEC_MODULE, ERR_INVALID_COMMENT, ERR_INVALID_COMMENT_TYPE, ERR_INVALID_COMPRESSED_DATA, ERR_INVALID_CRC32, ERR_INVALID_DATE, ERR_INVALID_ENCRYPTION_STRENGTH, ERR_INVALID_ENTRY_COMMENT, ERR_INVALID_ENTRY_COMMENT_TYPE, ERR_INVALID_ENTRY_NAME, ERR_INVALID_EXTRAFIELD, ERR_INVALID_EXTRAFIELD_DATA, ERR_INVALID_EXTRAFIELD_DATA_TYPE, ERR_INVALID_EXTRAFIELD_TYPE, ERR_INVALID_FILENAME_VALIDATION, ERR_INVALID_FUNCTION_OPTION, ERR_INVALID_GID, ERR_INVALID_LEVEL, ERR_INVALID_MAX_APPENDED_DATA_SIZE, ERR_INVALID_MAX_WORKERS, ERR_INVALID_MSDOS_ATTRIBUTES, ERR_INVALID_MSDOS_DATA, ERR_INVALID_PASSWORD, ERR_INVALID_PASSWORD_TYPE, ERR_INVALID_PASS_THROUGH, ERR_INVALID_READER_OPTIONS, ERR_INVALID_SIGNAL, ERR_INVALID_SIGNATURE, ERR_INVALID_SIGNATURE_DATA, ERR_INVALID_STRICTNESS, ERR_INVALID_UID, ERR_INVALID_UNCOMPRESSED_SIZE, ERR_INVALID_UNIX_EXTRA_FIELD_TYPE, ERR_INVALID_UNIX_ID_SIZE, ERR_INVALID_UNIX_MODE, ERR_INVALID_VERSION, ERR_ITERATOR_COMPLETED_TOO_SOON, ERR_LOCAL_FILE_HEADER_NOT_FOUND, ERR_OVERLAPPING_ENTRY, ERR_READABLE_CONSUMED, ERR_RESERVED_COMPRESSION_METHOD, ERR_SPLIT_ZIP_FILE, ERR_UNDEFINED_COMPRESSION_METHOD, ERR_UNDEFINED_READER, ERR_UNDEFINED_UNCOMPRESSED_SIZE, ERR_UNDETERMINED_SIZE, ERR_UNSAFE_FILENAME, ERR_UNSUPPORTED_COMPRESSION$1 as ERR_UNSUPPORTED_COMPRESSION, ERR_UNSUPPORTED_CONTEXT, ERR_UNSUPPORTED_CRYPTO_API, ERR_UNSUPPORTED_ENCRYPTION, ERR_UNSUPPORTED_ENCRYPTION_PASS_THROUGH, ERR_UNSUPPORTED_ENCRYPTION_USDZ, ERR_UNSUPPORTED_FORMAT, ERR_UNSUPPORTED_UINT64, ERR_WORKER_STARTUP_TIMEOUT, ERR_WRITER_NOT_INITIALIZED, ERR_ZIP_CRYPTO_LAST_MOD_DATE, ERR_ZIP_NOT_EMPTY, HttpRangeReader, HttpReader, Reader, SplitDataReader, SplitDataWriter, TextReader, TextWriter, Uint8ArrayReader, Uint8ArrayWriter, WARNING_APPENDED_DATA, WARNING_COMPRESSED_PATCHED_DATA, WARNING_DUPLICATE_FILENAME, WARNING_MALFORMED_EXTRA_FIELD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_BIT_FLAG, WARNING_MISMATCHED_LOCAL_FILE_HEADER_COMPRESSION_METHOD, WARNING_MISMATCHED_LOCAL_FILE_HEADER_CRC32_OR_SIZES, WARNING_MISMATCHED_ZIP64_END_OF_CENTRAL_DIRECTORY, WARNING_PREPENDED_DATA, WARNING_TRAILING_CENTRAL_DIRECTORY_DATA, WARNING_UNKNOWN_VERSION, WARNING_UNKNOWN_ZIP64_EXTENSIBLE_DATA, WARNING_UNSORTED_CENTRAL_DIRECTORY, WARNING_WRAPPED_ENTRIES_COUNT, Writer, ZipDirectoryEntry, ZipEntry, ZipFS, ZipFileEntry, ZipReader, ZipReaderStream, ZipWriter, ZipWriterStream, configure, createBlobTempStream, createOPFSTempStream, createSyncAccessHandleTempStream, fs, getMimeType, isZipFile, registerCodec, resetConfiguration, terminateWorkersAndModule as terminateWorkers, unregisterCodec };