@zip.js/zip.js 2.7.63 → 2.7.64

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 {
@@ -63,6 +63,7 @@ import {
63
63
  VERSION_ZIP64,
64
64
  VERSION_AES,
65
65
  DIRECTORY_SIGNATURE,
66
+ HEADER_SIZE,
66
67
  MIN_DATE,
67
68
  MAX_DATE,
68
69
  UNDEFINED_VALUE
@@ -99,6 +100,9 @@ import {
99
100
  PROPERTY_NAME_EXECUTABLE,
100
101
  Entry
101
102
  } from "./zip-entry.js";
103
+ import {
104
+ ZipReader
105
+ } from "./zip-reader.js";
102
106
 
103
107
  const ERR_DUPLICATED_NAME = "File already exists";
104
108
  const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB";
@@ -110,6 +114,7 @@ const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
110
114
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
111
115
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (make sure 'keepOrder' is set to 'true')";
112
116
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
117
+ const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
113
118
 
114
119
  const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]);
115
120
 
@@ -137,6 +142,99 @@ class ZipWriter {
137
142
  });
138
143
  }
139
144
 
145
+ async prependZip(reader) {
146
+ if (this.filenames.size) {
147
+ throw new Error(ERR_ZIP_NOT_EMPTY);
148
+ }
149
+ ({ reader } = initReader(reader));
150
+ const [zipEntriesReader, zipDataReader] = reader.readable.tee();
151
+ const zipReader = new ZipReader(new ReadableStream({
152
+ async start(controller) {
153
+ const reader = zipEntriesReader.getReader();
154
+ await readChunk();
155
+
156
+ async function readChunk() {
157
+ const { done, value } = await reader.read();
158
+ if (done) {
159
+ controller.close();
160
+ } else {
161
+ controller.enqueue(value);
162
+ await readChunk();
163
+ }
164
+ }
165
+ }
166
+ }));
167
+ const entries = await zipReader.getEntries();
168
+ await zipReader.close();
169
+ await zipDataReader.pipeTo(this.writer.writable, { preventClose: true, preventAbort: true });
170
+ this.writer.writable.size = this.offset = reader.size;
171
+ this.filenames = new Set(entries.map(entry => entry.filename));
172
+ this.files = new Map(entries.map(entry => {
173
+ const {
174
+ version,
175
+ compressionMethod,
176
+ lastModDate,
177
+ lastAccessDate,
178
+ creationDate,
179
+ rawFilename,
180
+ bitFlag,
181
+ encrypted,
182
+ uncompressedSize,
183
+ compressedSize,
184
+ diskOffset,
185
+ diskNumber,
186
+ zip64
187
+ } = entry;
188
+ let {
189
+ rawExtraFieldZip64,
190
+ rawExtraFieldAES,
191
+ rawExtraFieldExtendedTimestamp,
192
+ rawExtraFieldNTFS,
193
+ rawExtraField,
194
+ } = entry;
195
+ const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
196
+ rawExtraFieldZip64 = rawExtraFieldZip64 || new Uint8Array();
197
+ rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
198
+ rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
199
+ rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
200
+ rawExtraField = rawExtraField || new Uint8Array();
201
+ const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
202
+ const zip64UncompressedSize = zip64 && uncompressedSize > MAX_32_BITS;
203
+ const zip64CompressedSize = zip64 && compressedSize > MAX_32_BITS;
204
+ const {
205
+ headerArray,
206
+ headerView
207
+ } = getHeaderArrayData({
208
+ version,
209
+ bitflag: getBitflag(level, languageEncodingFlag, dataDescriptor, encrypted),
210
+ compressionMethod,
211
+ uncompressedSize,
212
+ compressedSize,
213
+ lastModDate,
214
+ rawFilename,
215
+ zip64CompressedSize,
216
+ zip64UncompressedSize,
217
+ extraFieldLength
218
+ });
219
+ Object.assign(entry, {
220
+ zip64UncompressedSize,
221
+ zip64CompressedSize,
222
+ zip64Offset: zip64 && this.offset - diskOffset > MAX_32_BITS,
223
+ zip64DiskNumberStart: zip64 && diskNumber > MAX_16_BITS,
224
+ rawExtraFieldZip64,
225
+ rawExtraFieldAES,
226
+ rawExtraFieldExtendedTimestamp,
227
+ rawExtraFieldNTFS,
228
+ rawExtraField,
229
+ extendedTimestamp: rawExtraFieldExtendedTimestamp.length > 0 || rawExtraFieldNTFS.length > 0,
230
+ extraFieldExtendedTimestampFlag: 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0),
231
+ headerArray,
232
+ headerView
233
+ });
234
+ return [entry.filename, entry];
235
+ }));
236
+ }
237
+
140
238
  async add(name = "", reader, options = {}) {
141
239
  const zipWriter = this;
142
240
  const {
@@ -172,6 +270,22 @@ class ZipWriter {
172
270
  }
173
271
  }
174
272
 
273
+ remove(entry) {
274
+ const { filenames, files } = this;
275
+ if (typeof entry == "string") {
276
+ entry = files.get(entry);
277
+ }
278
+ if (entry && entry.filename !== UNDEFINED_VALUE) {
279
+ const { filename } = entry;
280
+ if (filenames.has(filename) && files.has(filename)) {
281
+ filenames.delete(filename);
282
+ files.delete(filename);
283
+ return true;
284
+ }
285
+ }
286
+ return false;
287
+ }
288
+
175
289
  async close(comment = new Uint8Array(), options = {}) {
176
290
  const zipWriter = this;
177
291
  const { pendingAddFileCalls, writer } = this;
@@ -227,7 +341,8 @@ export {
227
341
  ERR_INVALID_EXTRAFIELD_DATA,
228
342
  ERR_INVALID_ENCRYPTION_STRENGTH,
229
343
  ERR_UNSUPPORTED_FORMAT,
230
- ERR_UNDEFINED_UNCOMPRESSED_SIZE
344
+ ERR_UNDEFINED_UNCOMPRESSED_SIZE,
345
+ ERR_ZIP_NOT_EMPTY
231
346
  };
232
347
 
233
348
  async function addFile(zipWriter, name, reader, options) {
@@ -308,7 +423,13 @@ async function addFile(zipWriter, name, reader, options) {
308
423
  const useUnicodeFileNames = getOptionValue(zipWriter, options, "useUnicodeFileNames", true);
309
424
  const useCompressionStream = getOptionValue(zipWriter, options, "useCompressionStream");
310
425
  const compressionMethod = getOptionValue(zipWriter, options, "compressionMethod");
311
- let dataDescriptor = getOptionValue(zipWriter, options, "dataDescriptor", true);
426
+ let dataDescriptor = getOptionValue(zipWriter, options, "dataDescriptor");
427
+ if (bufferedWrite && dataDescriptor === UNDEFINED_VALUE) {
428
+ dataDescriptor = false;
429
+ }
430
+ if (dataDescriptor === UNDEFINED_VALUE || zipCrypto) {
431
+ dataDescriptor = true;
432
+ }
312
433
  let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
313
434
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
314
435
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
@@ -354,10 +475,11 @@ async function addFile(zipWriter, name, reader, options) {
354
475
  uncompressedSize = maximumCompressedSize = MAX_32_BITS + 1;
355
476
  }
356
477
  } else {
357
- uncompressedSize = reader.size;
478
+ options.uncompressedSize = uncompressedSize = reader.size;
358
479
  maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
359
480
  }
360
481
  } else {
482
+ options.uncompressedSize = uncompressedSize;
361
483
  maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
362
484
  }
363
485
  }
@@ -413,7 +535,10 @@ async function addFile(zipWriter, name, reader, options) {
413
535
  passThrough,
414
536
  encrypted: Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted),
415
537
  signature,
416
- compressionMethod
538
+ compressionMethod,
539
+ uncompressedSize,
540
+ offset: zipWriter.offset - diskOffset,
541
+ diskNumberStart: diskNumber,
417
542
  });
