@zip.js/zip.js 2.8.37 → 2.8.39
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 +0 -12
- package/deno.json +3 -2
- package/dist/zip-core.js +161 -38
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core.js +154 -38
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-native.js +163 -40
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +162 -39
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +163 -40
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +163 -40
- 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 +162 -39
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +163 -40
- package/index-native.min.js +1 -1
- package/index.cjs +162 -39
- package/index.d.cts +22 -2
- package/index.d.ts +22 -2
- package/index.min.js +1 -1
- package/lib/core/codec-pool.js +2 -1
- package/lib/core/codec-worker.js +94 -18
- package/lib/core/configuration.js +2 -0
- package/lib/core/constants.js +4 -0
- package/lib/core/io.js +1 -1
- package/lib/core/streams/codec-stream.js +6 -2
- package/lib/core/streams/zip-crypto-stream.js +1 -1
- package/lib/core/streams/zip-entry-stream.js +29 -12
- package/lib/core/web-worker-base.js +26 -8
- package/lib/core/web-worker-inline-native.js +1 -1
- package/lib/core/web-worker-inline-wasm.js +1 -1
- package/lib/core/zip-reader.js +23 -1
- package/lib/core/zip-writer.js +15 -7
- package/lib/zip-core-reader.js +2 -1
- package/package.json +1 -1
- package/worker-message-property-names.js +1 -1
package/dist/zip-fs-core.js
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50;
|
|
46
46
|
const SPLIT_ZIP_FILE_SIGNATURE = 0x08074b50;
|
|
47
47
|
const DATA_DESCRIPTOR_RECORD_SIGNATURE = SPLIT_ZIP_FILE_SIGNATURE;
|
|
48
|
+
const ARCHIVE_EXTRA_DATA_SIGNATURE = 0x08064b50;
|
|
48
49
|
const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
|
|
49
50
|
const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
|
|
50
51
|
const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
|
|
@@ -76,6 +77,7 @@
|
|
|
76
77
|
const BITFLAG_LEVEL_FAST_MASK = 0b100;
|
|
77
78
|
const BITFLAG_LEVEL_SUPER_FAST_MASK = 0b110;
|
|
78
79
|
const BITFLAG_DATA_DESCRIPTOR = 0b1000;
|
|
80
|
+
const BITFLAG_STRONG_ENCRYPTION = 0b1000000;
|
|
79
81
|
const BITFLAG_LANG_ENCODING_FLAG = 0b100000000000;
|
|
80
82
|
const FILE_ATTR_MSDOS_DIR_MASK = 0b10000;
|
|
81
83
|
const FILE_ATTR_MSDOS_READONLY_MASK = 0x01;
|
|
@@ -159,6 +161,7 @@
|
|
|
159
161
|
maxWorkers,
|
|
160
162
|
terminateWorkerTimeout: 5000,
|
|
161
163
|
workerStarvationTimeout: 5000,
|
|
164
|
+
workerStartupTimeout: 5000,
|
|
162
165
|
useWebWorkers: true,
|
|
163
166
|
useCompressionStream: true,
|
|
164
167
|
transferStreams: true,
|
|
@@ -987,7 +990,7 @@
|
|
|
987
990
|
|
|
988
991
|
getDiskOffset(diskNumber) {
|
|
989
992
|
const { diskOffsets, size } = this;
|
|
990
|
-
const diskOffset = diskOffsets
|
|
993
|
+
const diskOffset = diskOffsets[diskNumber];
|
|
991
994
|
return diskOffset === UNDEFINED_VALUE ? size : diskOffset;
|
|
992
995
|
}
|
|
993
996
|
|
|
@@ -2575,7 +2578,7 @@
|
|
|
2575
2578
|
if (zipCrypto.password || zipCrypto.rawPassword) {
|
|
2576
2579
|
const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
|
|
2577
2580
|
zipCrypto.password = zipCrypto.rawPassword = null;
|
|
2578
|
-
if ((decryptedHeader
|
|
2581
|
+
if ((decryptedHeader[HEADER_LENGTH - 1] ^ zipCrypto.passwordVerification) != 0) {
|
|
2579
2582
|
throw new Error(ERR_INVALID_PASSWORD);
|
|
2580
2583
|
}
|
|
2581
2584
|
chunk = chunk.subarray(HEADER_LENGTH);
|
|
@@ -2748,7 +2751,7 @@
|
|
|
2748
2751
|
readable = pipeThroughBackpressured(readable, new CompressionStream(FORMAT_GZIP));
|
|
2749
2752
|
readable = pipeThrough(readable, gzipCrc32Stream);
|
|
2750
2753
|
} else {
|
|
2751
|
-
readable =
|
|
2754
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamZlib);
|
|
2752
2755
|
}
|
|
2753
2756
|
}
|
|
2754
2757
|
if (encrypted) {
|
|
@@ -2833,7 +2836,7 @@
|
|
|
2833
2836
|
if (codecStreams) {
|
|
2834
2837
|
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize }));
|
|
2835
2838
|
} else {
|
|
2836
|
-
readable =
|
|
2839
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib);
|
|
2837
2840
|
}
|
|
2838
2841
|
readable = mapInflateStreamError(readable);
|
|
2839
2842
|
}
|
|
@@ -2852,6 +2855,25 @@
|
|
|
2852
2855
|
}
|
|
2853
2856
|
}
|
|
2854
2857
|
|
|
2858
|
+
const deflateRawSupportByStream = new Map();
|
|
2859
|
+
|
|
2860
|
+
function supportsDeflateRaw(StreamClass) {
|
|
2861
|
+
if (!StreamClass) {
|
|
2862
|
+
return false;
|
|
2863
|
+
}
|
|
2864
|
+
let supported = deflateRawSupportByStream.get(StreamClass);
|
|
2865
|
+
if (supported === UNDEFINED_VALUE) {
|
|
2866
|
+
try {
|
|
2867
|
+
new StreamClass(FORMAT_DEFLATE_RAW);
|
|
2868
|
+
supported = true;
|
|
2869
|
+
} catch {
|
|
2870
|
+
supported = false;
|
|
2871
|
+
}
|
|
2872
|
+
deflateRawSupportByStream.set(StreamClass, supported);
|
|
2873
|
+
}
|
|
2874
|
+
return supported;
|
|
2875
|
+
}
|
|
2876
|
+
|
|
2855
2877
|
function setReadable(stream, readable, flush) {
|
|
2856
2878
|
readable = pipeThrough(readable, new TransformStream({ flush }));
|
|
2857
2879
|
Object.defineProperty(stream, "readable", {
|
|
@@ -2868,21 +2890,17 @@
|
|
|
2868
2890
|
return new CodecStreamClass(format, options);
|
|
2869
2891
|
}
|
|
2870
2892
|
|
|
2871
|
-
function
|
|
2872
|
-
const Stream = useCompressionStream && CompressionStreamNative ?
|
|
2893
|
+
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib) {
|
|
2894
|
+
const Stream = useCompressionStream && CompressionStreamNative ?
|
|
2895
|
+
CompressionStreamNative :
|
|
2896
|
+
CompressionStreamZlib || CompressionStreamNative;
|
|
2873
2897
|
const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
|
|
2874
2898
|
let codecStream;
|
|
2875
2899
|
try {
|
|
2876
2900
|
codecStream = new Stream(format, options);
|
|
2877
2901
|
} catch (error) {
|
|
2878
|
-
if (useCompressionStream) {
|
|
2879
|
-
|
|
2880
|
-
codecStream = new CompressionStreamZlib(format, options);
|
|
2881
|
-
} else if (CompressionStream) {
|
|
2882
|
-
codecStream = new CompressionStream(format, options);
|
|
2883
|
-
} else {
|
|
2884
|
-
throw error;
|
|
2885
|
-
}
|
|
2902
|
+
if (useCompressionStream && CompressionStreamZlib && Stream != CompressionStreamZlib) {
|
|
2903
|
+
codecStream = new CompressionStreamZlib(format, options);
|
|
2886
2904
|
} else {
|
|
2887
2905
|
throw error;
|
|
2888
2906
|
}
|
|
@@ -3143,6 +3161,7 @@
|
|
|
3143
3161
|
const MODULE_WORKER_OPTIONS = { type: "module" };
|
|
3144
3162
|
const ERROR_EVENT_TYPE = "error";
|
|
3145
3163
|
const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
|
|
3164
|
+
const ERR_WORKER_STARTUP_TIMEOUT = "Worker startup timeout";
|
|
3146
3165
|
|
|
3147
3166
|
let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
|
|
3148
3167
|
let transferStreamsSupported = true;
|
|
@@ -3246,7 +3265,7 @@
|
|
|
3246
3265
|
}
|
|
3247
3266
|
|
|
3248
3267
|
function createWebWorkerInterface(workerData, config) {
|
|
3249
|
-
const { baseURI, chunkSize } = config;
|
|
3268
|
+
const { baseURI, chunkSize, workerStartupTimeout } = config;
|
|
3250
3269
|
let { wasmURI } = config;
|
|
3251
3270
|
|
|
3252
3271
|
if (!workerData.interface) {
|
|
@@ -3263,9 +3282,26 @@
|
|
|
3263
3282
|
}
|
|
3264
3283
|
Object.assign(workerData, {
|
|
3265
3284
|
worker,
|
|
3285
|
+
workerAlive: false,
|
|
3266
3286
|
terminated: false,
|
|
3267
3287
|
interface: {
|
|
3268
|
-
run: () =>
|
|
3288
|
+
run: async () => {
|
|
3289
|
+
try {
|
|
3290
|
+
return await runWebWorker(workerData, { chunkSize, wasmURI, baseURI, workerStartupTimeout });
|
|
3291
|
+
} catch (error) {
|
|
3292
|
+
if (error && error.workerStartupFailed) {
|
|
3293
|
+
webWorkerSupported = false;
|
|
3294
|
+
const { reader } = workerData;
|
|
3295
|
+
if (reader) {
|
|
3296
|
+
reader.releaseLock();
|
|
3297
|
+
}
|
|
3298
|
+
workerData.reader = null;
|
|
3299
|
+
workerData.writer = null;
|
|
3300
|
+
return runWorker$1(workerData, config);
|
|
3301
|
+
}
|
|
3302
|
+
throw error;
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3269
3305
|
}
|
|
3270
3306
|
});
|
|
3271
3307
|
}
|
|
@@ -3275,15 +3311,23 @@
|
|
|
3275
3311
|
async function runWorker$1({ options, readable, writable, onTaskFinished }, config) {
|
|
3276
3312
|
let codecStream;
|
|
3277
3313
|
try {
|
|
3278
|
-
if (!options.
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
config
|
|
3285
|
-
|
|
3286
|
-
|
|
3314
|
+
if (options.compressed && !options.format) {
|
|
3315
|
+
const deflate = options.codecType.startsWith(CODEC_DEFLATE);
|
|
3316
|
+
const ZlibStream = deflate ? config.CompressionStreamZlib : config.DecompressionStreamZlib;
|
|
3317
|
+
const NativeStream = deflate ? config.CompressionStream : config.DecompressionStream;
|
|
3318
|
+
if (!options.useCompressionStream) {
|
|
3319
|
+
try {
|
|
3320
|
+
await initModule(config);
|
|
3321
|
+
} catch {
|
|
3322
|
+
if (!ZlibStream || ZlibStream.requiresModule) {
|
|
3323
|
+
options.useCompressionStream = true;
|
|
3324
|
+
}
|
|
3325
|
+
}
|
|
3326
|
+
} else if (ZlibStream && ZlibStream.requiresModule && !supportsDeflateRaw(NativeStream)) {
|
|
3327
|
+
try {
|
|
3328
|
+
await initModule(config);
|
|
3329
|
+
} catch {
|
|
3330
|
+
// ignored
|
|
3287
3331
|
}
|
|
3288
3332
|
}
|
|
3289
3333
|
}
|
|
@@ -3352,6 +3396,10 @@
|
|
|
3352
3396
|
writer: writable.getWriter()
|
|
3353
3397
|
});
|
|
3354
3398
|
}
|
|
3399
|
+
const { workerStartupTimeout } = config;
|
|
3400
|
+
if (!workerData.workerAlive && Number.isFinite(workerStartupTimeout) && workerStartupTimeout >= 0) {
|
|
3401
|
+
workerData.startupTimeout = setTimeout(() => onStartupTimeout(workerData), workerStartupTimeout);
|
|
3402
|
+
}
|
|
3355
3403
|
try {
|
|
3356
3404
|
const resultValue = await result;
|
|
3357
3405
|
await closeWritable();
|
|
@@ -3464,28 +3512,68 @@
|
|
|
3464
3512
|
} else {
|
|
3465
3513
|
worker = new Worker(webWorkerURI, webWorkerOptions);
|
|
3466
3514
|
}
|
|
3467
|
-
worker.addEventListener(MESSAGE_EVENT_TYPE, event =>
|
|
3515
|
+
worker.addEventListener(MESSAGE_EVENT_TYPE, event => {
|
|
3516
|
+
workerData.workerAlive = true;
|
|
3517
|
+
clearStartupTimeout(workerData);
|
|
3518
|
+
onMessage(event, workerData);
|
|
3519
|
+
});
|
|
3468
3520
|
worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
|
|
3469
3521
|
worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
|
|
3470
3522
|
return worker;
|
|
3471
3523
|
}
|
|
3472
3524
|
|
|
3525
|
+
function onStartupTimeout(workerData) {
|
|
3526
|
+
workerData.startupTimeout = null;
|
|
3527
|
+
if (workerData.workerAlive) {
|
|
3528
|
+
return;
|
|
3529
|
+
}
|
|
3530
|
+
const { rejectResult, writer } = workerData;
|
|
3531
|
+
terminateWorker$1(workerData);
|
|
3532
|
+
workerData.worker = null;
|
|
3533
|
+
if (rejectResult) {
|
|
3534
|
+
const error = new Error(ERR_WORKER_STARTUP_TIMEOUT);
|
|
3535
|
+
error.workerStartupFailed = true;
|
|
3536
|
+
rejectResult(error);
|
|
3537
|
+
if (writer) {
|
|
3538
|
+
writer.releaseLock();
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
function clearStartupTimeout(workerData) {
|
|
3544
|
+
const { startupTimeout } = workerData;
|
|
3545
|
+
if (startupTimeout) {
|
|
3546
|
+
clearTimeout(startupTimeout);
|
|
3547
|
+
workerData.startupTimeout = null;
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3473
3551
|
function onWorkerError(event, workerData) {
|
|
3474
3552
|
if (event.preventDefault) {
|
|
3475
3553
|
event.preventDefault();
|
|
3476
3554
|
}
|
|
3477
|
-
|
|
3555
|
+
clearStartupTimeout(workerData);
|
|
3556
|
+
const { workerAlive, rejectResult, writer, onTaskFinished } = workerData;
|
|
3478
3557
|
terminateWorker$1(workerData);
|
|
3558
|
+
if (!workerAlive) {
|
|
3559
|
+
workerData.worker = null;
|
|
3560
|
+
}
|
|
3479
3561
|
if (rejectResult) {
|
|
3480
|
-
|
|
3562
|
+
let error = event.error || new Error(event.message || ERROR_EVENT_TYPE);
|
|
3563
|
+
if (!workerAlive) {
|
|
3564
|
+
error = Object.assign(new Error(error.message || ERROR_EVENT_TYPE), { workerStartupFailed: true });
|
|
3565
|
+
}
|
|
3566
|
+
rejectResult(error);
|
|
3481
3567
|
if (writer) {
|
|
3482
3568
|
writer.releaseLock();
|
|
3483
3569
|
}
|
|
3484
|
-
|
|
3570
|
+
if (workerAlive) {
|
|
3571
|
+
onTaskFinished();
|
|
3572
|
+
}
|
|
3485
3573
|
}
|
|
3486
3574
|
}
|
|
3487
3575
|
|
|
3488
|
-
function sendMessage(message, { worker, writer, transferStreams }) {
|
|
3576
|
+
function sendMessage(message, { worker, writer, transferStreams, workerAlive }) {
|
|
3489
3577
|
try {
|
|
3490
3578
|
const { value, readable, writable } = message;
|
|
3491
3579
|
const transferables = [];
|
|
@@ -3493,7 +3581,7 @@
|
|
|
3493
3581
|
message.value = toExactUint8Array(value);
|
|
3494
3582
|
transferables.push(message.value.buffer);
|
|
3495
3583
|
}
|
|
3496
|
-
if (transferStreams && transferStreamsSupported) {
|
|
3584
|
+
if (transferStreams && transferStreamsSupported && workerAlive) {
|
|
3497
3585
|
if (readable) {
|
|
3498
3586
|
transferables.push(readable);
|
|
3499
3587
|
}
|
|
@@ -4049,6 +4137,7 @@
|
|
|
4049
4137
|
const ERR_SPLIT_ZIP_FILE = "Split zip file";
|
|
4050
4138
|
const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
|
|
4051
4139
|
const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
|
|
4140
|
+
const ERR_ENCRYPTED_CENTRAL_DIRECTORY = "Encrypted central directory is not supported";
|
|
4052
4141
|
const CHARSET_UTF8 = "utf-8";
|
|
4053
4142
|
const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
|
|
4054
4143
|
const CHARSET_CP437 = "cp437";
|
|
@@ -4126,6 +4215,7 @@
|
|
|
4126
4215
|
let prependedDataLength = 0;
|
|
4127
4216
|
let startOffset;
|
|
4128
4217
|
let zip64EndOfDirectory;
|
|
4218
|
+
let zip64EndOfDirectoryVersion2;
|
|
4129
4219
|
const requiresZip64 = directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS;
|
|
4130
4220
|
if (directoryDataOffset != MAX_32_BITS && diskNumber != MAX_16_BITS) {
|
|
4131
4221
|
directoryDataOffset += getDiskOffset$1(reader, diskNumber);
|
|
@@ -4155,6 +4245,7 @@
|
|
|
4155
4245
|
throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
|
|
4156
4246
|
}
|
|
4157
4247
|
zip64EndOfDirectory = true;
|
|
4248
|
+
zip64EndOfDirectoryVersion2 = getBigUint64(endOfDirectoryView, 4) > ZIP64_END_OF_CENTRAL_DIR_LENGTH - 12;
|
|
4158
4249
|
if (lastDiskNumber == MAX_16_BITS) {
|
|
4159
4250
|
lastDiskNumber = getUint32(endOfDirectoryView, 16);
|
|
4160
4251
|
} else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
|
|
@@ -4234,6 +4325,9 @@
|
|
|
4234
4325
|
for (let indexFile = 0; indexFile < filesLength; indexFile++) {
|
|
4235
4326
|
const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
|
|
4236
4327
|
if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
|
|
4328
|
+
if (indexFile == 0 && (zip64EndOfDirectoryVersion2 || detectEncryptedCentralDirectory(directoryView))) {
|
|
4329
|
+
throw new Error(ERR_ENCRYPTED_CENTRAL_DIRECTORY);
|
|
4330
|
+
}
|
|
4237
4331
|
throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
|
|
4238
4332
|
}
|
|
4239
4333
|
readCommonHeader(fileEntry, directoryView, offset + 6);
|
|
@@ -4461,6 +4555,9 @@
|
|
|
4461
4555
|
fileEntry.zipCrypto = zipCrypto;
|
|
4462
4556
|
}
|
|
4463
4557
|
if (encrypted) {
|
|
4558
|
+
if ((localDirectory.rawBitFlag & BITFLAG_STRONG_ENCRYPTION) == BITFLAG_STRONG_ENCRYPTION) {
|
|
4559
|
+
throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
|
|
4560
|
+
}
|
|
4464
4561
|
if (!zipCrypto && (extraFieldAES.strength < 1 || extraFieldAES.strength > 3)) {
|
|
4465
4562
|
throw new Error(ERR_UNSUPPORTED_ENCRYPTION);
|
|
4466
4563
|
} else if (!password && !rawPassword) {
|
|
@@ -4554,6 +4651,16 @@
|
|
|
4554
4651
|
}
|
|
4555
4652
|
};
|
|
4556
4653
|
|
|
4654
|
+
function detectEncryptedCentralDirectory(directoryView) {
|
|
4655
|
+
const maxOffset = Math.min(directoryView.byteLength, 1024) - 3;
|
|
4656
|
+
for (let offset = 0; offset < maxOffset; offset++) {
|
|
4657
|
+
if (getUint32(directoryView, offset) == ARCHIVE_EXTRA_DATA_SIGNATURE) {
|
|
4658
|
+
return true;
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
return false;
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4557
4664
|
function readCommonHeader(directory, dataView, offset) {
|
|
4558
4665
|
const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2);
|
|
4559
4666
|
const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED;
|
|
@@ -5068,6 +5175,7 @@
|
|
|
5068
5175
|
ERR_BAD_FORMAT: ERR_BAD_FORMAT,
|
|
5069
5176
|
ERR_CENTRAL_DIRECTORY_NOT_FOUND: ERR_CENTRAL_DIRECTORY_NOT_FOUND,
|
|
5070
5177
|
ERR_ENCRYPTED: ERR_ENCRYPTED,
|
|
5178
|
+
ERR_ENCRYPTED_CENTRAL_DIRECTORY: ERR_ENCRYPTED_CENTRAL_DIRECTORY,
|
|
5071
5179
|
ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND: ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND,
|
|
5072
5180
|
ERR_EOCDR_NOT_FOUND: ERR_EOCDR_NOT_FOUND,
|
|
5073
5181
|
ERR_EXTRAFIELD_ZIP64_NOT_FOUND: ERR_EXTRAFIELD_ZIP64_NOT_FOUND,
|
|
@@ -5417,7 +5525,11 @@
|
|
|
5417
5525
|
if (versionMadeBy > MAX_16_BITS) {
|
|
5418
5526
|
throw new Error(ERR_INVALID_VERSION);
|
|
5419
5527
|
}
|
|
5420
|
-
let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES
|
|
5528
|
+
let externalFileAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_EXTERNAL_FILE_ATTRIBUTES);
|
|
5529
|
+
const externalFileAttributesProvided = externalFileAttributes !== UNDEFINED_VALUE;
|
|
5530
|
+
if (!externalFileAttributesProvided) {
|
|
5531
|
+
externalFileAttributes = 0;
|
|
5532
|
+
}
|
|
5421
5533
|
if (!options[PROPERTY_NAME_DIRECTORY] && name.endsWith(DIRECTORY_SIGNATURE)) {
|
|
5422
5534
|
options[PROPERTY_NAME_DIRECTORY] = true;
|
|
5423
5535
|
}
|
|
@@ -5426,13 +5538,13 @@
|
|
|
5426
5538
|
if (!name.endsWith(DIRECTORY_SIGNATURE)) {
|
|
5427
5539
|
name += DIRECTORY_SIGNATURE;
|
|
5428
5540
|
}
|
|
5429
|
-
if (
|
|
5541
|
+
if (!externalFileAttributesProvided) {
|
|
5430
5542
|
externalFileAttributes = FILE_ATTR_MSDOS_DIR_MASK;
|
|
5431
5543
|
if (!msDosCompatible) {
|
|
5432
5544
|
externalFileAttributes |= (FILE_ATTR_UNIX_TYPE_DIR | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_DEFAULT_MASK) << 16;
|
|
5433
5545
|
}
|
|
5434
5546
|
}
|
|
5435
|
-
} else if (!msDosCompatible &&
|
|
5547
|
+
} else if (!msDosCompatible && !externalFileAttributesProvided) {
|
|
5436
5548
|
if (executable) {
|
|
5437
5549
|
externalFileAttributes = (FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_DEFAULT_MASK) << 16;
|
|
5438
5550
|
} else {
|
|
@@ -5441,6 +5553,7 @@
|
|
|
5441
5553
|
}
|
|
5442
5554
|
let unixExternalUpper;
|
|
5443
5555
|
if (!msDosCompatible) {
|
|
5556
|
+
const unixModeProvided = unixMode !== UNDEFINED_VALUE || Boolean(setuid || setgid || sticky);
|
|
5444
5557
|
unixExternalUpper = (externalFileAttributes >> 16) & MAX_16_BITS;
|
|
5445
5558
|
unixMode = unixMode === UNDEFINED_VALUE ? unixExternalUpper : (unixMode & MAX_16_BITS);
|
|
5446
5559
|
if (setuid) {
|
|
@@ -5458,10 +5571,12 @@
|
|
|
5458
5571
|
} else {
|
|
5459
5572
|
sticky = Boolean(unixMode & FILE_ATTR_UNIX_STICKY_MASK);
|
|
5460
5573
|
}
|
|
5461
|
-
if (
|
|
5462
|
-
|
|
5574
|
+
if (!externalFileAttributesProvided || unixModeProvided) {
|
|
5575
|
+
if (directory) {
|
|
5576
|
+
unixMode |= FILE_ATTR_UNIX_TYPE_DIR;
|
|
5577
|
+
}
|
|
5578
|
+
externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_16_BITS);
|
|
5463
5579
|
}
|
|
5464
|
-
externalFileAttributes = ((unixMode & MAX_16_BITS) << 16) | (externalFileAttributes & MAX_8_BITS);
|
|
5465
5580
|
}
|
|
5466
5581
|
({ msdosAttributesRaw, msdosAttributes } = normalizeMsdosAttributes(msdosAttributesRaw, msdosAttributes));
|
|
5467
5582
|
if (hasMsDosProvided) {
|
|
@@ -6184,6 +6299,7 @@
|
|
|
6184
6299
|
if (extraFieldLength > MAX_16_BITS) {
|
|
6185
6300
|
throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
|
|
6186
6301
|
}
|
|
6302
|
+
const dosLastModDate = new Date(Math.ceil(lastModDate.getTime() / 2000) * 2000);
|
|
6187
6303
|
const {
|
|
6188
6304
|
headerArray,
|
|
6189
6305
|
headerView,
|
|
@@ -6193,7 +6309,7 @@
|
|
|
6193
6309
|
bitFlag: getBitFlag(level, useUnicodeFileNames, dataDescriptor, encrypted, compressionMethod),
|
|
6194
6310
|
compressionMethod,
|
|
6195
6311
|
uncompressedSize,
|
|
6196
|
-
lastModDate:
|
|
6312
|
+
lastModDate: dosLastModDate < MIN_DATE ? MIN_DATE : dosLastModDate > MAX_DATE ? MAX_DATE : dosLastModDate,
|
|
6197
6313
|
rawFilename,
|
|
6198
6314
|
zip64CompressedSize,
|
|
6199
6315
|
zip64UncompressedSize,
|