@zip.js/zip.js 2.8.29 → 2.8.31
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/BENCHMARKS.md +35 -0
- package/deno.json +5 -4
- package/dist/zip-core.js +496 -218
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core.js +398 -195
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-native.js +588 -254
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +587 -253
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +501 -223
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-module.wasm +0 -0
- package/dist/zip-native.js +504 -226
- 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 +503 -225
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +588 -254
- package/index-native.min.js +1 -1
- package/index.cjs +587 -253
- package/index.d.cts +2814 -0
- package/index.d.ts +364 -1
- package/index.min.js +1 -1
- package/lib/core/codec-worker.js +0 -10
- package/lib/core/configuration.js +21 -33
- package/lib/core/constants.js +3 -0
- package/lib/core/io.js +11 -19
- package/lib/core/options.js +11 -1
- package/lib/core/streams/aes-crypto-stream.js +16 -20
- package/lib/core/streams/codecs/crc32.js +39 -11
- package/lib/core/streams/common-crypto.js +0 -2
- package/lib/core/streams/zip-crypto-stream.js +12 -16
- package/lib/core/streams/zip-entry-stream.js +69 -19
- package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
- package/lib/core/streams/zlib-wasm/zlib-streams-loader.js +1 -3
- package/lib/core/streams/zlib-wasm/zlib-streams.wasm +0 -0
- package/lib/core/util/base64.js +68 -0
- package/lib/core/util/decode-text.js +0 -1
- package/lib/core/util/default-mime-type.js +0 -3
- package/lib/core/util/inflate.js +194 -0
- package/lib/core/util/mime-type.js +26 -22
- package/lib/core/util/opfs-temp-stream.js +139 -0
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-template-native.js +5 -5
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/zip-fs.js +61 -10
- package/lib/core/zip-reader.js +162 -53
- package/lib/core/zip-writer.js +34 -41
- package/lib/core/zlib-streams-inline-template.js +3 -2
- package/lib/core/zlib-streams-inline.js +1 -1
- package/lib/zip-core-base.js +7 -2
- package/package.json +9 -6
- package/reserved-property-names.js +50 -0
- package/lib/core/util/mini-lz.js +0 -198
package/lib/core/zip-reader.js
CHANGED
|
@@ -82,7 +82,8 @@ import {
|
|
|
82
82
|
COMPRESSION_METHOD_DEFLATE_64,
|
|
83
83
|
FILE_ATTR_UNIX_SETUID_MASK,
|
|
84
84
|
FILE_ATTR_UNIX_SETGID_MASK,
|
|
85
|
-
FILE_ATTR_UNIX_STICKY_MASK
|
|
85
|
+
FILE_ATTR_UNIX_STICKY_MASK,
|
|
86
|
+
EMPTY_UINT8_ARRAY
|
|
86
87
|
} from "./constants.js";
|
|
87
88
|
import {
|
|
88
89
|
getConfiguration,
|
|
@@ -138,6 +139,11 @@ import {
|
|
|
138
139
|
OPTION_CHECK_OVERLAPPING_ENTRY,
|
|
139
140
|
OPTION_CHECK_AMBIGUITY,
|
|
140
141
|
OPTION_CHECK_SIGNATURE,
|
|
142
|
+
OPTION_STRICTNESS,
|
|
143
|
+
OPTION_MAX_APPENDED_DATA_SIZE,
|
|
144
|
+
STRICTNESS_STRICT,
|
|
145
|
+
STRICTNESS_BALANCED,
|
|
146
|
+
STRICTNESS_TOLERANT,
|
|
141
147
|
OPTION_USE_WEB_WORKERS,
|
|
142
148
|
OPTION_USE_COMPRESSION_STREAM,
|
|
143
149
|
OPTION_TRANSFER_STREAMS,
|
|
@@ -159,8 +165,6 @@ const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
|
|
|
159
165
|
const CHARSET_UTF8 = "utf-8";
|
|
160
166
|
const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
|
|
161
167
|
const CHARSET_CP437 = "cp437";
|
|
162
|
-
// bits of the general purpose flag that change how an entry is interpreted; the level bits (1-2) are excluded
|
|
163
|
-
// because they are informative only
|
|
164
168
|
const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
|
|
165
169
|
const ZIP64_PROPERTIES = [
|
|
166
170
|
[PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
|
|
@@ -202,8 +206,11 @@ class ZipReader {
|
|
|
202
206
|
if (reader.size < END_OF_CENTRAL_DIR_LENGTH) {
|
|
203
207
|
throw new Error(ERR_BAD_FORMAT);
|
|
204
208
|
}
|
|
205
|
-
|
|
206
|
-
const
|
|
209
|
+
const strictness = getStrictness(getOptionValue(zipReader, options, OPTION_STRICTNESS), getOptionValue(zipReader, options, OPTION_CHECK_AMBIGUITY));
|
|
210
|
+
const checkAmbiguity = strictness == STRICTNESS_STRICT;
|
|
211
|
+
const rejectAmbiguousEndOfDirectory = strictness != STRICTNESS_TOLERANT;
|
|
212
|
+
const maxAppendedDataSize = getMaxAppendedDataSize(getOptionValue(zipReader, options, OPTION_MAX_APPENDED_DATA_SIZE), strictness);
|
|
213
|
+
const { endOfDirectoryInfo, endOfDirectoryReachingEndCount } = await findEndOfCentralDirectory(reader, rejectAmbiguousEndOfDirectory, maxAppendedDataSize);
|
|
207
214
|
if (!endOfDirectoryInfo) {
|
|
208
215
|
const signatureArray = await readUint8Array(reader, 0, 4);
|
|
209
216
|
const signatureView = getDataView(signatureArray);
|
|
@@ -213,14 +220,16 @@ class ZipReader {
|
|
|
213
220
|
throw new Error(ERR_EOCDR_NOT_FOUND);
|
|
214
221
|
}
|
|
215
222
|
}
|
|
223
|
+
if (rejectAmbiguousEndOfDirectory && endOfDirectoryReachingEndCount > 1) {
|
|
224
|
+
throwAmbiguousArchive("multiple end of central directory records");
|
|
225
|
+
}
|
|
216
226
|
const endOfDirectoryView = getDataView(endOfDirectoryInfo);
|
|
217
227
|
let directoryDataLength = getUint32(endOfDirectoryView, 12);
|
|
218
228
|
let directoryDataOffset = getUint32(endOfDirectoryView, 16);
|
|
219
229
|
const commentOffset = endOfDirectoryInfo.offset;
|
|
220
230
|
const commentLength = getUint16(endOfDirectoryView, 20);
|
|
221
231
|
const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
|
|
222
|
-
|
|
223
|
-
if (checkAmbiguity && appendedDataOffset != reader.size) {
|
|
232
|
+
if (reader.size - appendedDataOffset > maxAppendedDataSize) {
|
|
224
233
|
throwAmbiguousArchive("appended data");
|
|
225
234
|
}
|
|
226
235
|
let lastDiskNumber = getUint16(endOfDirectoryView, 4);
|
|
@@ -233,7 +242,7 @@ class ZipReader {
|
|
|
233
242
|
if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
|
|
234
243
|
const endOfDirectoryLocatorArray = endOfDirectoryInfo.offset >= ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH ?
|
|
235
244
|
await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH) :
|
|
236
|
-
|
|
245
|
+
EMPTY_UINT8_ARRAY;
|
|
237
246
|
const endOfDirectoryLocatorView = getDataView(endOfDirectoryLocatorArray);
|
|
238
247
|
if (endOfDirectoryLocatorArray.length == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH &&
|
|
239
248
|
getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
|
|
@@ -299,14 +308,22 @@ class ZipReader {
|
|
|
299
308
|
throw new Error(ERR_BAD_FORMAT);
|
|
300
309
|
}
|
|
301
310
|
const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength - (reader.lastDiskOffset || 0);
|
|
302
|
-
if (
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
if (
|
|
306
|
-
|
|
311
|
+
if (directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
|
|
312
|
+
const storedPointsAtDirectory = getUint32(directoryView, offset) == CENTRAL_FILE_HEADER_SIGNATURE;
|
|
313
|
+
let reconcile = !storedPointsAtDirectory;
|
|
314
|
+
if (!reconcile && expectedDirectoryDataOffset >= 0 && expectedDirectoryDataOffset + 4 <= reader.size) {
|
|
315
|
+
const expectedSignatureArray = await readUint8Array(reader, expectedDirectoryDataOffset, 4, diskNumber);
|
|
316
|
+
reconcile = getUint32(getDataView(expectedSignatureArray), 0) == CENTRAL_FILE_HEADER_SIGNATURE;
|
|
317
|
+
}
|
|
318
|
+
if (reconcile) {
|
|
319
|
+
const originalDirectoryDataOffset = directoryDataOffset;
|
|
320
|
+
directoryDataOffset = expectedDirectoryDataOffset;
|
|
321
|
+
if (directoryDataOffset > originalDirectoryDataOffset) {
|
|
322
|
+
prependedDataLength += directoryDataOffset - originalDirectoryDataOffset;
|
|
323
|
+
}
|
|
324
|
+
directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
|
|
325
|
+
directoryView = getDataView(directoryArray);
|
|
307
326
|
}
|
|
308
|
-
directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
|
|
309
|
-
directoryView = getDataView(directoryArray);
|
|
310
327
|
}
|
|
311
328
|
}
|
|
312
329
|
const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset - (reader.lastDiskOffset || 0);
|
|
@@ -448,11 +465,11 @@ class ZipReader {
|
|
|
448
465
|
const extractPrependedData = getOptionValue(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
|
|
449
466
|
const extractAppendedData = getOptionValue(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
|
|
450
467
|
if (extractPrependedData) {
|
|
451
|
-
zipReader.prependedData = startOffset > 0 ? await readUint8Array(reader, 0, startOffset) :
|
|
468
|
+
zipReader.prependedData = startOffset > 0 ? await readUint8Array(reader, 0, startOffset) : EMPTY_UINT8_ARRAY;
|
|
452
469
|
}
|
|
453
|
-
zipReader.comment = commentLength ? await readUint8Array(reader, commentOffset + END_OF_CENTRAL_DIR_LENGTH, commentLength) :
|
|
470
|
+
zipReader.comment = commentLength ? await readUint8Array(reader, commentOffset + END_OF_CENTRAL_DIR_LENGTH, commentLength) : EMPTY_UINT8_ARRAY;
|
|
454
471
|
if (extractAppendedData) {
|
|
455
|
-
zipReader.appendedData = appendedDataOffset < reader.size ? await readUint8Array(reader, appendedDataOffset, reader.size - appendedDataOffset) :
|
|
472
|
+
zipReader.appendedData = appendedDataOffset < reader.size ? await readUint8Array(reader, appendedDataOffset, reader.size - appendedDataOffset) : EMPTY_UINT8_ARRAY;
|
|
456
473
|
}
|
|
457
474
|
return true;
|
|
458
475
|
}
|
|
@@ -584,8 +601,8 @@ class ZipEntry {
|
|
|
584
601
|
extraFieldLength,
|
|
585
602
|
filenameLength
|
|
586
603
|
} = localDirectory;
|
|
587
|
-
const checkAmbiguity = getOptionValue(zipEntry, options, OPTION_CHECK_AMBIGUITY);
|
|
588
|
-
let rawLocalFilename =
|
|
604
|
+
const checkAmbiguity = getStrictness(getOptionValue(zipEntry, options, OPTION_STRICTNESS), getOptionValue(zipEntry, options, OPTION_CHECK_AMBIGUITY)) == STRICTNESS_STRICT;
|
|
605
|
+
let rawLocalFilename = EMPTY_UINT8_ARRAY;
|
|
589
606
|
if (checkAmbiguity && (filenameLength || extraFieldLength)) {
|
|
590
607
|
const trailingDataArray = await readUint8Array(reader, offset + HEADER_SIZE, filenameLength + extraFieldLength, diskNumberStart);
|
|
591
608
|
rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
|
|
@@ -593,7 +610,7 @@ class ZipEntry {
|
|
|
593
610
|
} else {
|
|
594
611
|
localDirectory.rawExtraField = extraFieldLength ?
|
|
595
612
|
await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
|
|
596
|
-
|
|
613
|
+
EMPTY_UINT8_ARRAY;
|
|
597
614
|
}
|
|
598
615
|
readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
|
|
599
616
|
if (checkAmbiguity) {
|
|
@@ -620,12 +637,7 @@ class ZipEntry {
|
|
|
620
637
|
}
|
|
621
638
|
const dataOffset = offset + HEADER_SIZE + filenameLength + extraFieldLength;
|
|
622
639
|
const size = compressedSize;
|
|
623
|
-
const readable = reader.
|
|
624
|
-
Object.assign(readable, {
|
|
625
|
-
diskNumberStart,
|
|
626
|
-
offset: dataOffset,
|
|
627
|
-
size
|
|
628
|
-
});
|
|
640
|
+
const readable = reader.createReadable({ offset: dataOffset, size, diskNumberStart, chunkSize: getChunkSize(config) });
|
|
629
641
|
const signal = getOptionValue(zipEntry, options, OPTION_SIGNAL);
|
|
630
642
|
const checkPasswordOnly = getOptionValue(zipEntry, options, OPTION_CHECK_PASSWORD_ONLY);
|
|
631
643
|
let checkOverlappingEntry = getOptionValue(zipEntry, options, OPTION_CHECK_OVERLAPPING_ENTRY);
|
|
@@ -896,7 +908,6 @@ function readExtraFieldUnix(extraField, directory, isInfoZip) {
|
|
|
896
908
|
const view = getDataView(new Uint8Array(extraField.data));
|
|
897
909
|
let uid, gid;
|
|
898
910
|
if (isInfoZip) {
|
|
899
|
-
// Info-ZIP New Unix "ux" field (0x7875): version + variable-length uid/gid
|
|
900
911
|
let offset = 0;
|
|
901
912
|
const version = getUint8(view, offset++);
|
|
902
913
|
const uidSize = getUint8(view, offset++);
|
|
@@ -906,8 +917,6 @@ function readExtraFieldUnix(extraField, directory, isInfoZip) {
|
|
|
906
917
|
gid = unpackUnixId(extraField.data.subarray(offset, offset + gidSize));
|
|
907
918
|
Object.assign(extraField, { version, uid, gid });
|
|
908
919
|
} else if (extraField.data.length >= 4) {
|
|
909
|
-
// Info-ZIP Unix "Ux" field (0x7855): fixed 2-byte uid + gid (the file mode, if any, is
|
|
910
|
-
// carried in the external file attributes, not here)
|
|
911
920
|
uid = getUint16(view, 0);
|
|
912
921
|
gid = getUint16(view, 2);
|
|
913
922
|
Object.assign(extraField, { uid, gid });
|
|
@@ -959,7 +968,6 @@ function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory,
|
|
|
959
968
|
timeProperties.forEach((propertyName, indexProperty) => {
|
|
960
969
|
if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
|
|
961
970
|
const time = getUint32(extraFieldView, offset);
|
|
962
|
-
// the extended timestamp is a signed 32-bit time_t value
|
|
963
971
|
directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date((time | 0) * 1000);
|
|
964
972
|
const rawPropertyName = timeRawProperties[indexProperty];
|
|
965
973
|
extraFieldExtendedTimestamp[rawPropertyName] = time;
|
|
@@ -1034,26 +1042,133 @@ async function detectOverlappingEntry({
|
|
|
1034
1042
|
readRanges.set(index, range);
|
|
1035
1043
|
}
|
|
1036
1044
|
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1045
|
+
function getStrictness(strictness, checkAmbiguity) {
|
|
1046
|
+
if (strictness === UNDEFINED_VALUE) {
|
|
1047
|
+
return checkAmbiguity ? STRICTNESS_STRICT : STRICTNESS_BALANCED;
|
|
1048
|
+
}
|
|
1049
|
+
return strictness;
|
|
1050
|
+
}
|
|
1043
1051
|
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1052
|
+
function getMaxAppendedDataSize(maxAppendedDataSize, strictness) {
|
|
1053
|
+
if (maxAppendedDataSize !== UNDEFINED_VALUE) {
|
|
1054
|
+
return maxAppendedDataSize;
|
|
1055
|
+
}
|
|
1056
|
+
if (strictness == STRICTNESS_STRICT) {
|
|
1057
|
+
return 0;
|
|
1058
|
+
}
|
|
1059
|
+
if (strictness == STRICTNESS_TOLERANT) {
|
|
1060
|
+
return Infinity;
|
|
1061
|
+
}
|
|
1062
|
+
return MAX_16_BITS;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
const MAX_END_OF_CENTRAL_DIR_PROBES = 64;
|
|
1066
|
+
|
|
1067
|
+
const CENTRAL_DIRECTORY_UNREACHABLE = 0;
|
|
1068
|
+
const CENTRAL_DIRECTORY_PLAUSIBLE = 1;
|
|
1069
|
+
const CENTRAL_DIRECTORY_REACHABLE = 2;
|
|
1070
|
+
|
|
1071
|
+
async function findEndOfCentralDirectory(reader, rejectAmbiguous, maxAppendedDataSize) {
|
|
1072
|
+
const { size } = reader;
|
|
1073
|
+
const anchoredLength = Math.min(size, END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS);
|
|
1074
|
+
const remoteProbeBudget = { count: MAX_END_OF_CENTRAL_DIR_PROBES };
|
|
1075
|
+
let endOfDirectoryInfo;
|
|
1076
|
+
let plausibleEndOfDirectoryInfo;
|
|
1077
|
+
let endOfDirectoryReachingEndCount = 0;
|
|
1078
|
+
for await (const [anchoredView, anchoredOffset, anchoredArray, indexByte, offset] of scanEndOfCentralDirectory(reader, anchoredLength)) {
|
|
1079
|
+
const commentLength = getUint16(anchoredView, indexByte + 20);
|
|
1080
|
+
if (offset + END_OF_CENTRAL_DIR_LENGTH + commentLength == size) {
|
|
1081
|
+
const reachability = await getCentralDirectoryReachability(reader, anchoredView, anchoredOffset, indexByte, offset, size, remoteProbeBudget);
|
|
1082
|
+
if (reachability == CENTRAL_DIRECTORY_REACHABLE) {
|
|
1083
|
+
if (!endOfDirectoryInfo) {
|
|
1084
|
+
endOfDirectoryInfo = getEndOfCentralDirectoryInfo(anchoredArray, indexByte, offset);
|
|
1085
|
+
}
|
|
1086
|
+
endOfDirectoryReachingEndCount++;
|
|
1087
|
+
if (!rejectAmbiguous || endOfDirectoryReachingEndCount > 1) {
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
} else if (reachability == CENTRAL_DIRECTORY_PLAUSIBLE && !plausibleEndOfDirectoryInfo) {
|
|
1091
|
+
plausibleEndOfDirectoryInfo = getEndOfCentralDirectoryInfo(anchoredArray, indexByte, offset);
|
|
1054
1092
|
}
|
|
1055
1093
|
}
|
|
1056
1094
|
}
|
|
1095
|
+
if (!endOfDirectoryInfo) {
|
|
1096
|
+
endOfDirectoryInfo = plausibleEndOfDirectoryInfo;
|
|
1097
|
+
}
|
|
1098
|
+
if (!endOfDirectoryInfo) {
|
|
1099
|
+
endOfDirectoryInfo = await seekEndOfCentralDirectory(reader, maxAppendedDataSize, remoteProbeBudget);
|
|
1100
|
+
}
|
|
1101
|
+
return { endOfDirectoryInfo, endOfDirectoryReachingEndCount };
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
async function seekEndOfCentralDirectory(reader, maxAppendedDataSize, remoteProbeBudget) {
|
|
1105
|
+
const { size } = reader;
|
|
1106
|
+
const searchLength = Math.min(size, maxAppendedDataSize == Infinity ? size :
|
|
1107
|
+
END_OF_CENTRAL_DIR_LENGTH + MAX_16_BITS + maxAppendedDataSize);
|
|
1108
|
+
let firstSignatureInfo, plausibleInfo;
|
|
1109
|
+
for await (const [searchView, searchOffset, searchArray, indexByte, offset] of scanEndOfCentralDirectory(reader, searchLength)) {
|
|
1110
|
+
const record = getEndOfCentralDirectoryInfo(searchArray, indexByte, offset);
|
|
1111
|
+
if (!firstSignatureInfo) {
|
|
1112
|
+
firstSignatureInfo = record;
|
|
1113
|
+
}
|
|
1114
|
+
const reachability = await getCentralDirectoryReachability(reader, searchView, searchOffset, indexByte, offset, size, remoteProbeBudget);
|
|
1115
|
+
if (reachability == CENTRAL_DIRECTORY_REACHABLE) {
|
|
1116
|
+
return record;
|
|
1117
|
+
}
|
|
1118
|
+
if (reachability == CENTRAL_DIRECTORY_PLAUSIBLE && !plausibleInfo) {
|
|
1119
|
+
plausibleInfo = record;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return plausibleInfo || firstSignatureInfo;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
async function* scanEndOfCentralDirectory(reader, scanLength) {
|
|
1126
|
+
const scanOffset = reader.size - scanLength;
|
|
1127
|
+
const scanArray = await readUint8Array(reader, scanOffset, scanLength);
|
|
1128
|
+
const scanView = getDataView(scanArray);
|
|
1129
|
+
for (let indexByte = scanArray.length - END_OF_CENTRAL_DIR_LENGTH; indexByte >= 0; indexByte--) {
|
|
1130
|
+
if (getUint32(scanView, indexByte) == END_OF_CENTRAL_DIR_SIGNATURE) {
|
|
1131
|
+
yield [scanView, scanOffset, scanArray, indexByte, scanOffset + indexByte];
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
function getEndOfCentralDirectoryInfo(scanArray, indexByte, offset) {
|
|
1137
|
+
return { offset, buffer: scanArray.slice(indexByte, indexByte + END_OF_CENTRAL_DIR_LENGTH).buffer };
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
async function getCentralDirectoryReachability(reader, view, anchoredOffset, indexByte, offset, size, remoteProbeBudget) {
|
|
1141
|
+
const filesLength = getUint16(view, indexByte + 10);
|
|
1142
|
+
const directoryDataLength = getUint32(view, indexByte + 12);
|
|
1143
|
+
const directoryDataOffset = getUint32(view, indexByte + 16);
|
|
1144
|
+
if (filesLength == MAX_16_BITS || directoryDataLength == MAX_32_BITS || directoryDataOffset == MAX_32_BITS) {
|
|
1145
|
+
const locatorSignature = await readSignature(reader, view, anchoredOffset, offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, size, remoteProbeBudget);
|
|
1146
|
+
return locatorSignature == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE ? CENTRAL_DIRECTORY_REACHABLE : CENTRAL_DIRECTORY_UNREACHABLE;
|
|
1147
|
+
}
|
|
1148
|
+
if (!filesLength && !directoryDataLength) {
|
|
1149
|
+
return CENTRAL_DIRECTORY_PLAUSIBLE;
|
|
1150
|
+
}
|
|
1151
|
+
for (const centralDirectoryOffset of [offset - directoryDataLength, directoryDataOffset]) {
|
|
1152
|
+
if (await readSignature(reader, view, anchoredOffset, centralDirectoryOffset, size, remoteProbeBudget) == CENTRAL_FILE_HEADER_SIGNATURE) {
|
|
1153
|
+
return CENTRAL_DIRECTORY_REACHABLE;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return CENTRAL_DIRECTORY_UNREACHABLE;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
async function readSignature(reader, view, anchoredOffset, signatureOffset, size, remoteProbeBudget) {
|
|
1160
|
+
if (signatureOffset < 0 || signatureOffset + 4 > size) {
|
|
1161
|
+
return UNDEFINED_VALUE;
|
|
1162
|
+
}
|
|
1163
|
+
if (signatureOffset >= anchoredOffset) {
|
|
1164
|
+
return getUint32(view, signatureOffset - anchoredOffset);
|
|
1165
|
+
}
|
|
1166
|
+
if (remoteProbeBudget.count > 0) {
|
|
1167
|
+
remoteProbeBudget.count--;
|
|
1168
|
+
const signatureArray = await readUint8Array(reader, signatureOffset, 4);
|
|
1169
|
+
return getUint32(getDataView(signatureArray), 0);
|
|
1170
|
+
}
|
|
1171
|
+
return UNDEFINED_VALUE;
|
|
1057
1172
|
}
|
|
1058
1173
|
|
|
1059
1174
|
function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
|
|
@@ -1068,8 +1183,6 @@ function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
|
|
|
1068
1183
|
if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
|
|
1069
1184
|
throwAmbiguousArchive("mismatched local file header (compression method)");
|
|
1070
1185
|
}
|
|
1071
|
-
// when the data descriptor flag is set, the local signature and sizes are zeroed out; all-zero values are
|
|
1072
|
-
// also tolerated when the flag is clear because some tools produce them (streaming writers predating bit 3)
|
|
1073
1186
|
if (!localDirectory.bitFlag.dataDescriptor &&
|
|
1074
1187
|
(localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
|
|
1075
1188
|
(localDirectory.signature != zipEntry.signature ||
|
|
@@ -1118,10 +1231,6 @@ function getBigUint64(view, offset) {
|
|
|
1118
1231
|
return Number(view.getBigUint64(offset, true));
|
|
1119
1232
|
}
|
|
1120
1233
|
|
|
1121
|
-
function setUint32(view, offset, value) {
|
|
1122
|
-
view.setUint32(offset, value, true);
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
1234
|
function getDataView(array) {
|
|
1126
1235
|
return new DataView(array.buffer, array.byteOffset, array.byteLength);
|
|
1127
1236
|
}
|
package/lib/core/zip-writer.js
CHANGED
|
@@ -137,7 +137,8 @@ import {
|
|
|
137
137
|
MAX_DATE,
|
|
138
138
|
UNDEFINED_VALUE,
|
|
139
139
|
INFINITY_VALUE,
|
|
140
|
-
OBJECT_TYPE
|
|
140
|
+
OBJECT_TYPE,
|
|
141
|
+
EMPTY_UINT8_ARRAY
|
|
141
142
|
} from "./constants.js";
|
|
142
143
|
import {
|
|
143
144
|
getConfiguration,
|
|
@@ -218,7 +219,6 @@ const ERR_INVALID_VERSION = "Version exceeds 65535";
|
|
|
218
219
|
const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
|
|
219
220
|
const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
|
|
220
221
|
const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
|
|
221
|
-
// same message as the constant exported by zip-reader.js
|
|
222
222
|
const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
|
|
223
223
|
const MIN_UNIX_TIME = -2147483648;
|
|
224
224
|
const MAX_UNIX_TIME = 2147483647;
|
|
@@ -301,12 +301,12 @@ class ZipWriter {
|
|
|
301
301
|
rawExtraField,
|
|
302
302
|
} = entry;
|
|
303
303
|
const { level, languageEncodingFlag, dataDescriptor } = bitFlag;
|
|
304
|
-
rawExtraFieldZip64 = rawExtraFieldZip64 ||
|
|
305
|
-
rawExtraFieldAES = rawExtraFieldAES ||
|
|
306
|
-
rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp ||
|
|
307
|
-
rawExtraFieldNTFS = rawExtraFieldNTFS ||
|
|
308
|
-
rawExtraFieldUnix = rawExtraFieldUnix ||
|
|
309
|
-
rawExtraField = rawExtraField ||
|
|
304
|
+
rawExtraFieldZip64 = rawExtraFieldZip64 || EMPTY_UINT8_ARRAY;
|
|
305
|
+
rawExtraFieldAES = rawExtraFieldAES || EMPTY_UINT8_ARRAY;
|
|
306
|
+
rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || EMPTY_UINT8_ARRAY;
|
|
307
|
+
rawExtraFieldNTFS = rawExtraFieldNTFS || EMPTY_UINT8_ARRAY;
|
|
308
|
+
rawExtraFieldUnix = rawExtraFieldUnix || EMPTY_UINT8_ARRAY;
|
|
309
|
+
rawExtraField = rawExtraField || EMPTY_UINT8_ARRAY;
|
|
310
310
|
if (entry.extraFieldAES) {
|
|
311
311
|
compressionMethod = COMPRESSION_METHOD_AES;
|
|
312
312
|
}
|
|
@@ -412,7 +412,7 @@ class ZipWriter {
|
|
|
412
412
|
return false;
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
-
async close(comment =
|
|
415
|
+
async close(comment = EMPTY_UINT8_ARRAY, options = {}) {
|
|
416
416
|
const zipWriter = this;
|
|
417
417
|
const { pendingAddFileCalls, writer } = this;
|
|
418
418
|
const { writable } = writer;
|
|
@@ -728,7 +728,7 @@ function resolveMetadata(zipWriter, name, options) {
|
|
|
728
728
|
if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
|
|
729
729
|
throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
|
|
730
730
|
}
|
|
731
|
-
let rawExtraField =
|
|
731
|
+
let rawExtraField = EMPTY_UINT8_ARRAY;
|
|
732
732
|
const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
|
|
733
733
|
if (extraField) {
|
|
734
734
|
let extraFieldSize = 0;
|
|
@@ -789,8 +789,6 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
|
|
|
789
789
|
let maximumCompressedSize = 0;
|
|
790
790
|
let uncompressedSize = 0;
|
|
791
791
|
if (passThrough) {
|
|
792
|
-
// the headers of a passThrough entry describe the payload verbatim: without a
|
|
793
|
-
// reader they would declare content that is not there
|
|
794
792
|
if (!reader) {
|
|
795
793
|
throw new Error(ERR_UNDEFINED_READER);
|
|
796
794
|
}
|
|
@@ -801,8 +799,6 @@ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, op
|
|
|
801
799
|
}
|
|
802
800
|
const zip64Enabled = zip64 === true;
|
|
803
801
|
const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
|
|
804
|
-
// entries without a reader have no payload: write them as empty stored files instead of
|
|
805
|
-
// declaring a compressed or encrypted content that does not exist
|
|
806
802
|
const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
|
|
807
803
|
if (!reader) {
|
|
808
804
|
level = 0;
|
|
@@ -940,7 +936,6 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
|
|
|
940
936
|
fileEntry.diskNumberStart = writer.diskNumber;
|
|
941
937
|
fileEntry.offset = getSegmentOffset(zipWriter, writer);
|
|
942
938
|
if (usdz) {
|
|
943
|
-
// the padding depends on the entry offset, only known now that the writer is locked
|
|
944
939
|
const previousMetadataSize = entryInfo.metadataSize;
|
|
945
940
|
appendExtraFieldUSDZ(entryInfo, zipWriter.offset - writer.diskOffset);
|
|
946
941
|
fileEntry.size += entryInfo.metadataSize - previousMetadataSize;
|
|
@@ -983,6 +978,13 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
|
|
|
983
978
|
if (releaseLockWriter) {
|
|
984
979
|
releaseLockWriter();
|
|
985
980
|
}
|
|
981
|
+
if (bufferedWrite && fileWriter && fileWriter.dispose) {
|
|
982
|
+
try {
|
|
983
|
+
await fileWriter.dispose();
|
|
984
|
+
} catch {
|
|
985
|
+
// ignored
|
|
986
|
+
}
|
|
987
|
+
}
|
|
986
988
|
}
|
|
987
989
|
|
|
988
990
|
function requestLockCurrentFileEntry() {
|
|
@@ -1002,7 +1004,7 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
|
|
|
1002
1004
|
async function skipDiskIfNeeded() {
|
|
1003
1005
|
if (getLength(headerInfo.localHeaderArray) > writer.availableSize) {
|
|
1004
1006
|
writer.availableSize = 0;
|
|
1005
|
-
await writeData(writer,
|
|
1007
|
+
await writeData(writer, EMPTY_UINT8_ARRAY);
|
|
1006
1008
|
}
|
|
1007
1009
|
}
|
|
1008
1010
|
}
|
|
@@ -1113,8 +1115,7 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
|
|
|
1113
1115
|
}
|
|
1114
1116
|
const { writable } = writer;
|
|
1115
1117
|
if (reader) {
|
|
1116
|
-
reader.chunkSize
|
|
1117
|
-
const readable = reader.readable;
|
|
1118
|
+
const readable = reader.createReadable ? reader.createReadable({ chunkSize: getChunkSize(config) }) : reader.readable;
|
|
1118
1119
|
const size = reader.size;
|
|
1119
1120
|
const workerOptions = {
|
|
1120
1121
|
options: {
|
|
@@ -1214,13 +1215,9 @@ function getHeaderInfo(options) {
|
|
|
1214
1215
|
: compressionMethod !== COMPRESSION_METHOD_STORE);
|
|
1215
1216
|
let rawLocalExtraFieldZip64;
|
|
1216
1217
|
const uncompressedFile = passThrough || !compressed;
|
|
1217
|
-
// entries without a data descriptor are always buffered (cf. getFileEntry), so the
|
|
1218
|
-
// zip64 extra field values can be patched into the local header before flushing it
|
|
1219
1218
|
const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
|
|
1220
1219
|
const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
|
|
1221
1220
|
if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
|
|
1222
|
-
// APPNOTE 4.5.3: the zip64 extra field of a local header must include both the
|
|
1223
|
-
// uncompressed and compressed size fields
|
|
1224
1221
|
const length = 4 + 16;
|
|
1225
1222
|
const extraFieldZip64 = createRecordWriter(length);
|
|
1226
1223
|
extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
|
|
@@ -1234,7 +1231,7 @@ function getHeaderInfo(options) {
|
|
|
1234
1231
|
}
|
|
1235
1232
|
}
|
|
1236
1233
|
} else {
|
|
1237
|
-
rawLocalExtraFieldZip64 =
|
|
1234
|
+
rawLocalExtraFieldZip64 = EMPTY_UINT8_ARRAY;
|
|
1238
1235
|
}
|
|
1239
1236
|
let rawExtraFieldAES;
|
|
1240
1237
|
if (encrypted && !zipCrypto) {
|
|
@@ -1244,7 +1241,7 @@ function getHeaderInfo(options) {
|
|
|
1244
1241
|
rawExtraFieldAES = extraFieldAES.array;
|
|
1245
1242
|
rawExtraFieldAES[8] = encryptionStrength;
|
|
1246
1243
|
} else {
|
|
1247
|
-
rawExtraFieldAES =
|
|
1244
|
+
rawExtraFieldAES = EMPTY_UINT8_ARRAY;
|
|
1248
1245
|
}
|
|
1249
1246
|
let rawExtraFieldNTFS;
|
|
1250
1247
|
let rawExtraFieldExtendedTimestamp;
|
|
@@ -1267,8 +1264,7 @@ function getHeaderInfo(options) {
|
|
|
1267
1264
|
}
|
|
1268
1265
|
rawExtraFieldExtendedTimestamp = extraFieldTimestamp.array;
|
|
1269
1266
|
} else {
|
|
1270
|
-
|
|
1271
|
-
rawExtraFieldExtendedTimestamp = new Uint8Array();
|
|
1267
|
+
rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
|
|
1272
1268
|
}
|
|
1273
1269
|
try {
|
|
1274
1270
|
const lastModTimeNTFS = getTimeNTFS(lastModDate);
|
|
@@ -1283,10 +1279,10 @@ function getHeaderInfo(options) {
|
|
|
1283
1279
|
extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
|
|
1284
1280
|
rawExtraFieldNTFS = extraFieldNTFS.array;
|
|
1285
1281
|
} catch {
|
|
1286
|
-
rawExtraFieldNTFS =
|
|
1282
|
+
rawExtraFieldNTFS = EMPTY_UINT8_ARRAY;
|
|
1287
1283
|
}
|
|
1288
1284
|
} else {
|
|
1289
|
-
rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp =
|
|
1285
|
+
rawExtraFieldNTFS = rawExtraFieldExtendedTimestamp = EMPTY_UINT8_ARRAY;
|
|
1290
1286
|
}
|
|
1291
1287
|
let rawExtraFieldUnix;
|
|
1292
1288
|
try {
|
|
@@ -1312,10 +1308,10 @@ function getHeaderInfo(options) {
|
|
|
1312
1308
|
extraFieldUnix.uint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
|
|
1313
1309
|
rawExtraFieldUnix = extraFieldUnix.array;
|
|
1314
1310
|
} else {
|
|
1315
|
-
rawExtraFieldUnix =
|
|
1311
|
+
rawExtraFieldUnix = EMPTY_UINT8_ARRAY;
|
|
1316
1312
|
}
|
|
1317
1313
|
} catch {
|
|
1318
|
-
rawExtraFieldUnix =
|
|
1314
|
+
rawExtraFieldUnix = EMPTY_UINT8_ARRAY;
|
|
1319
1315
|
}
|
|
1320
1316
|
if (compressionMethod === UNDEFINED_VALUE) {
|
|
1321
1317
|
compressionMethod = compressed ? COMPRESSION_METHOD_DEFLATE : COMPRESSION_METHOD_STORE;
|
|
@@ -1382,7 +1378,7 @@ function getHeaderInfo(options) {
|
|
|
1382
1378
|
version,
|
|
1383
1379
|
compressionMethod,
|
|
1384
1380
|
extraFieldExtendedTimestampFlag,
|
|
1385
|
-
rawExtraFieldZip64:
|
|
1381
|
+
rawExtraFieldZip64: EMPTY_UINT8_ARRAY,
|
|
1386
1382
|
localExtraFieldZip64Length,
|
|
1387
1383
|
rawExtraFieldExtendedTimestamp,
|
|
1388
1384
|
rawExtraFieldNTFS,
|
|
@@ -1395,7 +1391,6 @@ function getHeaderInfo(options) {
|
|
|
1395
1391
|
function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
|
|
1396
1392
|
const { headerInfo } = entryInfo;
|
|
1397
1393
|
let { localHeaderArray, extraFieldLength } = headerInfo;
|
|
1398
|
-
let localHeaderArrayView;
|
|
1399
1394
|
let extraBytesLength = 64 - ((zipWriterOffset + getLength(localHeaderArray)) % 64);
|
|
1400
1395
|
if (extraBytesLength < 4) {
|
|
1401
1396
|
extraBytesLength += 64;
|
|
@@ -1408,7 +1403,7 @@ function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
|
|
|
1408
1403
|
headerInfo.localHeaderArray = localHeaderArray = new Uint8Array(getLength(previousLocalHeaderArray) + extraBytesLength);
|
|
1409
1404
|
arraySet(localHeaderArray, previousLocalHeaderArray);
|
|
1410
1405
|
arraySet(localHeaderArray, rawExtraFieldUSDZ, getLength(previousLocalHeaderArray));
|
|
1411
|
-
localHeaderArrayView = getDataView(localHeaderArray);
|
|
1406
|
+
const localHeaderArrayView = getDataView(localHeaderArray);
|
|
1412
1407
|
setUint16(localHeaderArrayView, 28, extraFieldLength + extraBytesLength);
|
|
1413
1408
|
headerInfo.localHeaderView = localHeaderArrayView;
|
|
1414
1409
|
entryInfo.metadataSize += extraBytesLength;
|
|
@@ -1416,7 +1411,7 @@ function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
|
|
|
1416
1411
|
|
|
1417
1412
|
function packUnixId(id) {
|
|
1418
1413
|
if (id === UNDEFINED_VALUE) {
|
|
1419
|
-
return
|
|
1414
|
+
return EMPTY_UINT8_ARRAY;
|
|
1420
1415
|
} else {
|
|
1421
1416
|
const dataArray = new Uint8Array(4);
|
|
1422
1417
|
const dataView = getDataView(dataArray);
|
|
@@ -1459,7 +1454,7 @@ function getDataDescriptorInfo({
|
|
|
1459
1454
|
dataDescriptor,
|
|
1460
1455
|
dataDescriptorSignature
|
|
1461
1456
|
}) {
|
|
1462
|
-
let dataDescriptorArray =
|
|
1457
|
+
let dataDescriptorArray = EMPTY_UINT8_ARRAY;
|
|
1463
1458
|
let dataDescriptorView, dataDescriptorOffset = 0;
|
|
1464
1459
|
let dataDescriptorLength = zip64 ? DATA_DESCRIPTOR_RECORD_ZIP_64_LENGTH : DATA_DESCRIPTOR_RECORD_LENGTH;
|
|
1465
1460
|
if (dataDescriptorSignature) {
|
|
@@ -1543,7 +1538,6 @@ function updateLocalHeader({
|
|
|
1543
1538
|
}
|
|
1544
1539
|
}
|
|
1545
1540
|
if (zip64 && localExtraFieldZip64Length) {
|
|
1546
|
-
// the local zip64 extra field always contains both size slots
|
|
1547
1541
|
const localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
|
|
1548
1542
|
setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
|
|
1549
1543
|
setBigUint64(localHeaderView, localHeaderOffset + 8, BigInt(compressedSize));
|
|
@@ -1597,7 +1591,7 @@ function createDirectoryRecords(files) {
|
|
|
1597
1591
|
}
|
|
1598
1592
|
rawExtraFieldZip64 = extraFieldZip64.array;
|
|
1599
1593
|
} else {
|
|
1600
|
-
rawExtraFieldZip64 =
|
|
1594
|
+
rawExtraFieldZip64 = EMPTY_UINT8_ARRAY;
|
|
1601
1595
|
}
|
|
1602
1596
|
fileEntry.rawExtraFieldZip64 = rawExtraFieldZip64;
|
|
1603
1597
|
fileEntry.zip64Offset = zip64Offset;
|
|
@@ -1612,7 +1606,7 @@ function createDirectoryRecords(files) {
|
|
|
1612
1606
|
extraFieldTimestamp.uint32(lastModTimeUnix);
|
|
1613
1607
|
rawExtraFieldTimestamp = extraFieldTimestamp.array;
|
|
1614
1608
|
} else {
|
|
1615
|
-
rawExtraFieldTimestamp =
|
|
1609
|
+
rawExtraFieldTimestamp = EMPTY_UINT8_ARRAY;
|
|
1616
1610
|
}
|
|
1617
1611
|
fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
|
|
1618
1612
|
const extraFieldLength = getLength(
|
|
@@ -1668,7 +1662,7 @@ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
|
|
|
1668
1662
|
await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
|
|
1669
1663
|
directoryDiskOffset = offset;
|
|
1670
1664
|
writer.availableSize = 0;
|
|
1671
|
-
await writeData(writer,
|
|
1665
|
+
await writeData(writer, EMPTY_UINT8_ARRAY);
|
|
1672
1666
|
}
|
|
1673
1667
|
if (indexFileEntry == 0) {
|
|
1674
1668
|
cdStartDiskNumber = writer.diskNumber;
|
|
@@ -1741,7 +1735,7 @@ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
|
|
|
1741
1735
|
const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
|
|
1742
1736
|
if (getLength(endOfdirectoryRecord.array) + commentLength > writer.availableSize) {
|
|
1743
1737
|
writer.availableSize = 0;
|
|
1744
|
-
await writeData(writer,
|
|
1738
|
+
await writeData(writer, EMPTY_UINT8_ARRAY);
|
|
1745
1739
|
}
|
|
1746
1740
|
lastDiskNumber = writer.diskNumber;
|
|
1747
1741
|
if (zip64) {
|
|
@@ -1838,7 +1832,6 @@ function getTimeUnix(date) {
|
|
|
1838
1832
|
return Math.floor(date.getTime() / 1000);
|
|
1839
1833
|
}
|
|
1840
1834
|
|
|
1841
|
-
// the extended timestamp extra field stores dates as signed 32-bit time_t values
|
|
1842
1835
|
function inUnixTimeRange(timeUnix) {
|
|
1843
1836
|
return timeUnix >= MIN_UNIX_TIME && timeUnix <= MAX_UNIX_TIME;
|
|
1844
1837
|
}
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
|
|
29
29
|
/* eslint-disable quotes */
|
|
30
30
|
|
|
31
|
-
import {
|
|
31
|
+
import { inflateRaw } from "./util/inflate.js";
|
|
32
|
+
import { base64Decode, base64Encode } from "./util/base64.js";
|
|
32
33
|
|
|
33
34
|
export function configureZlibModule(configure) {
|
|
34
35
|
const data = `__wasmBinary__`;
|
|
@@ -36,7 +37,7 @@ export function configureZlibModule(configure) {
|
|
|
36
37
|
configure({
|
|
37
38
|
wasmURI: () => {
|
|
38
39
|
if (!dataURI) {
|
|
39
|
-
dataURI = "data:application/wasm;base64," +
|
|
40
|
+
dataURI = "data:application/wasm;base64," + base64Encode(inflateRaw(base64Decode(data)));
|
|
40
41
|
}
|
|
41
42
|
return dataURI;
|
|
42
43
|
}
|