418
543
  const headerInfo = getHeaderInfo(options);
419
544
  const dataDescriptorInfo = getDataDescriptorInfo(options);
@@ -505,20 +630,26 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
505
630
  await lockPreviousFileEntry;
506
631
  await requestLockWriter();
507
632
  writingBufferedEntryData = true;
508
- if (!dataDescriptor) {
509
- blob = await writeExtraHeaderInfo(fileEntry, blob, writable, options);
510
- }
511
- await skipDiskIfNeeded(writable);
512
633
  fileEntry.diskNumberStart = writer.diskNumber;
513
634
  diskOffset = writer.diskOffset;
635
+ fileEntry.offset = zipWriter.offset - diskOffset;
636
+ if (fileEntry.zip64) {
637
+ setExtraFieldZip64Data(fileEntry);
638
+ }
639
+ if (fileEntry.zip64 || !dataDescriptor) {
640
+ blob = await patchLocalHeader(fileEntry, blob, writable, options);
641
+ }
642
+ await skipDiskIfNeeded(writable);
514
643
  await blob.stream().pipeTo(writable, { preventClose: true, preventAbort: true, signal });
515
644
  writable.size += blob.size;
516
645
  writingBufferedEntryData = false;
646
+ } else {
647
+ fileEntry.offset = zipWriter.offset - diskOffset;
648
+ if (fileEntry.zip64) {
649
+ setExtraFieldZip64Data(fileEntry);
650
+ }
517
651
  }
