@zip.js/zip.js 2.9.0 → 2.11.0

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.
Files changed (50) hide show
  1. package/README.md +40 -0
  2. package/deno.json +1 -1
  3. package/dist/zip-core-external.js +17 -46
  4. package/dist/zip-core-external.min.js +1 -1
  5. package/dist/zip-core.js +16 -46
  6. package/dist/zip-core.min.js +1 -1
  7. package/dist/zip-fs-core-external.js +170 -88
  8. package/dist/zip-fs-core-external.min.js +1 -1
  9. package/dist/zip-fs-core.js +171 -88
  10. package/dist/zip-fs-core.min.js +1 -1
  11. package/dist/zip-fs-external.js +170 -88
  12. package/dist/zip-fs-external.min.js +1 -1
  13. package/dist/zip-fs-native.js +174 -91
  14. package/dist/zip-fs-native.min.js +1 -1
  15. package/dist/zip-fs.js +175 -92
  16. package/dist/zip-fs.min.js +1 -1
  17. package/dist/zip-legacy.js +18 -48
  18. package/dist/zip-legacy.min.js +1 -1
  19. package/dist/zip-module.wasm +0 -0
  20. package/dist/zip-native.js +19 -49
  21. package/dist/zip-native.min.js +1 -1
  22. package/dist/zip-web-worker-native.js +1 -1
  23. package/dist/zip-web-worker.js +1 -1
  24. package/dist/zip.js +20 -50
  25. package/dist/zip.min.js +1 -1
  26. package/index-native.cjs +174 -91
  27. package/index-native.min.js +1 -1
  28. package/index.cjs +175 -92
  29. package/index.d.cts +92 -44
  30. package/index.d.ts +92 -44
  31. package/index.min.js +1 -1
  32. package/lib/core/codec-pool.js +0 -2
  33. package/lib/core/codec-registry.js +2 -0
  34. package/lib/core/streams/codec-stream.js +0 -2
  35. package/lib/core/streams/common-crypto.js +1 -3
  36. package/lib/core/streams/zip-entry-stream.js +2 -5
  37. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  38. package/lib/core/streams/zlib-wasm/zlib-streams.js +1 -1
  39. package/lib/core/streams/zlib-wasm/zlib-streams.wasm +0 -0
  40. package/lib/core/util/decode-cp437.js +4 -11
  41. package/lib/core/version.js +1 -1
  42. package/lib/core/web-worker-inline-native.js +1 -1
  43. package/lib/core/web-worker-inline-wasm.js +1 -1
  44. package/lib/core/zip-entry.js +0 -6
  45. package/lib/core/zip-fs.js +155 -44
  46. package/lib/core/zip-reader.js +1 -6
  47. package/lib/core/zip-writer.js +4 -19
  48. package/lib/core/zlib-streams-inline.js +1 -1
  49. package/lib/zip-core-reader.js +0 -1
  50. package/package.json +1 -1
@@ -1461,8 +1461,7 @@
1461
1461
  const GET_RANDOM_VALUES_SUPPORTED = typeof crypto != UNDEFINED_TYPE && typeof crypto.getRandomValues == FUNCTION_TYPE;
1462
1462
 
1463
1463
  const ERR_INVALID_PASSWORD = "Invalid password";
1464
- const ERR_INVALID_SIGNATURE = "Invalid signature";
1465
- const ERR_INVALID_AUTHENTICATION_CODE = ERR_INVALID_SIGNATURE;
1464
+ const ERR_INVALID_AUTHENTICATION_CODE = "Invalid authentication code";
1466
1465
  const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
1467
1466
  const ERR_UNSUPPORTED_CRYPTO_API = "Crypto API not supported";
1468
1467
 
@@ -2036,6 +2035,7 @@
2036
2035
  const ERR_INVALID_CODEC_DEFINITION = "Invalid codec definition";
2037
2036
  const ERR_RESERVED_COMPRESSION_METHOD = "Reserved compression method";
2038
2037
  const ERR_INVALID_CODEC_MODULE = "Invalid codec module";
2038
+ const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
2039
2039
 
