@zip.js/zip.js 2.6.33 → 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 (43) 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 +2479 -2364
  5. package/dist/zip-fs-full.min.js +1 -1
  6. package/dist/zip-fs.js +1236 -1121
  7. package/dist/zip-fs.min.js +1 -1
  8. package/dist/zip-full.js +1235 -1120
  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 +1236 -1121
  14. package/dist/zip.min.js +1 -1
  15. package/index-fflate.js +3 -1
  16. package/index.cjs +2479 -2364
  17. package/index.d.ts +33 -2
  18. package/index.js +3 -1
  19. package/lib/core/codec-pool.js +2 -2
  20. package/lib/core/codec-worker.js +321 -0
  21. package/lib/core/configuration.js +3 -3
  22. package/lib/core/constants.js +6 -5
  23. package/lib/core/io.js +64 -1
  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 +21 -11
  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 +7 -5
  35. package/lib/core/zip-writer.js +88 -42
  36. package/lib/z-worker-inline.js +1 -1
  37. package/lib/zip.js +1 -1
  38. package/package.json +5 -5
  39. package/tests/all/test-http-split-zip.js +37 -0
  40. package/tests/all/test-split-zip.js +25 -22
  41. package/tests/tests-data.js +2 -1
  42. package/lib/core/codec-interface.js +0 -115
  43. package/lib/core/codec-pool-worker.js +0 -293
@@ -1,6 +1,6 @@
1
1
  // Derived from https://github.com/xqdoo00o/jszip/blob/master/lib/sjcl.js and https://github.com/bitwiseshiftleft/sjcl
2
2
 
3
- /*// deno-lint-ignore-file no-this-alias *
3
+ // deno-lint-ignore-file no-this-alias
4
4
 
5
5
  /*
6
6
  * SJCL is open. You can use, modify and redistribute it under a BSD
@@ -0,0 +1,55 @@
1
+ /*
2
+ Copyright (c) 2022 Gildas Lormeau. All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in
12
+ the documentation and/or other materials provided with the distribution.
13
+
14
+ 3. The names of the authors may not be used to endorse or promote products
15
+ derived from this software without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
18
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
19
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
20
+ INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23
+ OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ /* global TransformStream */
30
+
31
+ export {
32
+ StreamAdapter
33
+ };
34
+
35
+ class StreamAdapter {
36
+
37
+ constructor(Codec) {
38
+ return class extends TransformStream {
39
+ constructor(options) {
40
+ const codec = new Codec(options);
41
+ super({
42
+ transform(chunk, controller) {
43
+ controller.enqueue(codec.append(chunk));
44
+ },
45
+ flush(controller) {
46
+ const chunk = codec.flush();
47
+ if (chunk) {
48
+ controller.enqueue(chunk);
49
+ }
50
+ }
51
+ });
52
+ }
53
+ };
54
+ }
55
+ }
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  /* global TransformStream */
30
+ // deno-lint-ignore-file no-this-alias
30
31
 
31
32
  import { Crc32 } from "./codecs/crc32.js";
