@zip.js/zip.js 2.6.32 → 2.6.34

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 (47) hide show
  1. package/dist/z-worker-fflate.js +1 -1
  2. package/dist/z-worker-pako.js +1 -1
  3. package/dist/z-worker.js +1 -1
  4. package/dist/zip-fs-full.js +2441 -2287
  5. package/dist/zip-fs-full.min.js +1 -1
  6. package/dist/zip-fs.js +1970 -1816
  7. package/dist/zip-fs.min.js +1 -1
  8. package/dist/zip-full.js +1969 -1815
  9. package/dist/zip-full.min.js +1 -1
  10. package/dist/zip-no-worker-deflate.min.js +1 -1
  11. package/dist/zip-no-worker-inflate.min.js +1 -1
  12. package/dist/zip-no-worker.min.js +1 -1
  13. package/dist/zip.js +1971 -1817
  14. package/dist/zip.min.js +1 -1
  15. package/index-fflate.js +3 -1
  16. package/index.cjs +2441 -2287
  17. package/index.d.ts +36 -7
  18. package/index.js +3 -1
  19. package/lib/core/codec-pool.js +6 -5
  20. package/lib/core/codec-worker.js +321 -0
  21. package/lib/core/configuration.js +11 -8
  22. package/lib/core/constants.js +11 -5
  23. package/lib/core/io.js +150 -51
  24. package/lib/core/streams/aes-crypto-stream.js +2 -0
  25. package/lib/core/streams/codec-stream.js +60 -13
  26. package/lib/core/streams/codecs/sjcl.js +1 -1
  27. package/lib/core/streams/stream-adapter.js +55 -0
  28. package/lib/core/streams/zip-crypto-stream.js +1 -0
  29. package/lib/core/streams/zip-entry-stream.js +1 -0
  30. package/lib/core/util/stream-codec-shim.js +2 -0
  31. package/lib/core/z-worker-core.js +23 -12
  32. package/lib/core/zip-entry.js +2 -1
  33. package/lib/core/zip-fs-core.js +1 -0
  34. package/lib/core/zip-reader.js +16 -12
  35. package/lib/core/zip-writer.js +102 -54
  36. package/lib/z-worker-inline.js +1 -1
  37. package/lib/zip.js +1 -1
  38. package/package.json +5 -5
  39. package/rollup-es5.config.dev.js +199 -0
  40. package/rollup-es5.config.js +243 -0
  41. package/tests/all/test-http-split-zip.js +37 -0
  42. package/tests/all/test-readable-stream.js +1 -2
  43. package/tests/all/test-readable-zip-stream.js +1 -1
  44. package/tests/all/test-split-zip.js +25 -22
  45. package/tests/tests-data.js +2 -1
  46. package/lib/core/codec-interface.js +0 -115
  47. package/lib/core/codec-pool-worker.js +0 -289
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  /* global BigInt, Response, ReadableStream, WritableStream */
30
+ // deno-lint-ignore-file no-this-alias
30
31
 
