@zip.js/zip.js 2.8.55 → 2.8.56

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.
@@ -141,6 +141,8 @@ export {
141
141
  checkFunctionOption,
142
142
  checkSignalOption,
143
143
  checkPasswordOption,
144
+ checkInteger,
145
+ checkIntegerOption,
144
146
  toNumber
145
147
  };
146
148
 
@@ -164,6 +166,18 @@ function checkPasswordOption(password, rawPassword) {
164
166
  }
165
167
  }
166
168
 
169
+ function checkInteger(value, maxValue, errorMessage) {
170
+ if (!Number.isInteger(value) || value < 0 || value > maxValue) {
171
+ throw new Error(errorMessage);
172
+ }
173
+ }
174
+
175
+ function checkIntegerOption(value, maxValue, errorMessage) {
176
+ if (value !== UNDEFINED_VALUE) {
177
+ checkInteger(value, maxValue, errorMessage);
178
+ }
179
+ }
180
+
167
181
  function toNumber(value) {
168
182
  return typeof value == STRING_TYPE && value.trim() ? Number(value) : value;
169
183
  }
@@ -544,8 +544,15 @@ class ZipReader {
544
544
  yield entry;
545
545
  }
546
546
  let offsetAfterSignature = offset;
547
- const digitalSignature = readDigitalSignature(directoryArray.subarray(offset)) ||
547
+ let digitalSignature = readDigitalSignature(directoryArray.subarray(offset)) ||
548
548
  (decryptedDirectory ? readDigitalSignature(dataAfterEncryptedDirectory) : UNDEFINED_VALUE);
