@zip.js/zip.js 2.8.53 → 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 +691 -482
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +698 -481
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +729 -511
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +691 -496
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +729 -511
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +743 -512
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +742 -511
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +700 -483
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +700 -483
- 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 +699 -482
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +1 -0
- package/index-native.cjs +743 -512
- package/index-native.min.js +1 -1
- package/index.cjs +742 -511
- package/index.d.cts +398 -42
- package/index.d.ts +398 -42
- package/index.min.js +1 -1
- package/lib/core/configuration.js +62 -21
- package/lib/core/constants.js +11 -1
- package/lib/core/io.js +33 -27
- package/lib/core/options.js +44 -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-fs.js +38 -27
- package/lib/core/zip-reader.js +58 -26
- package/lib/core/zip-writer.js +293 -177
- package/lib/zip-core-base.js +6 -1
- package/lib/zip-core-reader.js +1 -0
- package/lib/zip-core-writer.js +4 -0
- package/package.json +8 -2
|
@@ -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;
|
|
@@ -103,6 +105,8 @@ const HEADER_OFFSET_VERSION = 0;
|
|
|
103
105
|
const HEADER_OFFSET_SIGNATURE = 10;
|
|
104
106
|
const HEADER_OFFSET_COMPRESSED_SIZE = 14;
|
|
105
107
|
const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
|
|
108
|
+
const HEADER_OFFSET_FILENAME_LENGTH = 22;
|
|
109
|
+
const HEADER_OFFSET_EXTRAFIELD_LENGTH = 24;
|
|
106
110
|
const LOCAL_HEADER_COMMON_OFFSET = 4;
|
|
107
111
|
|
|
108
112
|
const MAX_DATE = new Date(2107, 11, 31, 23, 59, 58);
|
|
@@ -115,6 +119,7 @@ const FUNCTION_TYPE = "function";
|
|
|
115
119
|
const OBJECT_TYPE = "object";
|
|
116
120
|
const STRING_TYPE = "string";
|
|
117
121
|
const NUMBER_TYPE = "number";
|
|
122
|
+
const BOOLEAN_TYPE = "boolean";
|
|
118
123
|
|
|
119
124
|
const EMPTY_UINT8_ARRAY = new Uint8Array();
|
|
120
125
|
|
|
@@ -128,6 +133,7 @@ export {
|
|
|
128
133
|
COMPRESSION_METHOD_STORE,
|
|
129
134
|
COMPRESSION_METHOD_AES,
|
|
130
135
|
SPLIT_ZIP_FILE_SIGNATURE,
|
|
136
|
+
TEMPORARY_SPLIT_ZIP_FILE_SIGNATURE,
|
|
131
137
|
ARCHIVE_EXTRA_DATA_SIGNATURE,
|
|
132
138
|
DIGITAL_SIGNATURE_RECORD_SIGNATURE,
|
|
133
139
|
LOCAL_FILE_HEADER_SIGNATURE,
|
|
@@ -140,6 +146,7 @@ export {
|
|
|
140
146
|
DATA_DESCRIPTOR_RECORD_LENGTH,
|
|
141
147
|
DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH,
|
|
142
148
|
DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH,
|
|
149
|
+
SPLIT_ZIP_FILE_SIGNATURE_LENGTH,
|
|
143
150
|
EXTRAFIELD_TYPE_ZIP64,
|
|
144
151
|
EXTRAFIELD_TYPE_AES,
|
|
145
152
|
EXTRAFIELD_TYPE_NTFS,
|
|
@@ -188,6 +195,8 @@ export {
|
|
|
188
195
|
HEADER_OFFSET_SIGNATURE,
|
|
189
196
|
HEADER_OFFSET_COMPRESSED_SIZE,
|
|
190
197
|
HEADER_OFFSET_UNCOMPRESSED_SIZE,
|
|
198
|
+
HEADER_OFFSET_FILENAME_LENGTH,
|
|
199
|
+
HEADER_OFFSET_EXTRAFIELD_LENGTH,
|
|
191
200
|
LOCAL_HEADER_COMMON_OFFSET,
|
|
192
201
|
DIRECTORY_SIGNATURE,
|
|
193
202
|
MIN_DATE,
|
|
@@ -198,5 +207,6 @@ export {
|
|
|
198
207
|
FUNCTION_TYPE,
|
|
199
208
|
OBJECT_TYPE,
|
|
200
209
|
STRING_TYPE,
|
|
201
|
-
NUMBER_TYPE
|
|
210
|
+
NUMBER_TYPE,
|
|
211
|
+
BOOLEAN_TYPE
|
|
202
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
|
}
|
|
@@ -1001,8 +996,19 @@ function readUint8Array(reader, offset, size) {
|
|
|
1001
996
|
return reader.readUint8Array(offset, size);
|
|
1002
997
|
}
|
|
1003
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
|
+
|
|
1004
1009
|
export {
|
|
1005
1010
|
initStream,
|
|
1011
|
+
createReadable,
|
|
1006
1012
|
GenericReader,
|
|
1007
1013
|
GenericWriter,
|
|
1008
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";
|
|
@@ -75,6 +82,10 @@ const STRICTNESS_STRICT = "strict";
|
|
|
75
82
|
const STRICTNESS_BALANCED = "balanced";
|
|
76
83
|
const STRICTNESS_TOLERANT = "tolerant";
|
|
77
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
|
+
|
|
78
89
|
export {
|
|
79
90
|
OPTION_FILENAME_ENCODING,
|
|
80
91
|
OPTION_COMMENT_ENCODING,
|
|
@@ -123,5 +134,36 @@ export {
|
|
|
123
134
|
TEXT_TYPE_COMMENT,
|
|
124
135
|
STRICTNESS_STRICT,
|
|
125
136
|
STRICTNESS_BALANCED,
|
|
126
|
-
STRICTNESS_TOLERANT
|
|
127
|
-
|
|
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);
|