31
32
  import {
32
33
  MAX_32_BITS,
@@ -34,6 +35,7 @@ import {
34
35
  COMPRESSION_METHOD_DEFLATE,
35
36
  COMPRESSION_METHOD_STORE,
36
37
  COMPRESSION_METHOD_AES,
38
+ SPLIT_ZIP_FILE_SIGNATURE,
37
39
  LOCAL_FILE_HEADER_SIGNATURE,
38
40
  CENTRAL_FILE_HEADER_SIGNATURE,
39
41
  END_OF_CENTRAL_DIR_SIGNATURE,
@@ -54,7 +56,8 @@ import {
54
56
  BITFLAG_DATA_DESCRIPTOR,
55
57
  BITFLAG_LANG_ENCODING_FLAG,
56
58
  FILE_ATTR_MSDOS_DIR_MASK,
57
- DIRECTORY_SIGNATURE
59
+ DIRECTORY_SIGNATURE,
60
+ UNDEFINED_VALUE
58
61
  } from "./constants.js";
59
62
  import {
60
63
  getConfiguration,
@@ -76,7 +79,6 @@ import { decodeText } from "./util/decode-text.js";
76
79
  import { Crc32 } from "./streams/codecs/crc32.js";
77
80
  import { Entry } from "./zip-entry.js";
78
81
 
79
- const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
80
82
  const ERR_BAD_FORMAT = "File format is not recognized";
81
83
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
82
84
  const ERR_EOCDR_ZIP64_NOT_FOUND = "End of Zip64 central directory not found";
@@ -127,7 +129,7 @@ class ZipReader {
127
129
  let { reader } = zipReader;
128
130
  const { config } = zipReader;
129
131
  await initStream(reader);
130
- if (reader.size === undefined || !reader.readUint8Array) {
132
+ if (reader.size === UNDEFINED_VALUE || !reader.readUint8Array) {
131
133
  if (Array.isArray(reader)) {
132
134
  reader = new SplitZipReader(reader);
133
135
  } else {
@@ -149,15 +151,16 @@ class ZipReader {
149
151
  throw new Error(ERR_EOCDR_NOT_FOUND);
150
152
  }
151
153
  }
152
- const { lastDiskNumber } = reader;
153
154
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
154
155
  let directoryDataLength = getUint32(endOfDirectoryView, 12);
155
156
  let directoryDataOffset = getUint32(endOfDirectoryView, 16);
156
157
  const commentOffset = endOfDirectoryInfo.offset;
157
158
  const commentLength = getUint16(endOfDirectoryView, 20);
158
159
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
159
- let diskNumber = getUint16(endOfDirectoryView, 4);
160
- if (lastDiskNumber !== undefined && diskNumber != lastDiskNumber) {
160
+ const lastDiskNumber = getUint16(endOfDirectoryView, 4);
161
+ const expectedLastDiskNumber = reader.lastDiskNumber || 0;
162
+ let diskNumber = getUint16(endOfDirectoryView, 6);
163
+ if (expectedLastDiskNumber != lastDiskNumber) {
161
164
  throw new Error(ERR_SPLIT_ZIP_FILE);
162
165
  }
163
166
  let filesLength = getUint16(endOfDirectoryView, 8);
@@ -343,7 +346,7 @@ class ZipEntry {
343
346
  compressedSize
344
347
  } = zipEntry;
345
348
  const localDirectory = zipEntry.localDirectory = {};
346
- let dataArray = await readUint8Array(reader, offset, 30, diskNumberStart);
349
+ const dataArray = await readUint8Array(reader, offset, 30, diskNumberStart);
347
350
  const dataView = getDataView(dataArray);
348
351
  let password = getOptionValue(zipEntry, options, "password");
349
352
  password = password && password.length && password;
@@ -359,8 +362,9 @@ class ZipEntry {
359
362
  throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
360
363
  }
361
364
  readCommonHeader(localDirectory, dataView, 4);
362
- dataArray = await readUint8Array(reader, offset, 30 + localDirectory.filenameLength + localDirectory.extraFieldLength, diskNumberStart);
363
- localDirectory.rawExtraField = dataArray.subarray(30 + localDirectory.filenameLength);
365
+ localDirectory.rawExtraField = localDirectory.extraFieldLength ?
366
+ await readUint8Array(reader, offset + 30 + localDirectory.filenameLength, localDirectory.extraFieldLength, diskNumberStart) :
367
+ new Uint8Array();
364
368
  await readCommonFooter(zipEntry, localDirectory, dataView, 4);
365
369
  Object.assign(fileEntry, {
366
370
  lastAccessDate: localDirectory.lastAccessDate,
@@ -369,7 +373,7 @@ class ZipEntry {
369
373
  const encrypted = zipEntry.encrypted && localDirectory.encrypted;
370
374
  const zipCrypto = encrypted && !extraFieldAES;
371
375
  if (encrypted) {
372
- if (!zipCrypto && extraFieldAES.strength === undefined) {
376
+ if (!zipCrypto && extraFieldAES.strength === UNDEFINED_VALUE) {
373
377
  throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
374
378
  } else if (!password) {
375
379
  throw new Error(ERR_ENCRYPTED);
@@ -386,7 +390,7 @@ class ZipEntry {
386
390
  };
387
391
  }
388
392
  const { writable } = writer;
389
- if (writable.size === undefined) {
393
+ if (writable.size === UNDEFINED_VALUE) {
390
394
  writable.size = 0;
391
395
  }
392
396
  const signal = getOptionValue(zipEntry, options, "signal");
@@ -634,7 +638,7 @@ async function seekSignature(reader, signature, startOffset, minimumBytes, maxim
634
638
  }
635
639
 
636
640
  function getOptionValue(zipReader, options, name) {
637
- return options[name] === undefined ? zipReader.options[name] : options[name];
641
+ return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
638
642
  }
639
643
 
640
644
  function getDate(timeRaw) {
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  /* global BigInt, ReadableStream, WritableStream */
30
+ // deno-lint-ignore-file no-this-alias
30
31
 
31
32
  import {
32
33
  MAX_32_BITS,
@@ -34,19 +35,21 @@ import {
34
35
  COMPRESSION_METHOD_DEFLATE,
35
36
  COMPRESSION_METHOD_STORE,
36
37
  COMPRESSION_METHOD_AES,
38
+ SPLIT_ZIP_FILE_SIGNATURE,
37
39
  LOCAL_FILE_HEADER_SIGNATURE,
38
40
  DATA_DESCRIPTOR_RECORD_SIGNATURE,
39
41
  CENTRAL_FILE_HEADER_SIGNATURE,
40
42
  END_OF_CENTRAL_DIR_SIGNATURE,
41
43
  ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE,
42
44
  ZIP64_END_OF_CENTRAL_DIR_SIGNATURE,
43
- ZIP64_TOTAL_NUMBER_OF_DISKS,
44
45
  EXTRAFIELD_TYPE_AES,
45
46
  EXTRAFIELD_TYPE_ZIP64,
46
47
  EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP,
47
48
  EXTRAFIELD_TYPE_NTFS,
48
49
  EXTRAFIELD_TYPE_NTFS_TAG1,
49
50
  END_OF_CENTRAL_DIR_LENGTH,
51
+ ZIP64_END_OF_CENTRAL_DIR_LENGTH,
52
+ ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH,
50
53
  ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH,
51
54
  BITFLAG_ENCRYPTED,
52
55
  BITFLAG_DATA_DESCRIPTOR,
@@ -57,7 +60,9 @@ import {
57
60
  VERSION_AES,
58
61
  DIRECTORY_SIGNATURE,
59
62
  MIN_DATE,
60
- MAX_DATE
63
+ MAX_DATE,
64
+ UNDEFINED_VALUE,
65
+ FUNCTION_TYPE
61
66
  } from "./constants.js";
62
67
  import {
63
68
  getConfiguration,
@@ -69,7 +74,8 @@ import {
69
74
  } from "./codec-pool.js";
70
75
  import {
71
76
  initStream,
72
- BlobWriter
77
+ BlobWriter,
78
+ SplitZipWriter
73
79
  } from "./io.js";
74
80
  import { encodeText } from "./util/encode-text.js";
75
81
  import { Entry } from "./zip-entry.js";
@@ -85,7 +91,7 @@ const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
85
91
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (make sure 'keepOrder' is set to 'true')";
86
92
 
87
93
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
88
- const EXTRAFIELD_LENGTH_ZIP64 = 24;
94
+ const EXTRAFIELD_LENGTH_ZIP64 = 28;
89
95
 
90
96
  let workers = 0;
91
97
  const pendingEntries = [];
@@ -93,14 +99,26 @@ const pendingEntries = [];
93
99
  class ZipWriter {
94
100
 
95
101
  constructor(writer, options = {}) {
102
+ if (writer.writable === UNDEFINED_VALUE && typeof writer.next == FUNCTION_TYPE) {
103
+ writer = new SplitZipWriter(writer);
104
+ }
96
105
  if (writer instanceof WritableStream) {
97
106
  writer = { writable: writer };
98
107
  }
99
- if (writer.writable.size === undefined) {
108
+ if (writer.writable.size === UNDEFINED_VALUE) {
100
109
  writer.writable.size = 0;
101
110
  }
111
+ const splitZipFile = writer instanceof SplitZipWriter;
112
+ if (!splitZipFile) {
113
+ Object.assign(writer, {
114
+ diskNumber: 0,
115
+ diskOffset: 0,
116
+ availableSize: Infinity
117
+ });
118
+ }
102
119
  Object.assign(this, {
103
120
  writer,
121
+ addSplitZipSignature: splitZipFile,
104
122
  options,
105
123
  config: getConfiguration(),
106
124
  files: new Map(),
@@ -203,7 +221,7 @@ async function addFile(zipWriter, name, reader, options) {
203
221
  const password = getOptionValue(zipWriter, options, "password");
204
222
  const encryptionStrength = getOptionValue(zipWriter, options, "encryptionStrength") || 3;
205
223
  const zipCrypto = getOptionValue(zipWriter, options, "zipCrypto");
206
- if (password !== undefined && encryptionStrength !== undefined && (encryptionStrength < 1 || encryptionStrength > 3)) {
224
+ if (password !== UNDEFINED_VALUE && encryptionStrength !== UNDEFINED_VALUE && (encryptionStrength < 1 || encryptionStrength > 3)) {
207
225
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
208
226
  }
209
227
  let rawExtraField = new Uint8Array();
@@ -227,18 +245,18 @@ async function addFile(zipWriter, name, reader, options) {
227
245
  });
228
246
  }
229
247
  let extendedTimestamp = getOptionValue(zipWriter, options, "extendedTimestamp");
230
- if (extendedTimestamp === undefined) {
248
+ if (extendedTimestamp === UNDEFINED_VALUE) {
231
249
  extendedTimestamp = true;
232
250
  }
233
251
  let maximumCompressedSize = 0;
234
252
  let maximumEntrySize = 0;
235
253
  let keepOrder = getOptionValue(zipWriter, options, "keepOrder");
236
- if (keepOrder === undefined) {
254
+ if (keepOrder === UNDEFINED_VALUE) {
237
255
  keepOrder = true;
238
256
  }
239
257
  let uncompressedSize = 0;
240
258
  let msDosCompatible = getOptionValue(zipWriter, options, "msDosCompatible");
241
- if (msDosCompatible === undefined) {
259
+ if (msDosCompatible === UNDEFINED_VALUE) {
242
260
  msDosCompatible = true;
243
261
  }
244
262
  const internalFileAttribute = getOptionValue(zipWriter, options, "internalFileAttribute") || 0;
@@ -251,15 +269,16 @@ async function addFile(zipWriter, name, reader, options) {
251
269
  };
252
270
  }
253
271
  await initStream(reader);
254
- if (reader.size === undefined) {
272
+ if (reader.size === UNDEFINED_VALUE) {
255
273
  options.dataDescriptor = true;
256
- if (zip64 === undefined) {
274
+ if (zip64 || zip64 === UNDEFINED_VALUE) {
257
275
  zip64 = true;
276
+ maximumCompressedSize = MAX_32_BITS;
258
277
  }
259
278
  } else {
260
279
  uncompressedSize = reader.size;
280
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
261
281
  }
262
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
263
282
  }
264
283
  if (zipWriter.offset + zipWriter.pendingEntriesSize >= MAX_32_BITS ||
265
284
  uncompressedSize >= MAX_32_BITS ||
@@ -278,10 +297,10 @@ async function addFile(zipWriter, name, reader, options) {
278
297
  let dataDescriptorSignature = getOptionValue(zipWriter, options, "dataDescriptorSignature");
279
298
  const signal = getOptionValue(zipWriter, options, "signal");
280
299
  const useCompressionStream = getOptionValue(zipWriter, options, "useCompressionStream");
281
- if (dataDescriptor === undefined) {
300
+ if (dataDescriptor === UNDEFINED_VALUE) {
282
301
  dataDescriptor = true;
283
302
  }
284
- if (dataDescriptor && dataDescriptorSignature === undefined) {
303
+ if (dataDescriptor && dataDescriptorSignature === UNDEFINED_VALUE) {
285
304
  dataDescriptorSignature = false;
286
305
  }
287
306
  options = Object.assign({}, options, {
@@ -364,10 +383,21 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
364
383
  releaseLockWriter = () => delete zipWriter.lockWriter;
365
384
  }
366
385
  await initStream(fileWriter);
386
+ const { writable, diskNumber } = writer;
387
+ let { diskOffset } = writer;
388
+ if (zipWriter.addSplitZipSignature) {
389
+ delete zipWriter.addSplitZipSignature;
390
+ const signatureArray = new Uint8Array(4);
391
+ const signatureArrayView = new DataView(signatureArray.buffer);
392
+ setUint32(signatureArrayView, 0, SPLIT_ZIP_FILE_SIGNATURE);
393
+ await writeData(writable, signatureArray);
394
+ zipWriter.offset += 4;
395
+ }
367
396
  if (!bufferedWrite) {
368
397
  await lockPreviousFileEntry;
369
398
  }
370
399
  writingEntryData = true;
400
+ fileEntry.diskNumberStart = diskNumber;
371
401
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
372
402
  writingEntryData = false;
373
403
  files.set(name, fileEntry);
@@ -378,7 +408,6 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
378
408
  await lockPreviousFileEntry;
379
409
  await requestLockWriter();
380
410
  writingBufferedEntryData = true;
381
- const { writable } = writer;
382
411
  if (!dataDescriptor) {
383
412
  const arrayBuffer = await sliceAsArrayBuffer(blob, 0, 26);
384
413
  const arrayBufferView = new DataView(arrayBuffer);
@@ -395,13 +424,18 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
395
424
  await writeData(writable, new Uint8Array(arrayBuffer));
396
425
  blob = blob.slice(arrayBuffer.byteLength);
397
426
  }
427
+ fileEntry.diskNumberStart = writer.diskNumber;
428
+ diskOffset = writer.diskOffset;
398
429
  await blob.stream().pipeTo(writable, { preventClose: true, signal });
430
+ writable.size += blob.size;
399
431
  writingBufferedEntryData = false;
400
432
  }
401
- fileEntry.offset = zipWriter.offset;
433
+ fileEntry.offset = zipWriter.offset - diskOffset;
402
434
  if (fileEntry.zip64) {
403
- const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64);
404
- setBigUint64(rawExtraFieldZip64View, 20, BigInt(fileEntry.offset));
435
+ const { rawExtraFieldZip64, offset, diskNumberStart } = fileEntry;
436
+ const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
437
+ setBigUint64(rawExtraFieldZip64View, 20, BigInt(offset));
438
+ setUint32(rawExtraFieldZip64View, 28, diskNumberStart);
405
439
  } else if (fileEntry.offset >= MAX_32_BITS) {
406
440
  throw new Error(ERR_UNSUPPORTED_FORMAT);
407
441
  }
@@ -445,7 +479,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
445
479
  }
446
480
  }
447
481
 
448
- async function createFileEntry(reader, writer, pendingFileEntry, entryInfo, config, options) {
482
+ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryInfo, config, options) {
449
483
  const {
450
484
  headerInfo,
451
485
  dataDescriptorInfo
@@ -490,7 +524,7 @@ async function createFileEntry(reader, writer, pendingFileEntry, entryInfo, conf
490
524
  useCompressionStream
491
525
  } = options;
492
526
  const fileEntry = {
493
- lock: pendingFileEntry.lock,
527
+ lock,
494
528
  versionMadeBy,
495
529
  zip64,
496
530
  directory: Boolean(directory),
@@ -505,7 +539,8 @@ async function createFileEntry(reader, writer, pendingFileEntry, entryInfo, conf
505
539
  extendedTimestamp,
506
540
  msDosCompatible,
507
541
  internalFileAttribute,
508
- externalFileAttribute
542
+ externalFileAttribute,
543
+ diskNumberStart
509
544
  };
510
545
  let uncompressedSize = 0;
511
546
  let signature;
@@ -748,7 +783,7 @@ function setEntryInfo(entryInfo, options) {
748
783
  zipCrypto,
749
784
  dataDescriptor
750
785
  } = options;
751
- if ((!encrypted || zipCrypto) && signature !== undefined) {
786
+ if ((!encrypted || zipCrypto) && signature !== UNDEFINED_VALUE) {
752
787
  setUint32(headerView, 10, signature);
753
788
  if (dataDescriptor) {
754
789
  setUint32(dataDescriptorView, dataDescriptorOffset, signature);
@@ -777,10 +812,12 @@ function setEntryInfo(entryInfo, options) {
777
812
  }
778
813
 
779
814
  async function closeFile(zipWriter, comment, options) {
780
- const { files } = zipWriter;
815
+ const { files, writer } = zipWriter;
781
816
  let offset = 0;
782
817
  let directoryDataLength = 0;
783
- let directoryOffset = zipWriter.offset;
818
+ const { diskOffset, writable } = writer;
819
+ let { diskNumber } = writer;
820
+ let directoryOffset = zipWriter.offset - diskOffset;
784
821
  let filesLength = files.size;
785
822
  for (const [, {
786
823
  rawFilename,
@@ -809,7 +846,7 @@ async function closeFile(zipWriter, comment, options) {
809
846
  zip64 = true;
810
847
  }
811
848
  }
812
- const directoryArray = new Uint8Array(directoryDataLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH));
849
+ const directoryArray = new Uint8Array(directoryDataLength);
813
850
  const directoryView = getDataView(directoryArray);
814
851
  for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
815
852
  const {
@@ -828,7 +865,8 @@ async function closeFile(zipWriter, comment, options) {
828
865
  internalFileAttribute,
829
866
  externalFileAttribute,
830
867
  extendedTimestamp,
831
- lastModDate
868
+ lastModDate,
869
+ diskNumberStart
832
870
  } = fileEntry;
833
871
  let rawExtraFieldExtendedTimestamp;
834
872
  if (extendedTimestamp) {
@@ -847,17 +885,14 @@ async function closeFile(zipWriter, comment, options) {
847
885
  arraySet(directoryArray, headerArray, offset + 6);
848
886
  setUint16(directoryView, offset + 30, extraFieldLength);
849
887
  setUint16(directoryView, offset + 32, getLength(rawComment));
888
+ setUint16(directoryView, offset + 34, zip64 ? MAX_16_BITS : diskNumberStart);
850
889
  setUint16(directoryView, offset + 36, internalFileAttribute);
851
890
  if (externalFileAttribute) {
852
891
  setUint32(directoryView, offset + 38, externalFileAttribute);
853
892
  } else if (directory && msDosCompatible) {
854
893
  setUint8(directoryView, offset + 38, FILE_ATTR_MSDOS_DIR_MASK);
855
894
  }
856
- if (zip64) {
857
- setUint32(directoryView, offset + 42, MAX_32_BITS);
858
- } else {
859
- setUint32(directoryView, offset + 42, fileEntryOffset);
860
- }
895
+ setUint32(directoryView, offset + 42, zip64 ? MAX_32_BITS : fileEntryOffset);
861
896
  arraySet(directoryArray, rawFilename, offset + 46);
862
897
  arraySet(directoryArray, rawExtraFieldZip64, offset + 46 + getLength(rawFilename));
863
898
  arraySet(directoryArray, rawExtraFieldAES, offset + 46 + getLength(rawFilename, rawExtraFieldZip64));
@@ -874,39 +909,52 @@ async function closeFile(zipWriter, comment, options) {
874
909
  }
875
910
  }
876
911
  }
912
+ await initStream(writer);
913
+ await writeData(writable, directoryArray);
914
+ const endOfdirectoryArray = new Uint8Array(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
915
+ const endOfdirectoryView = getDataView(endOfdirectoryArray);
916
+ let lastDiskNumber = writer.diskNumber;
917
+ const { availableSize } = writer;
918
+ if (availableSize < endOfdirectoryArray.length) {
919
+ lastDiskNumber++;
920
+ }
921
+ offset = 0;
877
922
  if (zip64) {
878
- setUint32(directoryView, offset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
879
- setBigUint64(directoryView, offset + 4, BigInt(44));
880
- setUint16(directoryView, offset + 12, 45);
881
- setUint16(directoryView, offset + 14, 45);
882
- setBigUint64(directoryView, offset + 24, BigInt(filesLength));
883
- setBigUint64(directoryView, offset + 32, BigInt(filesLength));
884
- setBigUint64(directoryView, offset + 40, BigInt(directoryDataLength));
885
- setBigUint64(directoryView, offset + 48, BigInt(directoryOffset));
886
- setUint32(directoryView, offset + 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
887
- setBigUint64(directoryView, offset + 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
888
- setUint32(directoryView, offset + 72, ZIP64_TOTAL_NUMBER_OF_DISKS);
923
+ setUint32(endOfdirectoryView, 0, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
924
+ setBigUint64(endOfdirectoryView, 4, BigInt(44));
925
+ setUint16(endOfdirectoryView, 12, 45);
926
+ setUint16(endOfdirectoryView, 14, 45);
927
+ setUint32(endOfdirectoryView, 16, lastDiskNumber);
928
+ setUint32(endOfdirectoryView, 20, diskNumber);
929
+ setBigUint64(endOfdirectoryView, 24, BigInt(filesLength));
930
+ setBigUint64(endOfdirectoryView, 32, BigInt(filesLength));
931
+ setBigUint64(endOfdirectoryView, 40, BigInt(directoryDataLength));
932
+ setBigUint64(endOfdirectoryView, 48, BigInt(directoryOffset));
933
+ setUint32(endOfdirectoryView, 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
934
+ setBigUint64(endOfdirectoryView, 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
935
+ setUint32(endOfdirectoryView, 72, lastDiskNumber + 1);
936
+ diskNumber = MAX_16_BITS;
889
937
  filesLength = MAX_16_BITS;
890
938
  directoryOffset = MAX_32_BITS;
891
939
  directoryDataLength = MAX_32_BITS;
892
- offset += 76;
893
- }
894
- setUint32(directoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
895
- setUint16(directoryView, offset + 8, filesLength);
896
- setUint16(directoryView, offset + 10, filesLength);
897
- setUint32(directoryView, offset + 12, directoryDataLength);
898
- setUint32(directoryView, offset + 16, directoryOffset);
940
+ offset += ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
941
+ }
942
+ setUint32(endOfdirectoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
943
+ setUint16(endOfdirectoryView, offset + 4, lastDiskNumber);
944
+ setUint16(endOfdirectoryView, offset + 6, diskNumber);
945
+ setUint16(endOfdirectoryView, offset + 8, filesLength);
946
+ setUint16(endOfdirectoryView, offset + 10, filesLength);
947
+ setUint32(endOfdirectoryView, offset + 12, directoryDataLength);
948
+ setUint32(endOfdirectoryView, offset + 16, directoryOffset);
899
949
  const commentLength = getLength(comment);
900
950
  if (commentLength) {
901
951
  if (commentLength <= MAX_16_BITS) {
902
- setUint16(directoryView, offset + 20, commentLength);
952
+ setUint16(endOfdirectoryView, offset + 20, commentLength);
903
953
  } else {
904
954
  throw new Error(ERR_INVALID_COMMENT);
905
955
  }
906
956
  }
907
- const { writable } = zipWriter.writer;
908
- await initStream(zipWriter.writer);
909
- await writeData(writable, directoryArray);
957
+ await writeData(writable, endOfdirectoryArray);
910
958
  if (commentLength) {
911
959
  await writeData(writable, comment);
912
960
  }
@@ -935,7 +983,7 @@ function getTimeNTFS(date) {
935
983
  }
936
984
 
937
985
  function getOptionValue(zipWriter, options, name) {
938
- return options[name] === undefined ? zipWriter.options[name] : options[name];
986
+ return options[name] === UNDEFINED_VALUE ? zipWriter.options[name] : options[name];
939
987
  }
940
988
 
941
989
  function getMaximumCompressedSize(uncompressedSize) {