@zip.js/zip.js 2.6.28 → 2.6.30

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 (42) 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 +229 -109
  5. package/dist/zip-fs-full.min.js +1 -1
  6. package/dist/zip-fs.js +230 -109
  7. package/dist/zip-fs.min.js +1 -1
  8. package/dist/zip-full.js +230 -109
  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 +1 -4507
  14. package/dist/zip.min.js +1 -1
  15. package/index-fflate.js +3 -1
  16. package/index.cjs +10459 -0
  17. package/index.d.ts +8 -2
  18. package/index.js +3 -1
  19. package/lib/core/codec-pool-worker.js +14 -3
  20. package/lib/core/io.js +54 -2
  21. package/lib/core/streams/codec-stream.js +1 -4
  22. package/lib/core/streams/zip-crypto-stream.js +0 -2
  23. package/lib/core/zip-reader.js +119 -67
  24. package/lib/core/zip-writer.js +45 -32
  25. package/lib/z-worker-inline.js +1 -1
  26. package/package.json +1 -1
  27. package/rollup-fflate.config.dev.js +5 -2
  28. package/rollup-fflate.config.js +5 -2
  29. package/rollup.config.dev.js +5 -2
  30. package/rollup.config.js +8 -5
  31. package/tests/all/test-common-js.cjs +31 -0
  32. package/tests/all/test-split-zip.js +37 -0
  33. package/tests/data/lorem-split.z01 +0 -0
  34. package/tests/data/lorem-split.z02 +0 -0
  35. package/tests/data/lorem-split.z03 +0 -0
  36. package/tests/data/lorem-split.z04 +0 -0
  37. package/tests/data/lorem-split.z05 +0 -0
  38. package/tests/data/lorem-split.z06 +0 -0
  39. package/tests/data/lorem-split.z07 +0 -0
  40. package/tests/data/lorem-split.zip +0 -0
  41. package/tests/tests-data.js +2 -0
  42. package/tests/web-runner.js +4 -1
package/index.d.ts CHANGED
@@ -366,6 +366,11 @@ export class Data64URIReader extends Reader<string> { }
366
366
  */
367
367
  export class Uint8ArrayReader extends Reader<Uint8Array> { }
368
368
 
369
+ /**
370
+ * Represents a `Reader` instance used to read data provided as an array of `Reader` instances (i.e. split zip files).
371
+ */
372
+ export class SplitZipReader extends Reader<Reader<any>[] | ReadableReader[] | ReadableStream[]> { }
373
+
369
374
  /**
370
375
  * Represents a URL stored into a `string`.
371
376
  */