518
- fileEntry.offset = zipWriter.offset - diskOffset;
519
- if (fileEntry.zip64) {
520
- setZip64ExtraInfo(fileEntry, options);
521
- } else if (fileEntry.offset > MAX_32_BITS) {
652
+ if (fileEntry.offset > MAX_32_BITS && !fileEntry.zip64) {
522
653
  throw new Error(ERR_UNSUPPORTED_FORMAT);
523
654
  }
524
655
  zipWriter.offset += fileEntry.size;
@@ -585,12 +716,15 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
585
716
  const {
586
717
  localHeaderArray,
587
718
  headerArray,
719
+ headerView,
588
720
  lastModDate,
589
721
  rawLastModDate,
590
722
  encrypted,
591
723
  compressed,
592
724
  version,
593
725
  compressionMethod,
726
+ rawExtraFieldZip64,
727
+ localExtraFieldZip64Length,
594
728
  rawExtraFieldExtendedTimestamp,
595
729
  extraFieldExtendedTimestampFlag,
596
730
  rawExtraFieldNTFS,
@@ -639,6 +773,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
639
773
  rawFilename,
640
774
  commentUTF8: true,
641
775
  rawComment,
776
+ rawExtraFieldZip64,
777
+ localExtraFieldZip64Length,
642
778
  rawExtraFieldExtendedTimestamp,
643
779
  rawExtraFieldNTFS,
644
780
  rawExtraFieldAES,
@@ -692,28 +828,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
692
828
  } else {
693
829
  await writeData(writable, localHeaderArray);
694
830
  }
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;
709
- }
710
- rawExtraFieldZip64 = new Uint8Array(rawExtraFieldZip64Length);
711
- } else {
712
- rawExtraFieldZip64 = new Uint8Array();
713
- }
714
831
  setEntryInfo({
715
832
  signature,
716
- rawExtraFieldZip64,
717
833
  compressedSize,
718
834
  uncompressedSize,
719
835
  headerInfo,
@@ -735,8 +851,8 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
735
851
  compressionMethod,
736
852
  version,
737
853
  headerArray,
854
+ headerView,
738
855
  signature,
739
- rawExtraFieldZip64,
740
856
  extraFieldExtendedTimestampFlag,
741
857
  zip64UncompressedSize,
742
858
  zip64CompressedSize,
@@ -761,10 +877,62 @@ function getHeaderInfo(options) {
761
877
  rawExtraField,
762
878
  encryptionStrength,
763
879
  extendedTimestamp,
764
- encrypted
880
+ passThrough,
881
+ encrypted,
882
+ zip64UncompressedSize,
883
+ zip64CompressedSize,
884
+ zip64Offset,
885
+ zip64DiskNumberStart,
886
+ uncompressedSize,
887
+ offset,
888
+ diskNumberStart
765
889
  } = options;
766
890
  let { version, compressionMethod } = options;
767
891
  const compressed = !directory && (level > 0 || (level === UNDEFINED_VALUE && compressionMethod !== 0));
892
+ let rawExtraFieldZip64;
893
+ const uncompressedFile = passThrough || !compressed;
894
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
895
+ if (zip64) {
896
+ let rawExtraFieldZip64Length = 4;
897
+ if (zip64UncompressedSize) {
898
+ rawExtraFieldZip64Length += 8;
899
+ }
900
+ if (zip64CompressedSize) {
901
+ rawExtraFieldZip64Length += 8;
902
+ }
903
+ if (zip64Offset) {
904
+ rawExtraFieldZip64Length += 8;
905
+ }
906
+ if (zip64DiskNumberStart) {
907
+ rawExtraFieldZip64Length += 4;
908
+ }
909
+ rawExtraFieldZip64 = new Uint8Array(rawExtraFieldZip64Length);
910
+ const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
911
+ setUint16(rawExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
912
+ setUint16(rawExtraFieldZip64View, 2, getLength(rawExtraFieldZip64) - 4);
913
+ if (zip64ExtraFieldComplete) {
914
+ const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
915
+ let rawExtraFieldZip64Offset = 4;
916
+ if (zip64UncompressedSize) {
917
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
918
+ rawExtraFieldZip64Offset += 8;
919
+ }
920
+ if (zip64CompressedSize && uncompressedFile) {
921
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
922
+ rawExtraFieldZip64Offset += 8;
923
+ }
924
+ if (zip64Offset) {
925
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(offset));
926
+ rawExtraFieldZip64Offset += 8;
927
+ }
928
+ if (zip64DiskNumberStart) {
929
+ setUint32(rawExtraFieldZip64View, rawExtraFieldZip64Offset, diskNumberStart);
930
+ rawExtraFieldZip64Offset += 4;
931
+ }
932
+ }
933
+ } else {
934
+ rawExtraFieldZip64 = new Uint8Array();
935
+ }
768
936
  let rawExtraFieldAES;
769
937
  if (encrypted && !zipCrypto) {
770
938
  rawExtraFieldAES = new Uint8Array(getLength(EXTRAFIELD_DATA_AES) + 2);
@@ -813,69 +981,52 @@ function getHeaderInfo(options) {
813
981
  } else {
814
982
  rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = new Uint8Array();
815
983
  }
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
984
  if (compressionMethod === UNDEFINED_VALUE) {
824
985
  compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
825
986
  }
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
987
  if (zip64) {
838
988
  version = version > VERSION_ZIP64 ? version : VERSION_ZIP64;
839
989
  }
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;
990
+ if (encrypted && !zipCrypto) {
991
+ version = version > VERSION_AES ? version : VERSION_AES;
992
+ rawExtraFieldAES[9] = compressionMethod;
993
+ compressionMethod = COMPRESSION_METHOD_AES;
862
994
  }
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);
995
+ const localExtraFieldZip64Length = zip64ExtraFieldComplete ? getLength(rawExtraFieldZip64) : 0;
996
+ const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
997
+ const {
998
+ headerArray,
999
+ headerView,
1000
+ rawLastModDate
1001
+ } = getHeaderArrayData({
1002
+ version,
1003
+ bitflag: getBitflag(level, useUnicodeFileNames, dataDescriptor, encrypted),
1004
+ compressionMethod,
1005
+ uncompressedSize,
1006
+ lastModDate: lastModDate < MIN_DATE ? MIN_DATE : lastModDate > MAX_DATE ? MAX_DATE : lastModDate,
1007
+ rawFilename,
1008
+ zip64CompressedSize,
1009
+ zip64UncompressedSize,
1010
+ extraFieldLength
1011
+ });
1012
+ let localHeaderOffset = HEADER_SIZE + 4;
1013
+ const localHeaderArray = new Uint8Array(localHeaderOffset + getLength(rawFilename) + extraFieldLength);
871
1014
  const localHeaderView = getDataView(localHeaderArray);
872
1015
  setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE);
873
1016
  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));
