@zip.js/zip.js 2.8.50 → 2.8.52
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 +8 -3
- package/deno.json +1 -1
- package/dist/zip-core-external.js +88 -44
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +89 -43
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +460 -171
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +461 -170
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +460 -171
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +463 -170
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +463 -170
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +89 -43
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +89 -43
- package/dist/zip-native.min.js +1 -1
- package/dist/zip.js +89 -43
- package/dist/zip.min.js +1 -1
- package/index-native.cjs +463 -170
- package/index-native.min.js +1 -1
- package/index.cjs +463 -170
- package/index.d.cts +320 -9
- package/index.d.ts +320 -9
- package/index.min.js +1 -1
- package/lib/core/codec-worker.js +2 -0
- package/lib/core/constants.js +4 -0
- package/lib/core/io.js +32 -2
- package/lib/core/util/compatible-streams.js +3 -8
- package/lib/core/zip-entry.js +8 -0
- package/lib/core/zip-fs.js +289 -131
- package/lib/core/zip-reader.js +15 -6
- package/lib/core/zip-writer.js +135 -29
- package/lib/zip-core-writer.js +2 -0
- package/package.json +5 -5
package/lib/core/zip-fs.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global WritableStream, AbortController */
|
|
29
|
+
/* global WritableStream, AbortController, DOMException */
|
|
30
30
|
// deno-lint-ignore-file no-this-alias
|
|
31
31
|
|
|
32
32
|
import {
|
|
@@ -34,26 +34,31 @@ import {
|
|
|
34
34
|
Reader,
|
|
35
35
|
TextReader,
|
|
36
36
|
TextWriter,
|
|
37
|
+
getTextSize,
|
|
37
38
|
Data64URIReader,
|
|
38
39
|
Data64URIWriter,
|
|
39
40
|
Uint8ArrayReader,
|
|
40
41
|
Uint8ArrayWriter,
|
|
41
42
|
BlobReader,
|
|
42
43
|
BlobWriter,
|
|
43
|
-
HttpReader
|
|
44
|
+
HttpReader,
|
|
45
|
+
ownsWritable
|
|
44
46
|
} from "./io.js";
|
|
45
47
|
import {
|
|
46
48
|
ZipReader,
|
|
47
49
|
ERR_INVALID_PASSWORD
|
|
48
50
|
} from "./zip-reader.js";
|
|
49
51
|
import {
|
|
50
|
-
ZipWriter
|
|
52
|
+
ZipWriter,
|
|
53
|
+
getEntriesSize
|
|
51
54
|
} from "./zip-writer.js";
|
|
52
55
|
import {
|
|
53
56
|
Entry
|
|
54
57
|
} from "./zip-entry.js";
|
|
58
|
+
import { ProgressWatcherStream, callHandler } from "./codec-worker.js";
|
|
55
59
|
import {
|
|
56
60
|
UNDEFINED_VALUE,
|
|
61
|
+
FUNCTION_TYPE,
|
|
57
62
|
EXTRAFIELD_TYPE_ZIP64,
|
|
58
63
|
EXTRAFIELD_TYPE_AES,
|
|
59
64
|
EXTRAFIELD_TYPE_NTFS,
|
|
@@ -71,7 +76,10 @@ import { toCompatibleReadable, toCompatibleWritable } from "./util/compatible-st
|
|
|
71
76
|
|
|
72
77
|
const ERR_ENTRY_EXISTS = "Entry filename already exists";
|
|
73
78
|
const ERR_READABLE_CONSUMED = "Readable stream already consumed";
|
|
79
|
+
const ERR_INVALID_PASS_THROUGH = "Invalid passThrough option (use readerOptions.passThrough or set uncompressedSize for each entry)";
|
|
74
80
|
const ERR_ABORT_EXPORT = "zipjs-abort-export";
|
|
81
|
+
const ERR_ABORTED = "The operation was aborted";
|
|
82
|
+
const ABORT_ERROR_NAME = "AbortError";
|
|
75
83
|
const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
|
|
76
84
|
const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
|
|
77
85
|
EXTRAFIELD_TYPE_ZIP64,
|
|
@@ -106,6 +114,7 @@ class ZipEntry {
|
|
|
106
114
|
parent,
|
|
107
115
|
children: [],
|
|
108
116
|
uncompressedSize: params.uncompressedSize || 0,
|
|
117
|
+
undeterminedSize: params.undeterminedSize || params.uncompressedSize === UNDEFINED_VALUE,
|
|
109
118
|
passThrough: params.passThrough
|
|
110
119
|
});
|
|
111
120
|
if (parent || !fs.root) {
|
|
@@ -173,16 +182,17 @@ class ZipFileEntry extends ZipEntry {
|
|
|
173
182
|
|
|
174
183
|
async getData(writer, options = {}) {
|
|
175
184
|
const zipEntry = this;
|
|
176
|
-
if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) {
|
|
185
|
+
if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data && keepsContentType(writer, zipEntry.data))) {
|
|
177
186
|
return zipEntry.data;
|
|
178
187
|
} else {
|
|
179
188
|
const reader = zipEntry.reader = createReader(zipEntry.Reader, zipEntry.data, options);
|
|
180
|
-
const
|
|
181
|
-
await Promise.all([initStream(reader), initStream(writer,
|
|
182
|
-
const { readable } = reader;
|
|
189
|
+
const dataSize = zipEntry.uncompressedSize || reader.size;
|
|
190
|
+
await Promise.all([initStream(reader), initStream(writer, dataSize)]);
|
|
183
191
|
const { signal } = options;
|
|
192
|
+
const readable = createProgressReadable(zipEntry, reader, options, signal);
|
|
193
|
+
const preventClose = !ownsWritable(writer) && Boolean(options.preventClose);
|
|
184
194
|
zipEntry.uncompressedSize = reader.size;
|
|
185
|
-
await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal });
|
|
195
|
+
await toCompatibleReadable(readable).pipeTo(toCompatibleWritable(writer.writable), { signal, preventClose, preventAbort: preventClose });
|
|
186
196
|
return writer.getData ? writer.getData() : writer.writable;
|
|
187
197
|
}
|
|
188
198
|
}
|
|
@@ -313,7 +323,7 @@ class ZipDirectoryEntry extends ZipEntry {
|
|
|
313
323
|
Reader: TextReader,
|
|
314
324
|
Writer: TextWriter,
|
|
315
325
|
options,
|
|
316
|
-
uncompressedSize: text
|
|
326
|
+
uncompressedSize: getTextSize(text)
|
|
317
327
|
});
|
|
318
328
|
}
|
|
319
329
|
|
|
@@ -442,10 +452,16 @@ class ZipDirectoryEntry extends ZipEntry {
|
|
|
442
452
|
}
|
|
443
453
|
|
|
444
454
|
async importZip(reader, options = {}) {
|
|
445
|
-
|
|
446
|
-
|
|
455
|
+
let zipReader;
|
|
456
|
+
if (reader && typeof reader.getEntries == FUNCTION_TYPE) {
|
|
457
|
+
zipReader = reader;
|
|
458
|
+
options = Object.assign({}, zipReader.options, options);
|
|
459
|
+
} else {
|
|
460
|
+
await initStream(reader);
|
|
461
|
+
zipReader = new ZipReader(reader, options);
|
|
462
|
+
}
|
|
447
463
|
const importedEntries = [];
|
|
448
|
-
const entries = await zipReader.getEntries();
|
|
464
|
+
const entries = await zipReader.getEntries(options);
|
|
449
465
|
for (const entry of entries) {
|
|
450
466
|
let parent = this;
|
|
451
467
|
try {
|
|
@@ -467,7 +483,7 @@ class ZipDirectoryEntry extends ZipEntry {
|
|
|
467
483
|
importedEntries.push(addChild(parent, name, {
|
|
468
484
|
data: entry,
|
|
469
485
|
Reader: getZipBlobReader(Object.assign({}, options)),
|
|
470
|
-
uncompressedSize: entry.uncompressedSize,
|
|
486
|
+
uncompressedSize: options.passThrough ? entry.compressedSize : entry.uncompressedSize,
|
|
471
487
|
passThrough: options.passThrough
|
|
472
488
|
}));
|
|
473
489
|
} else {
|
|
@@ -509,11 +525,25 @@ class ZipDirectoryEntry extends ZipEntry {
|
|
|
509
525
|
}
|
|
510
526
|
const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
|
|
511
527
|
const zipWriter = new ZipWriter(writer, options);
|
|
512
|
-
await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry],
|
|
513
|
-
await zipWriter.close();
|
|
528
|
+
await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], getUncompressedSize), options, readers);
|
|
529
|
+
await zipWriter.close(options.globalComment);
|
|
514
530
|
return writer.getData ? writer.getData() : writer.writable;
|
|
515
531
|
}
|
|
516
532
|
|
|
533
|
+
getExportedSize(options = {}) {
|
|
534
|
+
const zipEntry = this;
|
|
535
|
+
options = Object.assign({}, options);
|
|
536
|
+
if (options.bufferedWrite === UNDEFINED_VALUE) {
|
|
537
|
+
options.bufferedWrite = true;
|
|
538
|
+
}
|
|
539
|
+
const writeOrderGuaranteed = !options.bufferedWrite ||
|
|
540
|
+
(options.keepOrder !== false && zipEntry.children.every(child => !child.children.length));
|
|
541
|
+
return getEntriesSize(options, Array.from(zipEntry.getChildren({ recursive: true }), child => {
|
|
542
|
+
const { name, entryOptions } = getChildEntryOptions(child, zipEntry, options);
|
|
543
|
+
return { name, size: child.directory ? 0 : getDeterminedSize(child, isPassThrough(child, options)), options: entryOptions };
|
|
544
|
+
}), writeOrderGuaranteed, options.globalComment);
|
|
545
|
+
}
|
|
546
|
+
|
|
517
547
|
getChildByName(name) {
|
|
518
548
|
const children = this.children;
|
|
519
549
|
for (let childIndex = 0; childIndex < children.length; childIndex++) {
|
|
@@ -524,6 +554,10 @@ class ZipDirectoryEntry extends ZipEntry {
|
|
|
524
554
|
}
|
|
525
555
|
}
|
|
526
556
|
|
|
557
|
+
getChildren(options = {}) {
|
|
558
|
+
return collectChildren(this, options.recursive);
|
|
559
|
+
}
|
|
560
|
+
|
|
527
561
|
isPasswordProtected() {
|
|
528
562
|
const children = this.children;
|
|
529
563
|
for (let childIndex = 0; childIndex < children.length; childIndex++) {
|
|
@@ -615,6 +649,10 @@ class FS {
|
|
|
615
649
|
return this.root.getChildByName(name);
|
|
616
650
|
}
|
|
617
651
|
|
|
652
|
+
getChildren(options) {
|
|
653
|
+
return this.root.getChildren(options);
|
|
654
|
+
}
|
|
655
|
+
|
|
618
656
|
addDirectory(name, options) {
|
|
619
657
|
return this.root.addDirectory(name, options);
|
|
620
658
|
}
|
|
@@ -713,6 +751,10 @@ class FS {
|
|
|
713
751
|
return this.root.exportZip(writer, options);
|
|
714
752
|
}
|
|
715
753
|
|
|
754
|
+
getExportedSize(options) {
|
|
755
|
+
return this.root.getExportedSize(options);
|
|
756
|
+
}
|
|
757
|
+
|
|
716
758
|
isPasswordProtected() {
|
|
717
759
|
return this.root.isPasswordProtected();
|
|
718
760
|
}
|
|
@@ -723,14 +765,14 @@ class FS {
|
|
|
723
765
|
}
|
|
724
766
|
|
|
725
767
|
const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
|
|
726
|
-
export { fs, ERR_ENTRY_EXISTS, ERR_READABLE_CONSUMED };
|
|
768
|
+
export { fs, ERR_ENTRY_EXISTS, ERR_READABLE_CONSUMED, ERR_INVALID_PASS_THROUGH, ERR_ABORTED };
|
|
727
769
|
|
|
728
|
-
function getTotalSize(entries,
|
|
770
|
+
function getTotalSize(entries, getEntrySize) {
|
|
729
771
|
let size = 0;
|
|
730
772
|
const pendingEntries = Array.from(entries);
|
|
731
773
|
while (pendingEntries.length) {
|
|
732
774
|
const entry = pendingEntries.pop();
|
|
733
|
-
size += entry
|
|
775
|
+
size += getEntrySize(entry) || 0;
|
|
734
776
|
for (const child of entry.children) {
|
|
735
777
|
pendingEntries.push(child);
|
|
736
778
|
}
|
|
@@ -738,6 +780,15 @@ function getTotalSize(entries, propertyName) {
|
|
|
738
780
|
return size;
|
|
739
781
|
}
|
|
740
782
|
|
|
783
|
+
function getUncompressedSize(entry) {
|
|
784
|
+
return entry.uncompressedSize;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
function getExtractedSize(entry, passThrough) {
|
|
788
|
+
const { data } = entry;
|
|
789
|
+
return passThrough && data instanceof Entry ? data.compressedSize : entry.uncompressedSize;
|
|
790
|
+
}
|
|
791
|
+
|
|
741
792
|
function getReadableReader(readable) {
|
|
742
793
|
let consumed;
|
|
743
794
|
return function () {
|
|
@@ -760,10 +811,17 @@ function getZipBlobReader(options) {
|
|
|
760
811
|
|
|
761
812
|
async init() {
|
|
762
813
|
const zipBlobReader = this;
|
|
763
|
-
|
|
764
|
-
const
|
|
814
|
+
const readerOptions = Object.assign({}, options, zipBlobReader.options);
|
|
815
|
+
const { checkOverlappingEntry, checkOverlappingEntryOnly } = readerOptions;
|
|
816
|
+
const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign(readerOptions, {
|
|
817
|
+
checkPasswordOnly: false,
|
|
818
|
+
checkOverlappingEntry: checkOverlappingEntryOnly || checkOverlappingEntry,
|
|
819
|
+
checkOverlappingEntryOnly: false,
|
|
820
|
+
preventClose: false
|
|
821
|
+
}));
|
|
765
822
|
zipBlobReader.data = data;
|
|
766
823
|
zipBlobReader.blobReader = new BlobReader(data);
|
|
824
|
+
zipBlobReader.size = data.size;
|
|
767
825
|
super.init();
|
|
768
826
|
}
|
|
769
827
|
|
|
@@ -777,6 +835,30 @@ function createReader(Reader, data, options) {
|
|
|
777
835
|
return Reader.prototype ? new Reader(data, options) : Reader(data, options);
|
|
778
836
|
}
|
|
779
837
|
|
|
838
|
+
function keepsContentType(writer, data) {
|
|
839
|
+
const { contentType } = writer;
|
|
840
|
+
if (contentType === UNDEFINED_VALUE) {
|
|
841
|
+
return true;
|
|
842
|
+
} else if (writer.constructor == BlobWriter) {
|
|
843
|
+
return data.type == contentType;
|
|
844
|
+
} else if (writer.constructor == Data64URIWriter) {
|
|
845
|
+
return data.startsWith(writer.data);
|
|
846
|
+
} else {
|
|
847
|
+
return true;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function createProgressReadable(zipEntry, reader, options, signal) {
|
|
852
|
+
const { onstart, onprogress, onend } = options;
|
|
853
|
+
const { readable } = reader;
|
|
854
|
+
const coreReaderReportsProgress = zipEntry.data instanceof Entry;
|
|
855
|
+
if (coreReaderReportsProgress || (!onstart && !onprogress && !onend)) {
|
|
856
|
+
return readable;
|
|
857
|
+
} else {
|
|
858
|
+
return toCompatibleReadable(readable).pipeThrough(new ProgressWatcherStream({ onstart, onprogress, onend, size: reader.size }), { signal });
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
780
862
|
async function initReaders(entry, options) {
|
|
781
863
|
const fileEntries = [];
|
|
782
864
|
const pendingEntries = [entry];
|
|
@@ -809,6 +891,7 @@ async function initReaders(entry, options) {
|
|
|
809
891
|
}
|
|
810
892
|
if (reader.size !== UNDEFINED_VALUE) {
|
|
811
893
|
child.uncompressedSize = reader.size;
|
|
894
|
+
child.undeterminedSize = false;
|
|
812
895
|
}
|
|
813
896
|
}));
|
|
814
897
|
return readers;
|
|
@@ -858,6 +941,90 @@ function aggregateEntryErrors(errors) {
|
|
|
858
941
|
return error;
|
|
859
942
|
}
|
|
860
943
|
|
|
944
|
+
function getChildEntryOptions(child, selectedEntry, options) {
|
|
945
|
+
const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
|
|
946
|
+
const childOptions = child.options || {};
|
|
947
|
+
let zipEntryMetadata = {};
|
|
948
|
+
let passThroughOptions = {};
|
|
949
|
+
if (child.data instanceof Entry) {
|
|
950
|
+
const {
|
|
951
|
+
externalFileAttributes,
|
|
952
|
+
versionMadeBy,
|
|
953
|
+
comment,
|
|
954
|
+
lastModDate,
|
|
955
|
+
creationDate,
|
|
956
|
+
lastAccessDate,
|
|
957
|
+
uncompressedSize,
|
|
958
|
+
encrypted,
|
|
959
|
+
zipCrypto,
|
|
960
|
+
crc32,
|
|
961
|
+
compressionMethod,
|
|
962
|
+
extraFieldAES,
|
|
963
|
+
internalFileAttributes,
|
|
964
|
+
extraField,
|
|
965
|
+
uid,
|
|
966
|
+
gid
|
|
967
|
+
} = child.data;
|
|
968
|
+
zipEntryMetadata = {
|
|
969
|
+
externalFileAttributes,
|
|
970
|
+
versionMadeBy,
|
|
971
|
+
comment,
|
|
972
|
+
lastModDate,
|
|
973
|
+
creationDate,
|
|
974
|
+
lastAccessDate,
|
|
975
|
+
internalFileAttributes
|
|
976
|
+
};
|
|
977
|
+
const userExtraField = getUserExtraField(extraField);
|
|
978
|
+
if (userExtraField) {
|
|
979
|
+
zipEntryMetadata.extraField = userExtraField;
|
|
980
|
+
}
|
|
981
|
+
if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
|
|
982
|
+
Object.assign(zipEntryMetadata, {
|
|
983
|
+
uid,
|
|
984
|
+
gid,
|
|
985
|
+
unixExtraFieldType: INFOZIP_EXTRA_FIELD_TYPE
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
if (isPassThrough(child, options)) {
|
|
989
|
+
let level, encryptionStrength;
|
|
990
|
+
if (compressionMethod === 0) {
|
|
991
|
+
level = 0;
|
|
992
|
+
}
|
|
993
|
+
if (extraFieldAES) {
|
|
994
|
+
encryptionStrength = extraFieldAES.strength;
|
|
995
|
+
}
|
|
996
|
+
passThroughOptions = {
|
|
997
|
+
passThrough: true,
|
|
998
|
+
encrypted,
|
|
999
|
+
zipCrypto,
|
|
1000
|
+
crc32,
|
|
1001
|
+
uncompressedSize,
|
|
1002
|
+
level,
|
|
1003
|
+
encryptionStrength,
|
|
1004
|
+
compressionMethod
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
const entryOptions = Object.assign({}, zipEntryMetadata, options, passThroughOptions, childOptions, { directory: child.directory });
|
|
1009
|
+
if (!child.directory && entryOptions.passThrough && entryOptions.uncompressedSize === UNDEFINED_VALUE) {
|
|
1010
|
+
throw new Error(ERR_INVALID_PASS_THROUGH);
|
|
1011
|
+
}
|
|
1012
|
+
return { name, entryOptions };
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
function getDeterminedSize(child, passThrough) {
|
|
1016
|
+
const { reader } = child;
|
|
1017
|
+
if (reader && reader.size !== UNDEFINED_VALUE) {
|
|
1018
|
+
return reader.size;
|
|
1019
|
+
}
|
|
1020
|
+
return child.undeterminedSize ? UNDEFINED_VALUE : getExtractedSize(child, passThrough);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
function isPassThrough(child, options) {
|
|
1024
|
+
const { readerOptions } = options;
|
|
1025
|
+
return Boolean(!child.directory && (child.passThrough || (readerOptions && readerOptions.passThrough)));
|
|
1026
|
+
}
|
|
1027
|
+
|
|
861
1028
|
function getUserExtraField(extraField) {
|
|
862
1029
|
if (extraField) {
|
|
863
1030
|
const userExtraField = new Map();
|
|
@@ -873,104 +1040,53 @@ function getUserExtraField(extraField) {
|
|
|
873
1040
|
}
|
|
874
1041
|
|
|
875
1042
|
async function exportZip(zipWriter, entry, totalSize, options, readers) {
|
|
1043
|
+
const { onstart, onprogress, onend, onentryprogress } = options;
|
|
876
1044
|
const selectedEntry = entry;
|
|
877
|
-
const
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
await
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
throw errorResult.reason;
|
|
889
|
-
}
|
|
890
|
-
} else {
|
|
891
|
-
for (const child of entry.children) {
|
|
892
|
-
await processChild(child);
|
|
893
|
-
}
|
|
894
|
-
}
|
|
1045
|
+
const totalEntries = getTotalSize(entry.children, () => 1);
|
|
1046
|
+
let writtenSize = 0;
|
|
1047
|
+
let writtenEntries = 0;
|
|
1048
|
+
if (onstart) {
|
|
1049
|
+
await callHandler(onstart, totalSize);
|
|
1050
|
+
}
|
|
1051
|
+
if (options.bufferedWrite) {
|
|
1052
|
+
await processChildren(entry);
|
|
1053
|
+
} else {
|
|
1054
|
+
for (const child of entry.getChildren({ recursive: true })) {
|
|
1055
|
+
await addChild(child);
|
|
895
1056
|
}
|
|
1057
|
+
}
|
|
1058
|
+
if (onend) {
|
|
1059
|
+
await callHandler(onend, writtenSize);
|
|
1060
|
+
}
|
|
896
1061
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
} = child.data;
|
|
920
|
-
zipEntryOptions = {
|
|
921
|
-
externalFileAttributes,
|
|
922
|
-
versionMadeBy,
|
|
923
|
-
comment,
|
|
924
|
-
lastModDate,
|
|
925
|
-
creationDate,
|
|
926
|
-
lastAccessDate,
|
|
927
|
-
internalFileAttributes
|
|
928
|
-
};
|
|
929
|
-
const userExtraField = getUserExtraField(extraField);
|
|
930
|
-
if (userExtraField) {
|
|
931
|
-
zipEntryOptions.extraField = userExtraField;
|
|
932
|
-
}
|
|
933
|
-
if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
|
|
934
|
-
Object.assign(zipEntryOptions, {
|
|
935
|
-
uid,
|
|
936
|
-
gid,
|
|
937
|
-
unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
|
|
938
|
-
});
|
|
939
|
-
}
|
|
940
|
-
if (child.passThrough) {
|
|
941
|
-
let level, encryptionStrength;
|
|
942
|
-
if (compressionMethod === 0) {
|
|
943
|
-
level = 0;
|
|
944
|
-
}
|
|
945
|
-
if (extraFieldAES) {
|
|
946
|
-
encryptionStrength = extraFieldAES.strength;
|
|
947
|
-
}
|
|
948
|
-
zipEntryOptions = Object.assign(zipEntryOptions, {
|
|
949
|
-
passThrough: true,
|
|
950
|
-
encrypted,
|
|
951
|
-
zipCrypto,
|
|
952
|
-
crc32,
|
|
953
|
-
uncompressedSize,
|
|
954
|
-
level,
|
|
955
|
-
encryptionStrength,
|
|
956
|
-
compressionMethod
|
|
957
|
-
});
|
|
1062
|
+
async function processChildren(entry) {
|
|
1063
|
+
const results = await Promise.allSettled(entry.children.map(async child => {
|
|
1064
|
+
await addChild(child);
|
|
1065
|
+
await processChildren(child);
|
|
1066
|
+
}));
|
|
1067
|
+
const errorResult = results.find(result => result.status == "rejected");
|
|
1068
|
+
if (errorResult) {
|
|
1069
|
+
throw errorResult.reason;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
async function addChild(child) {
|
|
1074
|
+
const { name, entryOptions } = getChildEntryOptions(child, selectedEntry, options);
|
|
1075
|
+
let entryWrittenSize = 0;
|
|
1076
|
+
const entryMetadata = await zipWriter.add(name, readers.get(child), Object.assign(entryOptions, {
|
|
1077
|
+
onstart: UNDEFINED_VALUE,
|
|
1078
|
+
onend: UNDEFINED_VALUE,
|
|
1079
|
+
onprogress: async indexProgress => {
|
|
1080
|
+
writtenSize += indexProgress - entryWrittenSize;
|
|
1081
|
+
entryWrittenSize = indexProgress;
|
|
1082
|
+
if (onprogress) {
|
|
1083
|
+
await callHandler(onprogress, writtenSize, totalSize);
|
|
958
1084
|
}
|
|
959
1085
|
}
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
entryOffsets.set(name, indexProgress);
|
|
965
|
-
try {
|
|
966
|
-
await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
|
|
967
|
-
} catch {
|
|
968
|
-
// ignored
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
}));
|
|
973
|
-
await process(zipWriter, child);
|
|
1086
|
+
}));
|
|
1087
|
+
writtenEntries++;
|
|
1088
|
+
if (onentryprogress) {
|
|
1089
|
+
await callHandler(onentryprogress, writtenEntries, totalEntries, entryMetadata);
|
|
974
1090
|
}
|
|
975
1091
|
}
|
|
976
1092
|
}
|
|
@@ -999,7 +1115,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
|
|
|
999
1115
|
})
|
|
1000
1116
|
);
|
|
1001
1117
|
} else if (handle.kind == "directory") {
|
|
1002
|
-
const directoryEntry = parentEntry.addDirectory(handle.name);
|
|
1118
|
+
const directoryEntry = parentEntry.addDirectory(handle.name, options);
|
|
1003
1119
|
addedEntries.push(directoryEntry);
|
|
1004
1120
|
for await (const childHandle of handle.values()) {
|
|
1005
1121
|
await addFile(directoryEntry, childHandle, addedEntries, entryName);
|
|
@@ -1021,14 +1137,29 @@ function addFileSystemHandle(zipEntry, handle, options) {
|
|
|
1021
1137
|
}
|
|
1022
1138
|
|
|
1023
1139
|
async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
|
|
1024
|
-
const
|
|
1025
|
-
const writtenSizes = new Map();
|
|
1140
|
+
const { onstart, onprogress, onend } = options;
|
|
1026
1141
|
const abortController = new AbortController();
|
|
1027
1142
|
const { signal } = abortController;
|
|
1028
1143
|
const releaseSignal = forwardAbort(options.signal, abortController);
|
|
1144
|
+
const getDataOptions = Object.assign({}, options, options.readerOptions, {
|
|
1145
|
+
signal,
|
|
1146
|
+
onstart: UNDEFINED_VALUE,
|
|
1147
|
+
onprogress: UNDEFINED_VALUE,
|
|
1148
|
+
onend: UNDEFINED_VALUE,
|
|
1149
|
+
preventClose: false
|
|
1150
|
+
});
|
|
1151
|
+
const totalSize = getTotalSize([zipEntry], entry => getExtractedSize(entry, getDataOptions.passThrough));
|
|
1029
1152
|
const exportedEntryNames = [];
|
|
1153
|
+
let exportAborted = false;
|
|
1154
|
+
let writtenSize = 0;
|
|
1030
1155
|
try {
|
|
1156
|
+
if (onstart) {
|
|
1157
|
+
await callHandler(onstart, totalSize);
|
|
1158
|
+
}
|
|
1031
1159
|
await exportChildren(zipEntry, directoryHandle);
|
|
1160
|
+
if (onend) {
|
|
1161
|
+
await callHandler(onend, writtenSize);
|
|
1162
|
+
}
|
|
1032
1163
|
} catch (error) {
|
|
1033
1164
|
try {
|
|
1034
1165
|
error.exportedEntryNames = exportedEntryNames;
|
|
@@ -1041,6 +1172,25 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
|
|
|
1041
1172
|
}
|
|
1042
1173
|
return directoryHandle;
|
|
1043
1174
|
|
|
1175
|
+
function createProgressWritable(writable) {
|
|
1176
|
+
const writer = writable.getWriter();
|
|
1177
|
+
return new WritableStream({
|
|
1178
|
+
async write(chunk) {
|
|
1179
|
+
await writer.write(chunk);
|
|
1180
|
+
writtenSize += chunk.length;
|
|
1181
|
+
if (onprogress) {
|
|
1182
|
+
await callHandler(onprogress, writtenSize, totalSize);
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
close() {
|
|
1186
|
+
return writer.close();
|
|
1187
|
+
},
|
|
1188
|
+
abort(reason) {
|
|
1189
|
+
return writer.abort(reason);
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1044
1194
|
async function exportChildren(entry, parentHandle) {
|
|
1045
1195
|
if (options.concurrent) {
|
|
1046
1196
|
const results = await Promise.allSettled(entry.children.map(child => exportChild(child, parentHandle)));
|
|
@@ -1059,10 +1209,10 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
|
|
|
1059
1209
|
|
|
1060
1210
|
async function exportChild(child, parentHandle) {
|
|
1061
1211
|
if (signal.aborted) {
|
|
1062
|
-
if (isExportAborted(signal.reason)) {
|
|
1212
|
+
if (exportAborted || isExportAborted(signal.reason)) {
|
|
1063
1213
|
return;
|
|
1064
1214
|
}
|
|
1065
|
-
throw signal.reason;
|
|
1215
|
+
throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
|
|
1066
1216
|
}
|
|
1067
1217
|
try {
|
|
1068
1218
|
if (child.directory) {
|
|
@@ -1071,22 +1221,15 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
|
|
|
1071
1221
|
} else {
|
|
1072
1222
|
const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
|
|
1073
1223
|
const writable = await fileHandle.createWritable();
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
try {
|
|
1080
|
-
await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
|
|
1081
|
-
} catch {
|
|
1082
|
-
// ignored
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
}));
|
|
1224
|
+
try {
|
|
1225
|
+
await child.getData({ writable: createProgressWritable(writable) }, getDataOptions);
|
|
1226
|
+
} catch (error) {
|
|
1227
|
+
throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
|
|
1228
|
+
}
|
|
1087
1229
|
exportedEntryNames.push(child.getRelativeName(zipEntry));
|
|
1088
1230
|
}
|
|
1089
1231
|
} catch (error) {
|
|
1232
|
+
exportAborted = true;
|
|
1090
1233
|
abortController.abort(new Error(ERR_ABORT_EXPORT));
|
|
1091
1234
|
try {
|
|
1092
1235
|
if (error.entryName === UNDEFINED_VALUE) {
|
|
@@ -1158,6 +1301,21 @@ function resetFS(fs) {
|
|
|
1158
1301
|
fs.root = new ZipDirectoryEntry(fs);
|
|
1159
1302
|
}
|
|
1160
1303
|
|
|
1304
|
+
function collectChildren(directory, recursive) {
|
|
1305
|
+
const children = [];
|
|
1306
|
+
const pendingDirectories = [directory];
|
|
1307
|
+
let directoryIndex = 0;
|
|
1308
|
+
while (directoryIndex < pendingDirectories.length) {
|
|
1309
|
+
for (const child of pendingDirectories[directoryIndex++].children) {
|
|
1310
|
+
children.push(child);
|
|
1311
|
+
if (recursive) {
|
|
1312
|
+
pendingDirectories.push(child);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return children;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1161
1319
|
function registerEntries(fs, entry) {
|
|
1162
1320
|
const pendingEntries = [entry];
|
|
1163
1321
|
while (pendingEntries.length) {
|