@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.
- package/dist/z-worker-fflate.js +1 -1
- package/dist/z-worker-pako.js +1 -1
- package/dist/z-worker.js +1 -1
- package/dist/zip-fs-full.js +229 -109
- package/dist/zip-fs-full.min.js +1 -1
- package/dist/zip-fs.js +230 -109
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-full.js +230 -109
- package/dist/zip-full.min.js +1 -1
- package/dist/zip-no-worker-deflate.min.js +1 -1
- package/dist/zip-no-worker-inflate.min.js +1 -1
- package/dist/zip-no-worker.min.js +1 -1
- package/dist/zip.js +1 -4507
- package/dist/zip.min.js +1 -1
- package/index-fflate.js +3 -1
- package/index.cjs +10459 -0
- package/index.d.ts +8 -2
- package/index.js +3 -1
- package/lib/core/codec-pool-worker.js +14 -3
- package/lib/core/io.js +54 -2
- package/lib/core/streams/codec-stream.js +1 -4
- package/lib/core/streams/zip-crypto-stream.js +0 -2
- package/lib/core/zip-reader.js +119 -67
- package/lib/core/zip-writer.js +45 -32
- package/lib/z-worker-inline.js +1 -1
- package/package.json +1 -1
- package/rollup-fflate.config.dev.js +5 -2
- package/rollup-fflate.config.js +5 -2
- package/rollup.config.dev.js +5 -2
- package/rollup.config.js +8 -5
- package/tests/all/test-common-js.cjs +31 -0
- package/tests/all/test-split-zip.js +37 -0
- package/tests/data/lorem-split.z01 +0 -0
- package/tests/data/lorem-split.z02 +0 -0
- package/tests/data/lorem-split.z03 +0 -0
- package/tests/data/lorem-split.z04 +0 -0
- package/tests/data/lorem-split.z05 +0 -0
- package/tests/data/lorem-split.z06 +0 -0
- package/tests/data/lorem-split.z07 +0 -0
- package/tests/data/lorem-split.zip +0 -0
- package/tests/tests-data.js +2 -0
- 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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
},
|
package/lib/core/zip-reader.js
CHANGED
|
@@ -68,12 +68,15 @@ import {
|
|
|
68
68
|
} from "./codec-pool.js";
|
|
69
69
|
import {
|
|
70
70
|
initStream,
|
|
71
|
-
|
|
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 = [
|
|
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
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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
|
-
|
|
153
|
-
|
|
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
|
|
195
|
-
directory
|
|
196
|
-
offset:
|
|
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
|
|
200
|
-
filenameUTF8
|
|
201
|
-
commentUTF8
|
|
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(
|
|
209
|
-
decodeText(
|
|
255
|
+
decodeText(rawFilename, filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437),
|
|
256
|
+
decodeText(rawComment, commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437)
|
|
210
257
|
]);
|
|
211
|
-
fileEntry
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
269
|
+
const { onprogress } = options;
|
|
270
|
+
if (onprogress) {
|
|
221
271
|
try {
|
|
222
|
-
await
|
|
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
|
|
314
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
451
|
-
for (let
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
|
478
|
-
|
|
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
|
|
491
|
-
|
|
492
|
-
|
|
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
|
}
|