1017
+ arraySet(localHeaderArray, rawFilename, localHeaderOffset);
1018
+ localHeaderOffset += getLength(rawFilename);
1019
+ if (zip64ExtraFieldComplete) {
1020
+ arraySet(localHeaderArray, rawExtraFieldZip64, localHeaderOffset);
1021
+ }
1022
+ localHeaderOffset += localExtraFieldZip64Length;
1023
+ arraySet(localHeaderArray, rawExtraFieldAES, localHeaderOffset);
1024
+ localHeaderOffset += getLength(rawExtraFieldAES);
1025
+ arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, localHeaderOffset);
1026
+ localHeaderOffset += getLength(rawExtraFieldExtendedTimestamp);
1027
+ arraySet(localHeaderArray, rawExtraFieldNTFS, localHeaderOffset);
1028
+ localHeaderOffset += getLength(rawExtraFieldNTFS);
1029
+ arraySet(localHeaderArray, rawExtraField, localHeaderOffset);
879
1030
  return {
880
1031
  localHeaderArray,
881
1032
  headerArray,
@@ -887,6 +1038,8 @@ function getHeaderInfo(options) {
887
1038
  version,
888
1039
  compressionMethod,
889
1040
  extraFieldExtendedTimestampFlag,
1041
+ rawExtraFieldZip64,
1042
+ localExtraFieldZip64Length,
890
1043
  rawExtraFieldExtendedTimestamp,
891
1044
  rawExtraFieldNTFS,
892
1045
  rawExtraFieldAES,
@@ -941,7 +1094,6 @@ function getDataDescriptorInfo(options) {
941
1094
  function setEntryInfo(entryInfo, options) {
942
1095
  const {
943
1096
  signature,
944
- rawExtraFieldZip64,
945
1097
  compressedSize,
946
1098
  uncompressedSize,
947
1099
  headerInfo,
@@ -957,8 +1109,6 @@ function setEntryInfo(entryInfo, options) {
957
1109
  } = dataDescriptorInfo;
958
1110
  const {
959
1111
  zip64,
960
- zip64UncompressedSize,
961
- zip64CompressedSize,
962
1112
  zipCrypto,
963
1113
  dataDescriptor
964
1114
  } = options;
@@ -969,19 +1119,6 @@ function setEntryInfo(entryInfo, options) {
969
1119
  }
970
1120
  }
971
1121
  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
1122
  if (dataDescriptor) {
986
1123
  setBigUint64(dataDescriptorView, dataDescriptorOffset + 4, BigInt(compressedSize));
987
1124
  setBigUint64(dataDescriptorView, dataDescriptorOffset + 12, BigInt(uncompressedSize));
@@ -996,44 +1133,82 @@ function setEntryInfo(entryInfo, options) {
996
1133
  }
997
1134
  }
998
1135
 
999
- async function writeExtraHeaderInfo(fileEntry, entryData, writable, { zipCrypto }) {
1136
+ async function patchLocalHeader(fileEntry, entryData, writable, { zipCrypto, dataDescriptor }) {
1137
+ const {
1138
+ zip64,
1139
+ rawFilename,
1140
+ localExtraFieldZip64Length,
1141
+ signature,
1142
+ encrypted,
1143
+ zip64UncompressedSize,
1144
+ zip64CompressedSize,
1145
+ zip64Offset,
1146
+ zip64DiskNumberStart,
1147
+ uncompressedSize,
1148
+ compressedSize,
1149
+ offset,
1150
+ diskNumberStart
1151
+ } = fileEntry;
1000
1152
  let arrayBuffer;
1001
- arrayBuffer = await entryData.slice(0, 26).arrayBuffer();
1002
- if (arrayBuffer.byteLength != 26) {
1003
- arrayBuffer = arrayBuffer.slice(0, 26);
1153
+ let rawExtraFieldZip64Offset = HEADER_SIZE + 4 + getLength(rawFilename);
1154
+ const arrayBufferSize = zip64 && localExtraFieldZip64Length ? rawExtraFieldZip64Offset + localExtraFieldZip64Length : HEADER_SIZE;
1155
+ arrayBuffer = await entryData.slice(0, arrayBufferSize).arrayBuffer();
1156
+ if (arrayBuffer.byteLength != arrayBufferSize) {
1157
+ arrayBuffer = arrayBuffer.slice(0, arrayBufferSize);
1004
1158
  }
1005
1159
  const arrayBufferView = new DataView(arrayBuffer);
1006
- if (!fileEntry.encrypted || zipCrypto) {
1007
- setUint32(arrayBufferView, 14, fileEntry.signature);
1160
+ if (!dataDescriptor) {
1161
+ if (!encrypted || zipCrypto) {
1162
+ setUint32(arrayBufferView, 14, signature);
1163
+ }
1164
+ if (!zip64) {
1165
+ setUint32(arrayBufferView, 18, compressedSize);
1166
+ setUint32(arrayBufferView, 22, uncompressedSize);
1167
+ }
1008
1168
  }
1009
- if (fileEntry.zip64) {
1169
+ if (zip64) {
1010
1170
  setUint32(arrayBufferView, 18, MAX_32_BITS);
1011
1171
  setUint32(arrayBufferView, 22, MAX_32_BITS);
1012
- } else {
1013
- setUint32(arrayBufferView, 18, fileEntry.compressedSize);
1014
- setUint32(arrayBufferView, 22, fileEntry.uncompressedSize);
1172
+ if (localExtraFieldZip64Length) {
1173
+ rawExtraFieldZip64Offset += 4;
1174
+ if (zip64UncompressedSize) {
1175
+ setBigUint64(arrayBufferView, rawExtraFieldZip64Offset, BigInt(uncompressedSize));
1176
+ rawExtraFieldZip64Offset += 8;
1177
+ }
1178
+ if (zip64CompressedSize) {
1179
+ setBigUint64(arrayBufferView, rawExtraFieldZip64Offset, BigInt(compressedSize));
1180
+ rawExtraFieldZip64Offset += 8;
1181
+ }
1182
+ if (zip64Offset) {
1183
+ setBigUint64(arrayBufferView, rawExtraFieldZip64Offset, BigInt(offset));
1184
+ rawExtraFieldZip64Offset += 8;
1185
+ }
1186
+ if (zip64DiskNumberStart) {
1187
+ setUint32(arrayBufferView, rawExtraFieldZip64Offset, diskNumberStart);
1188
+ }
1189
+ }
1015
1190
  }
1016
1191
  await writeData(writable, new Uint8Array(arrayBuffer));
1017
1192
  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;
1023
- const rawExtraFieldZip64View = getDataView(rawExtraFieldZip64);
1195
+ function setExtraFieldZip64Data(fileEntry) {
1196
+ const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64);
1024
1197
  let rawExtraFieldZip64Offset = 4;
1025
- if (zip64UncompressedSize) {
1198
+ if (fileEntry.zip64UncompressedSize) {
1199
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(fileEntry.uncompressedSize));
1026
1200
  rawExtraFieldZip64Offset += 8;
1027
1201
  }
1028
- if (zip64CompressedSize) {
1202
+ if (fileEntry.zip64CompressedSize) {
1203
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(fileEntry.compressedSize));
1029
1204
  rawExtraFieldZip64Offset += 8;
1030
1205
  }
1031
- if (zip64Offset) {
1032
- setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(offset));
1206
+ if (fileEntry.zip64Offset) {
1207
+ setBigUint64(rawExtraFieldZip64View, rawExtraFieldZip64Offset, BigInt(fileEntry.offset));
1033
1208
  rawExtraFieldZip64Offset += 8;
1034
1209
  }
1035
- if (zip64DiskNumberStart) {
1036
- setUint32(rawExtraFieldZip64View, rawExtraFieldZip64Offset, diskNumberStart);
1210
+ if (fileEntry.zip64DiskNumberStart) {
1211
+ setUint32(rawExtraFieldZip64View, rawExtraFieldZip64Offset, fileEntry.diskNumberStart);
1037
1212
  }
1038
1213
  }
1039
1214
 
@@ -1068,7 +1243,7 @@ async function closeFile(zipWriter, comment, options) {
1068
1243
  } else {
1069
1244
  rawExtraFieldTimestamp = new Uint8Array();
1070
1245
  }
1071
- fileEntry.rawExtraFieldCDExtendedTimestamp = rawExtraFieldTimestamp;
1246
+ fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
1072
1247
  directoryDataLength += 46 +
1073
1248
  getLength(
1074
1249
  rawFilename,
@@ -1089,12 +1264,13 @@ async function closeFile(zipWriter, comment, options) {
1089
1264
  rawFilename,
1090
1265
  rawExtraFieldZip64,
1091
1266
  rawExtraFieldAES,
1092
- rawExtraFieldCDExtendedTimestamp,
1267
+ rawExtraFieldExtendedTimestamp,
1093
1268
  rawExtraFieldNTFS,
1094
1269
  rawExtraField,
1095
1270
  rawComment,
1096
1271
  versionMadeBy,
1097
1272
  headerArray,
1273
+ headerView,
1098
1274
  zip64,
1099
1275
  zip64UncompressedSize,
1100
1276
  zip64CompressedSize,
@@ -1106,10 +1282,9 @@ async function closeFile(zipWriter, comment, options) {
1106
1282
  uncompressedSize,
1107
1283
  compressedSize
1108
1284
  } = fileEntry;
1109
- const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldCDExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
1285
+ const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraField);
1110
1286
  setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE);
1111
1287
  setUint16(directoryView, offset + 4, versionMadeBy);
1112
- const headerView = getDataView(headerArray);
1113
1288
  if (!zip64UncompressedSize) {
1114
1289
  setUint32(headerView, 18, uncompressedSize);
1115
1290
  }
@@ -1117,28 +1292,40 @@ async function closeFile(zipWriter, comment, options) {
1117
1292
  setUint32(headerView, 14, compressedSize);
1118
1293
  }
1119
1294
  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);
1295
+ let directoryOffset = offset + HEADER_SIZE + 4;
1296
+ setUint16(directoryView, directoryOffset, extraFieldLength);
1297
+ directoryOffset += 2;
1298
+ setUint16(directoryView, directoryOffset, getLength(rawComment));
1299
+ directoryOffset += 2;
1300
+ setUint16(directoryView, directoryOffset, zip64 && zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
1301
+ directoryOffset += 2;
1302
+ setUint16(directoryView, directoryOffset, internalFileAttributes);
1303
+ directoryOffset += 2;
1124
1304
  if (externalFileAttributes) {
1125
- setUint32(directoryView, offset + 38, externalFileAttributes);
1305
+ setUint32(directoryView, directoryOffset, externalFileAttributes);
1126
1306
  }
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;
1307
+ directoryOffset += 4;
1308
+ setUint32(directoryView, directoryOffset, zip64 && zip64Offset ? MAX_32_BITS : fileEntryOffset);
1309
+ directoryOffset += 4;
1310
+ arraySet(directoryArray, rawFilename, directoryOffset);
1311
+ directoryOffset += getLength(rawFilename);
1312
+ arraySet(directoryArray, rawExtraFieldZip64, directoryOffset);
1313
+ directoryOffset += getLength(rawExtraFieldZip64);
1314
+ arraySet(directoryArray, rawExtraFieldAES, directoryOffset);
1315
+ directoryOffset += getLength(rawExtraFieldAES);
1316
+ arraySet(directoryArray, rawExtraFieldExtendedTimestamp, directoryOffset);
1317
+ directoryOffset += getLength(rawExtraFieldExtendedTimestamp);
1318
+ arraySet(directoryArray, rawExtraFieldNTFS, directoryOffset);
1319
+ directoryOffset += getLength(rawExtraFieldNTFS);
1320
+ arraySet(directoryArray, rawExtraField, directoryOffset);
1321
+ directoryOffset += getLength(rawExtraField);
1322
+ arraySet(directoryArray, rawComment, directoryOffset);
1136
1323
  if (offset - directoryDiskOffset > writer.availableSize) {
1137
1324
  writer.availableSize = 0;
1138
1325
  await writeData(writable, directoryArray.slice(directoryDiskOffset, offset));
1139
1326
  directoryDiskOffset = offset;
1140
1327
  }
1141
- offset += directoryEntryLength;
1328
+ offset = directoryOffset;
1142
1329
  if (options.onprogress) {
1143
1330
  try {
1144
1331
  await options.onprogress(indexFileEntry + 1, files.size, new Entry(fileEntry));
@@ -1265,3 +1452,64 @@ function getLength(...arrayLikes) {
1265
1452
  arrayLikes.forEach(arrayLike => arrayLike && (result += arrayLike.length));
1266
1453
  return result;
1267
1454
  }
1455
+
1456
+ function getHeaderArrayData({
1457
+ version,
1458
+ bitflag,
1459
+ compressionMethod,
1460
+ uncompressedSize,
1461
+ compressedSize,
1462
+ lastModDate,
1463
+ rawFilename,
1464
+ zip64CompressedSize,
1465
+ zip64UncompressedSize,
1466
+ extraFieldLength
1467
+ }) {
1468
+ const headerArray = new Uint8Array(HEADER_SIZE);
1469
+ const headerView = getDataView(headerArray);
1470
+ setUint16(headerView, 0, version);
1471
+ setUint16(headerView, 2, bitflag);
1472
+ setUint16(headerView, 4, compressionMethod);
1473
+ const dateArray = new Uint32Array(1);
1474
+ const dateView = getDataView(dateArray);
1475
+ setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
1476
+ setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
1477
+ const rawLastModDate = dateArray[0];
1478
+ setUint32(headerView, 6, rawLastModDate);
1479
+ if (zip64CompressedSize || compressedSize !== UNDEFINED_VALUE) {
1480
+ setUint32(headerView, 14, zip64CompressedSize ? MAX_32_BITS : compressedSize);
1481
+ }
1482
+ if (zip64UncompressedSize || uncompressedSize !== UNDEFINED_VALUE) {
1483
+ setUint32(headerView, 18, zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
1484
+ }
1485
+ setUint16(headerView, 22, getLength(rawFilename));
1486
+ setUint16(headerView, 24, extraFieldLength);
1487
+ return {
1488
+ headerArray,
1489
+ headerView,
1490
+ rawLastModDate
1491
+ };
1492
+ }
1493
+
1494
+ function getBitflag(level, useUnicodeFileNames, dataDescriptor, encrypted) {
1495
+ let bitFlag = 0;
1496
+ if (useUnicodeFileNames) {
1497
+ bitFlag = bitFlag | BITFLAG_LANG_ENCODING_FLAG;
1498
+ }
1499
+ if (dataDescriptor) {
1500
+ bitFlag = bitFlag | BITFLAG_DATA_DESCRIPTOR;
1501
+ }
1502
+ if (level >= 1 && level < 3) {
1503
+ bitFlag = bitFlag | 0b110;
1504
+ }
1505
+ if (level >= 3 && level < 5) {
1506
+ bitFlag = bitFlag | 0b01;
1507
+ }
1508
+ if (level === 9) {
1509
+ bitFlag = bitFlag | 0b10;
1510
+ }
1511
+ if (encrypted) {
1512
+ bitFlag = bitFlag | BITFLAG_ENCRYPTED;
1513
+ }
1514
+ return bitFlag;
1515
+ }