549
+ if (!digitalSignature && !decryptedDirectory) {
550
+ const signatureRecordOffset = directoryDataOffset + offset;
551
+ const signatureRecordLength = Math.min(centralDirectoryEndOffset - signatureRecordOffset, 6 + MAX_16_BITS);
552
+ if (signatureRecordLength >= 6) {
553
+ digitalSignature = readDigitalSignature(await readUint8Array(reader, signatureRecordOffset, signatureRecordLength));
554
+ }
555
+ }
549
556
  if (digitalSignature) {
550
557
  zipReader.digitalSignature = digitalSignature;
551
558
  offsetAfterSignature = offset + 6 + digitalSignature.length;
@@ -235,6 +235,8 @@ import {
235
235
  checkFunctionOption,
236
236
  checkSignalOption,
237
237
  checkPasswordOption,
238
+ checkInteger,
239
+ checkIntegerOption,
238
240
  toNumber
239
241
  } from "./options.js";
240
242
 
@@ -276,6 +278,8 @@ const ERR_INVALID_SIGNATURE_DATA = "Signature data exceeds 64KB";
276
278
 
277
279
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
278
280
  const EXTRAFIELD_OFFSET_AES_VENDOR_VERSION = 4;
281
+ const EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD = 9;
282
+ const EXTRAFIELD_USDZ_MAX_LENGTH = 67;
279
283
  const VENDOR_VERSION_AE_1 = 1;
280
284
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
281
285
  const UNIX_EXTRA_FIELD_TYPE = "unix";
@@ -322,16 +326,14 @@ class ZipWriter {
322
326
  await zipReader.close();
323
327
  await initStream(this.writer);
324
328
  const { directoryOffset } = zipReader;
325
- let splitZipSignatureLength = 0;
326
329
  if (this.addSplitZipSignature) {
327
330
  delete this.addSplitZipSignature;
328
331
  if (!await startsWithSplitZipSignature(reader)) {
329
332
  await writeData(this.writer, getSplitZipSignatureArray());
330
- splitZipSignatureLength = SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
331
- this.offset += splitZipSignatureLength;
333
+ this.offset += SPLIT_ZIP_FILE_SIGNATURE_LENGTH;
332
334
  }
333
335
  }
334
- const entryPositions = await copyZipData(this, reader, entries, directoryOffset, splitZipSignatureLength);
336
+ const entryPositions = await copyZipData(this, reader, entries, directoryOffset);
335
337
  this.filenames = new Set(entries.map(entry => entry.filename));
336
338
  this.fileEntries = new Map(entries.map(entry => {
337
339
  const {
@@ -611,7 +613,8 @@ async function addFile(zipWriter, name, reader, options) {
611
613
  signature: options[PROPERTY_NAME_SIGNATURE],
612
614
  crc32: options.crc32 === UNDEFINED_VALUE ? options[PROPERTY_NAME_SIGNATURE] : options.crc32,
613
615
  offset: zipWriter.offset - diskOffset,
614
- diskNumberStart: diskNumber
616
+ diskNumberStart: diskNumber,
617
+ [OPTION_USDZ]: zipWriter.options[OPTION_USDZ]
615
618
  });
616
619
  const headerInfo = getHeaderInfo(options);
617
620
  const dataDescriptorInfo = getDataDescriptorInfo(options);
@@ -643,15 +646,9 @@ function resolveAttributes(zipWriter, name, options) {
643
646
  let setuid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETUID);
644
647
  let setgid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETGID);
645
648
  let sticky = getOptionValue(zipWriter, options, PROPERTY_NAME_STICKY);
646
- if (uid !== UNDEFINED_VALUE && (!Number.isInteger(uid) || uid < 0 || uid > MAX_32_BITS)) {
647
- throw new Error(ERR_INVALID_UID);
648
- }
649
- if (gid !== UNDEFINED_VALUE && (!Number.isInteger(gid) || gid < 0 || gid > MAX_32_BITS)) {
650
- throw new Error(ERR_INVALID_GID);
651
- }
652
- if (unixMode !== UNDEFINED_VALUE && (!Number.isInteger(unixMode) || unixMode < 0 || unixMode > MAX_16_BITS)) {
653
- throw new Error(ERR_INVALID_UNIX_MODE);
654
- }
649
+ checkIntegerOption(uid, MAX_32_BITS, ERR_INVALID_UID);
650
+ checkIntegerOption(gid, MAX_32_BITS, ERR_INVALID_GID);
651
+ checkIntegerOption(unixMode, MAX_16_BITS, ERR_INVALID_UNIX_MODE);
655
652
  if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
656
653
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
657
654
  }
@@ -673,9 +670,7 @@ function resolveAttributes(zipWriter, name, options) {
673
670
  msDosCompatible = true;
674
671
  versionMadeBy = (versionMadeBy & MAX_8_BITS);
675
672
  }
676
- if (msdosAttributesRaw !== UNDEFINED_VALUE && (!Number.isInteger(msdosAttributesRaw) || msdosAttributesRaw < 0 || msdosAttributesRaw > MAX_8_BITS)) {
677
- throw new Error(ERR_INVALID_MSDOS_ATTRIBUTES);
678
- }
673
+ checkIntegerOption(msdosAttributesRaw, MAX_8_BITS, ERR_INVALID_MSDOS_ATTRIBUTES);
679
674
  if (msdosAttributes && (typeof msdosAttributes !== OBJECT_TYPE || Array.isArray(msdosAttributes))) {
680
675
  throw new Error(ERR_INVALID_MSDOS_DATA);
681
676
  }
@@ -815,9 +810,7 @@ function resolveMetadata(zipWriter, name, options) {
815
810
  throw new Error(ERR_UNSUPPORTED_COMPRESSION);
816
811
  }
817
812
  let level = getNumberOptionValue(zipWriter, options, OPTION_LEVEL);
818
- if (level !== UNDEFINED_VALUE && (!Number.isInteger(level) || level < 0 || level > MAX_LEVEL)) {
819
- throw new Error(ERR_INVALID_LEVEL);
820
- }
813
+ checkIntegerOption(level, MAX_LEVEL, ERR_INVALID_LEVEL);
821
814
  if (zipWriter.options[OPTION_USDZ]) {
822
815
  if (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) {
823
816
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION_USDZ);
@@ -895,9 +888,7 @@ function serializeExtraField(extraField) {
895
888
  let extraFieldSize = 0;
896
889
  let offset = 0;
897
890
  extraField.forEach((data, type) => {
898
- if (!Number.isInteger(type) || type < 0 || type > MAX_16_BITS) {
899
- throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
900
- }
891
+ checkInteger(type, MAX_16_BITS, ERR_INVALID_EXTRAFIELD_TYPE);
901
892
  if (!(data instanceof Uint8Array)) {
902
893
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA_TYPE);
903
894
  }
@@ -1012,7 +1003,9 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
1012
1003
  const usdz = writerOptions[OPTION_USDZ];
1013
1004
  const files = new Map();
1014
1005
  let layoutDependsOnWriteOrder = Boolean(usdz);
1015
- let offset = 0;
1006
+ const initialOffset = writerOptions[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : writerOptions[OPTION_OFFSET];
1007
+ let offset = initialOffset;
1008
+ let minimumEntrySize = INFINITY_VALUE;
1016
1009
  for (const entry of entries) {
1017
1010
  let { name } = entry;
1018
1011
  const { size } = entry;
@@ -1036,7 +1029,7 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
1036
1029
  if (hasContent && !metadata.passThrough && isCompressed(sizes.compressionMethod, sizes.level)) {
1037
1030
  throw new Error(ERR_UNDETERMINED_SIZE);
1038
1031
  }
1039
- const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes);
1032
+ const entryOptions = Object.assign({}, options, attributesInfo.resolvedOptions, metadata, sizes, { [OPTION_USDZ]: usdz });
1040
1033
  const headerInfo = getHeaderInfo(entryOptions);
1041
1034
  const dataDescriptorInfo = getDataDescriptorInfo(entryOptions);
1042
1035
  const entryInfo = {
@@ -1047,15 +1040,17 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
1047
1040
  appendExtraFieldUSDZ(entryInfo, offset);
1048
1041
  }
1049
1042
  const compressedSize = hasContent ? maximumCompressedSize : 0;
1050
- if (offset >= MAX_32_BITS) {
1051
- layoutDependsOnWriteOrder = true;
1052
- }
1053
1043
  files.set(name, Object.assign({}, entryOptions, headerInfo, {
1054
1044
  offset,
1055
1045
  diskNumberStart: 0,
1056
1046
  compressedSize
1057
1047
  }));
1058
- offset += entryInfo.metadataSize + compressedSize;
1048
+ const entrySize = entryInfo.metadataSize + compressedSize;
1049
+ minimumEntrySize = Math.min(minimumEntrySize, entrySize);
1050
+ offset += entrySize;
1051
+ }
1052
+ if (files.size && offset - minimumEntrySize >= MAX_32_BITS) {
1053
+ layoutDependsOnWriteOrder = true;
1059
1054
  }
1060
1055
  if (layoutDependsOnWriteOrder && !writeOrderGuaranteed) {
1061
1056
  throw new Error(ERR_UNDETERMINED_SIZE);
@@ -1069,7 +1064,7 @@ async function getEntriesSize(writerOptions, entries, writeOrderGuaranteed, comm
1069
1064
  zip64 = true;
1070
1065
  }
1071
1066
  }
1072
- return offset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
1067
+ return offset - initialOffset + directoryDataLength + commentLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
1073
1068
  }
1074
1069
 
1075
1070
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
@@ -1566,12 +1561,13 @@ function getHeaderInfo(options) {
1566
1561
  if (passThrough && crc32 !== UNDEFINED_VALUE) {
1567
1562
  rawExtraFieldAES[EXTRAFIELD_OFFSET_AES_VENDOR_VERSION] = VENDOR_VERSION_AE_1;
1568
1563
  }
1569
- rawExtraFieldAES[9] = compressionMethod;
1564
+ setUint16(getDataView(rawExtraFieldAES), EXTRAFIELD_OFFSET_AES_COMPRESSION_METHOD, compressionMethod);
1570
1565
  compressionMethod = COMPRESSION_METHOD_AES;
1571
1566
  }
1572
1567
  const localExtraFieldZip64Length = writeLocalExtraFieldZip64 ? getLength(rawLocalExtraFieldZip64) : 0;
1573
1568
  const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField, rawLocalExtraField);
1574
- if (extraFieldLength > MAX_16_BITS) {
1569
+ const maximumUsdzExtraFieldLength = options[OPTION_USDZ] ? EXTRAFIELD_USDZ_MAX_LENGTH : 0;
1570
+ if (extraFieldLength + maximumUsdzExtraFieldLength > MAX_16_BITS) {
1575
1571
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
1576
1572
  }
1577
1573
  const dosLastModDate = new Date(Math.ceil(Math.floor(lastModDate.getTime() / 1000) / 2) * 2000);
@@ -1972,7 +1968,11 @@ async function writeDigitalSignatureRecord(zipWriter, directoryArray, options) {
1972
1968
  signatureRecord.writeUint32(DIGITAL_SIGNATURE_RECORD_SIGNATURE);
1973
1969
  signatureRecord.writeUint16(signatureDataLength);
1974
1970
  signatureRecord.writeBytes(signatureData);
1975
- await writeData(zipWriter.writer, signatureRecord.array);
1971
+ const { writer } = zipWriter;
1972
+ if (exceedsAvailableSize(writer, getLength(signatureRecord.array))) {
1973
+ await writer.closeDisk();
1974
+ }
1975
+ await writeData(writer, signatureRecord.array);
1976
1976
  return 6 + signatureDataLength;
1977
1977
  }
1978
1978
  return 0;
@@ -2083,7 +2083,7 @@ async function startsWithSplitZipSignature(reader) {
2083
2083
  return getUint32(getDataView(signatureArray), 0) == SPLIT_ZIP_FILE_SIGNATURE;
2084
2084
  }
2085
2085
 
2086
- async function copyZipData(zipWriter, reader, entries, directoryOffset, splitZipSignatureLength) {
2086
+ async function copyZipData(zipWriter, reader, entries, directoryOffset) {
2087
2087
  const { writer } = zipWriter;
2088
2088
  const entryPositions = new Map();
2089
2089
  if (writer.closeDisk) {
@@ -2104,9 +2104,10 @@ async function copyZipData(zipWriter, reader, entries, directoryOffset, splitZip
2104
2104
  }
2105
2105
  await copyData(zipWriter, reader, copiedLength, directoryOffset - copiedLength);
2106
2106
  } else {
2107
+ const baseOffset = zipWriter.offset;
2107
2108
  await copyData(zipWriter, reader, 0, directoryOffset);
2108
2109
  entries.forEach(entry => entryPositions.set(entry, {
2109
- offset: splitZipSignatureLength + getSourceOffset(reader, entry),
2110
+ offset: baseOffset + getSourceOffset(reader, entry),
2110
2111
  diskNumberStart: 0
2111
2112
  }));
2112
2113
  }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A JavaScript library to zip and unzip files in the browser, Deno and Node.js",
4
4
  "author": "Gildas Lormeau",
5
5
  "license": "BSD-3-Clause",
6
- "version": "2.8.55",
6
+ "version": "2.8.56",
7
7
  "type": "module",
8
8
  "keywords": [
9
9
  "zip",