@@ -579,7 +584,7 @@ export class ZipReader<Type> {
579
584
  * @param reader The `Reader` instance used to read data.
580
585
  * @param options The options.
581
586
  */
582
- constructor(reader: Reader<Type> | ReadableReader | ReadableStream, options?: ZipReaderConstructorOptions)
587
+ constructor(reader: Reader<Type> | ReadableReader | ReadableStream | Reader<any>[] | ReadableReader[] | ReadableStream[], options?: ZipReaderConstructorOptions)
583
588
  /**
584
589
  * The global comment of the zip file.
585
590
  */
@@ -1440,4 +1445,5 @@ export const ERR_INVALID_VERSION: string
1440
1445
  export const ERR_INVALID_EXTRAFIELD_TYPE: string
1441
1446
  export const ERR_INVALID_EXTRAFIELD_DATA: string
1442
1447
  export const ERR_INVALID_ENCRYPTION_STRENGTH: string
1443
- export const ERR_UNSUPPORTED_FORMAT: string
1448
+ export const ERR_UNSUPPORTED_FORMAT: string
1449
+ export const ERR_SPLIT_ZIP_FILE: string
package/index.js CHANGED
@@ -54,6 +54,7 @@ export {
54
54
  HttpRangeReader,
55
55
  Uint8ArrayWriter,
56
56
  Uint8ArrayReader,
57
+ SplitZipReader,
57
58
  ERR_HTTP_RANGE,
58
59
  ERR_BAD_FORMAT,
59
60
  ERR_EOCDR_NOT_FOUND,
@@ -75,6 +76,7 @@ export {
75
76
  ERR_INVALID_EXTRAFIELD_TYPE,
76
77
  ERR_INVALID_EXTRAFIELD_DATA,
77
78
  ERR_INVALID_ENCRYPTION_STRENGTH,
78
- ERR_UNSUPPORTED_FORMAT
79
+ ERR_UNSUPPORTED_FORMAT,
80
+ ERR_SPLIT_ZIP_FILE
79
81
  } from "./lib/zip-fs.js";
80
82
  export { getMimeType, terminateWorkers };
@@ -26,7 +26,7 @@
26
26
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
  */
28
28
 
29
- /* global Worker, URL, TransformStream */
29
+ /* global Worker, URL, TransformStream, setTimeout */
30
30
 
31
31
  import {
32
32
  Codec,
@@ -141,7 +141,7 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
141
141
  }
142
142
  workerData.worker.addEventListener(MESSAGE_EVENT_TYPE, onMessage, false);
143
143
  workerData.interface = {
144
- run() {
144
+ async run() {
145
145
  const { readable, writable, options } = workerData;
146
146
  const scripts = workerData.scripts.slice(1);
147
147
  const message = { type: MESSAGE_START, scripts, options, config: { chunkSize } };
@@ -155,7 +155,18 @@ function createWebWorkerInterface(workerData, { baseURL, chunkSize }) {
155
155
  sendMessage(message);
156
156
  initStreams(readable, writable);
157
157
  }
158
- return workerData.result;
158
+ const result = await workerData.result;
159
+ if (workerData.transferStreams && transferStreamsSupported && writable.locked) {
160
+ await waitForUnlockedWritable();
161
+ }
162
+ return result;
163
+
164
+ async function waitForUnlockedWritable() {
165
+ await new Promise(resolve => setTimeout(resolve, 10));
166
+ if (writable.locked) {
167
+ return await waitForUnlockedWritable();
168
+ }
169
+ }
159
170
  }
160
171
  };
161
172
  }
package/lib/core/io.js CHANGED
@@ -64,9 +64,9 @@ class Reader extends Stream {
64
64
  this.chunkOffset = 0;
65
65
  },
66
66
  async pull(controller) {
67
- const { offset = 0, size } = readable;
67
+ const { offset = 0, size, diskNumberStart } = readable;
68
68
  const { chunkOffset } = this;
69
- controller.enqueue(await reader.readUint8Array(offset + chunkOffset, Math.min(chunkSize, size - chunkOffset)));
69
+ controller.enqueue(await readUint8Array(reader, offset + chunkOffset, Math.min(chunkSize, size - chunkOffset), diskNumberStart));
70
70
  if (chunkOffset + chunkSize > size) {
71
71
  controller.close();
72
72
  } else {
@@ -483,6 +483,52 @@ class Uint8ArrayWriter extends Writer {
483
483
  }
484
484
  }
485
485
 
486
+ class SplitZipReader extends Reader {
487
+
488
+ constructor(readers) {
489
+ super();
490
+ this.readers = readers;
491
+ }
492
+
493
+ async init() {
494
+ super.init();
495
+ const reader = this;
496
+ const { readers } = reader;
497
+ reader.lastDiskNumber = 0;
498
+ await Promise.all(readers.map(async diskReader => {
499
+ await diskReader.init();
500
+ reader.size += diskReader.size;
501
+ }));
502
+ }
503
+
504
+ async readUint8Array(offset, length, diskNumber = 0) {
505
+ const reader = this;
506
+ const { readers } = this;
507
+ let result;
508
+ let currentDiskNumber = diskNumber;
509
+ if (currentDiskNumber == -1) {
510
+ currentDiskNumber = readers.length - 1;
511
+ }
512
+ let currentReaderOffset = offset;
513
+ while (currentReaderOffset >= readers[currentDiskNumber].size) {
514
+ currentReaderOffset -= readers[currentDiskNumber].size;
515
+ currentDiskNumber++;
516
+ }
517
+ const currentReader = readers[currentDiskNumber];
518
+ const currentReaderSize = currentReader.size;
519
+ if (currentReaderOffset + length <= currentReaderSize) {
520
+ result = await readUint8Array(currentReader, currentReaderOffset, length);
521
+ } else {
522
+ const chunkLength = currentReaderSize - currentReaderOffset;
523
+ result = new Uint8Array(length);
524
+ result.set(await readUint8Array(currentReader, currentReaderOffset, chunkLength));
525
+ result.set(await reader.readUint8Array(offset + chunkLength, length - chunkLength, diskNumber), chunkLength);
526
+ }
527
+ reader.lastDiskNumber = Math.max(currentDiskNumber, reader.lastDiskNumber);
528
+ return result;
529
+ }
530
+ }
531
+
486
532
  function isHttpFamily(url) {
487
533
  const { baseURL } = getConfiguration();
488
534
  const { protocol } = new URL(url, baseURL);
@@ -495,8 +541,13 @@ async function initStream(stream, initSize) {
495
541
  }
496
542
  }
497
543
 
544
+ function readUint8Array(reader, offset, size, diskNumber) {
545
+ return reader.readUint8Array(offset, size, diskNumber);
546
+ }
547
+
498
548
  export {
499
549
  initStream,
550
+ readUint8Array,
500
551
  Reader,
501
552
  Writer,
502
553
  TextReader,
@@ -509,5 +560,6 @@ export {
509
560
  Uint8ArrayWriter,
510
561
  HttpReader,
511
562
  HttpRangeReader,
563
+ SplitZipReader,
512
564
  ERR_HTTP_RANGE
513
565
  };
@@ -38,11 +38,8 @@
38
38
  class CodecStream extends TransformStream {
39
39
 
40
40
  constructor(Codec, options) {
41
- let codec;
41
+ const codec = new Codec(options);
42
42
  super({
43
- start() {
44
- codec = new Codec(options);
45
- },
46
43
  transform(chunk, controller) {
47
44
  controller.enqueue(codec.append(chunk));
48
45
  },
@@ -91,8 +91,6 @@ class ZipCryptoEncryptionStream extends TransformStream {
91
91
  }
92
92
  output.set(encrypt(zipCrypto, chunk), offset);
93
93
  controller.enqueue(output);
94
- },
95
- flush() {
96
94
  }
97
95
  });
98
96
  }
@@ -68,12 +68,15 @@ import {
68
68
  } from "./codec-pool.js";
69
69
  import {
70
70
  initStream,
71
- BlobReader
71
+ readUint8Array,
72
+ BlobReader,
73
+ SplitZipReader
72
74
  } from "./io.js";
73
75
  import { decodeText } from "./util/decode-text.js";
74
76
  import { Crc32 } from "./streams/codecs/crc32.js";
75
77
  import { Entry } from "./zip-entry.js";
76
78
 
79
+ const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
77
80
  const ERR_BAD_FORMAT = "File format is not recognized";
78
81
  const ERR_EOCDR_NOT_FOUND = "End of central directory not found";
79
82
  const ERR_EOCDR_ZIP64_NOT_FOUND = "End of Zip64 central directory not found";
@@ -84,9 +87,25 @@ const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
84
87
  const ERR_ENCRYPTED = "File contains encrypted entry";
85
88
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
86
89
  const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
90
+ const ERR_SPLIT_ZIP_FILE = "Split zip file";
87
91
  const CHARSET_UTF8 = "utf-8";
88
92
  const CHARSET_CP437 = "cp437";
89
- const ZIP64_PROPERTIES = ["uncompressedSize", "compressedSize", "offset"];
93
+ const ZIP64_PROPERTIES = [
94
+ ["uncompressedSize", MAX_32_BITS],
95
+ ["compressedSize", MAX_32_BITS],
96
+ ["offset", MAX_32_BITS],
97
+ ["diskNumberStart", MAX_16_BITS]
98
+ ];
99
+ const ZIP64_EXTRACTION = {
100
+ [MAX_16_BITS]: {
101
+ getValue: getUint32,
102
+ bytes: 4
103
+ },
104
+ [MAX_32_BITS]: {
105
+ getValue: getBigUint64,
106
+ bytes: 8
107
+ }
108
+ };
90
109
 
91
110
  class ZipReader {
92
111
 
@@ -109,8 +128,12 @@ class ZipReader {
109
128
  const { config } = zipReader;
110
129
  await initStream(reader);
111
130
  if (reader.size === undefined || !reader.readUint8Array) {
112
- const blob = await new Response(reader.readable).blob();
113
- reader = new BlobReader(blob);
131
+ if (Array.isArray(reader)) {
132
+ reader = new SplitZipReader(reader);
133
+ } else {
134
+ reader = new BlobReader(await new Response(reader.readable).blob());
135
+ }
136
+ await initStream(reader);
114
137
  }
115
138
  if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
116
139
  throw new Error(ERR_BAD_FORMAT);
@@ -118,46 +141,64 @@ class ZipReader {
118
141
  reader.chunkSize = getChunkSize(config);
119
142
  const endOfDirectoryInfo = await seekSignature(reader, END_OF_CENTRAL_DIR_SIGNATURE, reader.size, END_OF_CENTRAL_DIR_LENGTH, MAX_16_BITS * 16);
120
143
  if (!endOfDirectoryInfo) {
121
- throw new Error(ERR_EOCDR_NOT_FOUND);
144
+ const signatureArray = await readUint8Array(reader, 0, 4);
145
+ const signatureView = getDataView(signatureArray);
146
+ if (getUint32(signatureView) == SPLIT_ZIP_FILE_SIGNATURE) {
147
+ throw new Error(ERR_SPLIT_ZIP_FILE);
148
+ } else {
149
+ throw new Error(ERR_EOCDR_NOT_FOUND);
150
+ }
122
151
  }
152
+ const { lastDiskNumber } = reader;
123
153
  const endOfDirectoryView = getDataView(endOfDirectoryInfo);
124
154
  let directoryDataLength = getUint32(endOfDirectoryView, 12);
125
155
  let directoryDataOffset = getUint32(endOfDirectoryView, 16);
126
156
  const commentOffset = endOfDirectoryInfo.offset;
127
157
  const commentLength = getUint16(endOfDirectoryView, 20);
128
158
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
159
+ let diskNumber = getUint16(endOfDirectoryView, 4);
160
+ if (lastDiskNumber !== undefined && diskNumber != lastDiskNumber) {
161
+ throw new Error(ERR_SPLIT_ZIP_FILE);
162
+ }
129
163
  let filesLength = getUint16(endOfDirectoryView, 8);
130
164
  let prependedDataLength = 0;
131
165
  let startOffset = 0;
132
- if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS) {
166
+ if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
133
167
  const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH);
134
168
  const endOfDirectoryLocatorView = getDataView(endOfDirectoryLocatorArray);
135
169
  if (getUint32(endOfDirectoryLocatorView, 0) != ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
136
170
  throw new Error(ERR_EOCDR_ZIP64_NOT_FOUND);
137
171
  }
138
172
  directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8);
139
- let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
173
+ let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
140
174
  let endOfDirectoryView = getDataView(endOfDirectoryArray);
141
175
  const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
142
176
  if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
143
177
  const originalDirectoryDataOffset = directoryDataOffset;
144
178
  directoryDataOffset = expectedDirectoryDataOffset;
145
179
  prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
146
- endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH);
180
+ endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
147
181
  endOfDirectoryView = getDataView(endOfDirectoryArray);
148
182
  }
149
183
  if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
150
184
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
151
185
  }
152
- filesLength = getBigUint64(endOfDirectoryView, 32);
153
- directoryDataLength = getBigUint64(endOfDirectoryView, 40);
186
+ if (diskNumber == MAX_16_BITS) {
187
+ diskNumber = getUint32(endOfDirectoryView, 16);
188
+ }
189
+ if (filesLength == MAX_16_BITS) {
190
+ filesLength = getBigUint64(endOfDirectoryView, 32);
191
+ }
192
+ if (directoryDataLength == MAX_32_BITS) {
193
+ directoryDataLength = getBigUint64(endOfDirectoryView, 40);
194
+ }
154
195
  directoryDataOffset -= directoryDataLength;
155
196
  }
156
197
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
157
198
  throw new Error(ERR_BAD_FORMAT);
158
199
  }
