@intactfile/engines 0.1.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/README.md +68 -0
- package/dist/archive/diagnose.d.ts +37 -0
- package/dist/archive/diagnose.d.ts.map +1 -0
- package/dist/archive/diagnose.js +165 -0
- package/dist/archive/diagnose.js.map +1 -0
- package/dist/archive/format.d.ts +52 -0
- package/dist/archive/format.d.ts.map +1 -0
- package/dist/archive/format.js +87 -0
- package/dist/archive/format.js.map +1 -0
- package/dist/archive/host.d.ts +83 -0
- package/dist/archive/host.d.ts.map +1 -0
- package/dist/archive/host.js +92 -0
- package/dist/archive/host.js.map +1 -0
- package/dist/archive/index.d.ts +22 -0
- package/dist/archive/index.d.ts.map +1 -0
- package/dist/archive/index.js +19 -0
- package/dist/archive/index.js.map +1 -0
- package/dist/archive/salvage.d.ts +73 -0
- package/dist/archive/salvage.d.ts.map +1 -0
- package/dist/archive/salvage.js +210 -0
- package/dist/archive/salvage.js.map +1 -0
- package/dist/byte-source.d.ts +19 -0
- package/dist/byte-source.d.ts.map +1 -0
- package/dist/byte-source.js +16 -0
- package/dist/byte-source.js.map +1 -0
- package/dist/bytesource/blob.d.ts +14 -0
- package/dist/bytesource/blob.d.ts.map +1 -0
- package/dist/bytesource/blob.js +23 -0
- package/dist/bytesource/blob.js.map +1 -0
- package/dist/crc32.d.ts +2 -0
- package/dist/crc32.d.ts.map +1 -0
- package/dist/crc32.js +18 -0
- package/dist/crc32.js.map +1 -0
- package/dist/detect/index.d.ts +16 -0
- package/dist/detect/index.d.ts.map +1 -0
- package/dist/detect/index.js +159 -0
- package/dist/detect/index.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/jpeg/browser-loader.d.ts +21 -0
- package/dist/jpeg/browser-loader.d.ts.map +1 -0
- package/dist/jpeg/browser-loader.js +28 -0
- package/dist/jpeg/browser-loader.js.map +1 -0
- package/dist/jpeg/diagnose.d.ts +50 -0
- package/dist/jpeg/diagnose.d.ts.map +1 -0
- package/dist/jpeg/diagnose.js +124 -0
- package/dist/jpeg/diagnose.js.map +1 -0
- package/dist/jpeg/exif.d.ts +11 -0
- package/dist/jpeg/exif.d.ts.map +1 -0
- package/dist/jpeg/exif.js +50 -0
- package/dist/jpeg/exif.js.map +1 -0
- package/dist/jpeg/format.d.ts +106 -0
- package/dist/jpeg/format.d.ts.map +1 -0
- package/dist/jpeg/format.js +248 -0
- package/dist/jpeg/format.js.map +1 -0
- package/dist/jpeg/index.d.ts +18 -0
- package/dist/jpeg/index.d.ts.map +1 -0
- package/dist/jpeg/index.js +14 -0
- package/dist/jpeg/index.js.map +1 -0
- package/dist/jpeg/mozjpeg-host.d.ts +60 -0
- package/dist/jpeg/mozjpeg-host.d.ts.map +1 -0
- package/dist/jpeg/mozjpeg-host.js +138 -0
- package/dist/jpeg/mozjpeg-host.js.map +1 -0
- package/dist/jpeg/repair.d.ts +89 -0
- package/dist/jpeg/repair.d.ts.map +1 -0
- package/dist/jpeg/repair.js +216 -0
- package/dist/jpeg/repair.js.map +1 -0
- package/dist/node.d.ts +11 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +29 -0
- package/dist/node.js.map +1 -0
- package/dist/pdf/browser-loader.d.ts +30 -0
- package/dist/pdf/browser-loader.d.ts.map +1 -0
- package/dist/pdf/browser-loader.js +21 -0
- package/dist/pdf/browser-loader.js.map +1 -0
- package/dist/pdf/diagnose.d.ts +23 -0
- package/dist/pdf/diagnose.d.ts.map +1 -0
- package/dist/pdf/diagnose.js +113 -0
- package/dist/pdf/diagnose.js.map +1 -0
- package/dist/pdf/format.d.ts +61 -0
- package/dist/pdf/format.d.ts.map +1 -0
- package/dist/pdf/format.js +150 -0
- package/dist/pdf/format.js.map +1 -0
- package/dist/pdf/index.d.ts +17 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +12 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/qpdf-host.d.ts +66 -0
- package/dist/pdf/qpdf-host.d.ts.map +1 -0
- package/dist/pdf/qpdf-host.js +149 -0
- package/dist/pdf/qpdf-host.js.map +1 -0
- package/dist/pdf/rebuild.d.ts +32 -0
- package/dist/pdf/rebuild.d.ts.map +1 -0
- package/dist/pdf/rebuild.js +90 -0
- package/dist/pdf/rebuild.js.map +1 -0
- package/dist/pdf/repair.d.ts +61 -0
- package/dist/pdf/repair.d.ts.map +1 -0
- package/dist/pdf/repair.js +167 -0
- package/dist/pdf/repair.js.map +1 -0
- package/dist/png/diagnose.d.ts +50 -0
- package/dist/png/diagnose.d.ts.map +1 -0
- package/dist/png/diagnose.js +261 -0
- package/dist/png/diagnose.js.map +1 -0
- package/dist/png/format.d.ts +133 -0
- package/dist/png/format.d.ts.map +1 -0
- package/dist/png/format.js +350 -0
- package/dist/png/format.js.map +1 -0
- package/dist/png/index.d.ts +13 -0
- package/dist/png/index.d.ts.map +1 -0
- package/dist/png/index.js +10 -0
- package/dist/png/index.js.map +1 -0
- package/dist/png/repair.d.ts +31 -0
- package/dist/png/repair.d.ts.map +1 -0
- package/dist/png/repair.js +335 -0
- package/dist/png/repair.js.map +1 -0
- package/dist/sqlite/diagnose.d.ts +31 -0
- package/dist/sqlite/diagnose.d.ts.map +1 -0
- package/dist/sqlite/diagnose.js +169 -0
- package/dist/sqlite/diagnose.js.map +1 -0
- package/dist/sqlite/format.d.ts +103 -0
- package/dist/sqlite/format.d.ts.map +1 -0
- package/dist/sqlite/format.js +237 -0
- package/dist/sqlite/format.js.map +1 -0
- package/dist/sqlite/index.d.ts +24 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +19 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite/recover.d.ts +66 -0
- package/dist/sqlite/recover.d.ts.map +1 -0
- package/dist/sqlite/recover.js +305 -0
- package/dist/sqlite/recover.js.map +1 -0
- package/dist/sqlite/scan.d.ts +94 -0
- package/dist/sqlite/scan.d.ts.map +1 -0
- package/dist/sqlite/scan.js +356 -0
- package/dist/sqlite/scan.js.map +1 -0
- package/dist/sqlite/sqlite-host.d.ts +37 -0
- package/dist/sqlite/sqlite-host.d.ts.map +1 -0
- package/dist/sqlite/sqlite-host.js +80 -0
- package/dist/sqlite/sqlite-host.js.map +1 -0
- package/dist/sqlite/wal.d.ts +14 -0
- package/dist/sqlite/wal.d.ts.map +1 -0
- package/dist/sqlite/wal.js +79 -0
- package/dist/sqlite/wal.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/video/diagnose.d.ts +41 -0
- package/dist/video/diagnose.d.ts.map +1 -0
- package/dist/video/diagnose.js +188 -0
- package/dist/video/diagnose.js.map +1 -0
- package/dist/video/format.d.ts +87 -0
- package/dist/video/format.d.ts.map +1 -0
- package/dist/video/format.js +273 -0
- package/dist/video/format.js.map +1 -0
- package/dist/video/index.d.ts +21 -0
- package/dist/video/index.d.ts.map +1 -0
- package/dist/video/index.js +17 -0
- package/dist/video/index.js.map +1 -0
- package/dist/video/libav-host.d.ts +88 -0
- package/dist/video/libav-host.d.ts.map +1 -0
- package/dist/video/libav-host.js +66 -0
- package/dist/video/libav-host.js.map +1 -0
- package/dist/video/mp4-rebuild.d.ts +167 -0
- package/dist/video/mp4-rebuild.d.ts.map +1 -0
- package/dist/video/mp4-rebuild.js +270 -0
- package/dist/video/mp4-rebuild.js.map +1 -0
- package/dist/video/mp4box-host.d.ts +62 -0
- package/dist/video/mp4box-host.d.ts.map +1 -0
- package/dist/video/mp4box-host.js +209 -0
- package/dist/video/mp4box-host.js.map +1 -0
- package/dist/video/reconstruct.d.ts +97 -0
- package/dist/video/reconstruct.d.ts.map +1 -0
- package/dist/video/reconstruct.js +271 -0
- package/dist/video/reconstruct.js.map +1 -0
- package/dist/video/remux.d.ts +85 -0
- package/dist/video/remux.d.ts.map +1 -0
- package/dist/video/remux.js +350 -0
- package/dist/video/remux.js.map +1 -0
- package/dist/zip/diagnose.d.ts +22 -0
- package/dist/zip/diagnose.d.ts.map +1 -0
- package/dist/zip/diagnose.js +126 -0
- package/dist/zip/diagnose.js.map +1 -0
- package/dist/zip/format.d.ts +79 -0
- package/dist/zip/format.d.ts.map +1 -0
- package/dist/zip/format.js +129 -0
- package/dist/zip/format.js.map +1 -0
- package/dist/zip/repair.d.ts +32 -0
- package/dist/zip/repair.d.ts.map +1 -0
- package/dist/zip/repair.js +82 -0
- package/dist/zip/repair.js.map +1 -0
- package/dist/zip/salvage.d.ts +23 -0
- package/dist/zip/salvage.d.ts.map +1 -0
- package/dist/zip/salvage.js +140 -0
- package/dist/zip/salvage.js.map +1 -0
- package/dist/zip/scan.d.ts +64 -0
- package/dist/zip/scan.d.ts.map +1 -0
- package/dist/zip/scan.js +386 -0
- package/dist/zip/scan.js.map +1 -0
- package/dist/zip/writer.d.ts +14 -0
- package/dist/zip/writer.d.ts.map +1 -0
- package/dist/zip/writer.js +131 -0
- package/dist/zip/writer.js.map +1 -0
- package/package.json +71 -0
- package/src/archive/LICENSE-unrar.txt +53 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export const SIG_LFH = 0x04034b50; // PK\x03\x04
|
|
2
|
+
export const SIG_CDH = 0x02014b50; // PK\x01\x02
|
|
3
|
+
export const SIG_EOCD = 0x06054b50; // PK\x05\x06
|
|
4
|
+
export const SIG_DD = 0x08074b50; // PK\x07\x08
|
|
5
|
+
export const SIG_EOCD64 = 0x06064b50; // PK\x06\x06
|
|
6
|
+
export const SIG_EOCD64_LOC = 0x07064b50; // PK\x06\x07
|
|
7
|
+
export const LFH_FIXED_SIZE = 30;
|
|
8
|
+
export const CDH_FIXED_SIZE = 46;
|
|
9
|
+
export const EOCD_FIXED_SIZE = 22;
|
|
10
|
+
export const MAX_COMMENT = 0xffff;
|
|
11
|
+
export const FLAG_ENCRYPTED = 0x0001;
|
|
12
|
+
export const FLAG_DATA_DESCRIPTOR = 0x0008;
|
|
13
|
+
export const FLAG_UTF8 = 0x0800;
|
|
14
|
+
export const METHOD_STORE = 0;
|
|
15
|
+
export const METHOD_DEFLATE = 8;
|
|
16
|
+
export const U32_MAX = 0xffffffff;
|
|
17
|
+
export const U16_MAX = 0xffff;
|
|
18
|
+
export function readU16(b, o) {
|
|
19
|
+
return b[o] | (b[o + 1] << 8);
|
|
20
|
+
}
|
|
21
|
+
export function readU32(b, o) {
|
|
22
|
+
return (b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)) >>> 0;
|
|
23
|
+
}
|
|
24
|
+
export function readU64(b, o) {
|
|
25
|
+
// Safe up to 2^53-1; ZIP offsets beyond that are not supported.
|
|
26
|
+
const lo = readU32(b, o);
|
|
27
|
+
const hi = readU32(b, o + 4);
|
|
28
|
+
return hi * 0x1_0000_0000 + lo;
|
|
29
|
+
}
|
|
30
|
+
/** Parse the 30 fixed bytes of a local file header (signature already verified or not required). */
|
|
31
|
+
export function parseLocalHeader(b, o = 0) {
|
|
32
|
+
if (b.length - o < LFH_FIXED_SIZE)
|
|
33
|
+
return null;
|
|
34
|
+
return {
|
|
35
|
+
versionNeeded: readU16(b, o + 4),
|
|
36
|
+
flags: readU16(b, o + 6),
|
|
37
|
+
method: readU16(b, o + 8),
|
|
38
|
+
dosTime: readU16(b, o + 10),
|
|
39
|
+
dosDate: readU16(b, o + 12),
|
|
40
|
+
crc32: readU32(b, o + 14),
|
|
41
|
+
compressedSize: readU32(b, o + 18),
|
|
42
|
+
uncompressedSize: readU32(b, o + 22),
|
|
43
|
+
nameLength: readU16(b, o + 26),
|
|
44
|
+
extraLength: readU16(b, o + 28),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const KNOWN_METHODS = new Set([0, 1, 6, 8, 9, 12, 14, 93, 94, 95, 96, 97, 98, 99]);
|
|
48
|
+
/** Cheap plausibility check to reject false-positive PK\x03\x04 matches inside compressed data. */
|
|
49
|
+
export function localHeaderLooksSane(h) {
|
|
50
|
+
if (h.nameLength === 0 || h.nameLength > 4096)
|
|
51
|
+
return false;
|
|
52
|
+
if (h.versionNeeded > 0xff)
|
|
53
|
+
return false;
|
|
54
|
+
if (!KNOWN_METHODS.has(h.method))
|
|
55
|
+
return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse a zip64 extended-information extra field (id 0x0001) out of an LFH/CDH
|
|
60
|
+
* extra blob. Which 8-byte fields are present depends on which 32-bit header
|
|
61
|
+
* fields are 0xFFFFFFFF, in spec order: usize, csize, offset.
|
|
62
|
+
*/
|
|
63
|
+
export function parseZip64Extra(extra, needs) {
|
|
64
|
+
let o = 0;
|
|
65
|
+
while (o + 4 <= extra.length) {
|
|
66
|
+
const id = readU16(extra, o);
|
|
67
|
+
const size = readU16(extra, o + 2);
|
|
68
|
+
const body = extra.subarray(o + 4, Math.min(o + 4 + size, extra.length));
|
|
69
|
+
if (id === 0x0001) {
|
|
70
|
+
const result = { malformed: false };
|
|
71
|
+
let p = 0;
|
|
72
|
+
const take = () => {
|
|
73
|
+
if (p + 8 > body.length) {
|
|
74
|
+
result.malformed = true;
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
const v = readU64(body, p);
|
|
78
|
+
p += 8;
|
|
79
|
+
return v;
|
|
80
|
+
};
|
|
81
|
+
if (needs.uncompressedSize)
|
|
82
|
+
result.uncompressedSize = take();
|
|
83
|
+
if (needs.compressedSize)
|
|
84
|
+
result.compressedSize = take();
|
|
85
|
+
if (needs.localHeaderOffset)
|
|
86
|
+
result.localHeaderOffset = take();
|
|
87
|
+
if (o + 4 + size > extra.length)
|
|
88
|
+
result.malformed = true;
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
o += 4 + size;
|
|
92
|
+
}
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
export function parseEocd(b, o, absoluteOffset) {
|
|
96
|
+
if (b.length - o < EOCD_FIXED_SIZE)
|
|
97
|
+
return null;
|
|
98
|
+
if (readU32(b, o) !== SIG_EOCD)
|
|
99
|
+
return null;
|
|
100
|
+
return {
|
|
101
|
+
offset: absoluteOffset,
|
|
102
|
+
diskNumber: readU16(b, o + 4),
|
|
103
|
+
cdStartDisk: readU16(b, o + 6),
|
|
104
|
+
entriesOnDisk: readU16(b, o + 8),
|
|
105
|
+
totalEntries: readU16(b, o + 10),
|
|
106
|
+
cdSize: readU32(b, o + 12),
|
|
107
|
+
cdOffset: readU32(b, o + 16),
|
|
108
|
+
commentLength: readU16(b, o + 20),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** DOS timestamp for entries whose original date is unrecoverable. */
|
|
112
|
+
export const FALLBACK_DOS_DATE = ((2026 - 1980) << 9) | (1 << 5) | 1;
|
|
113
|
+
export const FALLBACK_DOS_TIME = 0;
|
|
114
|
+
/**
|
|
115
|
+
* The size actually occupied on disk can legitimately exceed the 32-bit size
|
|
116
|
+
* declared in the header when a writer (notably OneDrive/old Windows zips
|
|
117
|
+
* > 4 GiB) stored `size mod 2^32` without zip64 fields. The fix is
|
|
118
|
+
* deterministic: accept the actual size iff the difference is an exact
|
|
119
|
+
* multiple of 2^32.
|
|
120
|
+
*/
|
|
121
|
+
export function reconcileDeclaredSize(declared, actual) {
|
|
122
|
+
if (actual === declared)
|
|
123
|
+
return { size: actual, wrapAroundFixed: false };
|
|
124
|
+
const diff = actual - declared;
|
|
125
|
+
if (diff > 0 && diff % 0x1_0000_0000 === 0)
|
|
126
|
+
return { size: actual, wrapAroundFixed: true };
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/zip/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ByteSource } from '../byte-source.js';
|
|
2
|
+
import { type DamageClass } from './diagnose.js';
|
|
3
|
+
import { type EntryStatus } from './salvage.js';
|
|
4
|
+
export interface RepairEntryReport {
|
|
5
|
+
name: string;
|
|
6
|
+
headerOffset: number;
|
|
7
|
+
method: number;
|
|
8
|
+
status: EntryStatus;
|
|
9
|
+
included: boolean;
|
|
10
|
+
compressedSize: number | undefined;
|
|
11
|
+
uncompressedSize: number | undefined;
|
|
12
|
+
crc32: number | undefined;
|
|
13
|
+
notes: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface RepairReport {
|
|
16
|
+
damageClass: DamageClass;
|
|
17
|
+
entriesFound: number;
|
|
18
|
+
entriesIncluded: number;
|
|
19
|
+
entriesSkipped: number;
|
|
20
|
+
entries: RepairEntryReport[];
|
|
21
|
+
notes: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Rebuild a valid ZIP from every salvageable entry found by the forward scan.
|
|
25
|
+
* Central directory and EOCD are synthesized from scratch; corrupt entries are
|
|
26
|
+
* skipped but reported.
|
|
27
|
+
*/
|
|
28
|
+
export declare function repairZip(src: ByteSource): Promise<{
|
|
29
|
+
zip: Uint8Array;
|
|
30
|
+
report: RepairReport;
|
|
31
|
+
}>;
|
|
32
|
+
//# sourceMappingURL=repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../../src/zip/repair.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAG/D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC,CA4EnG"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { deflateSync, inflateSync } from 'fflate';
|
|
2
|
+
import { FLAG_ENCRYPTED, FLAG_UTF8, METHOD_DEFLATE } from './format.js';
|
|
3
|
+
import { analyzeZip } from './diagnose.js';
|
|
4
|
+
import { validateEntry } from './salvage.js';
|
|
5
|
+
import { buildZip } from './writer.js';
|
|
6
|
+
/**
|
|
7
|
+
* Rebuild a valid ZIP from every salvageable entry found by the forward scan.
|
|
8
|
+
* Central directory and EOCD are synthesized from scratch; corrupt entries are
|
|
9
|
+
* skipped but reported.
|
|
10
|
+
*/
|
|
11
|
+
export async function repairZip(src) {
|
|
12
|
+
const { scan, damageClass, notes } = await analyzeZip(src);
|
|
13
|
+
const out = [];
|
|
14
|
+
const entryReports = [];
|
|
15
|
+
for (const entry of scan.entries) {
|
|
16
|
+
const v = await validateEntry(src, entry);
|
|
17
|
+
let included = false;
|
|
18
|
+
if (v.status === 'ok' && v.storedData && v.crc32 !== undefined) {
|
|
19
|
+
let data = v.storedData;
|
|
20
|
+
const method = entry.method;
|
|
21
|
+
if (!v.exactStream && method === METHOD_DEFLATE) {
|
|
22
|
+
// The exact end of the original stream is unknown; re-compress the
|
|
23
|
+
// verified decoded bytes so the rebuilt entry is exact.
|
|
24
|
+
data = deflateSync(inflateSync(v.storedData));
|
|
25
|
+
v.notes.push('recompressed (original stream end was uncertain)');
|
|
26
|
+
}
|
|
27
|
+
out.push({
|
|
28
|
+
nameBytes: entry.nameBytes,
|
|
29
|
+
flags: entry.flags & FLAG_UTF8,
|
|
30
|
+
method,
|
|
31
|
+
dosTime: entry.dosTime,
|
|
32
|
+
dosDate: entry.dosDate,
|
|
33
|
+
crc32: v.crc32,
|
|
34
|
+
uncompressedSize: v.uncompressedSize ?? 0,
|
|
35
|
+
data,
|
|
36
|
+
});
|
|
37
|
+
included = true;
|
|
38
|
+
}
|
|
39
|
+
else if ((v.status === 'encrypted' || v.status === 'unsupported-method') &&
|
|
40
|
+
v.storedData &&
|
|
41
|
+
v.crc32 !== undefined &&
|
|
42
|
+
v.uncompressedSize !== undefined) {
|
|
43
|
+
// Carried over verbatim: unverifiable here, but usable by tools that
|
|
44
|
+
// support the method / know the password.
|
|
45
|
+
out.push({
|
|
46
|
+
nameBytes: entry.nameBytes,
|
|
47
|
+
flags: entry.flags & (FLAG_UTF8 | FLAG_ENCRYPTED),
|
|
48
|
+
method: entry.method,
|
|
49
|
+
dosTime: entry.dosTime,
|
|
50
|
+
dosDate: entry.dosDate,
|
|
51
|
+
crc32: v.crc32,
|
|
52
|
+
uncompressedSize: v.uncompressedSize,
|
|
53
|
+
data: v.storedData,
|
|
54
|
+
});
|
|
55
|
+
included = true;
|
|
56
|
+
}
|
|
57
|
+
entryReports.push({
|
|
58
|
+
name: entry.name,
|
|
59
|
+
headerOffset: entry.headerOffset,
|
|
60
|
+
method: entry.method,
|
|
61
|
+
status: v.status,
|
|
62
|
+
included,
|
|
63
|
+
compressedSize: v.storedData ? v.storedData.length : entry.complete ? entry.compressedSize : undefined,
|
|
64
|
+
uncompressedSize: v.uncompressedSize,
|
|
65
|
+
crc32: v.crc32,
|
|
66
|
+
notes: [...entry.notes, ...v.notes],
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const included = entryReports.filter((r) => r.included).length;
|
|
70
|
+
return {
|
|
71
|
+
zip: buildZip(out),
|
|
72
|
+
report: {
|
|
73
|
+
damageClass,
|
|
74
|
+
entriesFound: scan.entries.length,
|
|
75
|
+
entriesIncluded: included,
|
|
76
|
+
entriesSkipped: scan.entries.length - included,
|
|
77
|
+
entries: entryReports,
|
|
78
|
+
notes,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=repair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.js","sourceRoot":"","sources":["../../src/zip/repair.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ByteSource } from '../byte-source.js';
|
|
2
|
+
import type { ScannedEntry } from './scan.js';
|
|
3
|
+
export type EntryStatus = 'ok' | 'corrupt-data' | 'encrypted' | 'unsupported-method';
|
|
4
|
+
export interface ValidatedEntry {
|
|
5
|
+
entry: ScannedEntry;
|
|
6
|
+
status: EntryStatus;
|
|
7
|
+
/** Compressed bytes exactly as they should be stored in a rebuilt zip (null when not salvageable). */
|
|
8
|
+
storedData: Uint8Array | null;
|
|
9
|
+
/** For `ok`: verified or recomputed CRC of the uncompressed data. For pass-through: declared CRC. */
|
|
10
|
+
crc32: number | undefined;
|
|
11
|
+
uncompressedSize: number | undefined;
|
|
12
|
+
/** True when integrity was proven by a CRC match (vs merely recomputed). */
|
|
13
|
+
crcVerified: boolean;
|
|
14
|
+
/** True when storedData is known to be the exact stream (no trailing junk possible). */
|
|
15
|
+
exactStream: boolean;
|
|
16
|
+
notes: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Attempt to decode and integrity-check one scanned entry. Never throws:
|
|
20
|
+
* corruption is a classification, not an error.
|
|
21
|
+
*/
|
|
22
|
+
export declare function validateEntry(src: ByteSource, entry: ScannedEntry): Promise<ValidatedEntry>;
|
|
23
|
+
//# sourceMappingURL=salvage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salvage.d.ts","sourceRoot":"","sources":["../../src/zip/salvage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,cAAc,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAErF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,sGAAsG;IACtG,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,qGAAqG;IACrG,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAC;IACrB,wFAAwF;IACxF,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAKD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CA2IjG"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { inflateSync } from 'fflate';
|
|
2
|
+
import { crc32 } from '../crc32.js';
|
|
3
|
+
import { FLAG_ENCRYPTED, METHOD_DEFLATE, METHOD_STORE } from './format.js';
|
|
4
|
+
/** Decompression guard: refuse to inflate when the declared output exceeds this. */
|
|
5
|
+
const MAX_INFLATE = 2 * 1024 * 1024 * 1024;
|
|
6
|
+
/**
|
|
7
|
+
* Attempt to decode and integrity-check one scanned entry. Never throws:
|
|
8
|
+
* corruption is a classification, not an error.
|
|
9
|
+
*/
|
|
10
|
+
export async function validateEntry(src, entry) {
|
|
11
|
+
const notes = [];
|
|
12
|
+
const base = {
|
|
13
|
+
entry,
|
|
14
|
+
storedData: null,
|
|
15
|
+
crc32: entry.crc32,
|
|
16
|
+
uncompressedSize: entry.uncompressedSize,
|
|
17
|
+
crcVerified: false,
|
|
18
|
+
exactStream: false,
|
|
19
|
+
notes,
|
|
20
|
+
};
|
|
21
|
+
const raw = entry.compressedSize > 0 ? await src.read(entry.dataStart, entry.compressedSize) : new Uint8Array(0);
|
|
22
|
+
if (raw.length < entry.compressedSize) {
|
|
23
|
+
notes.push('compressed data missing from source');
|
|
24
|
+
return { ...base, status: 'corrupt-data' };
|
|
25
|
+
}
|
|
26
|
+
if (entry.flags & FLAG_ENCRYPTED) {
|
|
27
|
+
notes.push('entry is encrypted; carried over without verification');
|
|
28
|
+
return { ...base, storedData: entry.complete ? raw : null, status: 'encrypted' };
|
|
29
|
+
}
|
|
30
|
+
if (entry.method === METHOD_STORE) {
|
|
31
|
+
// Try the header-declared size first when the scan distrusted it: junk
|
|
32
|
+
// may trail a truthful size (e.g. a zeroed central directory).
|
|
33
|
+
if (entry.crc32 !== undefined &&
|
|
34
|
+
entry.altCompressedSize !== undefined &&
|
|
35
|
+
entry.altCompressedSize <= raw.length) {
|
|
36
|
+
const alt = raw.subarray(0, entry.altCompressedSize);
|
|
37
|
+
if (crc32(alt) === entry.crc32) {
|
|
38
|
+
notes.push('declared size verified against data');
|
|
39
|
+
return {
|
|
40
|
+
...base,
|
|
41
|
+
storedData: alt,
|
|
42
|
+
status: 'ok',
|
|
43
|
+
uncompressedSize: alt.length,
|
|
44
|
+
crcVerified: true,
|
|
45
|
+
exactStream: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const computed = crc32(raw);
|
|
50
|
+
if (entry.crc32 !== undefined && computed !== entry.crc32) {
|
|
51
|
+
notes.push(`stored data CRC mismatch (expected ${entry.crc32.toString(16)}, got ${computed.toString(16)})`);
|
|
52
|
+
return { ...base, status: 'corrupt-data' };
|
|
53
|
+
}
|
|
54
|
+
if (entry.crc32 === undefined) {
|
|
55
|
+
if (!entry.complete && !entry.dataEndUncertain) {
|
|
56
|
+
notes.push('stored data incomplete and integrity unverifiable');
|
|
57
|
+
return { ...base, status: 'corrupt-data' };
|
|
58
|
+
}
|
|
59
|
+
notes.push('CRC not declared; recomputed from data');
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...base,
|
|
63
|
+
storedData: raw,
|
|
64
|
+
status: 'ok',
|
|
65
|
+
crc32: computed,
|
|
66
|
+
uncompressedSize: raw.length,
|
|
67
|
+
crcVerified: entry.crc32 !== undefined,
|
|
68
|
+
exactStream: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (entry.method !== METHOD_DEFLATE) {
|
|
72
|
+
notes.push(`compression method ${entry.method} not supported by this engine`);
|
|
73
|
+
return {
|
|
74
|
+
...base,
|
|
75
|
+
storedData: entry.complete && entry.crc32 !== undefined ? raw : null,
|
|
76
|
+
status: 'unsupported-method',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (entry.uncompressedSize !== undefined && entry.uncompressedSize > MAX_INFLATE) {
|
|
80
|
+
notes.push('declared uncompressed size exceeds safety cap; not decoded');
|
|
81
|
+
return { ...base, status: 'unsupported-method' };
|
|
82
|
+
}
|
|
83
|
+
if (entry.crc32 !== undefined &&
|
|
84
|
+
entry.altCompressedSize !== undefined &&
|
|
85
|
+
entry.altCompressedSize <= raw.length) {
|
|
86
|
+
const alt = raw.subarray(0, entry.altCompressedSize);
|
|
87
|
+
try {
|
|
88
|
+
const decoded = inflateSync(alt);
|
|
89
|
+
if (crc32(decoded) === entry.crc32) {
|
|
90
|
+
notes.push('declared size verified against data');
|
|
91
|
+
return {
|
|
92
|
+
...base,
|
|
93
|
+
storedData: alt,
|
|
94
|
+
status: 'ok',
|
|
95
|
+
uncompressedSize: decoded.length,
|
|
96
|
+
crcVerified: true,
|
|
97
|
+
exactStream: true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// fall through to the scanned size
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let decoded;
|
|
106
|
+
try {
|
|
107
|
+
decoded = inflateSync(raw);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
notes.push(entry.complete ? 'deflate stream is corrupt' : 'deflate stream incomplete (truncated)');
|
|
111
|
+
return { ...base, status: 'corrupt-data' };
|
|
112
|
+
}
|
|
113
|
+
const computed = crc32(decoded);
|
|
114
|
+
if (entry.crc32 !== undefined) {
|
|
115
|
+
if (computed !== entry.crc32) {
|
|
116
|
+
notes.push(`CRC mismatch after inflate (expected ${entry.crc32.toString(16)}, got ${computed.toString(16)})`);
|
|
117
|
+
return { ...base, status: 'corrupt-data' };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else if (!entry.complete && !entry.dataEndUncertain) {
|
|
121
|
+
notes.push('data incomplete and no CRC to verify against');
|
|
122
|
+
return { ...base, status: 'corrupt-data' };
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
notes.push('CRC not recoverable from source; recomputed from decoded data');
|
|
126
|
+
}
|
|
127
|
+
if (entry.uncompressedSize !== undefined && decoded.length !== entry.uncompressedSize) {
|
|
128
|
+
notes.push(`decoded size ${decoded.length} differs from declared ${entry.uncompressedSize}`);
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
...base,
|
|
132
|
+
storedData: raw,
|
|
133
|
+
status: 'ok',
|
|
134
|
+
crc32: computed,
|
|
135
|
+
uncompressedSize: decoded.length,
|
|
136
|
+
crcVerified: entry.crc32 !== undefined,
|
|
137
|
+
exactStream: entry.endValidated,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=salvage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salvage.js","sourceRoot":"","sources":["../../src/zip/salvage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ByteSource } from '../byte-source.js';
|
|
2
|
+
import { type Eocd } from './format.js';
|
|
3
|
+
export interface ScannedEntry {
|
|
4
|
+
headerOffset: number;
|
|
5
|
+
dataStart: number;
|
|
6
|
+
method: number;
|
|
7
|
+
flags: number;
|
|
8
|
+
nameBytes: Uint8Array;
|
|
9
|
+
name: string;
|
|
10
|
+
dosTime: number;
|
|
11
|
+
dosDate: number;
|
|
12
|
+
/** Undefined when the header is zeroed (data-descriptor entry) and no descriptor was recovered. */
|
|
13
|
+
crc32: number | undefined;
|
|
14
|
+
/** Resolved compressed size; for incomplete entries, the bytes actually available. */
|
|
15
|
+
compressedSize: number;
|
|
16
|
+
uncompressedSize: number | undefined;
|
|
17
|
+
hasDescriptor: boolean;
|
|
18
|
+
descriptorLength: number;
|
|
19
|
+
usedZip64: boolean;
|
|
20
|
+
/** Compressed data fully present in the source. */
|
|
21
|
+
complete: boolean;
|
|
22
|
+
/** Size came from a structure scan, not from a trusted header field. */
|
|
23
|
+
sizeFromScan: boolean;
|
|
24
|
+
/** The exact end of the compressed stream is unknown (junk may trail it). */
|
|
25
|
+
dataEndUncertain: boolean;
|
|
26
|
+
/** Data end proven by a structural boundary or a validated data descriptor. */
|
|
27
|
+
endValidated: boolean;
|
|
28
|
+
/** Header-declared size kept as an alternative candidate when the scan distrusted it. */
|
|
29
|
+
altCompressedSize?: number;
|
|
30
|
+
/** OneDrive-style mod-2^32 size wraparound was detected and fixed. */
|
|
31
|
+
wrapAroundFixed: boolean;
|
|
32
|
+
notes: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface ScanResult {
|
|
35
|
+
entries: ScannedEntry[];
|
|
36
|
+
/** Offset of the first local header — non-zero means a garbage prefix. */
|
|
37
|
+
prefixOffset: number;
|
|
38
|
+
firstCdhOffset: number | undefined;
|
|
39
|
+
/** The source ends in the middle of an entry (header or data cut off). */
|
|
40
|
+
truncatedTail: boolean;
|
|
41
|
+
/** Number of resyncs over unparseable regions between entries. */
|
|
42
|
+
gaps: number;
|
|
43
|
+
notes: string[];
|
|
44
|
+
}
|
|
45
|
+
export interface EocdResult {
|
|
46
|
+
eocd: Eocd;
|
|
47
|
+
/** Overrides from the zip64 EOCD, when present and readable. */
|
|
48
|
+
zip64?: {
|
|
49
|
+
cdOffset: number;
|
|
50
|
+
cdSize: number;
|
|
51
|
+
totalEntries: number;
|
|
52
|
+
};
|
|
53
|
+
notes: string[];
|
|
54
|
+
}
|
|
55
|
+
/** Find the next plausible structural record (validated LFH, CDH, or EOCD) at or after `from`. */
|
|
56
|
+
export declare function nextStructuralBoundary(src: ByteSource, from: number): Promise<{
|
|
57
|
+
offset: number;
|
|
58
|
+
sig: number;
|
|
59
|
+
} | null>;
|
|
60
|
+
/** Forward streaming scan for local file entries; tolerates garbage prefixes, lying headers, and truncation. */
|
|
61
|
+
export declare function scanLocalEntries(src: ByteSource): Promise<ScanResult>;
|
|
62
|
+
/** Locate the EOCD record by scanning the file tail; resolves zip64 overrides when present. */
|
|
63
|
+
export declare function findEocd(src: ByteSource): Promise<EocdResult | null>;
|
|
64
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/zip/scan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAsBL,KAAK,IAAI,EACV,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,mGAAmG;IACnG,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,sFAAsF;IACtF,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,mDAAmD;IACnD,QAAQ,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,YAAY,EAAE,OAAO,CAAC;IACtB,6EAA6E;IAC7E,gBAAgB,EAAE,OAAO,CAAC;IAC1B,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC;IACtB,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,0EAA0E;IAC1E,aAAa,EAAE,OAAO,CAAC;IACvB,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,gEAAgE;IAChE,KAAK,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACnE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAkCD,kGAAkG;AAClG,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAajD;AAsED,gHAAgH;AAChH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAuN3E;AAED,+FAA+F;AAC/F,wBAAsB,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAoD1E"}
|