neozipkit 1.0.2 → 1.5.0
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/NEOZIP_APPNOTE.md +625 -0
- package/README.md +44 -11
- package/WHATS_NEW.md +153 -10
- package/dist/browser/ZipkitBrowser.d.ts.map +1 -1
- package/dist/browser/ZipkitBrowser.js +4 -6
- package/dist/browser/ZipkitBrowser.js.map +1 -1
- package/dist/browser/zstd-browser-shim.d.ts +17 -9
- package/dist/browser/zstd-browser-shim.d.ts.map +1 -1
- package/dist/browser/zstd-browser-shim.js +99 -21
- package/dist/browser/zstd-browser-shim.js.map +1 -1
- package/dist/browser-esm/index.js +6534 -1275
- package/dist/browser-esm/index.js.map +4 -4
- package/dist/browser-umd/index.js +6534 -1275
- package/dist/browser-umd/index.js.map +4 -4
- package/dist/browser-umd/index.min.js +6 -3
- package/dist/core/ZipCompress.d.ts +6 -0
- package/dist/core/ZipCompress.d.ts.map +1 -1
- package/dist/core/ZipCompress.js +12 -11
- package/dist/core/ZipCompress.js.map +1 -1
- package/dist/core/ZipCopy.d.ts.map +1 -1
- package/dist/core/ZipCopy.js +33 -25
- package/dist/core/ZipCopy.js.map +1 -1
- package/dist/core/ZipDecompress.d.ts.map +1 -1
- package/dist/core/ZipDecompress.js +13 -8
- package/dist/core/ZipDecompress.js.map +1 -1
- package/dist/core/ZipEntry.d.ts +24 -0
- package/dist/core/ZipEntry.d.ts.map +1 -1
- package/dist/core/ZipEntry.js +146 -14
- package/dist/core/ZipEntry.js.map +1 -1
- package/dist/core/Zipkit.d.ts +43 -11
- package/dist/core/Zipkit.d.ts.map +1 -1
- package/dist/core/Zipkit.js +132 -82
- package/dist/core/Zipkit.js.map +1 -1
- package/dist/core/components/HashCalculator.d.ts +22 -1
- package/dist/core/components/HashCalculator.d.ts.map +1 -1
- package/dist/core/components/HashCalculator.js +49 -6
- package/dist/core/components/HashCalculator.js.map +1 -1
- package/dist/core/components/Util.d.ts +3 -4
- package/dist/core/components/Util.d.ts.map +1 -1
- package/dist/core/components/Util.js +10 -8
- package/dist/core/components/Util.js.map +1 -1
- package/dist/core/constants/Headers.d.ts +2 -3
- package/dist/core/constants/Headers.d.ts.map +1 -1
- package/dist/core/constants/Headers.js +15 -5
- package/dist/core/constants/Headers.js.map +1 -1
- package/dist/core/constants/MetaPaths.d.ts +38 -0
- package/dist/core/constants/MetaPaths.d.ts.map +1 -0
- package/dist/core/constants/MetaPaths.js +79 -0
- package/dist/core/constants/MetaPaths.js.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +18 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/inflateZipPayload.d.ts +6 -0
- package/dist/core/inflateZipPayload.d.ts.map +1 -0
- package/dist/core/inflateZipPayload.js +28 -0
- package/dist/core/inflateZipPayload.js.map +1 -0
- package/dist/core/merkle/MerkleRoot.d.ts +109 -0
- package/dist/core/merkle/MerkleRoot.d.ts.map +1 -0
- package/dist/core/merkle/MerkleRoot.js +275 -0
- package/dist/core/merkle/MerkleRoot.js.map +1 -0
- package/dist/core/origin/OriginExtra.d.ts +43 -0
- package/dist/core/origin/OriginExtra.d.ts.map +1 -0
- package/dist/core/origin/OriginExtra.js +187 -0
- package/dist/core/origin/OriginExtra.js.map +1 -0
- package/dist/core/version.js +1 -1
- package/dist/core/zip64/Zip64.d.ts +138 -0
- package/dist/core/zip64/Zip64.d.ts.map +1 -0
- package/dist/core/zip64/Zip64.js +353 -0
- package/dist/core/zip64/Zip64.js.map +1 -0
- package/dist/node/ZipCompressNode.d.ts.map +1 -1
- package/dist/node/ZipCompressNode.js +40 -49
- package/dist/node/ZipCompressNode.js.map +1 -1
- package/dist/node/ZipCopyNode.d.ts.map +1 -1
- package/dist/node/ZipCopyNode.js +26 -26
- package/dist/node/ZipCopyNode.js.map +1 -1
- package/dist/node/ZipDecompressNode.d.ts.map +1 -1
- package/dist/node/ZipDecompressNode.js +21 -3
- package/dist/node/ZipDecompressNode.js.map +1 -1
- package/dist/node/ZipkitNode.d.ts +23 -1
- package/dist/node/ZipkitNode.d.ts.map +1 -1
- package/dist/node/ZipkitNode.js +158 -57
- package/dist/node/ZipkitNode.js.map +1 -1
- package/dist/node/ZstdNode.d.ts +14 -4
- package/dist/node/ZstdNode.d.ts.map +1 -1
- package/dist/node/ZstdNode.js +28 -4
- package/dist/node/ZstdNode.js.map +1 -1
- package/dist/node/buildZipBuffer.d.ts +49 -0
- package/dist/node/buildZipBuffer.d.ts.map +1 -0
- package/dist/node/buildZipBuffer.js +146 -0
- package/dist/node/buildZipBuffer.js.map +1 -0
- package/dist/node/index.d.ts +3 -0
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +6 -1
- package/dist/node/index.js.map +1 -1
- package/dist/node/inflateZipPayload.d.ts +5 -0
- package/dist/node/inflateZipPayload.d.ts.map +1 -0
- package/dist/node/inflateZipPayload.js +21 -0
- package/dist/node/inflateZipPayload.js.map +1 -0
- package/dist/types/index.js +2 -2
- package/node-esm.mjs +32 -0
- package/package.json +13 -6
- package/src/browser/ZipkitBrowser.ts +4 -6
- package/src/browser/zstd-browser-shim.ts +110 -28
- package/src/core/ZipCompress.ts +20 -13
- package/src/core/ZipCopy.ts +56 -27
- package/src/core/ZipDecompress.ts +14 -8
- package/src/core/ZipEntry.ts +200 -14
- package/src/core/Zipkit.ts +189 -98
- package/src/core/components/HashCalculator.ts +58 -6
- package/src/core/components/Util.ts +16 -7
- package/src/core/constants/Headers.ts +15 -4
- package/src/core/constants/MetaPaths.ts +86 -0
- package/src/core/index.ts +17 -0
- package/src/core/inflateZipPayload.ts +27 -0
- package/src/core/merkle/MerkleRoot.ts +312 -0
- package/src/core/origin/OriginExtra.ts +209 -0
- package/src/core/version.ts +1 -1
- package/src/core/zip64/Zip64.ts +473 -0
- package/src/node/ZipCompressNode.ts +40 -49
- package/src/node/ZipCopyNode.ts +31 -29
- package/src/node/ZipDecompressNode.ts +16 -3
- package/src/node/ZipkitNode.ts +203 -72
- package/src/node/ZstdNode.ts +33 -8
- package/src/node/buildZipBuffer.ts +221 -0
- package/src/node/index.ts +7 -0
- package/src/node/inflateZipPayload.ts +19 -0
- package/src/types/index.ts +2 -2
package/src/core/ZipEntry.ts
CHANGED
|
@@ -24,6 +24,17 @@ import {
|
|
|
24
24
|
import { ZipFileEntry, FileData } from '../types';
|
|
25
25
|
import { Logger } from './components/Logger';
|
|
26
26
|
import { crc32 } from './encryption/ZipCrypto';
|
|
27
|
+
import {
|
|
28
|
+
ZIP64_U16,
|
|
29
|
+
ZIP64_U32,
|
|
30
|
+
ZIP64_VERSION_NEEDED,
|
|
31
|
+
buildZip64Extra,
|
|
32
|
+
exceedsU16,
|
|
33
|
+
exceedsU32,
|
|
34
|
+
needsZip64Entry,
|
|
35
|
+
parseZip64Extra,
|
|
36
|
+
stripZip64FromExtra,
|
|
37
|
+
} from './zip64/Zip64';
|
|
27
38
|
|
|
28
39
|
const VER_ENCODING = 30;
|
|
29
40
|
const VER_EXTRACT = 10; // Version needed to extract (1.0)
|
|
@@ -49,6 +60,15 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
49
60
|
localHdrOffset: number = 0; // Relative offset to local header from File/Disk start
|
|
50
61
|
filename: string = ''; // File name
|
|
51
62
|
extraField: Buffer | null = null; // Extra field
|
|
63
|
+
/**
|
|
64
|
+
* Caller-supplied extra-field records (complete header id + size + payload).
|
|
65
|
+
* Written on the local header and the central-directory header beside 0x014E.
|
|
66
|
+
* Unknown ids parsed from an existing header (including ZipWiki 0x014F) are kept here
|
|
67
|
+
* so a later header rebuild does not drop them.
|
|
68
|
+
*/
|
|
69
|
+
additionalExtra: Buffer | null = null;
|
|
70
|
+
/** When false, local/central headers omit the Info-ZIP Unicode Path extra. */
|
|
71
|
+
emitUnicodePath = true;
|
|
52
72
|
comment: string | null = null; // Entry comment
|
|
53
73
|
|
|
54
74
|
// File Data
|
|
@@ -82,7 +102,14 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
82
102
|
universalTime: number | null = null; // Universal Time
|
|
83
103
|
uid: number | null = null; // User ID
|
|
84
104
|
gid: number | null = null; // Group ID
|
|
85
|
-
sha256: string | null = null; // SHA-256 hash of the file
|
|
105
|
+
sha256: string | null = null; // SHA-256 hash of the file (Extra Field 0x014E, bare content digest)
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* APPNOTE §6.3 v1 Merkle leaf: SHA-256(0x00 ‖ uncompressed payload).
|
|
109
|
+
* In-memory only (not written as a ZIP Extra today). Filled in the same streaming hash
|
|
110
|
+
* pass as `sha256` during create/extract — never reconstruct by re-reading payload when set.
|
|
111
|
+
*/
|
|
112
|
+
merkleLeafV1: string | null = null;
|
|
86
113
|
|
|
87
114
|
// Symbolic link data
|
|
88
115
|
isSymlink: boolean = false; // Entry is a symbolic link
|
|
@@ -93,6 +120,14 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
93
120
|
originalEntry: string | null = null; // Original entry name for hard links
|
|
94
121
|
inode: number | null = null; // Inode number for hard links
|
|
95
122
|
|
|
123
|
+
/** True when Zip64 extra (0x0001) was applied or will be emitted (8-byte data descriptors). */
|
|
124
|
+
usesZip64Extra: boolean = false;
|
|
125
|
+
/**
|
|
126
|
+
* When true, emit Zip64 Extra Field `0x0001` and version-needed 45 even if
|
|
127
|
+
* sizes/offsets fit classic u16/u32 fields (APPNOTE MAY; for testing).
|
|
128
|
+
*/
|
|
129
|
+
forceZip64: boolean = false;
|
|
130
|
+
|
|
96
131
|
fileData?: FileData;
|
|
97
132
|
|
|
98
133
|
/**
|
|
@@ -299,6 +334,31 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
299
334
|
this.neoCryptoFlags = _data.readUInt16LE(7);
|
|
300
335
|
}
|
|
301
336
|
}
|
|
337
|
+
} else if (_id === HDR_ID.ZIP64) {
|
|
338
|
+
const z64 = parseZip64Extra(_data, {
|
|
339
|
+
uncompressedSize: this.uncompressedSize,
|
|
340
|
+
compressedSize: this.compressedSize,
|
|
341
|
+
localHdrOffset: this.localHdrOffset,
|
|
342
|
+
diskStart: this.volNumber,
|
|
343
|
+
});
|
|
344
|
+
this.usesZip64Extra = true;
|
|
345
|
+
if (z64.uncompressedSize !== undefined) {
|
|
346
|
+
this.uncompressedSize = z64.uncompressedSize;
|
|
347
|
+
}
|
|
348
|
+
if (z64.compressedSize !== undefined) {
|
|
349
|
+
this.compressedSize = z64.compressedSize;
|
|
350
|
+
}
|
|
351
|
+
if (z64.localHdrOffset !== undefined) {
|
|
352
|
+
this.localHdrOffset = z64.localHdrOffset;
|
|
353
|
+
}
|
|
354
|
+
if (z64.diskStart !== undefined) {
|
|
355
|
+
this.volNumber = z64.diskStart;
|
|
356
|
+
}
|
|
357
|
+
} else if (_id !== HDR_ID.UNICODE_PATH) {
|
|
358
|
+
const rec = Buffer.from(this.extraField.subarray(i, i + 4 + _len));
|
|
359
|
+
this.additionalExtra = this.additionalExtra
|
|
360
|
+
? Buffer.concat([this.additionalExtra, rec])
|
|
361
|
+
: rec;
|
|
302
362
|
}
|
|
303
363
|
// Skip Unicode Path here as we already processed it
|
|
304
364
|
i += 4 + _len;
|
|
@@ -323,10 +383,30 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
323
383
|
* @returns true if the filename contains non-ASCII characters or special characters
|
|
324
384
|
*/
|
|
325
385
|
needsUnicodeHandling(): boolean {
|
|
386
|
+
if (!this.emitUnicodePath) return false;
|
|
326
387
|
// Check if filename contains non-ASCII characters or special characters like apostrophes
|
|
327
388
|
return /[^\x00-\x7E]|['"]/.test(this.filename);
|
|
328
389
|
}
|
|
329
390
|
|
|
391
|
+
/** Version needed to extract. Method 93 (zstd) is 6.3; Zip64 is 4.5. */
|
|
392
|
+
private versionNeededToExtract(): number {
|
|
393
|
+
let ver = VER_EXTRACT;
|
|
394
|
+
if (this.cmpMethod === CMP_METHOD.AES_ENCRYPT) ver = VER_AES_EXTRACT;
|
|
395
|
+
else if (this.cmpMethod === CMP_METHOD.ZSTD) ver = 63;
|
|
396
|
+
if (
|
|
397
|
+
this.forceZip64 ||
|
|
398
|
+
needsZip64Entry(
|
|
399
|
+
this.uncompressedSize,
|
|
400
|
+
this.compressedSize,
|
|
401
|
+
this.localHdrOffset,
|
|
402
|
+
this.volNumber
|
|
403
|
+
)
|
|
404
|
+
) {
|
|
405
|
+
ver = Math.max(ver, ZIP64_VERSION_NEEDED);
|
|
406
|
+
}
|
|
407
|
+
return ver;
|
|
408
|
+
}
|
|
409
|
+
|
|
330
410
|
/**
|
|
331
411
|
* Adds UTF-8 Unicode Path field to a buffer
|
|
332
412
|
* @param buffer - The buffer to write to
|
|
@@ -382,13 +462,38 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
382
462
|
if (isNeoEncrypt) {
|
|
383
463
|
extraFieldLen += NEO_CRYPTO_EXTRA_FIELD_SIZE;
|
|
384
464
|
}
|
|
465
|
+
|
|
466
|
+
const sha256Local = this.sha256 ? Buffer.from(this.sha256, 'hex') : null;
|
|
467
|
+
const sha256LocalLen = sha256Local && sha256Local.length > 0 ? 4 + sha256Local.length : 0;
|
|
468
|
+
const callerExtra = stripZip64FromExtra(this.additionalExtra);
|
|
469
|
+
const callerExtraLen = callerExtra?.length ?? 0;
|
|
470
|
+
|
|
471
|
+
const useZip64Sizes =
|
|
472
|
+
this.forceZip64 ||
|
|
473
|
+
exceedsU32(this.uncompressedSize) ||
|
|
474
|
+
exceedsU32(this.compressedSize);
|
|
475
|
+
if (useZip64Sizes) {
|
|
476
|
+
this.usesZip64Extra = true;
|
|
477
|
+
}
|
|
478
|
+
const zip64LocalExtra = useZip64Sizes
|
|
479
|
+
? buildZip64Extra(
|
|
480
|
+
{
|
|
481
|
+
uncompressedSize: this.uncompressedSize,
|
|
482
|
+
compressedSize: this.compressedSize,
|
|
483
|
+
},
|
|
484
|
+
{ forLocal: true }
|
|
485
|
+
)
|
|
486
|
+
: null;
|
|
487
|
+
const zip64LocalLen = zip64LocalExtra?.length ?? 0;
|
|
488
|
+
|
|
489
|
+
extraFieldLen += sha256LocalLen + callerExtraLen + zip64LocalLen;
|
|
385
490
|
|
|
386
491
|
const data = Buffer.alloc(LOCAL_HDR.SIZE + this.filename.length + extraFieldLen);
|
|
387
492
|
|
|
388
493
|
// "PK\003\004"
|
|
389
494
|
data.writeUInt32LE(LOCAL_HDR.SIGNATURE, 0);
|
|
390
495
|
// version needed to extract (NeoEncrypt keeps standard ZIP method — use normal extract version)
|
|
391
|
-
const verExtract = this.
|
|
496
|
+
const verExtract = this.versionNeededToExtract();
|
|
392
497
|
data.writeUInt16LE(verExtract, LOCAL_HDR.VER_EXTRACT);
|
|
393
498
|
// general purpose bit flag
|
|
394
499
|
data.writeUInt16LE(this.bitFlags >>> 0, LOCAL_HDR.FLAGS);
|
|
@@ -398,10 +503,15 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
398
503
|
data.writeUInt32LE(this.timeDateDOS >>> 0, LOCAL_HDR.TIMEDATE_DOS);
|
|
399
504
|
// uncompressed file crc-32 value (AE-2 stores 0)
|
|
400
505
|
data.writeUInt32LE(this.aesVersion === 2 ? 0 : this.crc, LOCAL_HDR.CRC);
|
|
401
|
-
// compressed
|
|
402
|
-
data.writeUInt32LE(
|
|
403
|
-
|
|
404
|
-
|
|
506
|
+
// compressed / uncompressed sizes (Zip64 sentinels when needed)
|
|
507
|
+
data.writeUInt32LE(
|
|
508
|
+
useZip64Sizes ? ZIP64_U32 : this.compressedSize,
|
|
509
|
+
LOCAL_HDR.CMP_SIZE
|
|
510
|
+
);
|
|
511
|
+
data.writeUInt32LE(
|
|
512
|
+
useZip64Sizes ? ZIP64_U32 : this.uncompressedSize,
|
|
513
|
+
LOCAL_HDR.UNCMP_SIZE
|
|
514
|
+
);
|
|
405
515
|
// filename length
|
|
406
516
|
data.writeUInt16LE(this.filename.length, LOCAL_HDR.FNAME_LEN);
|
|
407
517
|
// extra field length
|
|
@@ -420,6 +530,12 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
420
530
|
extraOffset = this.addUnicodePathField(data, extraOffset);
|
|
421
531
|
}
|
|
422
532
|
|
|
533
|
+
// Zip64 sizes first among optional extras so Node can patch them by scanning
|
|
534
|
+
if (zip64LocalExtra) {
|
|
535
|
+
zip64LocalExtra.copy(data, extraOffset);
|
|
536
|
+
extraOffset += zip64LocalLen;
|
|
537
|
+
}
|
|
538
|
+
|
|
423
539
|
// Add AES extra field
|
|
424
540
|
if (isAes) {
|
|
425
541
|
data.writeUInt16LE(HDR_ID.AES, extraOffset);
|
|
@@ -445,6 +561,17 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
445
561
|
extraOffset += NEO_CRYPTO_EXTRA_FIELD_SIZE;
|
|
446
562
|
}
|
|
447
563
|
|
|
564
|
+
if (sha256Local && sha256LocalLen > 0) {
|
|
565
|
+
data.writeUInt16LE(HDR_ID.SHA256, extraOffset);
|
|
566
|
+
data.writeUInt16LE(sha256Local.length, extraOffset + 2);
|
|
567
|
+
sha256Local.copy(data, extraOffset + 4);
|
|
568
|
+
extraOffset += sha256LocalLen;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (callerExtra && callerExtraLen > 0) {
|
|
572
|
+
callerExtra.copy(data, extraOffset);
|
|
573
|
+
}
|
|
574
|
+
|
|
448
575
|
return data;
|
|
449
576
|
}
|
|
450
577
|
|
|
@@ -485,7 +612,45 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
485
612
|
const isNeoEncrypt = this.neoCryptoAlgorithm > 0;
|
|
486
613
|
const neoLen = isNeoEncrypt ? NEO_CRYPTO_EXTRA_FIELD_SIZE : 0;
|
|
487
614
|
|
|
488
|
-
const
|
|
615
|
+
const callerExtra = stripZip64FromExtra(this.additionalExtra);
|
|
616
|
+
const callerExtraLen = callerExtra?.length ?? 0;
|
|
617
|
+
|
|
618
|
+
const zip64Fields: {
|
|
619
|
+
uncompressedSize?: number;
|
|
620
|
+
compressedSize?: number;
|
|
621
|
+
localHdrOffset?: number;
|
|
622
|
+
diskStart?: number;
|
|
623
|
+
} = {};
|
|
624
|
+
if (this.forceZip64 || exceedsU32(this.uncompressedSize)) {
|
|
625
|
+
zip64Fields.uncompressedSize = this.uncompressedSize;
|
|
626
|
+
}
|
|
627
|
+
if (this.forceZip64 || exceedsU32(this.compressedSize)) {
|
|
628
|
+
zip64Fields.compressedSize = this.compressedSize;
|
|
629
|
+
}
|
|
630
|
+
if (this.forceZip64 || exceedsU32(this.localHdrOffset)) {
|
|
631
|
+
zip64Fields.localHdrOffset = this.localHdrOffset;
|
|
632
|
+
}
|
|
633
|
+
if (exceedsU16(this.volNumber)) {
|
|
634
|
+
zip64Fields.diskStart = this.volNumber;
|
|
635
|
+
}
|
|
636
|
+
const zip64CentralExtra =
|
|
637
|
+
Object.keys(zip64Fields).length > 0 ? buildZip64Extra(zip64Fields) : null;
|
|
638
|
+
if (zip64CentralExtra) {
|
|
639
|
+
this.usesZip64Extra = true;
|
|
640
|
+
}
|
|
641
|
+
const zip64CentralLen = zip64CentralExtra?.length ?? 0;
|
|
642
|
+
|
|
643
|
+
const extraLen =
|
|
644
|
+
utfLen +
|
|
645
|
+
sha256Len +
|
|
646
|
+
uidgidLen +
|
|
647
|
+
symlinkLen +
|
|
648
|
+
hardlinkLen +
|
|
649
|
+
(needsUnicode ? unicodePathLen : 0) +
|
|
650
|
+
aesLen +
|
|
651
|
+
neoLen +
|
|
652
|
+
callerExtraLen +
|
|
653
|
+
zip64CentralLen;
|
|
489
654
|
|
|
490
655
|
// Calculate actual filename length (ASCII conversion may change length)
|
|
491
656
|
const asciiName = this.filename.replace(/[^\x00-\x7E]/g, '?');
|
|
@@ -499,7 +664,7 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
499
664
|
// Version made by - Needs to be set for NeoZip
|
|
500
665
|
data.writeUInt16LE(this.isUpdated ? this.VER_MADE_BY : this.verMadeBy, CENTRAL_DIR.VER_MADE);
|
|
501
666
|
// Version needed to extract
|
|
502
|
-
const centralVerExtract = this.
|
|
667
|
+
const centralVerExtract = this.versionNeededToExtract();
|
|
503
668
|
data.writeInt16LE(this.isUpdated ? centralVerExtract : this.verMadeBy, CENTRAL_DIR.VER_EXT);
|
|
504
669
|
// Encrypt, Decrypt Flags
|
|
505
670
|
data.writeInt16LE(this.bitFlags >>> 0, CENTRAL_DIR.FLAGS);
|
|
@@ -509,10 +674,15 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
509
674
|
data.writeUInt32LE(this.timeDateDOS >>> 0, CENTRAL_DIR.TIMEDATE_DOS);
|
|
510
675
|
// Uncompressed file CRC-32 value (AE-2 stores 0)
|
|
511
676
|
data.writeUInt32LE(this.aesVersion === 2 ? 0 : this.crc, CENTRAL_DIR.CRC);
|
|
512
|
-
// Compressed
|
|
513
|
-
data.writeUInt32LE(
|
|
514
|
-
|
|
515
|
-
|
|
677
|
+
// Compressed / uncompressed sizes and local offset (Zip64 sentinels when needed)
|
|
678
|
+
data.writeUInt32LE(
|
|
679
|
+
zip64Fields.compressedSize !== undefined ? ZIP64_U32 : this.compressedSize,
|
|
680
|
+
CENTRAL_DIR.CMP_SIZE
|
|
681
|
+
);
|
|
682
|
+
data.writeUInt32LE(
|
|
683
|
+
zip64Fields.uncompressedSize !== undefined ? ZIP64_U32 : this.uncompressedSize,
|
|
684
|
+
CENTRAL_DIR.UNCMP_SIZE
|
|
685
|
+
);
|
|
516
686
|
// Filename Length
|
|
517
687
|
data.writeUInt16LE(this.filename.length, CENTRAL_DIR.FNAME_LEN);
|
|
518
688
|
// Extra Field Length
|
|
@@ -520,13 +690,19 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
520
690
|
// File Comment Length
|
|
521
691
|
data.writeUInt16LE(commentLen, CENTRAL_DIR.COMMENT_LEN);
|
|
522
692
|
// Volume Number Start
|
|
523
|
-
data.writeUInt16LE(
|
|
693
|
+
data.writeUInt16LE(
|
|
694
|
+
zip64Fields.diskStart !== undefined ? ZIP64_U16 : this.volNumber,
|
|
695
|
+
CENTRAL_DIR.DISK_NUM
|
|
696
|
+
);
|
|
524
697
|
// Internal File Attributes
|
|
525
698
|
data.writeUInt16LE(this.intFileAttr >>> 0, CENTRAL_DIR.INT_FILE_ATTR);
|
|
526
699
|
// External File Attributes
|
|
527
700
|
data.writeUInt32LE(this.extFileAttr >>> 0, CENTRAL_DIR.EXT_FILE_ATTR);
|
|
528
701
|
// Local Header Offset
|
|
529
|
-
data.writeUInt32LE(
|
|
702
|
+
data.writeUInt32LE(
|
|
703
|
+
zip64Fields.localHdrOffset !== undefined ? ZIP64_U32 : this.localHdrOffset,
|
|
704
|
+
CENTRAL_DIR.LOCAL_HDR_OFFSET
|
|
705
|
+
);
|
|
530
706
|
|
|
531
707
|
// Write filename - use ASCII filename (replacing non-ASCII with ?)
|
|
532
708
|
// This ensures compatibility with older ZIP readers
|
|
@@ -544,6 +720,12 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
544
720
|
// Add Extra Field data after file comment
|
|
545
721
|
let extraOffset = currentOffset;
|
|
546
722
|
|
|
723
|
+
// Zip64 extended information (sizes / offset / disk)
|
|
724
|
+
if (zip64CentralExtra) {
|
|
725
|
+
zip64CentralExtra.copy(data, extraOffset);
|
|
726
|
+
extraOffset += zip64CentralLen;
|
|
727
|
+
}
|
|
728
|
+
|
|
547
729
|
// Add Universal Time field
|
|
548
730
|
if (this.universalTime) {
|
|
549
731
|
data.writeUInt16LE(HDR_ID.UNV_TIME, extraOffset); // 0x5455
|
|
@@ -630,6 +812,10 @@ export default class ZipEntry implements ZipFileEntry {
|
|
|
630
812
|
extraOffset += NEO_CRYPTO_EXTRA_FIELD_SIZE;
|
|
631
813
|
}
|
|
632
814
|
|
|
815
|
+
if (callerExtra && callerExtraLen > 0) {
|
|
816
|
+
callerExtra.copy(data, extraOffset);
|
|
817
|
+
}
|
|
818
|
+
|
|
633
819
|
return data;
|
|
634
820
|
}
|
|
635
821
|
|