@zip.js/zip.js 2.7.63 → 2.7.65

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.
@@ -26,7 +26,7 @@
26
26
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
  */
28
28
 
29
- /* global TransformStream, Response */
29
+ /* global TransformStream, Response, ReadableStream */
30
30
  // deno-lint-ignore-file no-this-alias
31
31
 
32
32
  import {
@@ -55,6 +55,9 @@ import {
55
55
  BITFLAG_ENCRYPTED,
56
56
  BITFLAG_DATA_DESCRIPTOR,
57
57
  BITFLAG_LANG_ENCODING_FLAG,
58
+ BITFLAG_LEVEL_FAST_MASK,
59
+ BITFLAG_LEVEL_SUPER_FAST_MASK,
60
+ BITFLAG_LEVEL_MAX_MASK,
58
61
  FILE_ATTR_MSDOS_DIR_MASK,
59
62
  FILE_ATTR_UNIX_TYPE_DIR,
60
63
  FILE_ATTR_UNIX_EXECUTABLE_MASK,
@@ -63,6 +66,10 @@ import {
63
66
  VERSION_ZIP64,
64
67
  VERSION_AES,
65
68
  DIRECTORY_SIGNATURE,
69
+ HEADER_SIZE,
70
+ HEADER_OFFSET_SIGNATURE,
71
+ HEADER_OFFSET_COMPRESSED_SIZE,
72
+ HEADER_OFFSET_UNCOMPRESSED_SIZE,
66
73
  MIN_DATE,
67
74
  MAX_DATE,
68
75
  UNDEFINED_VALUE
@@ -77,8 +84,8 @@ import {
77
84
  } from "./codec-pool.js";
78
85
  import {
79
86
  initStream,
80
- initReader,
81
- initWriter
87
+ GenericWriter,
88
+ GenericReader
82
89
  } from "./io.js";
83
90
  import { encodeText } from "./util/encode-text.js";
84
91
  import {
@@ -99,6 +106,9 @@ import {
99
106
  PROPERTY_NAME_EXECUTABLE,
100
107
  Entry
101
108
  } from "./zip-entry.js";
109
+ import {
110
+ ZipReader
111
+ } from "./zip-reader.js";
102
112
 
103
113
  const ERR_DUPLICATED_NAME = "File already exists";
104
114
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
@@ -110,6 +120,7 @@ const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
110
120
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
111
121
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (make sure 'keepOrder' is set to 'true')";
112
122
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
123
+ const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
113
124
 
114
125
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
115
126
 
@@ -119,7 +130,7 @@ const pendingEntries = [];
119
130
  class ZipWriter {
120
131
 
121
132
  constructor(writer, options = {}) {
122
- writer = initWriter(writer);
133
+ writer = new GenericWriter(writer);
123
134
  const addSplitZipSignature =
124
135
  writer.availableSize !== UNDEFINED_VALUE && writer.availableSize > 0 && writer.availableSize !== Infinity &&
125
136
  writer.maxSize !== UNDEFINED_VALUE && writer.maxSize > 0 && writer.maxSize !== Infinity;
@@ -130,13 +141,106 @@ class ZipWriter {
130
141
  config: getConfiguration(),
131
142
  files: new Map(),
132
143
  filenames: new Set(),
133
- offset: options.offset === UNDEFINED_VALUE ? writer.writable.size : options.offset,
144
+ offset: options.offset === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options.offset,
134
145
  pendingEntriesSize: 0,
135
146
  pendingAddFileCalls: new Set(),
136
147
  bufferedWrites: 0
137
148
  });
138
149
  }
139
150
 
151
+ async prependZip(reader) {
152
+ if (this.filenames.size) {
153
+ throw new Error(ERR_ZIP_NOT_EMPTY);
154
+ }
155
+ ({ reader } = new GenericReader(reader));
156
+ const [zipEntriesReader, zipDataReader] = reader.readable.tee();
157
+ const zipReader = new ZipReader(new ReadableStream({
158
+ async start(controller) {
159
+ const reader = zipEntriesReader.getReader();
160
+ await readChunk();
161
+
162
+ async function readChunk() {
163
+ const { done, value } = await reader.read();
164
+ if (done) {
165
+ controller.close();
166
+ } else {
167
+ controller.enqueue(value);
168
+ await readChunk();
169
+ }
170
+ }
171
+ }
172
+ }));
173
+ const entries = await zipReader.getEntries();
174
+ await zipReader.close();
175
+ await zipDataReader.pipeTo(this.writer.writable, { preventClose: true, preventAbort: true });
176
+ this.writer.size = this.offset = reader.size;
177
+ this.filenames = new Set(entries.map(entry => entry.filename));
178
+ this.files = new Map(entries.map(entry => {
179
+ const {
180
+ version,
181
+ compressionMethod,
182
+ lastModDate,
183
+ lastAccessDate,
184
+ creationDate,
185
+ rawFilename,
186
+ bitFlag,
187
+ encrypted,
188
+ uncompressedSize,
189
+ compressedSize,
190
+ diskOffset,
191
+ diskNumber,
192
+ zip64
193
+ } = entry;
194
+ let {
195
+ rawExtraFieldZip64,
196
+ rawExtraFieldAES,
197
+ rawExtraFieldExtendedTimestamp,
198
+ rawExtraFieldNTFS,
199
+ rawExtraField,
200
+ } = entry;
201
+ const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
202
+ rawExtraFieldZip64 = rawExtraFieldZip64 || new Uint8Array();
203
+ rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
204
+ rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
205
+ rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
206
+ rawExtraField = rawExtraField || new Uint8Array();
207
+ const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
208
+ const zip64UncompressedSize = zip64 && uncompressedSize > MAX_32_BITS;
209
+ const zip64CompressedSize = zip64 && compressedSize > MAX_32_BITS;
210
+ const {
211
+ headerArray,
212
+ headerView
213
+ } = getHeaderArrayData({
214
+ version,
215
+ bitflag: getBitflag(level, languageEncodingFlag, dataDescriptor, encrypted),
216
+ compressionMethod,
217
+ uncompressedSize,
218
+ compressedSize,
219
+ lastModDate,
220
+ rawFilename,
221
+ zip64CompressedSize,
222
+ zip64UncompressedSize,
223
+ extraFieldLength
224
+ });
225
+ Object.assign(entry, {
226
+ zip64UncompressedSize,
227
+ zip64CompressedSize,
228
+ zip64Offset: zip64 && this.offset - diskOffset > MAX_32_BITS,
229
+ zip64DiskNumberStart: zip64 && diskNumber > MAX_16_BITS,
230
+ rawExtraFieldZip64,
231
+ rawExtraFieldAES,
232
+ rawExtraFieldExtendedTimestamp,
233
+ rawExtraFieldNTFS,
234
+ rawExtraField,
235
+ extendedTimestamp: rawExtraFieldExtendedTimestamp.length > 0 || rawExtraFieldNTFS.length > 0,
236
+ extraFieldExtendedTimestampFlag: 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0),
237
+ headerArray,
238
+ headerView
239
+ });
240
+ return [entry.filename, entry];
241
+ }));
242
+ }
243
+
140
244
  async add(name = "", reader, options = {}) {
141
245
  const zipWriter = this;
142
246
  const {
@@ -172,6 +276,22 @@ class ZipWriter {
172
276
  }
173
277
  }
174
278
 
279
+ remove(entry) {
280
+ const { filenames, files } = this;
281
+ if (typeof entry == "string") {
282
+ entry = files.get(entry);
283
+ }
284
+ if (entry && entry.filename !== UNDEFINED_VALUE) {
285
+ const { filename } = entry;
286
+ if (filenames.has(filename) && files.has(filename)) {
287
+ filenames.delete(filename);
288
+ files.delete(filename);
289
+ return true;
290
+ }
291
+ }
292
+ return false;
293
+ }
294
+
175
295
  async close(comment = new Uint8Array(), options = {}) {
176
296
  const zipWriter = this;
177
297
  const { pendingAddFileCalls, writer } = this;
@@ -227,7 +347,8 @@ export {
227
347
  ERR_INVALID_EXTRAFIELD_DATA,
228
348
  ERR_INVALID_ENCRYPTION_STRENGTH,
229
349
  ERR_UNSUPPORTED_FORMAT,
230
- ERR_UNDEFINED_UNCOMPRESSED_SIZE
350
+ ERR_UNDEFINED_UNCOMPRESSED_SIZE,
351
+ ERR_ZIP_NOT_EMPTY
231
352
  };
232
353
 
233
354
  async function addFile(zipWriter, name, reader, options) {
@@ -308,7 +429,13 @@ async function addFile(zipWriter, name, reader, options) {
308
429
  const useUnicodeFileNames = getOptionValue(zipWriter, options, "useUnicodeFileNames", true);
309
430
  const useCompressionStream = getOptionValue(zipWriter, options, "useCompressionStream");
310
431
  const compressionMethod = getOptionValue(zipWriter, options, "compressionMethod");
311
- let dataDescriptor = getOptionValue(zipWriter, options, "dataDescriptor", true);
432
+ let dataDescriptor = getOptionValue(zipWriter, options, "dataDescriptor");
433
+ if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
434
+ dataDescriptor = false;
435
+ }
436
+ if (dataDescriptor === UNDEFINED_VALUE || zipCrypto) {
437
+ dataDescriptor = true;
438
+ }
312
439
  let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
313
440
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
314
441
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
@@ -344,7 +471,7 @@ async function addFile(zipWriter, name, reader, options) {
344
471
  }
345
472
  const zip64Enabled = zip64 === true;
346
473
  if (reader) {
347
- reader = initReader(reader);
474
+ reader = new GenericReader(reader);
348
475
  await initStream(reader);
349
476
  if (!passThrough) {
350
477
  if (reader.size === UNDEFINED_VALUE) {
@@ -354,10 +481,11 @@ async function addFile(zipWriter, name, reader, options) {
354
481
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
355
482
  }
356
483
  } else {
357
- uncompressedSize = reader.size;
484
+ options.uncompressedSize = uncompressedSize = reader.size;
358
485
  maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
359
486
  }
360
487
  } else {
488
+ options.uncompressedSize = uncompressedSize;
361
489
  maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
362
490
  }
363
491
  }
@@ -413,7 +541,10 @@ async function addFile(zipWriter, name, reader, options) {
413
541
  passThrough,
414
542
  encrypted: Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted),
415
543
  signature,
416
- compressionMethod
544
+ compressionMethod,
545
+ uncompressedSize,
546
+ offset: zipWriter.offset - diskOffset,
547
+ diskNumberStart: diskNumber,
417
548
  });
418
549
  const headerInfo = getHeaderInfo(options);
419
550
  const dataDescriptorInfo = getDataDescriptorInfo(options);
@@ -465,8 +596,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
465
596
  }
466
597
  if ((options.bufferedWrite || zipWriter.writerLocked || (zipWriter.bufferedWrites && keepOrder) || !dataDescriptor) && !usdz) {
467
598
  fileWriter = new TransformStream();
468
- blobPromise = new Response(fileWriter.readable).blob();
469
- fileWriter.writable.size = 0;
599
+ fileWriter.size = 0;
470
600
  bufferedWrite = true;
471
601
  zipWriter.bufferedWrites++;
472
602
  await initStream(writer);
@@ -475,19 +605,22 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
475
605
  await requestLockWriter();
476
606
  }
477
607
  await initStream(fileWriter);
478
- const { writable } = writer;
479
- let { diskOffset } = writer;
608
+ const { writable, diskOffset } = writer;
480
609
  if (zipWriter.addSplitZipSignature) {
481
610
  delete zipWriter.addSplitZipSignature;
482
611
  const signatureArray = new Uint8Array(4);
483
612
  const signatureArrayView = getDataView(signatureArray);
484
613
  setUint32(signatureArrayView, 0, SPLIT_ZIP_FILE_SIGNATURE);
485
- await writeData(writable, signatureArray);
614
+ await writeData(writer, signatureArray);
486
615
  zipWriter.offset += 4;
487
616
  }
488
617
  if (usdz) {
489
618
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
490
619
  }
620
+ const {
621
+ localHeaderView,
622
+ localHeaderArray
623
+ } = headerInfo;
491
624
  if (!bufferedWrite) {
492
625
  await lockPreviousFileEntry;
493
626
  await skipDiskIfNeeded(writable);
@@ -495,30 +628,38 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
495
628
  const { diskNumber } = writer;
496
629
  writingEntryData = true;
497
630
  fileEntry.diskNumberStart = diskNumber;
631
+ if (bufferedWrite) {
632
+ blobPromise = new Response(fileWriter.readable).blob();
633
+ } else {
634
+ await writeData(fileWriter, localHeaderArray);
635
+ }
498
636
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
637
+ const { zip64 } = fileEntry;
499
638
  writingEntryData = false;
500
639
  files.set(name, fileEntry);
501
640
  fileEntry.filename = name;
502
641
  if (bufferedWrite) {
503
- await fileWriter.writable.getWriter().close();
504
- let blob = await blobPromise;
505
- await lockPreviousFileEntry;
642
+ const [blob] = await Promise.all([blobPromise, fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
506
643
  await requestLockWriter();
507
644
  writingBufferedEntryData = true;
508
- if (!dataDescriptor) {
509
- blob = await writeExtraHeaderInfo(fileEntry, blob, writable, options);
645
+ fileEntry.diskNumberStart = writer.diskNumber;
646
+ fileEntry.offset = zipWriter.offset - writer.diskOffset;
647
+ if (zip64) {
648
+ updateZip64ExtraField(fileEntry);
510
649
  }
650
+ updateLocalHeader(fileEntry, localHeaderView);
511
651
  await skipDiskIfNeeded(writable);
512
- fileEntry.diskNumberStart = writer.diskNumber;
513
- diskOffset = writer.diskOffset;
652
+ await writeData(writer, localHeaderArray);
514
653
  await blob.stream().pipeTo(writable, { preventClose: true, preventAbort: true, signal });
515
- writable.size += blob.size;
654
+ writer.size += fileWriter.size;
516
655
  writingBufferedEntryData = false;
656
+ } else {
657
+ fileEntry.offset = zipWriter.offset - diskOffset;
658
+ if (zip64) {
659
+ updateZip64ExtraField(fileEntry);
660
+ }
517
661
  }
518
- fileEntry.offset = zipWriter.offset - diskOffset;
519
- if (fileEntry.zip64) {
520
- setZip64ExtraInfo(fileEntry, options);
521
- } else if (fileEntry.offset > MAX_32_BITS) {
662
+ if (fileEntry.offset > MAX_32_BITS && !zip64) {
522
663
  throw new Error(ERR_UNSUPPORTED_FORMAT);
523
664
  }
524
665
  zipWriter.offset += fileEntry.size;
@@ -535,9 +676,9 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
535
676
  }
536
677
  }
537
678
  if (bufferedWrite) {
538
- zipWriter.offset += fileWriter.writable.size;
679
+ zipWriter.offset += fileWriter.size;
539
680
  } else {
540
- zipWriter.offset = fileWriter.writable.size;
681
+ zipWriter.offset = fileWriter.size;
541
682
  }
542
683
  }
543
684
  files.delete(name);
@@ -583,14 +724,16 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
583
724
  metadataSize
584
725
  } = entryInfo;
585
726
  const {
586
- localHeaderArray,
587
727
  headerArray,
728
+ headerView,
588
729
  lastModDate,
589
730
  rawLastModDate,
590
731
  encrypted,
591
732
  compressed,
592
733
  version,
593
734
  compressionMethod,
735
+ rawExtraFieldZip64,
736
+ localExtraFieldZip64Length,
594
737
  rawExtraFieldExtendedTimestamp,
595
738
  extraFieldExtendedTimestampFlag,
596
739
  rawExtraFieldNTFS,
@@ -639,6 +782,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
639
782
  rawFilename,
640
783
  commentUTF8: true,
641
784
  rawComment,
785
+ rawExtraFieldZip64,
786
+ localExtraFieldZip64Length,
642
787
  rawExtraFieldExtendedTimestamp,
643
788
  rawExtraFieldNTFS,
644
789
  rawExtraFieldAES,
@@ -660,9 +805,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
660
805
  const { writable } = writer;
661
806
  if (reader) {
662
807
  reader.chunkSize = getChunkSize(config);
663
- await writeData(writable, localHeaderArray);
664
808
  const readable = reader.readable;
665
- const size = readable.size = reader.size;
809
+ const size = reader.size;
666
810
  const workerOptions = {
667
811
  options: {
668
812
  codecType: CODEC_DEFLATE,
@@ -682,45 +826,31 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
682
826
  config,
683
827
  streamOptions: { signal, size, onstart, onprogress, onend }
684
828
  };
685
- const result = await runWorker({ readable, writable }, workerOptions);
686
- compressedSize = result.outputSize;
687
- if (!passThrough) {
688
- uncompressedSize = result.inputSize;
689
- signature = result.signature;
690
- }
691
- writable.size += uncompressedSize;
692
- } else {
693
- await writeData(writable, localHeaderArray);
694
- }
695
- let rawExtraFieldZip64;
696
- if (zip64) {
697
- let rawExtraFieldZip64Length = 4;
698
- if (zip64UncompressedSize) {
699
- rawExtraFieldZip64Length += 8;
700
- }
701
- if (zip64CompressedSize) {
702
- rawExtraFieldZip64Length += 8;
703
- }
704
- if (zip64Offset) {
705
- rawExtraFieldZip64Length += 8;
706
- }
707
- if (zip64DiskNumberStart) {
708
- rawExtraFieldZip64Length += 4;
829
+ try {
830
+ const result = await runWorker({ readable, writable }, workerOptions);
831
+ compressedSize = result.outputSize;
832
+ writer.size += compressedSize;
833
+ if (!passThrough) {
834
+ uncompressedSize = result.inputSize;
835
+ signature = result.signature;
836
+ }
837
+ } catch (error) {
838
+ if (error.outputSize !== UNDEFINED_VALUE) {
839
+ writer.size += error.outputSize;
840
+ }
841
+ throw error;
709
842
  }
710
- rawExtraFieldZip64 = new Uint8Array(rawExtraFieldZip64Length);
711
- } else {
712
- rawExtraFieldZip64 = new Uint8Array();
843
+
713
844
  }
714
845
  setEntryInfo({
715
846
  signature,
716
- rawExtraFieldZip64,
717
847
  compressedSize,
718
848
  uncompressedSize,
719
849
  headerInfo,
720
850
  dataDescriptorInfo
721
851
  }, options);
722
852
  if (dataDescriptor) {
723
- await writeData(writable, dataDescriptorArray);
853
+ await writeData(writer, dataDescriptorArray);
724
854
  }
725
855
  Object.assign(fileEntry, {
726
856
  uncompressedSize,
@@ -735,8 +865,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
735
865
  compressionMethod,
736
866
  version,
737
867
  headerArray,
868
+ headerView,
738
869
  signature,
739
- rawExtraFieldZip64,
740
870
  extraFieldExtendedTimestampFlag,
741
871
  zip64UncompressedSize,
742
872
  zip64CompressedSize,
@@ -761,10 +891,62 @@ function getHeaderInfo(options) {
761
891
  rawExtraField,
762
892
  encryptionStrength,
763
893
  extendedTimestamp,
764
- encrypted
894
+ passThrough,
895
+ encrypted,
896
+ zip64UncompressedSize,
897
+ zip64CompressedSize,
898
+ zip64Offset,
899
+ zip64DiskNumberStart,
900
+ uncompressedSize,
901
+ offset,
902
+ diskNumberStart
765
903
  } = options;
766
904
  let { version, compressionMethod } = options;
767
905
  const compressed = !directory && (level > 0 || (level === UNDEFINED_VALUE && compressionMethod !== 0));
906
+ let rawExtraFieldZip64;
907
+ const uncompressedFile = passThrough || !compressed;
908
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
909
+ if (zip64) {
910
+ let rawExtraFieldZip64Length = 4;
911
+ if (zip64UncompressedSize) {
912
+ rawExtraFieldZip64Length += 8;
913
+ }
914
+ if (zip64CompressedSize) {
915
+ rawExtraFieldZip64Length += 8;
916
+ }
917
+ if (zip64Offset) {
918
+ rawExtraFieldZip64Length += 8;
919
+ }
920
+ if (zip64DiskNumberStart) {
921
+ rawExtraFieldZip64Length += 4;
922
+ }
923
+ rawExtraFieldZip64 = new Uint8Array(rawExtraFieldZip64Length);
924
+ const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
925
+ setUint16(rawExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
926
+ setUint16(rawExtraFieldZip64View, 2, getLength(rawExtraFieldZip64) - 4);
927
+ if (zip64ExtraFieldComplete) {
928
+ const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
929
+ let rawExtraFieldZip64Offset = 4;
930
+ if (zip64UncompressedSize) {
931
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
932
+ rawExtraFieldZip64Offset += 8;
933
+ }
934
+ if (zip64CompressedSize && uncompressedFile) {
935
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
936
+ rawExtraFieldZip64Offset += 8;
937
+ }
938
+ if (zip64Offset) {
939
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(offset));
940
+ rawExtraFieldZip64Offset += 8;
941
+ }
942
+ if (zip64DiskNumberStart) {
943
+ setUint32(rawExtraFieldZip64View, rawExtraFieldZip64Offset, diskNumberStart);
944
+ rawExtraFieldZip64Offset += 4;
945
+ }
946
+ }
947
+ } else {
948
+ rawExtraFieldZip64 = new Uint8Array();
949
+ }
768
950
  let rawExtraFieldAES;
769
951
  if (encrypted && !zipCrypto) {
770
952
  rawExtraFieldAES = new Uint8Array(getLength(EXTRAFIELD_DATA_AES) + 2);
@@ -813,71 +995,55 @@ function getHeaderInfo(options) {
813
995
  } else {
814
996
  rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = new Uint8Array();
815
997
  }
816
- let bitFlag = 0;
817
- if (useUnicodeFileNames) {
818
- bitFlag = bitFlag | BITFLAG_LANG_ENCODING_FLAG;
819
- }
820
- if (dataDescriptor) {
821
- bitFlag = bitFlag | BITFLAG_DATA_DESCRIPTOR;
822
- }
823
998
  if (compressionMethod === UNDEFINED_VALUE) {
824
999
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
825
1000
  }
826
- if (compressionMethod == COMPRESSION_METHOD_DEFLATE) {
827
- if (level >= 1 && level < 3) {
828
- bitFlag = bitFlag | 0b110;
829
- }
830
- if (level >= 3 && level < 5) {
831
- bitFlag = bitFlag | 0b01;
832
- }
833
- if (level === 9) {
834
- bitFlag = bitFlag | 0b10;
835
- }
836
- }
837
1001
  if (zip64) {
838
1002
  version = version > VERSION_ZIP64 ? version : VERSION_ZIP64;
839
1003
  }
840
- if (encrypted) {
841
- bitFlag = bitFlag | BITFLAG_ENCRYPTED;
842
- if (!zipCrypto) {
843
- version = version > VERSION_AES ? version : VERSION_AES;
844
- rawExtraFieldAES[9] = compressionMethod;
845
- compressionMethod = COMPRESSION_METHOD_AES;
846
- }
847
- }
848
- const headerArray = new Uint8Array(26);
849
- const headerView = getDataView(headerArray);
850
- setUint16(headerView, 0, version);
851
- setUint16(headerView, 2, bitFlag);
852
- setUint16(headerView, 4, compressionMethod);
853
- const dateArray = new Uint32Array(1);
854
- const dateView = getDataView(dateArray);
855
- let lastModDateMsDos;
856
- if (lastModDate < MIN_DATE) {
857
- lastModDateMsDos = MIN_DATE;
858
- } else if (lastModDate > MAX_DATE) {
859
- lastModDateMsDos = MAX_DATE;
860
- } else {
861
- lastModDateMsDos = lastModDate;
1004
+ if (encrypted && !zipCrypto) {
1005
+ version = version > VERSION_AES ? version : VERSION_AES;
1006
+ rawExtraFieldAES[9] = compressionMethod;
1007
+ compressionMethod = COMPRESSION_METHOD_AES;
862
1008
  }
863
- setUint16(dateView, 0, (((lastModDateMsDos.getHours() << 6) | lastModDateMsDos.getMinutes()) << 5) | lastModDateMsDos.getSeconds() / 2);
864
- setUint16(dateView, 2, ((((lastModDateMsDos.getFullYear() - 1980) << 4) | (lastModDateMsDos.getMonth() + 1)) << 5) | lastModDateMsDos.getDate());
865
- const rawLastModDate = dateArray[0];
866
- setUint32(headerView, 6, rawLastModDate);
867
- setUint16(headerView, 22, getLength(rawFilename));
868
- const extraFieldLength = getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
869
- setUint16(headerView, 24, extraFieldLength);
870
- const localHeaderArray = new Uint8Array(30 + getLength(rawFilename) + extraFieldLength);
1009
+ const localExtraFieldZip64Length = zip64ExtraFieldComplete ? getLength(rawExtraFieldZip64) : 0;
1010
+ const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
1011
+ const {
1012
+ headerArray,
1013
+ headerView,
1014
+ rawLastModDate
1015
+ } = getHeaderArrayData({
1016
+ version,
1017
+ bitflag: getBitflag(level, useUnicodeFileNames, dataDescriptor, encrypted),
1018
+ compressionMethod,
1019
+ uncompressedSize,
1020
+ lastModDate: lastModDate < MIN_DATE ? MIN_DATE : lastModDate > MAX_DATE ? MAX_DATE : lastModDate,
1021
+ rawFilename,
1022
+ zip64CompressedSize,
1023
+ zip64UncompressedSize,
1024
+ extraFieldLength
1025
+ });
1026
+ let localHeaderOffset = HEADER_SIZE + 4;
1027
+ const localHeaderArray = new Uint8Array(localHeaderOffset + getLength(rawFilename) + extraFieldLength);
871
1028
  const localHeaderView = getDataView(localHeaderArray);
872
1029
  setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE);
873
1030
  arraySet(localHeaderArray, headerArray, 4);
874
- arraySet(localHeaderArray, rawFilename, 30);
875
- arraySet(localHeaderArray, rawExtraFieldAES, 30 + getLength(rawFilename));
876
- arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, 30 + getLength(rawFilename, rawExtraFieldAES));
877
- arraySet(localHeaderArray, rawExtraFieldNTFS, 30 + getLength(rawFilename, rawExtraFieldAES, rawExtraFieldExtendedTimestamp));
878
- arraySet(localHeaderArray, rawExtraField, 30 + getLength(rawFilename, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS));
1031
+ arraySet(localHeaderArray, rawFilename, localHeaderOffset);
1032
+ localHeaderOffset += getLength(rawFilename);
1033
+ if (zip64ExtraFieldComplete) {
1034
+ arraySet(localHeaderArray, rawExtraFieldZip64, localHeaderOffset);
1035
+ }
1036
+ localHeaderOffset += localExtraFieldZip64Length;
1037
+ arraySet(localHeaderArray, rawExtraFieldAES, localHeaderOffset);
1038
+ localHeaderOffset += getLength(rawExtraFieldAES);
1039
+ arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, localHeaderOffset);
1040
+ localHeaderOffset += getLength(rawExtraFieldExtendedTimestamp);
1041
+ arraySet(localHeaderArray, rawExtraFieldNTFS, localHeaderOffset);
1042
+ localHeaderOffset += getLength(rawExtraFieldNTFS);
1043
+ arraySet(localHeaderArray, rawExtraField, localHeaderOffset);
879
1044
  return {
880
1045
  localHeaderArray,
1046
+ localHeaderView,
881
1047
  headerArray,
882
1048
  headerView,
883
1049
  lastModDate,
@@ -887,6 +1053,8 @@ function getHeaderInfo(options) {
887
1053
  version,
888
1054
  compressionMethod,
889
1055
  extraFieldExtendedTimestampFlag,
1056
+ rawExtraFieldZip64,
1057
+ localExtraFieldZip64Length,
890
1058
  rawExtraFieldExtendedTimestamp,
891
1059
  rawExtraFieldNTFS,
892
1060
  rawExtraFieldAES,
@@ -915,12 +1083,11 @@ function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
915
1083
  entryInfo.metadataSize += extraBytesLength;
916
1084
  }
917
1085
 
918
- function getDataDescriptorInfo(options) {
919
- const {
920
- zip64,
921
- dataDescriptor,
922
- dataDescriptorSignature
923
- } = options;
1086
+ function getDataDescriptorInfo({
1087
+ zip64,
1088
+ dataDescriptor,
1089
+ dataDescriptorSignature
1090
+ }) {
924
1091
  let dataDescriptorArray = new Uint8Array();
925
1092
  let dataDescriptorView, dataDescriptorOffset = 0;
926
1093
  if (dataDescriptor) {
@@ -938,15 +1105,17 @@ function getDataDescriptorInfo(options) {
938
1105
  };
939
1106
  }
940
1107
 
941
- function setEntryInfo(entryInfo, options) {
942
- const {
943
- signature,
944
- rawExtraFieldZip64,
945
- compressedSize,
946
- uncompressedSize,
947
- headerInfo,
948
- dataDescriptorInfo
949
- } = entryInfo;
1108
+ function setEntryInfo({
1109
+ signature,
1110
+ compressedSize,
1111
+ uncompressedSize,
1112
+ headerInfo,
1113
+ dataDescriptorInfo
1114
+ }, {
1115
+ zip64,
1116
+ zipCrypto,
1117
+ dataDescriptor
1118
+ }) {
950
1119
  const {
951
1120
  headerView,
952
1121
  encrypted
@@ -955,40 +1124,20 @@ function setEntryInfo(entryInfo, options) {
955
1124
  dataDescriptorView,
956
1125
  dataDescriptorOffset
957
1126
  } = dataDescriptorInfo;
958
- const {
959
- zip64,
960
- zip64UncompressedSize,
961
- zip64CompressedSize,
962
- zipCrypto,
963
- dataDescriptor
964
- } = options;
965
1127
  if ((!encrypted || zipCrypto) && signature !== UNDEFINED_VALUE) {
966
- setUint32(headerView, 10, signature);
1128
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
967
1129
  if (dataDescriptor) {
968
1130
  setUint32(dataDescriptorView, dataDescriptorOffset, signature);
969
1131
  }
970
1132
  }
971
1133
  if (zip64) {
972
- const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
973
- setUint16(rawExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
974
- setUint16(rawExtraFieldZip64View, 2, getLength(rawExtraFieldZip64) - 4);
975
- let rawExtraFieldZip64Offset = 4;
976
- if (zip64UncompressedSize) {
977
- setUint32(headerView, 18, MAX_32_BITS);
978
- setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
979
- rawExtraFieldZip64Offset += 8;
980
- }
981
- if (zip64CompressedSize) {
982
- setUint32(headerView, 14, MAX_32_BITS);
983
- setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(compressedSize));
984
- }
985
1134
  if (dataDescriptor) {
986
1135
  setBigUint64(dataDescriptorView, dataDescriptorOffset + 4, BigInt(compressedSize));
987
1136
  setBigUint64(dataDescriptorView, dataDescriptorOffset + 12, BigInt(uncompressedSize));
988
1137
  }
989
1138
  } else {
990
- setUint32(headerView, 14, compressedSize);
991
- setUint32(headerView, 18, uncompressedSize);
1139
+ setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, compressedSize);
1140
+ setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, uncompressedSize);
992
1141
  if (dataDescriptor) {
993
1142
  setUint32(dataDescriptorView, dataDescriptorOffset + 4, compressedSize);
994
1143
  setUint32(dataDescriptorView, dataDescriptorOffset + 8, uncompressedSize);
@@ -996,36 +1145,72 @@ function setEntryInfo(entryInfo, options) {
996
1145
  }
997
1146
  }
998
1147
 
999
- async function writeExtraHeaderInfo(fileEntry, entryData, writable, { zipCrypto }) {
1000
- let arrayBuffer;
1001
- arrayBuffer = await entryData.slice(0, 26).arrayBuffer();
1002
- if (arrayBuffer.byteLength != 26) {
1003
- arrayBuffer = arrayBuffer.slice(0, 26);
1004
- }
1005
- const arrayBufferView = new DataView(arrayBuffer);
1006
- if (!fileEntry.encrypted || zipCrypto) {
1007
- setUint32(arrayBufferView, 14, fileEntry.signature);
1008
- }
1009
- if (fileEntry.zip64) {
1010
- setUint32(arrayBufferView, 18, MAX_32_BITS);
1011
- setUint32(arrayBufferView, 22, MAX_32_BITS);
1012
- } else {
1013
- setUint32(arrayBufferView, 18, fileEntry.compressedSize);
1014
- setUint32(arrayBufferView, 22, fileEntry.uncompressedSize);
1148
+ function updateLocalHeader({
1149
+ rawFilename,
1150
+ dataDescriptor,
1151
+ encrypted,
1152
+ zip64,
1153
+ localExtraFieldZip64Length,
1154
+ signature,
1155
+ compressedSize,
1156
+ uncompressedSize,
1157
+ offset,
1158
+ diskNumberStart,
1159
+ zip64UncompressedSize,
1160
+ zip64CompressedSize,
1161
+ zip64Offset,
1162
+ zip64DiskNumberStart
1163
+ }, localHeaderView) {
1164
+ if (!dataDescriptor) {
1165
+ if (!encrypted) {
1166
+ setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + 4, signature);
1167
+ }
1168
+ if (!zip64) {
1169
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, compressedSize);
1170
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, uncompressedSize);
1171
+ }
1172
+ }
1173
+ if (zip64) {
1174
+ if (localExtraFieldZip64Length) {
1175
+ let localHeaderOffset = HEADER_SIZE + 4 + getLength(rawFilename) + 4;
1176
+ if (zip64UncompressedSize) {
1177
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
1178
+ localHeaderOffset += 8;
1179
+ }
1180
+ if (zip64CompressedSize) {
1181
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(compressedSize));
1182
+ localHeaderOffset += 8;
1183
+ }
1184
+ if (zip64Offset) {
1185
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(offset));
1186
+ localHeaderOffset += 8;
1187
+ }
1188
+ if (zip64DiskNumberStart) {
1189
+ setUint32(localHeaderView, localHeaderOffset, diskNumberStart);
1190
+ }
1191
+ }
1015
1192
  }
1016
- await writeData(writable, new Uint8Array(arrayBuffer));
1017
- return entryData.slice(arrayBuffer.byteLength);
1018
1193
  }
1019
1194
 
1020
- function setZip64ExtraInfo(fileEntry, options) {
1021
- const { rawExtraFieldZip64, offset, diskNumberStart } = fileEntry;
1022
- const { zip64UncompressedSize, zip64CompressedSize, zip64Offset, zip64DiskNumberStart } = options;
1195
+ function updateZip64ExtraField({
1196
+ compressedSize,
1197
+ uncompressedSize,
1198
+ offset,
1199
+ diskNumberStart,
1200
+ zip64UncompressedSize,
1201
+ zip64CompressedSize,
1202
+ zip64Offset,
1203
+ zip64DiskNumberStart,
1204
+ rawExtraFieldZip64
1205
+ }) {
1023
1206
  const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
1024
1207
  let rawExtraFieldZip64Offset = 4;
1025
1208
  if (zip64UncompressedSize) {
1209
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
1026
1210
  rawExtraFieldZip64Offset += 8;
1027
1211
  }
1028
1212
  if (zip64CompressedSize) {
1213
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(compressedSize));
1029
1214
  rawExtraFieldZip64Offset += 8;
1030
1215
  }
1031
1216
  if (zip64Offset) {
@@ -1039,7 +1224,7 @@ function setZip64ExtraInfo(fileEntry, options) {
1039
1224
 
1040
1225
  async function closeFile(zipWriter, comment, options) {
1041
1226
  const { files, writer } = zipWriter;
1042
- const { diskOffset, writable } = writer;
1227
+ const { diskOffset } = writer;
1043
1228
  let { diskNumber } = writer;
1044
1229
  let offset = 0;
1045
1230
  let directoryDataLength = 0;
@@ -1068,7 +1253,7 @@ async function closeFile(zipWriter, comment, options) {
1068
1253
  } else {
1069
1254
  rawExtraFieldTimestamp = new Uint8Array();
1070
1255
  }
1071
- fileEntry.rawExtraFieldCDExtendedTimestamp = rawExtraFieldTimestamp;
1256
+ fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
1072
1257
  directoryDataLength += 46 +
1073
1258
  getLength(
1074
1259
  rawFilename,
@@ -1089,12 +1274,13 @@ async function closeFile(zipWriter, comment, options) {
1089
1274
  rawFilename,
1090
1275
  rawExtraFieldZip64,
1091
1276
  rawExtraFieldAES,
1092
- rawExtraFieldCDExtendedTimestamp,
1277
+ rawExtraFieldExtendedTimestamp,
1093
1278
  rawExtraFieldNTFS,
1094
1279
  rawExtraField,
1095
1280
  rawComment,
1096
1281
  versionMadeBy,
1097
1282
  headerArray,
1283
+ headerView,
1098
1284
  zip64,
1099
1285
  zip64UncompressedSize,
1100
1286
  zip64CompressedSize,
@@ -1106,39 +1292,50 @@ async function closeFile(zipWriter, comment, options) {
1106
1292
  uncompressedSize,
1107
1293
  compressedSize
1108
1294
  } = fileEntry;
1109
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldCDExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
1295
+ const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
1110
1296
  setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE);
1111
1297
  setUint16(directoryView, offset + 4, versionMadeBy);
1112
- const headerView = getDataView(headerArray);
1113
1298
  if (!zip64UncompressedSize) {
1114
- setUint32(headerView, 18, uncompressedSize);
1299
+ setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, uncompressedSize);
1115
1300
  }
1116
1301
  if (!zip64CompressedSize) {
1117
- setUint32(headerView, 14, compressedSize);
1302
+ setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, compressedSize);
1118
1303
  }
1119
1304
  arraySet(directoryArray, headerArray, offset + 6);
1120
- setUint16(directoryView, offset + 30, extraFieldLength);
1121
- setUint16(directoryView, offset + 32, getLength(rawComment));
1122
- setUint16(directoryView, offset + 34, zip64 && zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
1123
- setUint16(directoryView, offset + 36, internalFileAttributes);
1305
+ let directoryOffset = offset + HEADER_SIZE + 4;
1306
+ setUint16(directoryView, directoryOffset, extraFieldLength);
1307
+ directoryOffset += 2;
1308
+ setUint16(directoryView, directoryOffset, getLength(rawComment));
1309
+ directoryOffset += 2;
1310
+ setUint16(directoryView, directoryOffset, zip64 && zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
1311
+ directoryOffset += 2;
1312
+ setUint16(directoryView, directoryOffset, internalFileAttributes);
1313
+ directoryOffset += 2;
1124
1314
  if (externalFileAttributes) {
1125
- setUint32(directoryView, offset + 38, externalFileAttributes);
1315
+ setUint32(directoryView, directoryOffset, externalFileAttributes);
1126
1316
  }
1127
- setUint32(directoryView, offset + 42, zip64 && zip64Offset ? MAX_32_BITS : fileEntryOffset);
1128
- arraySet(directoryArray, rawFilename, offset + 46);
1129
- arraySet(directoryArray, rawExtraFieldZip64, offset + 46 + getLength(rawFilename));
1130
- arraySet(directoryArray, rawExtraFieldAES, offset + 46 + getLength(rawFilename, rawExtraFieldZip64));
1131
- arraySet(directoryArray, rawExtraFieldCDExtendedTimestamp, offset + 46 + getLength(rawFilename, rawExtraFieldZip64, rawExtraFieldAES));
1132
- arraySet(directoryArray, rawExtraFieldNTFS, offset + 46 + getLength(rawFilename, rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldCDExtendedTimestamp));
1133
- arraySet(directoryArray, rawExtraField, offset + 46 + getLength(rawFilename, rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldCDExtendedTimestamp, rawExtraFieldNTFS));
1134
- arraySet(directoryArray, rawComment, offset + 46 + getLength(rawFilename) + extraFieldLength);
1135
- const directoryEntryLength = 46 + getLength(rawFilename, rawComment) + extraFieldLength;
1317
+ directoryOffset += 4;
1318
+ setUint32(directoryView, directoryOffset, zip64 && zip64Offset ? MAX_32_BITS : fileEntryOffset);
1319
+ directoryOffset += 4;
1320
+ arraySet(directoryArray, rawFilename, directoryOffset);
1321
+ directoryOffset += getLength(rawFilename);
1322
+ arraySet(directoryArray, rawExtraFieldZip64, directoryOffset);
1323
+ directoryOffset += getLength(rawExtraFieldZip64);
1324
+ arraySet(directoryArray, rawExtraFieldAES, directoryOffset);
1325
+ directoryOffset += getLength(rawExtraFieldAES);
1326
+ arraySet(directoryArray, rawExtraFieldExtendedTimestamp, directoryOffset);
1327
+ directoryOffset += getLength(rawExtraFieldExtendedTimestamp);
1328
+ arraySet(directoryArray, rawExtraFieldNTFS, directoryOffset);
1329
+ directoryOffset += getLength(rawExtraFieldNTFS);
1330
+ arraySet(directoryArray, rawExtraField, directoryOffset);
1331
+ directoryOffset += getLength(rawExtraField);
1332
+ arraySet(directoryArray, rawComment, directoryOffset);
1136
1333
  if (offset - directoryDiskOffset > writer.availableSize) {
1137
1334
  writer.availableSize = 0;
1138
- await writeData(writable, directoryArray.slice(directoryDiskOffset, offset));
1335
+ await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
1139
1336
  directoryDiskOffset = offset;
1140
1337
  }
1141
- offset += directoryEntryLength;
1338
+ offset = directoryOffset;
1142
1339
  if (options.onprogress) {
1143
1340
  try {
1144
1341
  await options.onprogress(indexFileEntry + 1, files.size, new Entry(fileEntry));
@@ -1148,7 +1345,7 @@ async function closeFile(zipWriter, comment, options) {
1148
1345
  }
1149
1346
  }
1150
1347
  }
1151
- await writeData(writable, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
1348
+ await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
1152
1349
  let lastDiskNumber = writer.diskNumber;
1153
1350
  const { availableSize } = writer;
1154
1351
  if (availableSize < END_OF_CENTRAL_DIR_LENGTH) {
@@ -1204,17 +1401,18 @@ async function closeFile(zipWriter, comment, options) {
1204
1401
  throw new Error(ERR_INVALID_COMMENT);
1205
1402
  }
1206
1403
  }
1207
- await writeData(writable, endOfdirectoryArray);
1404
+ await writeData(writer, endOfdirectoryArray);
1208
1405
  if (commentLength) {
1209
- await writeData(writable, comment);
1406
+ await writeData(writer, comment);
1210
1407
  }
1211
1408
  }
1212
1409
 
1213
- async function writeData(writable, array) {
1410
+ async function writeData(writer, array) {
1411
+ const { writable } = writer;
1214
1412
  const streamWriter = writable.getWriter();
1215
1413
  try {
1216
1414
  await streamWriter.ready;
1217
- writable.size += getLength(array);
1415
+ writer.size += getLength(array);
1218
1416
  await streamWriter.write(array);
1219
1417
  } finally {
1220
1418
  streamWriter.releaseLock();
@@ -1265,3 +1463,65 @@ function getLength(...arrayLikes) {
1265
1463
  arrayLikes.forEach(arrayLike => arrayLike && (result += arrayLike.length));
1266
1464
  return result;
1267
1465
  }
1466
+
1467
+ function getHeaderArrayData({
1468
+ version,
1469
+ bitflag,
1470
+ compressionMethod,
1471
+ uncompressedSize,
1472
+ compressedSize,
1473
+ lastModDate,
1474
+ rawFilename,
1475
+ zip64CompressedSize,
1476
+ zip64UncompressedSize,
1477
+ extraFieldLength
1478
+ }) {
1479
+ const headerArray = new Uint8Array(HEADER_SIZE);
1480
+ const headerView = getDataView(headerArray);
1481
+ setUint16(headerView, 0, version);
1482
+ setUint16(headerView, 2, bitflag);
1483
+ setUint16(headerView, 4, compressionMethod);
1484
+ const dateArray = new Uint32Array(1);
1485
+ const dateView = getDataView(dateArray);
1486
+ setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
1487
+ setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
1488
+ const rawLastModDate = dateArray[0];
1489
+ setUint32(headerView, 6, rawLastModDate);
1490
+ if (zip64CompressedSize || compressedSize !== UNDEFINED_VALUE) {
1491
+ setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, zip64CompressedSize ? MAX_32_BITS : compressedSize);
1492
+ }
1493
+ if (zip64UncompressedSize || uncompressedSize !== UNDEFINED_VALUE) {
1494
+ setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
1495
+ }
1496
+ setUint16(headerView, 22, getLength(rawFilename));
1497
+ setUint16(headerView, 24, extraFieldLength);
1498
+ return {
1499
+ headerArray,
1500
+ headerView,
1501
+ rawLastModDate
1502
+ };
1503
+ }
1504
+
1505
+
1506
+ function getBitflag(level, useUnicodeFileNames, dataDescriptor, encrypted) {
1507
+ let bitFlag = 0;
1508
+ if (useUnicodeFileNames) {
1509
+ bitFlag = bitFlag | BITFLAG_LANG_ENCODING_FLAG;
1510
+ }
1511
+ if (dataDescriptor) {
1512
+ bitFlag = bitFlag | BITFLAG_DATA_DESCRIPTOR;
1513
+ }
1514
+ if (level >= 0 && level < 2) {
1515
+ bitFlag = bitFlag | BITFLAG_LEVEL_SUPER_FAST_MASK;
1516
+ }
1517
+ if (level >= 3 && level < 6) {
1518
+ bitFlag = bitFlag | BITFLAG_LEVEL_FAST_MASK;
1519
+ }
1520
+ if (level == 9) {
1521
+ bitFlag = bitFlag | BITFLAG_LEVEL_MAX_MASK;
1522
+ }
1523
+ if (encrypted) {
1524
+ bitFlag = bitFlag | BITFLAG_ENCRYPTED;
1525
+ }
1526
+ return bitFlag;
1527
+ }