2040
2040
  const RESERVED_COMPRESSION_METHODS = [
2041
2041
  COMPRESSION_METHOD_STORE,
@@ -2135,8 +2135,7 @@
2135
2135
 
2136
2136
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
2137
2137
  const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
2138
- const ERR_INVALID_CRC32 = ERR_INVALID_SIGNATURE;
2139
- const ERR_UNSUPPORTED_COMPRESSION$2 = "Compression method not supported";
2138
+ const ERR_INVALID_CRC32 = "Invalid CRC32";
2140
2139
  const FORMAT_DEFLATE_RAW = "deflate-raw";
2141
2140
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
2142
2141
  const FORMAT_GZIP = "gzip";
@@ -2404,7 +2403,7 @@
2404
2403
 
2405
2404
  function createCodecStream(CodecStreamClass, format, options) {
2406
2405
  if (!CodecStreamClass) {
2407
- throw new Error(ERR_UNSUPPORTED_COMPRESSION$2);
2406
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
2408
2407
  }
2409
2408
  return new CodecStreamClass(format, options);
2410
2409
  }
@@ -3475,21 +3474,14 @@
3475
3474
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3476
3475
  */
3477
3476
 
3478
- /* global TextDecoder */
3479
-
3480
3477
  const CP437 = "\0\u263A\u263B\u2665\u2666\u2663\u2660\u2022\u25D8\u25CB\u25D9\u2642\u2640\u266A\u266B\u263C\u25BA\u25C4\u2195\u203C\u00B6\u00A7\u25AC\u21A8\u2191\u2193\u2192\u2190\u221F\u2194\u25B2\u25BC !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00C7\u00FC\u00E9\u00E2\u00E4\u00E0\u00E5\u00E7\u00EA\u00EB\u00E8\u00EF\u00EE\u00EC\u00C4\u00C5\u00C9\u00E6\u00C6\u00F4\u00F6\u00F2\u00FB\u00F9\u00FF\u00D6\u00DC\u00A2\u00A3\u00A5\u20A7\u0192\u00E1\u00ED\u00F3\u00FA\u00F1\u00D1\u00AA\u00BA\u00BF\u2310\u00AC\u00BD\u00BC\u00A1\u00AB\u00BB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\u00DF\u0393\u03C0\u03A3\u03C3\u00B5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\u00B1\u2265\u2264\u2320\u2321\u00F7\u2248\u00B0\u2219\u00B7\u221A\u207F\u00B2\u25A0\u00A0".split("");
3481
- const VALID_CP437 = CP437.length == 256;
3482
3478
 
3483
3479
  function decodeCP437(stringValue) {
3484
- if (VALID_CP437) {
3485
- let result = "";
3486
- for (let indexCharacter = 0; indexCharacter < stringValue.length; indexCharacter++) {
3487
- result += CP437[stringValue[indexCharacter]];
3488
- }
3489
- return result;
3490
- } else {
3491
- return new TextDecoder().decode(stringValue);
3480
+ let result = "";
3481
+ for (let indexCharacter = 0; indexCharacter < stringValue.length; indexCharacter++) {
3482
+ result += CP437[stringValue[indexCharacter]];
3492
3483
  }
3484
+ return result;
3493
3485
  }
3494
3486
 
3495
3487
  /*
@@ -4575,8 +4567,6 @@
4575
4567
  const PROPERTY_NAME_RAW_CREATION_DATE = "rawCreationDate";
4576
4568
  const PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES = "internalFileAttributes";
4577
4569
  const PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttributes";
4578
- const PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES = "internalFileAttribute";
4579
- const PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES = "externalFileAttribute";
4580
4570
  const PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW = "msdosAttributesRaw";
4581
4571
  const PROPERTY_NAME_MSDOS_ATTRIBUTES = "msdosAttributes";
4582
4572
  const PROPERTY_NAME_MS_DOS_COMPATIBLE = "msDosCompatible";
@@ -4635,8 +4625,6 @@
4635
4625
  PROPERTY_NAME_DISK_NUMBER_START,
4636
4626
  PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES,
4637
4627
  PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES,
4638
- PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES,
4639
- PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES,
4640
4628
  PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW,
4641
4629
  PROPERTY_NAME_MSDOS_ATTRIBUTES,
4642
4630
  PROPERTY_NAME_MS_DOS_COMPATIBLE,
@@ -4724,7 +4712,6 @@
4724
4712
  const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
4725
4713
  const ERR_ENCRYPTED = "File contains encrypted entry";
4726
4714
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
4727
- const ERR_UNSUPPORTED_COMPRESSION$1 = "Compression method not supported";
4728
4715
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
4729
4716
  const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
4730
4717
  const ERR_ENTRY_DATA_OUT_OF_BOUNDS = "Entry data out of bounds";
@@ -5105,8 +5092,6 @@
5105
5092
  sticky,
5106
5093
  symlink,
5107
5094
  unixExternalUpper,
5108
- internalFileAttribute: fileEntry.internalFileAttributes,
5109
- externalFileAttribute: fileEntry.externalFileAttributes,
5110
5095
  executable,
5111
5096
  directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || fileEntry.filename.endsWith(DIRECTORY_SIGNATURE),
5112
5097
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
@@ -5305,7 +5290,7 @@
5305
5290
  rawPassword = rawPassword && rawPassword.length && rawPassword;
5306
5291
  if (extraFieldAES) {
5307
5292
  if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
5308
- throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
5293
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5309
5294
  }
5310
5295
  }
5311
5296
  if (dataArray.length < HEADER_SIZE || getUint32$1(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
@@ -5361,7 +5346,7 @@
5361
5346
  }
5362
5347
  const registeredCodec = passThrough ? UNDEFINED_VALUE : getRegisteredCodec(compressionMethod);
5363
5348
  if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64 && !registeredCodec && !passThrough) {
5364
- throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
5349
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5365
5350
  }
5366
5351
  if (encrypted) {
5367
5352
  if (!zipCrypto && (extraFieldAES.strength < 1 || extraFieldAES.strength > 3)) {
@@ -6213,14 +6198,13 @@
6213
6198
  ERR_INVALID_FILENAME_VALIDATION: ERR_INVALID_FILENAME_VALIDATION,
6214
6199
  ERR_INVALID_MAX_APPENDED_DATA_SIZE: ERR_INVALID_MAX_APPENDED_DATA_SIZE,
6215
6200
  ERR_INVALID_PASSWORD: ERR_INVALID_PASSWORD,
6216
- ERR_INVALID_SIGNATURE: ERR_INVALID_SIGNATURE,
6217
6201
  ERR_INVALID_STRICTNESS: ERR_INVALID_STRICTNESS,
6218
6202
  ERR_INVALID_UNCOMPRESSED_SIZE: ERR_INVALID_UNCOMPRESSED_SIZE,
6219
6203
  ERR_LOCAL_FILE_HEADER_NOT_FOUND: ERR_LOCAL_FILE_HEADER_NOT_FOUND,
6220
6204
  ERR_OVERLAPPING_ENTRY: ERR_OVERLAPPING_ENTRY,
6221
6205
  ERR_SPLIT_ZIP_FILE: ERR_SPLIT_ZIP_FILE,
6222
6206
  ERR_UNSAFE_FILENAME: ERR_UNSAFE_FILENAME,
6223
- ERR_UNSUPPORTED_COMPRESSION: ERR_UNSUPPORTED_COMPRESSION$1,
6207
+ ERR_UNSUPPORTED_COMPRESSION: ERR_UNSUPPORTED_COMPRESSION,
6224
6208
  ERR_UNSUPPORTED_ENCRYPTION: ERR_UNSUPPORTED_ENCRYPTION,
6225
6209
  ERR_UNSUPPORTED_UINT64: ERR_UNSUPPORTED_UINT64,
6226
6210
  ERR_WORKER_STARTUP_TIMEOUT: ERR_WORKER_STARTUP_TIMEOUT,
@@ -6288,7 +6272,6 @@
6288
6272
  const ERR_INVALID_EXTRAFIELD_TYPE = "Invalid extra field type (must be integer 0..65535)";
6289
6273
  const ERR_INVALID_EXTRAFIELD_DATA_TYPE = "Invalid extra field data (must be a Uint8Array)";
6290
6274
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
6291
- const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
6292
6275
  const MIN_UNIX_TIME = -2147483648;
6293
6276
  const MAX_UNIX_TIME = 2147483647;
6294
6277
  const MIN_NTFS_TIME = BigInt(0);
@@ -6728,9 +6711,7 @@
6728
6711
  Object.assign(fileEntry, {
6729
6712
  name,
6730
6713
  comment,
6731
- extraField,
6732
- [PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES]: fileEntry.internalFileAttributes,
6733
- [PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES]: fileEntry.externalFileAttributes
6714
+ extraField
6734
6715
  });
6735
6716
  return new Entry(fileEntry);
6736
6717
  }
@@ -6777,7 +6758,7 @@
6777
6758
  if (versionMadeBy > MAX_16_BITS) {
6778
6759
  throw new Error(ERR_INVALID_VERSION);
6779
6760
  }
6780
- let externalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_EXTERNAL_FILE_ATTRIBUTES);
6761
+ let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
6781
6762
  const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
6782
6763
  if (!externalFileAttributesProvided) {
6783
6764
  externalFileAttributes = 0;
@@ -6887,7 +6868,7 @@
6887
6868
  const rawLastModDate = getOptionValue(zipWriter, options, PROPERTY_NAME_RAW_LAST_MODIFICATION_DATE);
6888
6869
  const lastAccessDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_LAST_ACCESS_DATE);
6889
6870
  const creationDate = getDateOptionValue(zipWriter, options, PROPERTY_NAME_CREATION_DATE);
6890
- const internalFileAttributes = getAliasedOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, PROPERTY_NAME_DEPRECATED_INTERNAL_FILE_ATTRIBUTES, 0);
6871
+ const internalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_INTERNAL_FILE_ATTRIBUTES, 0);
6891
6872
  const passThrough = getOptionValue(zipWriter, options, OPTION_PASS_THROUGH);
6892
6873
  const password = getOptionValue(zipWriter, options, OPTION_PASSWORD);
6893
6874
  const rawPassword = getOptionValue(zipWriter, options, OPTION_RAW_PASSWORD);
@@ -8356,16 +8337,6 @@
8356
8337
  return checkFunctionOption(getOptionValue(zipWriter, options, name));
8357
8338
  }
8358
8339
 
8359
- function getAliasedOptionValue(zipWriter, options, name, deprecatedName, defaultValue) {
8360
- const value = getAliasedValue(options, name, deprecatedName);
8361
- const result = value === UNDEFINED_VALUE ? getAliasedValue(zipWriter.options, name, deprecatedName) : value;
8362
- return result === UNDEFINED_VALUE ? defaultValue : result;
8363
- }
8364
-
8365
- function getAliasedValue(options, name, deprecatedName) {
8366
- return options[name] === UNDEFINED_VALUE ? options[deprecatedName] : options[name];
8367
- }
8368
-
8369
8340
  function getNumberOptionValue(zipWriter, options, name, defaultValue) {
8370
8341
  return toNumber(getOptionValue(zipWriter, options, name, defaultValue));
8371
8342
  }
@@ -8624,7 +8595,7 @@
8624
8595
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8625
8596
  */
8626
8597
 
8627
- const VERSION = "2.9.0";
8598
+ const VERSION = "2.11.0";
8628
8599
 
8629
8600
  /*
8630
8601
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -9103,7 +9074,14 @@
9103
9074
 
9104
9075
 
9105
9076
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
9077
+ const ERR_DUPLICATE_IMPORTED_ENTRY = "Duplicate entry filename in the imported zip file";
9078
+ const ERR_INVALID_DUPLICATES = "Invalid duplicates option (must be \"throw\", \"keep-first\" or \"keep-last\")";
9079
+ const ERR_ANCESTOR_ENTRY = "Entry is a ancestor of target entry";
9106
9080
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
9081
+ const DUPLICATES_THROW = "throw";
9082
+ const DUPLICATES_KEEP_FIRST = "keep-first";
9083
+ const DUPLICATES_KEEP_LAST = "keep-last";
9084
+ const DUPLICATES_VALUES = new Set([DUPLICATES_THROW, DUPLICATES_KEEP_FIRST, DUPLICATES_KEEP_LAST]);
9107
9085
  const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
9108
9086
  const ERR_INVALID_READER_OPTIONS = "Invalid readerOptions (must be an object)";
9109
9087
  const ERR_ZIP_CRYPTO_LAST_MOD_DATE = "The last modification date of an entry encrypted with ZipCrypto cannot be changed when passThrough is set";
@@ -9180,12 +9158,26 @@
9180
9158
  }
9181
9159
 
9182
9160
  rename(name) {
9183
- const parent = this.parent;
9184
- if (parent && parent.getChildByName(name)) {
9185
- throw new Error(ERR_ENTRY_EXISTS);
9186
- } else {
9187
- this.name = name;
9161
+ const zipEntry = this;
9162
+ let parent = zipEntry.parent;
9163
+ if (parent) {
9164
+ const path = splitPath(name);
9165
+ if (path) {
9166
+ name = path.pop();
9167
+ parent = getPathParent(parent, path, zipEntry);
9168
+ }
9169
+ const existingChild = parent.getChildByName(name);
9170
+ if (existingChild && existingChild != zipEntry) {
9171
+ throw new Error(ERR_ENTRY_EXISTS);
9172
+ }
9173
+ if (parent != zipEntry.parent) {
9174
+ detach(zipEntry);
9175
+ zipEntry.parent = parent;
9176
+ parent.children.push(zipEntry);
9177
+ registerEntries(zipEntry.fs, zipEntry);
9178
+ }
9188
9179
  }
9180
+ zipEntry.name = name;
9189
9181
  }
9190
9182
 
9191
9183
  setOptions(options) {
@@ -9278,47 +9270,47 @@
9278
9270
  }
9279
9271
 
9280
9272
  replaceBlob(blob) {
9281
- Object.assign(this, {
9273
+ replaceContent(this, {
9282
9274
  data: blob,
9283
9275
  Reader: BlobReader,
9284
9276
  Writer: BlobWriter,
9285
- reader: null
9277
+ uncompressedSize: blob.size
9286
9278
  });
9287
9279
  }
9288
9280
 
9289
9281
  replaceText(text) {
9290
- Object.assign(this, {
9282
+ replaceContent(this, {
9291
9283
  data: text,
9292
9284
  Reader: TextReader,
9293
9285
  Writer: TextWriter,
9294
- reader: null
9286
+ uncompressedSize: getTextSize(text)
9295
9287
  });
9296
9288
  }
9297
9289
 
9298
9290
  replaceData64URI(dataURI) {
9299
- Object.assign(this, {
9291
+ replaceContent(this, {
9300
9292
  data: dataURI,
9301
9293
  Reader: Data64URIReader,
9302
9294
  Writer: Data64URIWriter,
9303
- reader: null
9295
+ uncompressedSize: getData64URISize(dataURI)
9304
9296
  });
9305
9297
  }
9306
9298
 
9307
9299
  replaceUint8Array(array) {
9308
- Object.assign(this, {
9300
+ replaceContent(this, {
9309
9301
  data: array,
9310
9302
  Reader: Uint8ArrayReader,
9311
9303
  Writer: Uint8ArrayWriter,
9312
- reader: null
9304
+ uncompressedSize: array.length
9313
9305
  });
9314
9306
  }
9315
9307
 
9316
9308
  replaceReadable(readable) {
9317
- Object.assign(this, {
9309
+ replaceContent(this, {
9318
9310
  data: null,
9319
9311
  Reader: getReadableReader(readable),
9320
9312
  Writer: null,
9321
- reader: null
9313
+ uncompressedSize: UNDEFINED_VALUE
9322
9314
  });
9323
9315
  }
9324
9316
  }
@@ -9368,17 +9360,12 @@
9368
9360
  }
9369
9361
 
9370
9362
  addData64URI(name, dataURI, options = {}) {
9371
- let dataEnd = dataURI.length;
9372
- while (dataURI.charAt(dataEnd - 1) == "=") {
9373
- dataEnd--;
9374
- }
9375
- const dataStart = dataURI.indexOf(",") + 1;
9376
9363
  return addChild(this, name, {
9377
9364
  data: dataURI,
9378
9365
  Reader: Data64URIReader,
9379
9366
  Writer: Data64URIWriter,
9380
9367
  options,
9381
- uncompressedSize: Math.floor((dataEnd - dataStart) * 0.75)
9368
+ uncompressedSize: getData64URISize(dataURI)
9382
9369
  });
9383
9370
  }
9384
9371
 
@@ -9486,6 +9473,7 @@
9486
9473
  await initStream(reader);
9487
9474
  zipReader = new ZipReader(reader, options);
9488
9475
  }
9476
+ const duplicates = checkDuplicatesOption(options.duplicates);
9489
9477
  const importedEntries = [];
9490
9478
  const entries = await zipReader.getEntries(options);
9491
9479
  for (const entry of entries) {
@@ -9493,19 +9481,42 @@
9493
9481
  try {
9494
9482
  const path = entry.filename.split("/").filter(pathPart => pathPart != "" && pathPart != ".");
9495
9483
  const name = path.pop();
9496
- path.forEach(pathPart => {
9484
+ let skippedEntry = false;
9485
+ for (const pathPart of path) {
9497
9486
  const previousParent = parent;
9498
9487
  parent = parent.getChildByName(pathPart);
9499
9488
  if (parent) {
9500
9489
  if (!parent.directory) {
9501
- throw new Error(ERR_ENTRY_EXISTS);
9490
+ if (duplicates == DUPLICATES_KEEP_FIRST) {
9491
+ skippedEntry = true;
9492
+ break;
9493
+ } else if (duplicates == DUPLICATES_KEEP_LAST) {
9494
+ this.fs.remove(parent);
9495
+ parent = new ZipDirectoryEntry(this.fs, pathPart, { data: null }, previousParent);
9496
+ importedEntries.push(parent);
9497
+ } else {
9498
+ throw new Error(ERR_DUPLICATE_IMPORTED_ENTRY);
9499
+ }
9502
9500
  }
9503
9501
  } else {
9504
9502
  parent = new ZipDirectoryEntry(this.fs, pathPart, { data: null }, previousParent);
9505
9503
  importedEntries.push(parent);
9506
9504
  }
9507
- });
9505
+ }
9506
+ if (skippedEntry) {
9507
+ continue;
9508
+ }
9508
9509
  if (!entry.directory) {
9510
+ const existingChild = parent.getChildByName(name);
9511
+ if (existingChild) {
9512
+ if (duplicates == DUPLICATES_KEEP_FIRST) {
9513
+ continue;
9514
+ } else if (duplicates == DUPLICATES_KEEP_LAST) {
9515
+ this.fs.remove(existingChild);
9516
+ } else {
9517
+ throw new Error(ERR_DUPLICATE_IMPORTED_ENTRY);
9518
+ }
9519
+ }
9509
9520
  importedEntries.push(addChild(parent, name, {
9510
9521
  data: entry,
9511
9522
  Reader: getZipBlobReader(Object.assign({}, options)),
@@ -9516,11 +9527,17 @@
9516
9527
  let directoryEntry = parent;
9517
9528
  if (name) {
9518
9529
  directoryEntry = parent.getChildByName(name);
9519
- if (directoryEntry) {
9520
- if (!directoryEntry.directory) {
9521
- throw new Error(ERR_ENTRY_EXISTS);
9530
+ if (directoryEntry && !directoryEntry.directory) {
9531
+ if (duplicates == DUPLICATES_KEEP_FIRST) {
9532
+ continue;
9533
+ } else if (duplicates == DUPLICATES_KEEP_LAST) {
9534
+ this.fs.remove(directoryEntry);
9535
+ directoryEntry = UNDEFINED_VALUE;
9536
+ } else {
9537
+ throw new Error(ERR_DUPLICATE_IMPORTED_ENTRY);
9522
9538
  }
9523
- } else {
9539
+ }
9540
+ if (!directoryEntry) {
9524
9541
  directoryEntry = new ZipDirectoryEntry(this.fs, name, { data: null }, parent);
9525
9542
  importedEntries.push(directoryEntry);
9526
9543
  }
@@ -9530,6 +9547,7 @@
9530
9547
  }
9531
9548
  }
9532
9549
  } catch (error) {
9550
+ importedEntries.reverse().forEach(importedEntry => this.fs.remove(importedEntry));
9533
9551
  try {
9534
9552
  error.cause = {
9535
9553
  entry
@@ -9648,7 +9666,7 @@
9648
9666
  }
9649
9667
  }
9650
9668
  } else {
9651
- throw new Error("Entry is a ancestor of target entry");
9669
+ throw new Error(ERR_ANCESTOR_ENTRY);
9652
9670
  }
9653
9671
  } else {
9654
9672
  throw new Error("Target entry is not a directory");
@@ -9660,7 +9678,7 @@
9660
9678
  const path = fullname.split("/");
9661
9679
  let node = this.root;
9662
9680
  for (let index = 0; node && index < path.length; index++) {
9663
- node = node.getChildByName(path[index]);
9681
+ node = node.directory ? node.getChildByName(path[index]) : UNDEFINED_VALUE;
9664
9682
  }
9665
9683
  if (!node) {
9666
9684
  node = this.entries.find(entry => entry && (entry == this.root || entry.isDescendantOf(this.root)) &&
@@ -9722,33 +9740,27 @@
9722
9740
  }
9723
9741
 
9724
9742
  importBlob(blob, options) {
9725
- resetFS(this);
9726
- return this.root.importBlob(blob, options);
9743
+ return resetAndImport(this, root => root.importBlob(blob, options));
9727
9744
  }
9728
9745
 
9729
9746
  importData64URI(dataURI, options) {
9730
- resetFS(this);
9731
- return this.root.importData64URI(dataURI, options);
9747
+ return resetAndImport(this, root => root.importData64URI(dataURI, options));
9732
9748
  }
9733
9749
 
9734
9750
  importUint8Array(array, options) {
9735
- resetFS(this);
9736
- return this.root.importUint8Array(array, options);
9751
+ return resetAndImport(this, root => root.importUint8Array(array, options));
9737
9752
  }
9738
9753
 
9739
9754
  importHttpContent(url, options) {
9740
- resetFS(this);
9741
- return this.root.importHttpContent(url, options);
9755
+ return resetAndImport(this, root => root.importHttpContent(url, options));
9742
9756
  }
9743
9757
 
9744
9758
  importReadable(readable, options) {
9745
- resetFS(this);
9746
- return this.root.importReadable(readable, options);
9759
+ return resetAndImport(this, root => root.importReadable(readable, options));
9747
9760
  }
9748
9761
 
9749
9762
  importZip(reader, options) {
9750
- resetFS(this);
9751
- return this.root.importZip(reader, options);
9763
+ return resetAndImport(this, root => root.importZip(reader, options));
9752
9764
  }
9753
9765
 
9754
9766
  exportBlob(options) {
@@ -10068,6 +10080,25 @@
10068
10080
  return readerOptions;
10069
10081
  }
10070
10082
 
10083
+ function replaceContent(zipEntry, params) {
10084
+ const { uncompressedSize } = params;
10085
+ Object.assign(zipEntry, params, {
10086
+ reader: null,
10087
+ passThrough: UNDEFINED_VALUE,
10088
+ uncompressedSize: uncompressedSize === UNDEFINED_VALUE ? 0 : uncompressedSize,
10089
+ undeterminedSize: uncompressedSize === UNDEFINED_VALUE
10090
+ });
10091
+ }
10092
+
10093
+ function getData64URISize(dataURI) {
10094
+ let dataEnd = dataURI.length;
10095
+ while (dataURI.charAt(dataEnd - 1) == "=") {
10096
+ dataEnd--;
10097
+ }
10098
+ const dataStart = dataURI.indexOf(",") + 1;
10099
+ return Math.floor((dataEnd - dataStart) * 0.75);
10100
+ }
10101
+
10071
10102
  function isPassThrough(child, options) {
10072
10103
  const { readerOptions } = options;
10073
10104
  return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
@@ -10357,6 +10388,15 @@
10357
10388
  fs.root = new ZipDirectoryEntry(fs);
10358
10389
  }
10359
10390
 
10391
+ function resetAndImport(fs, importFunction) {
10392
+ const { entries, entryIdCounter, root } = fs;
10393
+ resetFS(fs);
10394
+ return importFunction(fs.root).catch(error => {
10395
+ Object.assign(fs, { entries, entryIdCounter, root });
10396
+ throw error;
10397
+ });
10398
+ }
10399
+
10360
10400
  function collectChildren(directory, recursive) {
10361
10401
  const children = [];
10362
10402
  const pendingDirectories = [directory];
@@ -10385,12 +10425,54 @@
10385
10425
 
10386
10426
  function addChild(parent, name, params, directory) {
10387
10427
  if (parent.directory) {
10428
+ const path = splitPath(name);
10429
+ if (path) {
10430
+ name = path.pop();
10431
+ parent = getPathParent(parent, path);
10432
+ }
10388
10433
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
10389
10434
  } else {
10390
10435
  throw new Error("Parent entry is not a directory");
10391
10436
  }
10392
10437
  }
10393
10438
 
10439
+ function checkDuplicatesOption(duplicates) {
10440
+ if (duplicates === UNDEFINED_VALUE) {
10441
+ return DUPLICATES_THROW;
10442
+ } else if (DUPLICATES_VALUES.has(duplicates)) {
10443
+ return duplicates;
10444
+ } else {
10445
+ throw new Error(ERR_INVALID_DUPLICATES);
10446
+ }
10447
+ }
10448
+
10449
+ function splitPath(name) {
10450
+ if (name.includes("/")) {
10451
+ const path = name.split("/").filter(pathPart => pathPart != "" && pathPart != ".");
10452
+ if (path.length) {
10453
+ return path;
10454
+ }
10455
+ }
10456
+ }
10457
+
10458
+ function getPathParent(parent, path, movedEntry) {
10459
+ path.forEach(pathPart => {
10460
+ const previousParent = parent;
10461
+ parent = parent.getChildByName(pathPart);
10462
+ if (parent) {
10463
+ if (!parent.directory) {
10464
+ throw new Error(ERR_ENTRY_EXISTS);
10465
+ }
10466
+ if (movedEntry && (parent == movedEntry || parent.isDescendantOf(movedEntry))) {
10467
+ throw new Error(ERR_ANCESTOR_ENTRY);
10468
+ }
10469
+ } else {
10470
+ parent = new ZipDirectoryEntry(previousParent.fs, pathPart, { data: null }, previousParent);
10471
+ }
10472
+ });
10473
+ return parent;
10474
+ }
10475
+
10394
10476
  exports.BlobReader = BlobReader;
10395
10477
  exports.BlobWriter = BlobWriter;
10396
10478
  exports.Data64URIReader = Data64URIReader;
@@ -10400,6 +10482,7 @@
10400
10482
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
10401
10483
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
10402
10484
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
10485
+ exports.ERR_DUPLICATE_IMPORTED_ENTRY = ERR_DUPLICATE_IMPORTED_ENTRY;
10403
10486
  exports.ERR_ENCRYPTED = ERR_ENCRYPTED;
10404
10487
  exports.ERR_ENCRYPTED_CENTRAL_DIRECTORY = ERR_ENCRYPTED_CENTRAL_DIRECTORY;
10405
10488
  exports.ERR_ENTRY_DATA_OUT_OF_BOUNDS = ERR_ENTRY_DATA_OUT_OF_BOUNDS;
@@ -10417,6 +10500,7 @@
10417
10500
  exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
10418
10501
  exports.ERR_INVALID_CRC32 = ERR_INVALID_CRC32;
10419
10502
  exports.ERR_INVALID_DATE = ERR_INVALID_DATE;
10503
+ exports.ERR_INVALID_DUPLICATES = ERR_INVALID_DUPLICATES;
10420
10504
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
10421
10505
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
10422
10506
  exports.ERR_INVALID_ENTRY_COMMENT_TYPE = ERR_INVALID_ENTRY_COMMENT_TYPE;
@@ -10438,7 +10522,6 @@
10438
10522
  exports.ERR_INVALID_PASS_THROUGH = ERR_INVALID_PASS_THROUGH;
10439
10523
  exports.ERR_INVALID_READER_OPTIONS = ERR_INVALID_READER_OPTIONS;
10440
10524
  exports.ERR_INVALID_SIGNAL = ERR_INVALID_SIGNAL;
10441
- exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE;
10442
10525
  exports.ERR_INVALID_SIGNATURE_DATA = ERR_INVALID_SIGNATURE_DATA;
10443
10526
  exports.ERR_INVALID_STRICTNESS = ERR_INVALID_STRICTNESS;
10444
10527
  exports.ERR_INVALID_UID = ERR_INVALID_UID;
@@ -10458,7 +10541,7 @@
10458
10541
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
10459
10542
  exports.ERR_UNDETERMINED_SIZE = ERR_UNDETERMINED_SIZE;
10460
10543
  exports.ERR_UNSAFE_FILENAME = ERR_UNSAFE_FILENAME;
10461
- exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
10544
+ exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION;
10462
10545
  exports.ERR_UNSUPPORTED_CONTEXT = ERR_UNSUPPORTED_CONTEXT;
10463
10546
  exports.ERR_UNSUPPORTED_CRYPTO_API = ERR_UNSUPPORTED_CRYPTO_API;
10464
10547
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;