159
200
  let offset = 0;
160
- let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
201
+ let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
161
202
  let directoryView = getDataView(directoryArray);
162
203
  if (directoryDataLength) {
163
204
  const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength;
@@ -165,7 +206,7 @@ class ZipReader {
165
206
  const originalDirectoryDataOffset = directoryDataOffset;
166
207
  directoryDataOffset = expectedDirectoryDataOffset;
167
208
  prependedDataLength = directoryDataOffset - originalDirectoryDataOffset;
168
- directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength);
209
+ directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
169
210
  directoryView = getDataView(directoryArray);
170
211
  }
171
212
  }
@@ -186,40 +227,49 @@ class ZipReader {
186
227
  const commentOffset = extraFieldOffset + fileEntry.extraFieldLength;
187
228
  const versionMadeBy = getUint16(directoryView, offset + 4);
188
229
  const msDosCompatible = (versionMadeBy & 0) == 0;
230
+ const rawFilename = directoryArray.subarray(filenameOffset, extraFieldOffset);
231
+ const commentLength = getUint16(directoryView, offset + 32);
232
+ const endOffset = commentOffset + commentLength;
233
+ const rawComment = directoryArray.subarray(commentOffset, endOffset);
234
+ const filenameUTF8 = languageEncodingFlag;
235
+ const commentUTF8 = languageEncodingFlag;
236
+ const directory = msDosCompatible && ((getUint8(directoryView, offset + 38) & FILE_ATTR_MSDOS_DIR_MASK) == FILE_ATTR_MSDOS_DIR_MASK);
237
+ const offsetFileEntry = getUint32(directoryView, offset + 42) + prependedDataLength;
189
238
  Object.assign(fileEntry, {
190
239
  versionMadeBy,
191
240
  msDosCompatible,
192
241
  compressedSize: 0,
193
242
  uncompressedSize: 0,
194
- commentLength: getUint16(directoryView, offset + 32),
195
- directory: msDosCompatible && ((getUint8(directoryView, offset + 38) & FILE_ATTR_MSDOS_DIR_MASK) == FILE_ATTR_MSDOS_DIR_MASK),
196
- offset: getUint32(directoryView, offset + 42) + prependedDataLength,
243
+ commentLength,
244
+ directory,
245
+ offset: offsetFileEntry,
246
+ diskNumberStart: getUint16(directoryView, offset + 34),
197
247
  internalFileAttribute: getUint16(directoryView, offset + 36),
198
248
  externalFileAttribute: getUint32(directoryView, offset + 38),
199
- rawFilename: directoryArray.subarray(filenameOffset, extraFieldOffset),
200
- filenameUTF8: languageEncodingFlag,
201
- commentUTF8: languageEncodingFlag,
249
+ rawFilename,
250
+ filenameUTF8,
251
+ commentUTF8,
202
252
  rawExtraField: directoryArray.subarray(extraFieldOffset, commentOffset)
203
253
  });
204
- startOffset = Math.max(fileEntry.offset, startOffset);
205
- const endOffset = commentOffset + fileEntry.commentLength;
206
- fileEntry.rawComment = directoryArray.subarray(commentOffset, endOffset);
207
254
  const [filename, comment] = await Promise.all([
208
- decodeText(fileEntry.rawFilename, fileEntry.filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437),
209
- decodeText(fileEntry.rawComment, fileEntry.commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437)
255
+ decodeText(rawFilename, filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437),
256
+ decodeText(rawComment, commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437)
210
257
  ]);
211
- fileEntry.filename = filename;
212
- fileEntry.comment = comment;
213
- if (!fileEntry.directory && fileEntry.filename.endsWith(DIRECTORY_SIGNATURE)) {
214
- fileEntry.directory = true;
215
- }
258
+ Object.assign(fileEntry, {
259
+ rawComment,
260
+ filename,
261
+ comment,
262
+ directory: directory || filename.endsWith(DIRECTORY_SIGNATURE)
263
+ });
264
+ startOffset = Math.max(offsetFileEntry, startOffset);
216
265
  await readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
217
266
  const entry = new Entry(fileEntry);
218
267
  entry.getData = (writer, options) => fileEntry.getData(writer, entry, options);
219
268
  offset = endOffset;
220
- if (options.onprogress) {
269
+ const { onprogress } = options;
270
+ if (onprogress) {
221
271
  try {
222
- await options.onprogress(indexFile + 1, filesLength, new Entry(fileEntry));
272
+ await onprogress(indexFile + 1, filesLength, new Entry(fileEntry));
223
273
  } catch (_error) {
224
274
  // ignored
225
275
  }
@@ -263,7 +313,8 @@ export {
263
313
  ERR_UNSUPPORTED_ENCRYPTION,
264
314
  ERR_UNSUPPORTED_COMPRESSION,
265
315
  ERR_INVALID_SIGNATURE,
266
- ERR_INVALID_PASSWORD
316
+ ERR_INVALID_PASSWORD,
317
+ ERR_SPLIT_ZIP_FILE
267
318
  };
268
319
 
269
320
  class ZipEntry {
@@ -281,6 +332,7 @@ class ZipEntry {
281
332
  const {
282
333
  reader,
283
334
  offset,
335
+ diskNumberStart,
284
336
  extraFieldAES,
285
337
  compressionMethod,
286
338
  config,
@@ -291,7 +343,7 @@ class ZipEntry {
291
343
  compressedSize
292
344
  } = zipEntry;
293
345
  const localDirectory = zipEntry.localDirectory = {};
294
- let dataArray = await readUint8Array(reader, offset, 30);
346
+ let dataArray = await readUint8Array(reader, offset, 30, diskNumberStart);
295
347
  const dataView = getDataView(dataArray);
296
348
  let password = getOptionValue(zipEntry, options, "password");
297
349
  password = password && password.length && password;
@@ -307,11 +359,13 @@ class ZipEntry {
307
359
  throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
308
360
  }
309
361
  readCommonHeader(localDirectory, dataView, 4);
310
- dataArray = await readUint8Array(reader, offset, 30 + localDirectory.filenameLength + localDirectory.extraFieldLength);
362
+ dataArray = await readUint8Array(reader, offset, 30 + localDirectory.filenameLength + localDirectory.extraFieldLength, diskNumberStart);
311
363
  localDirectory.rawExtraField = dataArray.subarray(30 + localDirectory.filenameLength);
312
364
  await readCommonFooter(zipEntry, localDirectory, dataView, 4);
313
- fileEntry.lastAccessDate = localDirectory.lastAccessDate;
314
- fileEntry.creationDate = localDirectory.creationDate;
365
+ Object.assign(fileEntry, {
366
+ lastAccessDate: localDirectory.lastAccessDate,
367
+ creationDate: localDirectory.creationDate
368
+ });
315
369
  const encrypted = zipEntry.encrypted && localDirectory.encrypted;
316
370
  const zipCrypto = encrypted && !extraFieldAES;
317
371
  if (encrypted) {
@@ -323,6 +377,7 @@ class ZipEntry {
323
377
  }
324
378
  const dataOffset = offset + 30 + localDirectory.filenameLength + localDirectory.extraFieldLength;
325
379
  const readable = reader.readable;
380
+ readable.diskNumberStart = diskNumberStart;
326
381
  readable.offset = dataOffset;
327
382
  const size = readable.size = compressedSize;
328
383
  if (writer instanceof WritableStream) {
@@ -407,9 +462,11 @@ async function readCommonFooter(fileEntry, directory, dataView, offset) {
407
462
  // ignored
408
463
  }
409
464
  const compressionMethod = getUint16(dataView, offset + 4);
410
- directory.signature = getUint32(dataView, offset + 10);
411
- directory.uncompressedSize = getUint32(dataView, offset + 18);
412
- directory.compressedSize = getUint32(dataView, offset + 14);
465
+ Object.assign(directory, {
466
+ signature: getUint32(dataView, offset + 10),
467
+ uncompressedSize: getUint32(dataView, offset + 18),
468
+ compressedSize: getUint32(dataView, offset + 14)
469
+ });
413
470
  const extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64);
414
471
  if (extraFieldZip64) {
415
472
  readExtraFieldZip64(extraFieldZip64, directory);
@@ -447,35 +504,31 @@ async function readCommonFooter(fileEntry, directory, dataView, offset) {
447
504
  function readExtraFieldZip64(extraFieldZip64, directory) {
448
505
  directory.zip64 = true;
449
506
  const extraFieldView = getDataView(extraFieldZip64.data);
450
- extraFieldZip64.values = [];
451
- for (let indexValue = 0; indexValue < Math.floor(extraFieldZip64.data.length / 8); indexValue++) {
452
- extraFieldZip64.values.push(getBigUint64(extraFieldView, 0 + indexValue * 8));
453
- }
454
- const missingProperties = ZIP64_PROPERTIES.filter(propertyName => directory[propertyName] == MAX_32_BITS);
455
- for (let indexMissingProperty = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
456
- extraFieldZip64[missingProperties[indexMissingProperty]] = extraFieldZip64.values[indexMissingProperty];
457
- }
458
- ZIP64_PROPERTIES.forEach(propertyName => {
459
- if (directory[propertyName] == MAX_32_BITS) {
460
- if (extraFieldZip64[propertyName] !== undefined) {
461
- directory[propertyName] = extraFieldZip64[propertyName];
462
- } else {
463
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
464
- }
507
+ const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
508
+ for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
509
+ const [propertyName, max] = missingProperties[indexMissingProperty];
510
+ if (directory[propertyName] == max) {
511
+ const extraction = ZIP64_EXTRACTION[max];
512
+ directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
513
+ offset += extraction.bytes;
514
+ } else if (extraFieldZip64[propertyName]) {
515
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
465
516
  }
466
- });
517
+ }
467
518
  }
468
519
 
469
520
  async function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
470
521
  const extraFieldView = getDataView(extraFieldUnicode.data);
471
- extraFieldUnicode.version = getUint8(extraFieldView, 0);
472
- extraFieldUnicode.signature = getUint32(extraFieldView, 1);
473
522
  const crc32 = new Crc32();
474
523
  crc32.append(fileEntry[rawPropertyName]);
475
524
  const dataViewSignature = getDataView(new Uint8Array(4));
476
525
  dataViewSignature.setUint32(0, crc32.get(), true);
477
- extraFieldUnicode[propertyName] = await decodeText(extraFieldUnicode.data.subarray(5));
478
- extraFieldUnicode.valid = !fileEntry.bitFlag.languageEncodingFlag && extraFieldUnicode.signature == getUint32(dataViewSignature, 0);
526
+ Object.assign(extraFieldUnicode, {
527
+ version: getUint8(extraFieldView, 0),
528
+ signature: getUint32(extraFieldView, 1),
529
+ [propertyName]: await decodeText(extraFieldUnicode.data.subarray(5)),
530
+ valid: !fileEntry.bitFlag.languageEncodingFlag && extraFieldUnicode.signature == getUint32(dataViewSignature, 0)
531
+ });
479
532
  if (extraFieldUnicode.valid) {
480
533
  directory[propertyName] = extraFieldUnicode[propertyName];
481
534
  directory[propertyName + "UTF8"] = true;
@@ -484,12 +537,15 @@ async function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropert
484
537
 
485
538
  function readExtraFieldAES(extraFieldAES, directory, compressionMethod) {
486
539
  const extraFieldView = getDataView(extraFieldAES.data);
487
- extraFieldAES.vendorVersion = getUint8(extraFieldView, 0);
488
- extraFieldAES.vendorId = getUint8(extraFieldView, 2);
489
540
  const strength = getUint8(extraFieldView, 4);
490
- extraFieldAES.strength = strength;
491
- extraFieldAES.originalCompressionMethod = compressionMethod;
492
- directory.compressionMethod = extraFieldAES.compressionMethod = getUint16(extraFieldView, 5);
541
+ Object.assign(extraFieldAES, {
542
+ vendorVersion: getUint8(extraFieldView, 0),
543
+ vendorId: getUint8(extraFieldView, 2),
544
+ strength,
545
+ originalCompressionMethod: compressionMethod,
546
+ compressionMethod: getUint16(extraFieldView, 5)
547
+ });
548
+ directory.compressionMethod = extraFieldAES.compressionMethod;
493
549
  }
494
550
 
495
551
  function readExtraFieldNTFS(extraFieldNTFS, directory) {
@@ -621,8 +677,4 @@ function setUint32(view, offset, value) {
621
677
 
622
678
  function getDataView(array) {
623
679
  return new DataView(array.buffer);
624
- }
625
-
626
- function readUint8Array(reader, offset, size) {
627
- return reader.readUint8Array(offset, size);
628
680
  }