@zip.js/zip.js 2.8.52 → 2.8.54
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/README.md +1 -1
- package/deno.json +2 -1
- package/dist/zip-core-external.js +839 -528
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +847 -527
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +880 -557
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +829 -538
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +880 -557
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +895 -558
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +894 -557
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +849 -529
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +849 -529
- package/dist/zip-native.min.js +1 -1
- package/dist/zip-web-worker-native.js +1 -1
- package/dist/zip-web-worker.js +1 -1
- package/dist/zip.js +848 -528
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +2 -1
- package/index-native.cjs +895 -558
- package/index-native.min.js +1 -1
- package/index.cjs +894 -557
- package/index.d.cts +672 -78
- package/index.d.ts +672 -78
- package/index.min.js +1 -1
- package/lib/core/codec-worker-web.js +13 -4
- package/lib/core/configuration.js +62 -21
- package/lib/core/constants.js +16 -1
- package/lib/core/io.js +44 -29
- package/lib/core/options.js +46 -2
- package/lib/core/streams/aes-crypto-stream.js +12 -12
- package/lib/core/util/decode-text.js +11 -2
- package/lib/core/web-worker-base.js +3 -2
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/zip-entry.js +8 -0
- package/lib/core/zip-fs.js +38 -27
- package/lib/core/zip-reader.js +149 -60
- package/lib/core/zip-writer.js +329 -189
- package/lib/zip-core-base.js +6 -1
- package/lib/zip-core-reader.js +1 -0
- package/lib/zip-core-writer.js +5 -0
- package/package.json +11 -3
|
@@ -83,6 +83,7 @@ function createWebWorkerInterface(workerData, config) {
|
|
|
83
83
|
worker,
|
|
84
84
|
workerAlive: false,
|
|
85
85
|
terminated: false,
|
|
86
|
+
startupError: null,
|
|
86
87
|
interface: {
|
|
87
88
|
run: async () => {
|
|
88
89
|
try {
|
|
@@ -110,6 +111,13 @@ function createWebWorkerInterface(workerData, config) {
|
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
async function runWebWorker(workerData, config) {
|
|
114
|
+
if (!workerData.worker) {
|
|
115
|
+
const { startupError } = workerData;
|
|
116
|
+
workerData.startupError = null;
|
|
117
|
+
const error = startupError || new Error(ERR_WORKER_STARTUP_TIMEOUT);
|
|
118
|
+
error.workerStartupFailed = true;
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
113
121
|
let resolveResult, rejectResult;
|
|
114
122
|
const result = new Promise((resolve, reject) => {
|
|
115
123
|
resolveResult = resolve;
|
|
@@ -323,11 +331,12 @@ function onWorkerError(event, workerData) {
|
|
|
323
331
|
if (!workerAlive) {
|
|
324
332
|
workerData.worker = null;
|
|
325
333
|
}
|
|
334
|
+
let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
|
|
335
|
+
if (!workerAlive) {
|
|
336
|
+
error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
|
|
337
|
+
workerData.startupError = error;
|
|
338
|
+
}
|
|
326
339
|
if (rejectResult) {
|
|
327
|
-
let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
|
|
328
|
-
if (!workerAlive) {
|
|
329
|
-
error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
|
|
330
|
-
}
|
|
331
340
|
rejectResult(error);
|
|
332
341
|
if (writer) {
|
|
333
342
|
writer.releaseLock();
|
|
@@ -32,8 +32,15 @@ import {
|
|
|
32
32
|
UNDEFINED_VALUE,
|
|
33
33
|
UNDEFINED_TYPE
|
|
34
34
|
} from "./constants.js";
|
|
35
|
+
import {
|
|
36
|
+
checkFunctionOption,
|
|
37
|
+
toNumber
|
|
38
|
+
} from "./options.js";
|
|
35
39
|
|
|
40
|
+
const DEFAULT_CHUNK_SIZE = 64 * 1024;
|
|
36
41
|
const MINIMUM_CHUNK_SIZE = 64;
|
|
42
|
+
const MINIMUM_PROPERTY_VALUE = 1;
|
|
43
|
+
const ERR_INVALID_MAX_WORKERS = "Invalid maxWorkers (must be an integer greater than 0)";
|
|
37
44
|
let maxWorkers = 2;
|
|
38
45
|
try {
|
|
39
46
|
if (typeof navigator != UNDEFINED_TYPE && navigator.hardwareConcurrency) {
|
|
@@ -45,7 +52,7 @@ try {
|
|
|
45
52
|
const DEFAULT_CONFIGURATION = {
|
|
46
53
|
workerURI: "./core/web-worker-wasm.js",
|
|
47
54
|
wasmURI: "./core/streams/zlib-wasm/zlib-streams.wasm",
|
|
48
|
-
chunkSize:
|
|
55
|
+
chunkSize: DEFAULT_CHUNK_SIZE,
|
|
49
56
|
maxWorkers,
|
|
50
57
|
terminateWorkerTimeout: 5000,
|
|
51
58
|
workerStarvationTimeout: 5000,
|
|
@@ -57,24 +64,38 @@ const DEFAULT_CONFIGURATION = {
|
|
|
57
64
|
DecompressionStream: typeof DecompressionStream != UNDEFINED_TYPE && DecompressionStream
|
|
58
65
|
};
|
|
59
66
|
|
|
60
|
-
const
|
|
67
|
+
const PROPERTY_NAME_MAX_WORKERS = "maxWorkers";
|
|
68
|
+
|
|
69
|
+
const STRING_PROPERTY_NAMES = [
|
|
61
70
|
"baseURI",
|
|
62
71
|
"wasmURI",
|
|
63
|
-
"workerURI"
|
|
64
|
-
|
|
72
|
+
"workerURI"
|
|
73
|
+
];
|
|
74
|
+
const BOOLEAN_PROPERTY_NAMES = [
|
|
75
|
+
"useCompressionStream",
|
|
76
|
+
"useWebWorkers",
|
|
77
|
+
"transferStreams"
|
|
78
|
+
];
|
|
79
|
+
const NUMBER_PROPERTY_NAMES = [
|
|
65
80
|
"chunkSize",
|
|
66
|
-
|
|
81
|
+
PROPERTY_NAME_MAX_WORKERS,
|
|
67
82
|
"terminateWorkerTimeout",
|
|
68
83
|
"workerStarvationTimeout",
|
|
69
|
-
"workerStartupTimeout"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"
|
|
84
|
+
"workerStartupTimeout"
|
|
85
|
+
];
|
|
86
|
+
const FUNCTION_PROPERTY_NAMES = [
|
|
87
|
+
"createWorker",
|
|
73
88
|
"CompressionStream",
|
|
74
89
|
"DecompressionStream",
|
|
75
90
|
"CompressionStreamFallback",
|
|
76
91
|
"DecompressionStreamFallback"
|
|
77
92
|
];
|
|
93
|
+
const CONFIGURABLE_PROPERTY_NAMES = [
|
|
94
|
+
...STRING_PROPERTY_NAMES,
|
|
95
|
+
...BOOLEAN_PROPERTY_NAMES,
|
|
96
|
+
...NUMBER_PROPERTY_NAMES,
|
|
97
|
+
...FUNCTION_PROPERTY_NAMES
|
|
98
|
+
];
|
|
78
99
|
|
|
79
100
|
const config = { ...DEFAULT_CONFIGURATION };
|
|
80
101
|
|
|
@@ -83,7 +104,9 @@ export {
|
|
|
83
104
|
setDefaultConfiguration,
|
|
84
105
|
resetConfiguration,
|
|
85
106
|
getConfiguration,
|
|
86
|
-
getChunkSize
|
|
107
|
+
getChunkSize,
|
|
108
|
+
normalizeChunkSize,
|
|
109
|
+
ERR_INVALID_MAX_WORKERS
|
|
87
110
|
};
|
|
88
111
|
|
|
89
112
|
function getConfiguration() {
|
|
@@ -91,20 +114,43 @@ function getConfiguration() {
|
|
|
91
114
|
}
|
|
92
115
|
|
|
93
116
|
function getChunkSize(config) {
|
|
94
|
-
return
|
|
117
|
+
return normalizeChunkSize(config.chunkSize);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function normalizeChunkSize(chunkSize) {
|
|
121
|
+
chunkSize = toNumber(chunkSize);
|
|
122
|
+
return Number.isInteger(chunkSize) && chunkSize >= MINIMUM_PROPERTY_VALUE ? Math.max(chunkSize, MINIMUM_CHUNK_SIZE) : DEFAULT_CHUNK_SIZE;
|
|
95
123
|
}
|
|
96
124
|
|
|
97
125
|
function configure(configuration) {
|
|
98
|
-
|
|
126
|
+
Object.assign(config, checkConfiguration(normalizeConfiguration(configuration)));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function checkConfiguration(configuration) {
|
|
130
|
+
const checkedConfiguration = {};
|
|
99
131
|
for (const propertyName of CONFIGURABLE_PROPERTY_NAMES) {
|
|
100
132
|
const propertyValue = configuration[propertyName];
|
|
101
133
|
if (propertyValue !== UNDEFINED_VALUE) {
|
|
102
|
-
|
|
134
|
+
checkedConfiguration[propertyName] = checkPropertyValue(propertyName, propertyValue);
|
|
103
135
|
}
|
|
104
136
|
}
|
|
137
|
+
return checkedConfiguration;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function checkPropertyValue(propertyName, propertyValue) {
|
|
141
|
+
if (NUMBER_PROPERTY_NAMES.includes(propertyName)) {
|
|
142
|
+
propertyValue = toNumber(propertyValue);
|
|
143
|
+
if (propertyName == PROPERTY_NAME_MAX_WORKERS && (!Number.isInteger(propertyValue) || propertyValue < MINIMUM_PROPERTY_VALUE)) {
|
|
144
|
+
throw new Error(ERR_INVALID_MAX_WORKERS);
|
|
145
|
+
}
|
|
146
|
+
} else if (FUNCTION_PROPERTY_NAMES.includes(propertyName)) {
|
|
147
|
+
checkFunctionOption(propertyValue);
|
|
148
|
+
}
|
|
149
|
+
return propertyValue;
|
|
105
150
|
}
|
|
106
151
|
|
|
107
152
|
function normalizeConfiguration(configuration) {
|
|
153
|
+
configuration = configuration || {};
|
|
108
154
|
const { CompressionStreamZlib, DecompressionStreamZlib } = configuration;
|
|
109
155
|
if (CompressionStreamZlib === UNDEFINED_VALUE && DecompressionStreamZlib === UNDEFINED_VALUE) {
|
|
110
156
|
return configuration;
|
|
@@ -120,14 +166,9 @@ function normalizeConfiguration(configuration) {
|
|
|
120
166
|
}
|
|
121
167
|
|
|
122
168
|
function setDefaultConfiguration(configuration) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (propertyValue !== UNDEFINED_VALUE) {
|
|
127
|
-
DEFAULT_CONFIGURATION[propertyName] = propertyValue;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
configure(configuration);
|
|
169
|
+
const checkedConfiguration = checkConfiguration(normalizeConfiguration(configuration));
|
|
170
|
+
Object.assign(DEFAULT_CONFIGURATION, checkedConfiguration);
|
|
171
|
+
Object.assign(config, checkedConfiguration);
|
|
131
172
|
}
|
|
132
173
|
|
|
133
174
|
function resetConfiguration() {
|
package/lib/core/constants.js
CHANGED
|
@@ -36,6 +36,7 @@ const COMPRESSION_METHOD_AES = 0x63;
|
|
|
36
36
|
|
|
37
37
|
const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
|
38
38
|
const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
|
|
39
|
+
const TEMPORARY_SPLIT_ZIP_FILE_SIGNATURE = 0x30304b50;
|
|
39
40
|
const DATA_DESCRIPTOR_RECORD_SIGNATURE = SPLIT_ZIP_FILE_SIGNATURE;
|
|
40
41
|
const ARCHIVE_EXTRA_DATA_SIGNATURE = 0x08064b50;
|
|
41
42
|
const DIGITAL_SIGNATURE_RECORD_SIGNATURE = 0x05054b50;
|
|
@@ -52,6 +53,7 @@ const ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH = END_OF_CENTRAL_DIR_LENGTH + ZIP64_
|
|
|
52
53
|
const DATA_DESCRIPTOR_RECORD_LENGTH = 12;
|
|
53
54
|
const DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH = 20;
|
|
54
55
|
const DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH = 4;
|
|
56
|
+
const SPLIT_ZIP_FILE_SIGNATURE_LENGTH = 4;
|
|
55
57
|
|
|
56
58
|
const EXTRAFIELD_TYPE_ZIP64 = 0x0001;
|
|
57
59
|
const EXTRAFIELD_TYPE_AES = 0x9901;
|
|
@@ -93,6 +95,9 @@ const VERSION_DEFLATE = 0x14;
|
|
|
93
95
|
const VERSION_ZIP64 = 0x2D;
|
|
94
96
|
const VERSION_AES = 0x33;
|
|
95
97
|
|
|
98
|
+
const VERSION_MADE_BY_MSDOS = 0x0014;
|
|
99
|
+
const VERSION_MADE_BY_UNIX = 0x0300;
|
|
100
|
+
|
|
96
101
|
const DIRECTORY_SIGNATURE = "/";
|
|
97
102
|
|
|
98
103
|
const HEADER_SIZE = 30;
|
|
@@ -100,6 +105,8 @@ const HEADER_OFFSET_VERSION = 0;
|
|
|
100
105
|
const HEADER_OFFSET_SIGNATURE = 10;
|
|
101
106
|
const HEADER_OFFSET_COMPRESSED_SIZE = 14;
|
|
102
107
|
const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
|
|
108
|
+
const HEADER_OFFSET_FILENAME_LENGTH = 22;
|
|
109
|
+
const HEADER_OFFSET_EXTRAFIELD_LENGTH = 24;
|
|
103
110
|
const LOCAL_HEADER_COMMON_OFFSET = 4;
|
|
104
111
|
|
|
105
112
|
const MAX_DATE = new Date(2107, 11, 31, 23, 59, 58);
|
|
@@ -112,6 +119,7 @@ const FUNCTION_TYPE = "function";
|
|
|
112
119
|
const OBJECT_TYPE = "object";
|
|
113
120
|
const STRING_TYPE = "string";
|
|
114
121
|
const NUMBER_TYPE = "number";
|
|
122
|
+
const BOOLEAN_TYPE = "boolean";
|
|
115
123
|
|
|
116
124
|
const EMPTY_UINT8_ARRAY = new Uint8Array();
|
|
117
125
|
|
|
@@ -125,6 +133,7 @@ export {
|
|
|
125
133
|
COMPRESSION_METHOD_STORE,
|
|
126
134
|
COMPRESSION_METHOD_AES,
|
|
127
135
|
SPLIT_ZIP_FILE_SIGNATURE,
|
|
136
|
+
TEMPORARY_SPLIT_ZIP_FILE_SIGNATURE,
|
|
128
137
|
ARCHIVE_EXTRA_DATA_SIGNATURE,
|
|
129
138
|
DIGITAL_SIGNATURE_RECORD_SIGNATURE,
|
|
130
139
|
LOCAL_FILE_HEADER_SIGNATURE,
|
|
@@ -137,6 +146,7 @@ export {
|
|
|
137
146
|
DATA_DESCRIPTOR_RECORD_LENGTH,
|
|
138
147
|
DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH,
|
|
139
148
|
DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH,
|
|
149
|
+
SPLIT_ZIP_FILE_SIGNATURE_LENGTH,
|
|
140
150
|
EXTRAFIELD_TYPE_ZIP64,
|
|
141
151
|
EXTRAFIELD_TYPE_AES,
|
|
142
152
|
EXTRAFIELD_TYPE_NTFS,
|
|
@@ -176,6 +186,8 @@ export {
|
|
|
176
186
|
FILE_ATTR_UNIX_SETGID_MASK,
|
|
177
187
|
FILE_ATTR_UNIX_STICKY_MASK,
|
|
178
188
|
VERSION_DEFLATE,
|
|
189
|
+
VERSION_MADE_BY_MSDOS,
|
|
190
|
+
VERSION_MADE_BY_UNIX,
|
|
179
191
|
VERSION_ZIP64,
|
|
180
192
|
VERSION_AES,
|
|
181
193
|
HEADER_SIZE,
|
|
@@ -183,6 +195,8 @@ export {
|
|
|
183
195
|
HEADER_OFFSET_SIGNATURE,
|
|
184
196
|
HEADER_OFFSET_COMPRESSED_SIZE,
|
|
185
197
|
HEADER_OFFSET_UNCOMPRESSED_SIZE,
|
|
198
|
+
HEADER_OFFSET_FILENAME_LENGTH,
|
|
199
|
+
HEADER_OFFSET_EXTRAFIELD_LENGTH,
|
|
186
200
|
LOCAL_HEADER_COMMON_OFFSET,
|
|
187
201
|
DIRECTORY_SIGNATURE,
|
|
188
202
|
MIN_DATE,
|
|
@@ -193,5 +207,6 @@ export {
|
|
|
193
207
|
FUNCTION_TYPE,
|
|
194
208
|
OBJECT_TYPE,
|
|
195
209
|
STRING_TYPE,
|
|
196
|
-
NUMBER_TYPE
|
|
210
|
+
NUMBER_TYPE,
|
|
211
|
+
BOOLEAN_TYPE
|
|
197
212
|
};
|
package/lib/core/io.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global Blob, atob, btoa, XMLHttpRequest, URL, fetch, ReadableStream, WritableStream,
|
|
29
|
+
/* global Blob, atob, btoa, XMLHttpRequest, URL, fetch, ReadableStream, WritableStream, TransformStream */
|
|
30
30
|
// deno-lint-ignore-file no-this-alias
|
|
31
31
|
|
|
32
32
|
import {
|
|
@@ -36,9 +36,10 @@ import {
|
|
|
36
36
|
END_OF_CENTRAL_DIR_LENGTH,
|
|
37
37
|
EMPTY_UINT8_ARRAY
|
|
38
38
|
} from "./constants.js";
|
|
39
|
-
import { getConfiguration, getChunkSize } from "./configuration.js";
|
|
39
|
+
import { getConfiguration, getChunkSize, normalizeChunkSize } from "./configuration.js";
|
|
40
40
|
import { concat, toExactUint8Array } from "./util/array.js";
|
|
41
41
|
import { toCompatibleReadable, toCompatibleWritable, streamToBlob } from "./util/compatible-streams.js";
|
|
42
|
+
import { decodeTextRemovingBOM } from "./util/decode-text.js";
|
|
42
43
|
|
|
43
44
|
const ERR_HTTP_STATUS = "HTTP error ";
|
|
44
45
|
const ERR_HTTP_RANGE = "HTTP Range not supported";
|
|
@@ -83,6 +84,7 @@ class Reader extends Stream {
|
|
|
83
84
|
createReadable({ offset = 0, size, chunkSize = getChunkSize(getConfiguration()) } = {}) {
|
|
84
85
|
const reader = this;
|
|
85
86
|
let chunkOffset = 0;
|
|
87
|
+
chunkSize = normalizeChunkSize(chunkSize);
|
|
86
88
|
return new ReadableStream({
|
|
87
89
|
async pull(controller) {
|
|
88
90
|
const dataSize = size === UNDEFINED_VALUE ? chunkSize : Math.min(chunkSize, size - chunkOffset);
|
|
@@ -90,7 +92,7 @@ class Reader extends Stream {
|
|
|
90
92
|
if (data.length) {
|
|
91
93
|
controller.enqueue(data);
|
|
92
94
|
}
|
|
93
|
-
if ((chunkOffset + chunkSize >= size) || (
|
|
95
|
+
if ((chunkOffset + chunkSize >= size) || (!data.length && dataSize)) {
|
|
94
96
|
controller.close();
|
|
95
97
|
} else {
|
|
96
98
|
chunkOffset += chunkSize;
|
|
@@ -170,31 +172,31 @@ class Data64URIWriter extends Writer {
|
|
|
170
172
|
Object.assign(this, {
|
|
171
173
|
contentType,
|
|
172
174
|
data: "data:" + (contentType || "") + ";base64,",
|
|
173
|
-
|
|
175
|
+
pendingCharacters: ""
|
|
174
176
|
});
|
|
175
177
|
}
|
|
176
178
|
|
|
177
179
|
writeUint8Array(array) {
|
|
178
180
|
const writer = this;
|
|
179
181
|
let indexArray;
|
|
180
|
-
let dataString = writer.
|
|
181
|
-
const delta = writer.
|
|
182
|
-
writer.
|
|
182
|
+
let dataString = writer.pendingCharacters;
|
|
183
|
+
const delta = writer.pendingCharacters.length;
|
|
184
|
+
writer.pendingCharacters = "";
|
|
183
185
|
for (indexArray = 0; indexArray < (Math.floor((delta + array.length) / 3) * 3) - delta; indexArray++) {
|
|
184
186
|
dataString += String.fromCharCode(array[indexArray]);
|
|
185
187
|
}
|
|
186
188
|
for (; indexArray < array.length; indexArray++) {
|
|
187
|
-
writer.
|
|
189
|
+
writer.pendingCharacters += String.fromCharCode(array[indexArray]);
|
|
188
190
|
}
|
|
189
191
|
if (dataString.length > 2) {
|
|
190
192
|
writer.data += btoa(dataString);
|
|
191
193
|
} else {
|
|
192
|
-
writer.
|
|
194
|
+
writer.pendingCharacters = dataString + writer.pendingCharacters;
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
getData() {
|
|
197
|
-
return this.data + btoa(this.
|
|
199
|
+
return this.data + btoa(this.pendingCharacters);
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
|
|
@@ -224,7 +226,7 @@ class BlobReader extends Reader {
|
|
|
224
226
|
constructor(blob) {
|
|
225
227
|
super();
|
|
226
228
|
Object.assign(this, {
|
|
227
|
-
blob,
|
|
229
|
+
sourceBlob: blob,
|
|
228
230
|
size: blob.size
|
|
229
231
|
});
|
|
230
232
|
if (!blobSliceProbe) {
|
|
@@ -234,13 +236,13 @@ class BlobReader extends Reader {
|
|
|
234
236
|
|
|
235
237
|
createReadable(options) {
|
|
236
238
|
const reader = this;
|
|
237
|
-
const {
|
|
239
|
+
const { sourceBlob, size } = reader;
|
|
238
240
|
const { offset = 0, size: readSize = size - offset } = options || {};
|
|
239
241
|
if (!offset && readSize >= size) {
|
|
240
|
-
return toCompatibleReadable(
|
|
242
|
+
return toCompatibleReadable(sourceBlob.stream());
|
|
241
243
|
}
|
|
242
244
|
if (blobSliceReliable) {
|
|
243
|
-
return toCompatibleReadable(
|
|
245
|
+
return toCompatibleReadable(sourceBlob.slice(offset, offset + readSize).stream());
|
|
244
246
|
}
|
|
245
247
|
return super.createReadable(options);
|
|
246
248
|
}
|
|
@@ -249,7 +251,7 @@ class BlobReader extends Reader {
|
|
|
249
251
|
const reader = this;
|
|
250
252
|
const offsetEnd = offset + length;
|
|
251
253
|
const readsWholeBlob = !offset && offsetEnd >= reader.size;
|
|
252
|
-
const blob = readsWholeBlob ? reader.
|
|
254
|
+
const blob = readsWholeBlob ? reader.sourceBlob : reader.sourceBlob.slice(offset, offsetEnd);
|
|
253
255
|
let arrayBuffer = await blob.arrayBuffer();
|
|
254
256
|
const sliceIgnoredByBuggyImplementation = arrayBuffer.byteLength > length;
|
|
255
257
|
if (sliceIgnoredByBuggyImplementation) {
|
|
@@ -271,12 +273,12 @@ class BlobWriter extends Stream {
|
|
|
271
273
|
}
|
|
272
274
|
});
|
|
273
275
|
writer.contentType = contentType;
|
|
274
|
-
writer.
|
|
275
|
-
writer.
|
|
276
|
+
writer.blobPromise = streamToBlob(transformStream.readable, contentType);
|
|
277
|
+
writer.blobPromise.catch(() => { });
|
|
276
278
|
}
|
|
277
279
|
|
|
278
280
|
getData() {
|
|
279
|
-
return this.
|
|
281
|
+
return this.blobPromise;
|
|
280
282
|
}
|
|
281
283
|
}
|
|
282
284
|
|
|
@@ -310,7 +312,7 @@ function getTextSize(text) {
|
|
|
310
312
|
class TextWriter extends BlobWriter {
|
|
311
313
|
|
|
312
314
|
constructor(encoding) {
|
|
313
|
-
super(
|
|
315
|
+
super();
|
|
314
316
|
Object.assign(this, {
|
|
315
317
|
encoding,
|
|
316
318
|
utf8: !encoding || encoding.toLowerCase() == "utf-8"
|
|
@@ -326,14 +328,7 @@ class TextWriter extends BlobWriter {
|
|
|
326
328
|
if (blob.text && utf8) {
|
|
327
329
|
return blob.text();
|
|
328
330
|
} else {
|
|
329
|
-
|
|
330
|
-
return new Promise((resolve, reject) => {
|
|
331
|
-
Object.assign(reader, {
|
|
332
|
-
onload: ({ target }) => resolve(target.result),
|
|
333
|
-
onerror: () => reject(reader.error)
|
|
334
|
-
});
|
|
335
|
-
reader.readAsText(blob, encoding);
|
|
336
|
-
});
|
|
331
|
+
return decodeTextRemovingBOM(new Uint8Array(await blob.arrayBuffer()), encoding);
|
|
337
332
|
}
|
|
338
333
|
}
|
|
339
334
|
}
|
|
@@ -791,9 +786,8 @@ class SplitDataReader extends Reader {
|
|
|
791
786
|
|
|
792
787
|
async init() {
|
|
793
788
|
const reader = this;
|
|
794
|
-
const { readers } = reader;
|
|
795
789
|
reader.lastDiskNumber = 0;
|
|
796
|
-
await Promise.all(readers.map(
|
|
790
|
+
const readers = reader.readers = await Promise.all(reader.readers.map(initDiskReader));
|
|
797
791
|
reader.diskOffsets = readers.map(diskReader => {
|
|
798
792
|
const diskOffset = reader.size;
|
|
799
793
|
reader.size += diskReader.size;
|
|
@@ -988,12 +982,33 @@ async function initStream(stream, initSize) {
|
|
|
988
982
|
}
|
|
989
983
|
}
|
|
990
984
|
|
|
985
|
+
async function initDiskReader(diskReader) {
|
|
986
|
+
diskReader = new GenericReader(diskReader);
|
|
987
|
+
await initStream(diskReader);
|
|
988
|
+
if (diskReader.size === UNDEFINED_VALUE || !diskReader.readUint8Array) {
|
|
989
|
+
diskReader = new BlobReader(await streamToBlob(diskReader.readable));
|
|
990
|
+
await initStream(diskReader);
|
|
991
|
+
}
|
|
992
|
+
return diskReader;
|
|
993
|
+
}
|
|
994
|
+
|
|
991
995
|
function readUint8Array(reader, offset, size) {
|
|
992
996
|
return reader.readUint8Array(offset, size);
|
|
993
997
|
}
|
|
994
998
|
|
|
999
|
+
function createReadable(reader, options) {
|
|
1000
|
+
if (reader.createReadable) {
|
|
1001
|
+
return reader.createReadable(options);
|
|
1002
|
+
} else if (reader.readUint8Array) {
|
|
1003
|
+
return Reader.prototype.createReadable.call(reader, options);
|
|
1004
|
+
} else {
|
|
1005
|
+
return reader.readable;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
|
|
995
1009
|
export {
|
|
996
1010
|
initStream,
|
|
1011
|
+
createReadable,
|
|
997
1012
|
GenericReader,
|
|
998
1013
|
GenericWriter,
|
|
999
1014
|
ownsWritable,
|
package/lib/core/options.js
CHANGED
|
@@ -26,6 +26,13 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
import {
|
|
30
|
+
BOOLEAN_TYPE,
|
|
31
|
+
FUNCTION_TYPE,
|
|
32
|
+
STRING_TYPE,
|
|
33
|
+
UNDEFINED_VALUE
|
|
34
|
+
} from "./constants.js";
|
|
35
|
+
|
|
29
36
|
const OPTION_FILENAME_ENCODING = "filenameEncoding";
|
|
30
37
|
const OPTION_COMMENT_ENCODING = "commentEncoding";
|
|
31
38
|
const OPTION_DECODE_TEXT = "decodeText";
|
|
@@ -39,6 +46,7 @@ const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
|
|
|
39
46
|
const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
|
|
40
47
|
const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
|
|
41
48
|
const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
|
|
49
|
+
const OPTION_CHECK_LOCAL_DIRECTORY = "checkLocalDirectory";
|
|
42
50
|
const OPTION_CHECK_SIGNATURE = "checkSignature";
|
|
43
51
|
const OPTION_CHECK_CRC32 = "checkCrc32";
|
|
44
52
|
const OPTION_CHECK_AUTHENTICATION_CODE = "checkAuthenticationCode";
|
|
@@ -74,6 +82,10 @@ const STRICTNESS_STRICT = "strict";
|
|
|
74
82
|
const STRICTNESS_BALANCED = "balanced";
|
|
75
83
|
const STRICTNESS_TOLERANT = "tolerant";
|
|
76
84
|
|
|
85
|
+
const ERR_INVALID_FUNCTION_OPTION = "Invalid option (must be a function)";
|
|
86
|
+
const ERR_INVALID_SIGNAL = "Invalid signal (must be an AbortSignal instance)";
|
|
87
|
+
const ERR_INVALID_PASSWORD_TYPE = "Invalid password (password must be a string, rawPassword must be a Uint8Array)";
|
|
88
|
+
|
|
77
89
|
export {
|
|
78
90
|
OPTION_FILENAME_ENCODING,
|
|
79
91
|
OPTION_COMMENT_ENCODING,
|
|
@@ -88,6 +100,7 @@ export {
|
|
|
88
100
|
OPTION_CHECK_OVERLAPPING_ENTRY_ONLY,
|
|
89
101
|
OPTION_CHECK_OVERLAPPING_ENTRY,
|
|
90
102
|
OPTION_CHECK_AMBIGUITY,
|
|
103
|
+
OPTION_CHECK_LOCAL_DIRECTORY,
|
|
91
104
|
OPTION_CHECK_SIGNATURE,
|
|
92
105
|
OPTION_CHECK_CRC32,
|
|
93
106
|
OPTION_CHECK_AUTHENTICATION_CODE,
|
|
@@ -121,5 +134,36 @@ export {
|
|
|
121
134
|
TEXT_TYPE_COMMENT,
|
|
122
135
|
STRICTNESS_STRICT,
|
|
123
136
|
STRICTNESS_BALANCED,
|
|
124
|
-
STRICTNESS_TOLERANT
|
|
125
|
-
|
|
137
|
+
STRICTNESS_TOLERANT,
|
|
138
|
+
ERR_INVALID_FUNCTION_OPTION,
|
|
139
|
+
ERR_INVALID_SIGNAL,
|
|
140
|
+
ERR_INVALID_PASSWORD_TYPE,
|
|
141
|
+
checkFunctionOption,
|
|
142
|
+
checkSignalOption,
|
|
143
|
+
checkPasswordOption,
|
|
144
|
+
toNumber
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
function checkFunctionOption(value) {
|
|
148
|
+
if (value && typeof value != FUNCTION_TYPE) {
|
|
149
|
+
throw new Error(ERR_INVALID_FUNCTION_OPTION);
|
|
150
|
+
}
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function checkSignalOption(signal) {
|
|
155
|
+
if (signal && (typeof signal.addEventListener != FUNCTION_TYPE || typeof signal.aborted != BOOLEAN_TYPE)) {
|
|
156
|
+
throw new Error(ERR_INVALID_SIGNAL);
|
|
157
|
+
}
|
|
158
|
+
return signal || UNDEFINED_VALUE;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function checkPasswordOption(password, rawPassword) {
|
|
162
|
+
if ((password && typeof password != STRING_TYPE) || (rawPassword && !(rawPassword instanceof Uint8Array))) {
|
|
163
|
+
throw new Error(ERR_INVALID_PASSWORD_TYPE);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function toNumber(value) {
|
|
168
|
+
return typeof value == STRING_TYPE && value.trim() ? Number(value) : value;
|
|
169
|
+
}
|
|
@@ -102,13 +102,13 @@ class AESDecryptionStream extends TransformStream {
|
|
|
102
102
|
const {
|
|
103
103
|
ctr,
|
|
104
104
|
hmac,
|
|
105
|
-
|
|
105
|
+
pendingInput,
|
|
106
106
|
ready
|
|
107
107
|
} = this;
|
|
108
108
|
if (hmac && ctr) {
|
|
109
109
|
await ready;
|
|
110
|
-
const chunkToDecrypt = subarray(
|
|
111
|
-
const originalAuthenticationCode = subarray(
|
|
110
|
+
const chunkToDecrypt = subarray(pendingInput, 0, pendingInput.length - AUTHENTICATION_CODE_LENGTH);
|
|
111
|
+
const originalAuthenticationCode = subarray(pendingInput, pendingInput.length - AUTHENTICATION_CODE_LENGTH);
|
|
112
112
|
let decryptedChunkArray = EMPTY_UINT8_ARRAY;
|
|
113
113
|
if (chunkToDecrypt.length) {
|
|
114
114
|
const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
|
|
@@ -117,7 +117,7 @@ class AESDecryptionStream extends TransformStream {
|
|
|
117
117
|
decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
|
|
118
118
|
}
|
|
119
119
|
const authenticationCode = subarray(fromBits(codecBytes, hmac.digest()), 0, AUTHENTICATION_CODE_LENGTH);
|
|
120
|
-
let invalidAuthenticationCode =
|
|
120
|
+
let invalidAuthenticationCode = pendingInput.length < AUTHENTICATION_CODE_LENGTH ? 1 : 0;
|
|
121
121
|
for (let indexByte = 0; indexByte < AUTHENTICATION_CODE_LENGTH; indexByte++) {
|
|
122
122
|
invalidAuthenticationCode |= authenticationCode[indexByte] ^ originalAuthenticationCode[indexByte];
|
|
123
123
|
}
|
|
@@ -161,14 +161,14 @@ class AESEncryptionStream extends TransformStream {
|
|
|
161
161
|
const {
|
|
162
162
|
ctr,
|
|
163
163
|
hmac,
|
|
164
|
-
|
|
164
|
+
pendingInput,
|
|
165
165
|
ready
|
|
166
166
|
} = this;
|
|
167
167
|
if (hmac && ctr) {
|
|
168
168
|
await ready;
|
|
169
169
|
let encryptedChunkArray = EMPTY_UINT8_ARRAY;
|
|
170
|
-
if (
|
|
171
|
-
const encryptedChunk = ctr.update(toBits(codecBytes,
|
|
170
|
+
if (pendingInput.length) {
|
|
171
|
+
const encryptedChunk = ctr.update(toBits(codecBytes, pendingInput));
|
|
172
172
|
hmac.update(encryptedChunk);
|
|
173
173
|
encryptedChunkArray = fromBits(codecBytes, encryptedChunk);
|
|
174
174
|
}
|
|
@@ -190,7 +190,7 @@ function initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength) {
|
|
|
190
190
|
ready: new Promise(resolve => aesCrypto.resolveReady = resolve),
|
|
191
191
|
password: encodePassword(password, rawPassword),
|
|
192
192
|
strength: encryptionStrength - 1,
|
|
193
|
-
|
|
193
|
+
pendingInput: EMPTY_UINT8_ARRAY
|
|
194
194
|
});
|
|
195
195
|
}
|
|
196
196
|
|
|
@@ -198,10 +198,10 @@ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifyAuthen
|
|
|
198
198
|
const {
|
|
199
199
|
ctr,
|
|
200
200
|
hmac,
|
|
201
|
-
|
|
201
|
+
pendingInput
|
|
202
202
|
} = aesCrypto;
|
|
203
|
-
if (
|
|
204
|
-
input = concat(
|
|
203
|
+
if (pendingInput.length) {
|
|
204
|
+
input = concat(pendingInput, input);
|
|
205
205
|
}
|
|
206
206
|
const inputLength = input.length - paddingEnd;
|
|
207
207
|
output = expand(output, paddingStart + (inputLength - (inputLength % BLOCK_LENGTH)));
|
|
@@ -217,7 +217,7 @@ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifyAuthen
|
|
|
217
217
|
}
|
|
218
218
|
output.set(fromBits(codecBytes, outputChunk), offset + paddingStart);
|
|
219
219
|
}
|
|
220
|
-
aesCrypto.
|
|
220
|
+
aesCrypto.pendingInput = subarray(input, offset);
|
|
221
221
|
return output;
|
|
222
222
|
}
|
|
223
223
|
|
|
@@ -31,13 +31,22 @@
|
|
|
31
31
|
import { decodeCP437 } from "./decode-cp437.js";
|
|
32
32
|
|
|
33
33
|
export {
|
|
34
|
-
decodeText
|
|
34
|
+
decodeText,
|
|
35
|
+
decodeTextRemovingBOM
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
function decodeText(value, encoding) {
|
|
39
|
+
return decode(value, encoding, true);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function decodeTextRemovingBOM(value, encoding) {
|
|
43
|
+
return decode(value, encoding, false);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function decode(value, encoding, ignoreBOM) {
|
|
38
47
|
if (encoding && encoding.trim().toLowerCase() == "cp437") {
|
|
39
48
|
return decodeCP437(value);
|
|
40
49
|
} else {
|
|
41
|
-
return new TextDecoder(encoding, { ignoreBOM
|
|
50
|
+
return new TextDecoder(encoding, { ignoreBOM }).decode(value);
|
|
42
51
|
}
|
|
43
52
|
}
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
MESSAGE_READY
|
|
45
45
|
} from "./streams/codec-stream.js";
|
|
46
46
|
import { getChunkSize } from "./configuration.js";
|
|
47
|
+
import { toCompatibleReadable, toCompatibleWritable } from "./util/compatible-streams.js";
|
|
47
48
|
import { toExactUint8Array } from "./util/array.js";
|
|
48
49
|
import { ensureCodecStreams } from "./codec-registry.js";
|
|
49
50
|
|
|
@@ -138,7 +139,7 @@ async function init(message) {
|
|
|
138
139
|
config.DecompressionStreamFallback = config.DecompressionStreamZlib;
|
|
139
140
|
}
|
|
140
141
|
const strategy = { highWaterMark: 1 };
|
|
141
|
-
const readable = message.readable
|
|
142
|
+
const readable = message.readable ? toCompatibleReadable(message.readable) : new ReadableStream({
|
|
142
143
|
async pull(controller) {
|
|
143
144
|
const result = new Promise(resolve => pendingPullMessages.set(messageId, resolve));
|
|
144
145
|
sendMessage({ type: MESSAGE_PULL, messageId });
|
|
@@ -150,7 +151,7 @@ async function init(message) {
|
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
153
|
}, strategy);
|
|
153
|
-
writable = message.writable
|
|
154
|
+
writable = message.writable ? toCompatibleWritable(message.writable) : new WritableStream({
|
|
154
155
|
async write(value) {
|
|
155
156
|
let resolveAckData;
|
|
156
157
|
const ackData = new Promise(resolve => resolveAckData = resolve);
|