32
33
  import {
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  /* global TransformStream */
30
+ // deno-lint-ignore-file no-this-alias
30
31
 
31
32
  import { Crc32Stream } from "./crc32-stream.js";
32
33
  import {
@@ -27,6 +27,8 @@
27
27
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
28
  */
29
29
 
30
+ // deno-lint-ignore-file no-this-alias
31
+
30
32
  export {
31
33
  initShimAsyncCodec
32
34
  };
@@ -29,23 +29,23 @@
29
29
  /* global self, importScripts, addEventListener, postMessage, ReadableStream, WritableStream */
30
30
 
31
31
  import { UNDEFINED_VALUE } from "./constants.js";
32
+ import { StreamAdapter } from "./streams/stream-adapter.js";
32
33
  import {
33
- Codec,
34
- getCodecStreamClass,
34
+ CodecStream,
35
35
  MESSAGE_EVENT_TYPE,
36
36
  MESSAGE_START,
37
37
  MESSAGE_PULL,
38
38
  MESSAGE_DATA,
39
39
  MESSAGE_ACK_DATA,
40
40
  MESSAGE_CLOSE
41
- } from "./codec-interface.js";
41
+ } from "./streams/codec-stream.js";
42
42
 
43
43
  const pendingPullMessages = new Map();
44
44
  const pendingDataMessages = new Map();
45
- let codec;
45
+
46
46
  let messageId = 0;
47
47
 
48
- addEventListener(MESSAGE_EVENT_TYPE, async event => {
48
+ addEventListener(MESSAGE_EVENT_TYPE, event => {
49
49
  const message = event.data;
50
50
  const { type, messageId, data, done } = message;
51
51
  try {
@@ -79,15 +79,15 @@ async function init(message) {
79
79
  config.CompressionStreamNative = self.CompressionStream;
80
80
  config.DecompressionStreamNative = self.DecompressionStream;
81
81
  if (self.Deflate) {
82
- config.CompressionStream = getCodecStreamClass(self.Deflate);
82
+ config.CompressionStream = new StreamAdapter(self.Deflate);
83
83
  }
84
84
  if (self.Inflate) {
85
- config.DecompressionStream = getCodecStreamClass(self.Inflate);
85
+ config.DecompressionStream = new StreamAdapter(self.Inflate);
86
86
  }
87
87
  const strategy = { highWaterMark: 1, size: () => config.chunkSize };
88
88
  const readable = message.readable || new ReadableStream({
89
89
  async pull(controller) {
90
- let result = new Promise(resolve => pendingPullMessages.set(messageId, resolve));
90
+ const result = new Promise(resolve => pendingPullMessages.set(messageId, resolve));
91
91
  sendMessage({ type: MESSAGE_PULL, messageId });
92
92
  messageId = (messageId + 1) % Number.MAX_SAFE_INTEGER;
93
93
  const { value, done } = await result;
@@ -107,14 +107,24 @@ async function init(message) {
107
107
  await ackData;
108
108
  }
109
109
  }, strategy);
110
- codec = new Codec(readable, writable, options, config);
111
- const result = await codec.run();
110
+ const codecStream = new CodecStream(options, config);
111
+ await readable.pipeThrough(codecStream).pipeTo(writable, { preventAbort: true });
112
112
  try {
113
113
  await writable.close();
114
114
  } catch (_error) {
115
115
  // ignored
116
116
  }
117
- sendMessage({ type: MESSAGE_CLOSE, result });
117
+ const {
118
+ signature,
119
+ size
120
+ } = codecStream;
121
+ sendMessage({
122
+ type: MESSAGE_CLOSE,
123
+ result: {
124
+ signature,
125
+ size
126
+ }
127
+ });
118
128
  } catch (error) {
119
129
  sendErrorMessage(error);
120
130
  }
@@ -32,7 +32,8 @@ const PROPERTY_NAMES = [
32
32
  "rawExtraField", "bitFlag", "extraFieldZip64", "extraFieldUnicodePath", "extraFieldUnicodeComment",
33
33
  "extraFieldAES", "filenameUTF8", "commentUTF8", "offset", "zip64", "compressionMethod",
34
34
  "extraFieldNTFS", "lastAccessDate", "creationDate", "extraFieldExtendedTimestamp",
35
- "version", "versionMadeBy", "msDosCompatible", "internalFileAttribute", "externalFileAttribute"];
35
+ "version", "versionMadeBy", "msDosCompatible", "internalFileAttribute", "externalFileAttribute",
36
+ "diskNumberStart"];
36
37
 
37
38
  class Entry {
38
39
 
@@ -27,6 +27,7 @@
27
27
  */
28
28
 
29
29
  /* global WritableStream */
30
+ // deno-lint-ignore-file no-this-alias
30
31
 
31
32
  import {
32
33
  initStream,
@@ -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,
@@ -77,7 +79,6 @@ import { decodeText } from "./util/decode-text.js";
77
79
  import { Crc32 } from "./streams/codecs/crc32.js";
78
80
  import { Entry } from "./zip-entry.js";
79
81
 
80
- const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
81
82
  const ERR_BAD_FORMAT = "File format is not recognized";
82
83
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
83
84
  const ERR_EOCDR_ZIP64_NOT_FOUND = "End of Zip64 central directory not found";
@@ -150,15 +151,16 @@ class ZipReader {
150
151
  throw new Error(ERR_EOCDR_NOT_FOUND);
151
152
  }
152
153
  }
153
- const { lastDiskNumber } = reader;
154
154
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
155
155
  let directoryDataLength = getUint32(endOfDirectoryView, 12);
156
156
  let directoryDataOffset = getUint32(endOfDirectoryView, 16);
157
157
  const commentOffset = endOfDirectoryInfo.offset;
158
158
  const commentLength = getUint16(endOfDirectoryView, 20);
159
159
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
160
- let diskNumber = getUint16(endOfDirectoryView, 4);
161
- if (lastDiskNumber !== UNDEFINED_VALUE && diskNumber != lastDiskNumber) {
160
+ const lastDiskNumber = getUint16(endOfDirectoryView, 4);
161
+ const expectedLastDiskNumber = reader.lastDiskNumber || 0;
162
+ let diskNumber = getUint16(endOfDirectoryView, 6);
163
+ if (expectedLastDiskNumber != lastDiskNumber) {
162
164
  throw new Error(ERR_SPLIT_ZIP_FILE);
163
165
  }
164
166
  let filesLength = getUint16(endOfDirectoryView, 8);
@@ -344,7 +346,7 @@ class ZipEntry {
344
346
  compressedSize
345
347
  } = zipEntry;
346
348
  const localDirectory = zipEntry.localDirectory = {};
347
- let dataArray = await readUint8Array(reader, offset, 30, diskNumberStart);
349
+ const dataArray = await readUint8Array(reader, offset, 30, diskNumberStart);
348
350
  const dataView = getDataView(dataArray);
349
351
  let password = getOptionValue(zipEntry, options, "password");
350
352
  password = password && password.length && password;
@@ -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,
@@ -58,7 +61,8 @@ import {
58
61
  DIRECTORY_SIGNATURE,
59
62
  MIN_DATE,
60
63
  MAX_DATE,
61
- UNDEFINED_VALUE
64
+ UNDEFINED_VALUE,
65
+ FUNCTION_TYPE
62
66
  } from "./constants.js";
63
67
  import {
64
68
  getConfiguration,
@@ -70,7 +74,8 @@ import {
70
74
  } from "./codec-pool.js";
71
75
  import {
72
76
  initStream,
73
- BlobWriter
77
+ BlobWriter,
78
+ SplitZipWriter
74
79
  } from "./io.js";
75
80
  import { encodeText } from "./util/encode-text.js";
76
81
  import { Entry } from "./zip-entry.js";
@@ -86,7 +91,7 @@ const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
86
91
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (make sure 'keepOrder' is set to 'true')";
87
92
 
88
93
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
89
- const EXTRAFIELD_LENGTH_ZIP64 = 24;
94
+ const EXTRAFIELD_LENGTH_ZIP64 = 28;
90
95
 
91
96
  let workers = 0;
92
97
  const pendingEntries = [];
@@ -94,14 +99,26 @@ const pendingEntries = [];
94
99
  class ZipWriter {
95
100
 
96
101
  constructor(writer, options = {}) {
102
+ if (writer.writable === UNDEFINED_VALUE && typeof writer.next == FUNCTION_TYPE) {
103
+ writer = new SplitZipWriter(writer);
104
+ }
97
105
  if (writer instanceof WritableStream) {
98
106
  writer = { writable: writer };
99
107
  }
100
108
  if (writer.writable.size === UNDEFINED_VALUE) {
101
109
  writer.writable.size = 0;
102
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
+ }
103
119
  Object.assign(this, {
104
120
  writer,
121
+ addSplitZipSignature: splitZipFile,
105
122
  options,
106
123
  config: getConfiguration(),
107
124
  files: new Map(),
@@ -366,10 +383,21 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
366
383
  releaseLockWriter = () => delete zipWriter.lockWriter;
367
384
  }
368
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
+ }
369
396
  if (!bufferedWrite) {
370
397
  await lockPreviousFileEntry;
371
398
  }
372
399
  writingEntryData = true;
400
+ fileEntry.diskNumberStart = diskNumber;
373
401
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
374
402
  writingEntryData = false;
375
403
  files.set(name, fileEntry);
@@ -380,7 +408,6 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
380
408
  await lockPreviousFileEntry;
381
409
  await requestLockWriter();
382
410
  writingBufferedEntryData = true;
383
- const { writable } = writer;
384
411
  if (!dataDescriptor) {
385
412
  const arrayBuffer = await sliceAsArrayBuffer(blob, 0, 26);
386
413
  const arrayBufferView = new DataView(arrayBuffer);
@@ -397,13 +424,18 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
397
424
  await writeData(writable, new Uint8Array(arrayBuffer));
398
425
  blob = blob.slice(arrayBuffer.byteLength);
399
426
  }
427
+ fileEntry.diskNumberStart = writer.diskNumber;
428
+ diskOffset = writer.diskOffset;
400
429
  await blob.stream().pipeTo(writable, { preventClose: true, signal });
430
+ writable.size += blob.size;
401
431
  writingBufferedEntryData = false;
402
432
  }
403
- fileEntry.offset = zipWriter.offset;
433
+ fileEntry.offset = zipWriter.offset - diskOffset;
404
434
  if (fileEntry.zip64) {
405
- const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64);
406
- 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);
407
439
  } else if (fileEntry.offset >= MAX_32_BITS) {
408
440
  throw new Error(ERR_UNSUPPORTED_FORMAT);
409
441
  }
@@ -447,7 +479,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
447
479
  }
448
480
  }
449
481
 
450
- async function createFileEntry(reader, writer, pendingFileEntry, entryInfo, config, options) {
482
+ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryInfo, config, options) {
451
483
  const {
452
484
  headerInfo,
453
485
  dataDescriptorInfo
@@ -492,7 +524,7 @@ async function createFileEntry(reader, writer, pendingFileEntry, entryInfo, conf
492
524
  useCompressionStream
493
525
  } = options;
494
526
  const fileEntry = {
495
- lock: pendingFileEntry.lock,
527
+ lock,
496
528
  versionMadeBy,
497
529
  zip64,
498
530
  directory: Boolean(directory),
@@ -507,7 +539,8 @@ async function createFileEntry(reader, writer, pendingFileEntry, entryInfo, conf
507
539
  extendedTimestamp,
508
540
  msDosCompatible,
509
541
  internalFileAttribute,
510
- externalFileAttribute
542
+ externalFileAttribute,
543
+ diskNumberStart
511
544
  };
512
545
  let uncompressedSize = 0;
513
546
  let signature;
@@ -779,10 +812,12 @@ function setEntryInfo(entryInfo, options) {
779
812
  }
780
813
 
781
814
  async function closeFile(zipWriter, comment, options) {
782
- const { files } = zipWriter;
815
+ const { files, writer } = zipWriter;
783
816
  let offset = 0;
784
817
  let directoryDataLength = 0;
785
- let directoryOffset = zipWriter.offset;
818
+ const { diskOffset, writable } = writer;
819
+ let { diskNumber } = writer;
820
+ let directoryOffset = zipWriter.offset - diskOffset;
786
821
  let filesLength = files.size;
787
822
  for (const [, {
788
823
  rawFilename,
@@ -811,7 +846,7 @@ async function closeFile(zipWriter, comment, options) {
811
846
  zip64 = true;
812
847
  }
813
848
  }
814
- const directoryArray = new Uint8Array(directoryDataLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH));
849
+ const directoryArray = new Uint8Array(directoryDataLength);
815
850
  const directoryView = getDataView(directoryArray);
816
851
  for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
817
852
  const {
@@ -830,7 +865,8 @@ async function closeFile(zipWriter, comment, options) {
830
865
  internalFileAttribute,
831
866
  externalFileAttribute,
832
867
  extendedTimestamp,
833
- lastModDate
868
+ lastModDate,
869
+ diskNumberStart
834
870
  } = fileEntry;
835
871
  let rawExtraFieldExtendedTimestamp;
836
872
  if (extendedTimestamp) {
@@ -849,17 +885,14 @@ async function closeFile(zipWriter, comment, options) {
849
885
  arraySet(directoryArray, headerArray, offset + 6);
850
886
  setUint16(directoryView, offset + 30, extraFieldLength);
851
887
  setUint16(directoryView, offset + 32, getLength(rawComment));
888
+ setUint16(directoryView, offset + 34, zip64 ? MAX_16_BITS : diskNumberStart);
852
889
  setUint16(directoryView, offset + 36, internalFileAttribute);
853
890
  if (externalFileAttribute) {
854
891
  setUint32(directoryView, offset + 38, externalFileAttribute);
855
892
  } else if (directory && msDosCompatible) {
856
893
  setUint8(directoryView, offset + 38, FILE_ATTR_MSDOS_DIR_MASK);
857
894
  }
858
- if (zip64) {
859
- setUint32(directoryView, offset + 42, MAX_32_BITS);
860
- } else {
861
- setUint32(directoryView, offset + 42, fileEntryOffset);
862
- }
895
+ setUint32(directoryView, offset + 42, zip64 ? MAX_32_BITS : fileEntryOffset);
863
896
  arraySet(directoryArray, rawFilename, offset + 46);
864
897
  arraySet(directoryArray, rawExtraFieldZip64, offset + 46 + getLength(rawFilename));
865
898
  arraySet(directoryArray, rawExtraFieldAES, offset + 46 + getLength(rawFilename, rawExtraFieldZip64));
@@ -876,39 +909,52 @@ async function closeFile(zipWriter, comment, options) {
876
909
  }
877
910
  }
878
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;
879
922
  if (zip64) {
880
- setUint32(directoryView, offset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
881
- setBigUint64(directoryView, offset + 4, BigInt(44));
882
- setUint16(directoryView, offset + 12, 45);
883
- setUint16(directoryView, offset + 14, 45);
884
- setBigUint64(directoryView, offset + 24, BigInt(filesLength));
885
- setBigUint64(directoryView, offset + 32, BigInt(filesLength));
886
- setBigUint64(directoryView, offset + 40, BigInt(directoryDataLength));
887
- setBigUint64(directoryView, offset + 48, BigInt(directoryOffset));
888
- setUint32(directoryView, offset + 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
889
- setBigUint64(directoryView, offset + 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
890
- 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;
891
937
  filesLength = MAX_16_BITS;
892
938
  directoryOffset = MAX_32_BITS;
893
939
  directoryDataLength = MAX_32_BITS;
894
- offset += 76;
895
- }
896
- setUint32(directoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
897
- setUint16(directoryView, offset + 8, filesLength);
898
- setUint16(directoryView, offset + 10, filesLength);
899
- setUint32(directoryView, offset + 12, directoryDataLength);
900
- 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);
901
949
  const commentLength = getLength(comment);
902
950
  if (commentLength) {
903
951
  if (commentLength <= MAX_16_BITS) {
904
- setUint16(directoryView, offset + 20, commentLength);
952
+ setUint16(endOfdirectoryView, offset + 20, commentLength);
905
953
  } else {
906
954
  throw new Error(ERR_INVALID_COMMENT);
907
955
  }
908
956
  }
909
- const { writable } = zipWriter.writer;
910
- await initStream(zipWriter.writer);
911
- await writeData(writable, directoryArray);
957
+ await writeData(writable, endOfdirectoryArray);
912
958
  if (commentLength) {
913
959
  await writeData(writable, comment);
914
960
  }