@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
package/README.md
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# @intactfile/engines
|
|
2
|
+
|
|
3
|
+
The repair engines behind [IntactFile](https://www.intactfile.com) — the SDK for
|
|
4
|
+
the Business plan. Repair corrupted files **entirely in-process**: nothing is
|
|
5
|
+
uploaded, the file never leaves the machine. Runs in the browser (via injected
|
|
6
|
+
WASM loaders) and in Node (the default loaders resolve their `.wasm` from
|
|
7
|
+
`node_modules` — no wiring needed).
|
|
8
|
+
|
|
9
|
+
> Repairing files programmatically requires an active IntactFile **Business**
|
|
10
|
+
> subscription. See the [CLI](https://www.npmjs.com/package/@intactfile/cli) and
|
|
11
|
+
> the [MCP server](https://www.npmjs.com/package/@intactfile/mcp), or the docs at
|
|
12
|
+
> https://www.intactfile.com/docs.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install @intactfile/engines
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Requires **Node ≥ 22** (the SQLite writer uses the built-in `node:sqlite`).
|
|
21
|
+
|
|
22
|
+
## Usage (Node)
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { detectFormat } from "@intactfile/engines";
|
|
26
|
+
import { NodeFileSource } from "@intactfile/engines/node";
|
|
27
|
+
import { repairPdf } from "@intactfile/engines/pdf";
|
|
28
|
+
|
|
29
|
+
const src = await NodeFileSource.open("broken.pdf");
|
|
30
|
+
const { pdf, report } = await repairPdf(src);
|
|
31
|
+
await src.close();
|
|
32
|
+
|
|
33
|
+
console.log(report.outcome); // "success" | "partial" | "failed"
|
|
34
|
+
if (report.outcome !== "failed") {
|
|
35
|
+
await (await import("node:fs/promises")).writeFile("fixed.pdf", pdf);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Feed engines a `ByteSource`: `NodeFileSource.open(path)` (random-access over an
|
|
40
|
+
fs handle), or `new MemorySource(buffer)` for bytes you already hold.
|
|
41
|
+
|
|
42
|
+
## Entry points
|
|
43
|
+
|
|
44
|
+
| Import | Function | Returns |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `@intactfile/engines` | `detectFormat(src)` | `{ format, container?, confidence, notes }` |
|
|
47
|
+
| `@intactfile/engines` | `repairZip(src)` | `{ zip, report }` (ZIP/DOCX/XLSX/PPTX) |
|
|
48
|
+
| `@intactfile/engines/pdf` | `repairPdf(src)` | `{ pdf, report }` |
|
|
49
|
+
| `@intactfile/engines/video` | `remuxVideo(src)`, `reconstructMoov(broken, reference)` | `{ video, report }` |
|
|
50
|
+
| `@intactfile/engines/jpeg` | `repairJpeg(src, { reference? })` | `{ image?, preview?, report }` |
|
|
51
|
+
| `@intactfile/engines/png` | `repairPng(src)` | `{ image?, report }` |
|
|
52
|
+
| `@intactfile/engines/sqlite` | `recoverSqlite(src)` | `{ db?, report }` |
|
|
53
|
+
| `@intactfile/engines/archive` | `salvageArchive(src, { password? })` | `{ files, report }` |
|
|
54
|
+
|
|
55
|
+
Every `*Report` carries an honest `outcome` (`success` / `partial` / `failed`),
|
|
56
|
+
a `damageClass`, `bytesIn`/`bytesOut`, and human-readable notes — the engines
|
|
57
|
+
never fake a success.
|
|
58
|
+
|
|
59
|
+
## Privacy
|
|
60
|
+
|
|
61
|
+
The Node path is entirely filesystem + in-process WebAssembly. The only network
|
|
62
|
+
code anywhere is the browser WASM loaders (`*-browser-loader.ts`), never on the
|
|
63
|
+
Node path. Your files are never transmitted.
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
UNLICENSED — © IntactFile. Usage is governed by the IntactFile terms; the
|
|
68
|
+
Business subscription grants the right to repair programmatically at scale.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RAR/7z archive diagnosis — a pure signature + header sniff. No wasm anywhere
|
|
3
|
+
* in this import chain, so it is safe in the browser-facing root/subpath export
|
|
4
|
+
* and runs without loading the 7-Zip wasm.
|
|
5
|
+
*
|
|
6
|
+
* What it can prove from raw bytes:
|
|
7
|
+
* - format family (7z, RAR4, RAR5) and whether a ZIP was handed in by mistake;
|
|
8
|
+
* - 7z: start-header CRC and end-header CRC are both standard CRC32 and are
|
|
9
|
+
* validated here — this catches corrupt header offsets, a zeroed/flipped
|
|
10
|
+
* end-of-archive header, and (because 7z stores its directory at the END of
|
|
11
|
+
* the file) tail truncation that runs past EOF;
|
|
12
|
+
* - RAR4/RAR5: whether the first block is a valid main header, and whether the
|
|
13
|
+
* archive declares header encryption (RAR4 MHD_PASSWORD, RAR5 encryption
|
|
14
|
+
* block type 4).
|
|
15
|
+
*
|
|
16
|
+
* Honesty rules (docs/03): 7z encryption of the *data* (or an encoded end
|
|
17
|
+
* header) cannot be told apart from a merely compressed header by raw bytes —
|
|
18
|
+
* a plain 7z also writes an encoded header — so this sniff never guesses
|
|
19
|
+
* "encrypted" for 7z; that verdict is left to salvage, which lists the archive
|
|
20
|
+
* and reads the real per-entry Encrypted flags.
|
|
21
|
+
*/
|
|
22
|
+
import type { ByteSource } from '../byte-source.js';
|
|
23
|
+
import type { Confidence } from '../types.js';
|
|
24
|
+
export type ArchiveFormat = '7z' | 'rar4' | 'rar5' | 'rar' | 'zip' | 'unknown';
|
|
25
|
+
export type ArchiveDamageClass = 'none' | 'truncated' | 'header-damage' | 'not-archive' | 'encrypted' | 'unknown';
|
|
26
|
+
export interface ArchiveDiagnosis {
|
|
27
|
+
format: ArchiveFormat;
|
|
28
|
+
damageClass: ArchiveDamageClass;
|
|
29
|
+
confidence: Confidence;
|
|
30
|
+
notes: string[];
|
|
31
|
+
/** Offset of the recognized signature; > 0 means a garbage prefix precedes it. */
|
|
32
|
+
signatureOffset: number | null;
|
|
33
|
+
/** 7z only: absolute offset where the end-of-archive header should begin. */
|
|
34
|
+
endHeaderOffset: number | null;
|
|
35
|
+
}
|
|
36
|
+
export declare function diagnoseArchive(src: ByteSource): Promise<ArchiveDiagnosis>;
|
|
37
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../src/archive/diagnose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAwB9C,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;AAE/E,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,WAAW,GACX,eAAe,GACf,aAAa,GACb,WAAW,GACX,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,WAAW,EAAE,kBAAkB,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kFAAkF;IAClF,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,6EAA6E;IAC7E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAOD,wBAAsB,eAAe,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2DhF"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { crc32 } from '../crc32.js';
|
|
2
|
+
import { KENCODED_HEADER, KHEADER, RAR4_MHD_ENCRYPTVER, RAR4_TYPE_MAIN, RAR5_TYPE_ENCRYPTION, RAR5_TYPE_MAIN, SEVENZIP_START_HEADER_SIZE, SIG_7Z, SIG_RAR4, SIG_RAR5, SIG_RAR_COMMON, SIG_ZIP_DD, SIG_ZIP_EOCD, SIG_ZIP_LFH, indexOfSig, matchAt, readU16LE, readU32LE, readU64LE, readVint, } from './format.js';
|
|
3
|
+
/** Window scanned for a signature hiding behind a leading garbage prefix. */
|
|
4
|
+
const PREFIX_SCAN_WINDOW = 64 * 1024;
|
|
5
|
+
const hex = (n) => `0x${(n >>> 0).toString(16)}`;
|
|
6
|
+
export async function diagnoseArchive(src) {
|
|
7
|
+
const notes = [];
|
|
8
|
+
const size = src.size;
|
|
9
|
+
const done = (format, damageClass, confidence, signatureOffset = null, endHeaderOffset = null) => ({ format, damageClass, confidence, notes, signatureOffset, endHeaderOffset });
|
|
10
|
+
if (size === 0) {
|
|
11
|
+
notes.push('file is empty');
|
|
12
|
+
return done('unknown', 'not-archive', 'high');
|
|
13
|
+
}
|
|
14
|
+
const head = await src.read(0, Math.min(size, 64));
|
|
15
|
+
// ZIP: recognized but explicitly deferred to the existing zip engine.
|
|
16
|
+
if (matchAt(head, SIG_ZIP_LFH) || matchAt(head, SIG_ZIP_EOCD) || matchAt(head, SIG_ZIP_DD)) {
|
|
17
|
+
notes.push('ZIP archive detected — use the ZIP engine (diagnoseZip / repairZip); the archive engine handles 7z and RAR only');
|
|
18
|
+
return done('zip', 'none', 'high', 0);
|
|
19
|
+
}
|
|
20
|
+
if (matchAt(head, SIG_7Z))
|
|
21
|
+
return diagnose7z(src, size, 0, notes, done);
|
|
22
|
+
if (matchAt(head, SIG_RAR_COMMON))
|
|
23
|
+
return diagnoseRar(head, 0, size, notes, done);
|
|
24
|
+
// Tolerant scan: a signature can hide behind leading junk (e.g. an email
|
|
25
|
+
// MIME preamble left in front of the archive).
|
|
26
|
+
const window = size <= head.length ? head : await src.read(0, Math.min(size, PREFIX_SCAN_WINDOW));
|
|
27
|
+
const at7z = indexOfSig(window, SIG_7Z, 1);
|
|
28
|
+
const atRar = indexOfSig(window, SIG_RAR_COMMON, 1);
|
|
29
|
+
const candidates = [at7z, atRar].filter((x) => x > 0).sort((a, b) => a - b);
|
|
30
|
+
const at = candidates[0];
|
|
31
|
+
if (at !== undefined) {
|
|
32
|
+
const is7z = at === at7z;
|
|
33
|
+
const format = is7z
|
|
34
|
+
? '7z'
|
|
35
|
+
: matchAt(window, SIG_RAR5, at)
|
|
36
|
+
? 'rar5'
|
|
37
|
+
: matchAt(window, SIG_RAR4, at)
|
|
38
|
+
? 'rar4'
|
|
39
|
+
: 'rar';
|
|
40
|
+
notes.push(`${is7z ? '7z' : 'RAR'} signature found at offset ${at} behind ${at} bytes of leading data; ` +
|
|
41
|
+
'the prefix must be stripped before the archive can be opened');
|
|
42
|
+
return done(format, 'header-damage', 'medium', at);
|
|
43
|
+
}
|
|
44
|
+
const atZip = indexOfSig(window, SIG_ZIP_LFH, 1);
|
|
45
|
+
if (atZip > 0) {
|
|
46
|
+
notes.push(`ZIP local header found at offset ${atZip} (garbage prefix) — use the ZIP engine`);
|
|
47
|
+
return done('zip', 'header-damage', 'medium', atZip);
|
|
48
|
+
}
|
|
49
|
+
notes.push('no 7z or RAR signature found (ZIP is handled separately by the zip engine)');
|
|
50
|
+
return done('unknown', 'not-archive', size > PREFIX_SCAN_WINDOW ? 'medium' : 'high');
|
|
51
|
+
}
|
|
52
|
+
async function diagnose7z(src, size, off, notes, done) {
|
|
53
|
+
if (size - off < SEVENZIP_START_HEADER_SIZE) {
|
|
54
|
+
notes.push('7z signature present but the 32-byte start header is incomplete: file is truncated');
|
|
55
|
+
return done('7z', 'truncated', 'high', off);
|
|
56
|
+
}
|
|
57
|
+
const sh = await src.read(off, SEVENZIP_START_HEADER_SIZE);
|
|
58
|
+
const major = sh[6];
|
|
59
|
+
const minor = sh[7];
|
|
60
|
+
if (major !== 0)
|
|
61
|
+
notes.push(`unexpected 7z format version ${major}.${minor} (expected 0.x)`);
|
|
62
|
+
const startCrcStored = readU32LE(sh, 8);
|
|
63
|
+
const startCrcCalc = crc32(sh.subarray(12, 32)); // CRC of the 20-byte NextHeader info
|
|
64
|
+
if (startCrcStored !== startCrcCalc) {
|
|
65
|
+
notes.push(`start-header CRC mismatch (stored ${hex(startCrcStored)}, computed ${hex(startCrcCalc)}): ` +
|
|
66
|
+
'the header offsets are corrupt');
|
|
67
|
+
return done('7z', 'header-damage', 'high', off);
|
|
68
|
+
}
|
|
69
|
+
const nextHeaderOffset = readU64LE(sh, 12);
|
|
70
|
+
const nextHeaderSize = readU64LE(sh, 20);
|
|
71
|
+
const nextHeaderCrc = readU32LE(sh, 28);
|
|
72
|
+
const endHeaderOffset = off + SEVENZIP_START_HEADER_SIZE + nextHeaderOffset;
|
|
73
|
+
if (nextHeaderOffset === 0 && nextHeaderSize === 0) {
|
|
74
|
+
notes.push('start header is valid and the archive is empty (no packed streams)');
|
|
75
|
+
return done('7z', 'none', 'high', off, endHeaderOffset);
|
|
76
|
+
}
|
|
77
|
+
const endHeaderEnd = endHeaderOffset + nextHeaderSize;
|
|
78
|
+
if (endHeaderEnd > size) {
|
|
79
|
+
notes.push(`end-of-archive header runs to offset ${endHeaderEnd} but the file ends at ${size}: truncated. ` +
|
|
80
|
+
'7z stores its directory at the end of the file, so a tail cut takes the entry list with it');
|
|
81
|
+
return done('7z', 'truncated', 'high', off, endHeaderOffset);
|
|
82
|
+
}
|
|
83
|
+
const footer = await src.read(endHeaderOffset, nextHeaderSize);
|
|
84
|
+
if (footer.length < nextHeaderSize) {
|
|
85
|
+
notes.push('end-of-archive header could not be read in full: truncated');
|
|
86
|
+
return done('7z', 'truncated', 'high', off, endHeaderOffset);
|
|
87
|
+
}
|
|
88
|
+
const footerCrcCalc = crc32(footer);
|
|
89
|
+
if (footerCrcCalc !== nextHeaderCrc) {
|
|
90
|
+
if (footer.every((b) => b === 0)) {
|
|
91
|
+
notes.push('end-of-archive header is zeroed out: the entry directory was destroyed in place');
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
notes.push(`end-of-archive header CRC mismatch (stored ${hex(nextHeaderCrc)}, computed ${hex(footerCrcCalc)}): ` +
|
|
95
|
+
'the entry directory is corrupt');
|
|
96
|
+
}
|
|
97
|
+
return done('7z', 'header-damage', 'high', off, endHeaderOffset);
|
|
98
|
+
}
|
|
99
|
+
const kind = footer[0];
|
|
100
|
+
if (kind === KENCODED_HEADER) {
|
|
101
|
+
notes.push('end-of-archive header is encoded (compressed and/or encrypted); per-entry integrity and any ' +
|
|
102
|
+
'encryption are confirmed only by salvage (list + extract)');
|
|
103
|
+
}
|
|
104
|
+
else if (kind === KHEADER) {
|
|
105
|
+
notes.push('end-of-archive header is a plain, intact header');
|
|
106
|
+
}
|
|
107
|
+
return done('7z', 'none', 'high', off, endHeaderOffset);
|
|
108
|
+
}
|
|
109
|
+
function diagnoseRar(head, off, size, notes, done) {
|
|
110
|
+
// --- RAR5 ---
|
|
111
|
+
if (matchAt(head, SIG_RAR5, off)) {
|
|
112
|
+
const blockStart = off + SIG_RAR5.length;
|
|
113
|
+
if (size - blockStart < 5) {
|
|
114
|
+
notes.push('RAR5 signature present but no block header follows: file is truncated');
|
|
115
|
+
return done('rar5', 'truncated', 'high', off);
|
|
116
|
+
}
|
|
117
|
+
let p = blockStart + 4; // skip the 4-byte header CRC32
|
|
118
|
+
const hsize = readVint(head, p);
|
|
119
|
+
if (!hsize) {
|
|
120
|
+
notes.push('RAR5 block header size is unreadable: truncated');
|
|
121
|
+
return done('rar5', 'truncated', 'medium', off);
|
|
122
|
+
}
|
|
123
|
+
p += hsize.length;
|
|
124
|
+
const htype = readVint(head, p);
|
|
125
|
+
if (!htype) {
|
|
126
|
+
notes.push('RAR5 block header type is unreadable: truncated');
|
|
127
|
+
return done('rar5', 'truncated', 'medium', off);
|
|
128
|
+
}
|
|
129
|
+
if (htype.value === RAR5_TYPE_ENCRYPTION) {
|
|
130
|
+
notes.push('RAR5 archive opens with an encryption header: the archive and its headers are password-protected');
|
|
131
|
+
return done('rar5', 'encrypted', 'high', off);
|
|
132
|
+
}
|
|
133
|
+
if (htype.value === RAR5_TYPE_MAIN) {
|
|
134
|
+
notes.push('RAR5 main archive header present; structure looks intact');
|
|
135
|
+
return done('rar5', 'none', 'high', off);
|
|
136
|
+
}
|
|
137
|
+
notes.push(`RAR5 first block has unexpected type ${htype.value} (expected main=1 or encryption=4): header damaged`);
|
|
138
|
+
return done('rar5', 'header-damage', 'medium', off);
|
|
139
|
+
}
|
|
140
|
+
// --- RAR4 ---
|
|
141
|
+
if (matchAt(head, SIG_RAR4, off)) {
|
|
142
|
+
const blockStart = off + SIG_RAR4.length;
|
|
143
|
+
if (size - blockStart < 7) {
|
|
144
|
+
notes.push('RAR4 signature present but the main header is incomplete: file is truncated');
|
|
145
|
+
return done('rar4', 'truncated', 'high', off);
|
|
146
|
+
}
|
|
147
|
+
const type = head[blockStart + 2];
|
|
148
|
+
const flags = readU16LE(head, blockStart + 3);
|
|
149
|
+
if (type !== RAR4_TYPE_MAIN) {
|
|
150
|
+
notes.push(`RAR4 first block type ${hex(type)} is not a main header (0x73): header damaged`);
|
|
151
|
+
return done('rar4', 'header-damage', 'medium', off);
|
|
152
|
+
}
|
|
153
|
+
if (flags & RAR4_MHD_ENCRYPTVER) {
|
|
154
|
+
notes.push('RAR4 main header sets the password flag: the archive headers are encrypted');
|
|
155
|
+
return done('rar4', 'encrypted', 'high', off);
|
|
156
|
+
}
|
|
157
|
+
notes.push('RAR4 main header present; structure looks intact');
|
|
158
|
+
return done('rar4', 'none', 'high', off);
|
|
159
|
+
}
|
|
160
|
+
// RAR mark present but the version discriminator byte is neither 0x00 nor 0x01.
|
|
161
|
+
const verByte = head[off + 6] ?? 0;
|
|
162
|
+
notes.push(`RAR mark header present but version byte ${hex(verByte)} is neither RAR4 (0x00) nor RAR5 (0x01): header damaged`);
|
|
163
|
+
return done('rar', 'header-damage', 'medium', off);
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/archive/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure byte-level constants and helpers for RAR/7z archive sniffing. No wasm in
|
|
3
|
+
* this import chain, so it is safe in the browser-facing diagnosis path.
|
|
4
|
+
*
|
|
5
|
+
* Signatures (docs/14 §RAR/7z):
|
|
6
|
+
* 7z 37 7A BC AF 27 1C
|
|
7
|
+
* RAR4 52 61 72 21 1A 07 00 ("Rar!\x1a\x07\x00")
|
|
8
|
+
* RAR5 52 61 72 21 1A 07 01 00 ("Rar!\x1a\x07\x01\x00")
|
|
9
|
+
* ZIP 50 4B 03 04 / 05 06 / 07 08 (handled by the existing zip engine)
|
|
10
|
+
*/
|
|
11
|
+
export declare const SIG_7Z: readonly [55, 122, 188, 175, 39, 28];
|
|
12
|
+
export declare const SIG_RAR4: readonly [82, 97, 114, 33, 26, 7, 0];
|
|
13
|
+
export declare const SIG_RAR5: readonly [82, 97, 114, 33, 26, 7, 1, 0];
|
|
14
|
+
/** RAR mark head without the version discriminator (byte 6): "Rar!\x1a\x07". */
|
|
15
|
+
export declare const SIG_RAR_COMMON: readonly [82, 97, 114, 33, 26, 7];
|
|
16
|
+
export declare const SIG_ZIP_LFH: readonly [80, 75, 3, 4];
|
|
17
|
+
export declare const SIG_ZIP_EOCD: readonly [80, 75, 5, 6];
|
|
18
|
+
export declare const SIG_ZIP_DD: readonly [80, 75, 7, 8];
|
|
19
|
+
/** The 7z start header is a fixed 32-byte record before any packed data. */
|
|
20
|
+
export declare const SEVENZIP_START_HEADER_SIZE = 32;
|
|
21
|
+
/** 7z NextHeader property ids (first byte of the end-of-archive header). */
|
|
22
|
+
export declare const KHEADER = 1;
|
|
23
|
+
export declare const KENCODED_HEADER = 23;
|
|
24
|
+
/** RAR5 block header types (the value of the "header type" vint). */
|
|
25
|
+
export declare const RAR5_TYPE_MAIN = 1;
|
|
26
|
+
export declare const RAR5_TYPE_FILE = 2;
|
|
27
|
+
export declare const RAR5_TYPE_SERVICE = 3;
|
|
28
|
+
export declare const RAR5_TYPE_ENCRYPTION = 4;
|
|
29
|
+
export declare const RAR5_TYPE_ENDARC = 5;
|
|
30
|
+
/** RAR4 block header types. */
|
|
31
|
+
export declare const RAR4_TYPE_MAIN = 115;
|
|
32
|
+
export declare const RAR4_TYPE_FILE = 116;
|
|
33
|
+
/** RAR4 main-header flag: whole-archive headers are password-encrypted. */
|
|
34
|
+
export declare const RAR4_MHD_ENCRYPTVER = 128;
|
|
35
|
+
export declare function matchAt(bytes: Uint8Array, sig: readonly number[], offset?: number): boolean;
|
|
36
|
+
/** First offset at or after `from` where `sig` occurs, or -1. */
|
|
37
|
+
export declare function indexOfSig(bytes: Uint8Array, sig: readonly number[], from?: number): number;
|
|
38
|
+
export declare function readU16LE(b: Uint8Array, o: number): number;
|
|
39
|
+
export declare function readU32LE(b: Uint8Array, o: number): number;
|
|
40
|
+
/** Little-endian u64 as a Number. 7z offsets never exceed 2^53 in practice. */
|
|
41
|
+
export declare function readU64LE(b: Uint8Array, o: number): number;
|
|
42
|
+
export interface Vint {
|
|
43
|
+
value: number;
|
|
44
|
+
/** Bytes consumed. */
|
|
45
|
+
length: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* RAR5 variable-width integer: 7 bits per byte, little-endian, high bit is the
|
|
49
|
+
* continuation flag. Returns null when the buffer ends mid-vint.
|
|
50
|
+
*/
|
|
51
|
+
export declare function readVint(b: Uint8Array, o: number): Vint | null;
|
|
52
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/archive/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,eAAO,MAAM,MAAM,sCAAgD,CAAC;AACpE,eAAO,MAAM,QAAQ,sCAAsD,CAAC;AAC5E,eAAO,MAAM,QAAQ,yCAA4D,CAAC;AAClF,gFAAgF;AAChF,eAAO,MAAM,cAAc,mCAAgD,CAAC;AAE5E,eAAO,MAAM,WAAW,yBAAoC,CAAC;AAC7D,eAAO,MAAM,YAAY,yBAAoC,CAAC;AAC9D,eAAO,MAAM,UAAU,yBAAoC,CAAC;AAE5D,4EAA4E;AAC5E,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,4EAA4E;AAC5E,eAAO,MAAM,OAAO,IAAO,CAAC;AAC5B,eAAO,MAAM,eAAe,KAAO,CAAC;AAEpC,qEAAqE;AACrE,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,cAAc,IAAI,CAAC;AAChC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AACtC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,+BAA+B;AAC/B,eAAO,MAAM,cAAc,MAAO,CAAC;AACnC,eAAO,MAAM,cAAc,MAAO,CAAC;AACnC,2EAA2E;AAC3E,eAAO,MAAM,mBAAmB,MAAS,CAAC;AAE1C,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,SAAI,GAAG,OAAO,CAMtF;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,SAAI,GAAG,MAAM,CAQtF;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,MAAM,WAAW,IAAI;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAY9D"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure byte-level constants and helpers for RAR/7z archive sniffing. No wasm in
|
|
3
|
+
* this import chain, so it is safe in the browser-facing diagnosis path.
|
|
4
|
+
*
|
|
5
|
+
* Signatures (docs/14 §RAR/7z):
|
|
6
|
+
* 7z 37 7A BC AF 27 1C
|
|
7
|
+
* RAR4 52 61 72 21 1A 07 00 ("Rar!\x1a\x07\x00")
|
|
8
|
+
* RAR5 52 61 72 21 1A 07 01 00 ("Rar!\x1a\x07\x01\x00")
|
|
9
|
+
* ZIP 50 4B 03 04 / 05 06 / 07 08 (handled by the existing zip engine)
|
|
10
|
+
*/
|
|
11
|
+
export const SIG_7Z = [0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c];
|
|
12
|
+
export const SIG_RAR4 = [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00];
|
|
13
|
+
export const SIG_RAR5 = [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00];
|
|
14
|
+
/** RAR mark head without the version discriminator (byte 6): "Rar!\x1a\x07". */
|
|
15
|
+
export const SIG_RAR_COMMON = [0x52, 0x61, 0x72, 0x21, 0x1a, 0x07];
|
|
16
|
+
export const SIG_ZIP_LFH = [0x50, 0x4b, 0x03, 0x04];
|
|
17
|
+
export const SIG_ZIP_EOCD = [0x50, 0x4b, 0x05, 0x06];
|
|
18
|
+
export const SIG_ZIP_DD = [0x50, 0x4b, 0x07, 0x08];
|
|
19
|
+
/** The 7z start header is a fixed 32-byte record before any packed data. */
|
|
20
|
+
export const SEVENZIP_START_HEADER_SIZE = 32;
|
|
21
|
+
/** 7z NextHeader property ids (first byte of the end-of-archive header). */
|
|
22
|
+
export const KHEADER = 0x01;
|
|
23
|
+
export const KENCODED_HEADER = 0x17;
|
|
24
|
+
/** RAR5 block header types (the value of the "header type" vint). */
|
|
25
|
+
export const RAR5_TYPE_MAIN = 1;
|
|
26
|
+
export const RAR5_TYPE_FILE = 2;
|
|
27
|
+
export const RAR5_TYPE_SERVICE = 3;
|
|
28
|
+
export const RAR5_TYPE_ENCRYPTION = 4;
|
|
29
|
+
export const RAR5_TYPE_ENDARC = 5;
|
|
30
|
+
/** RAR4 block header types. */
|
|
31
|
+
export const RAR4_TYPE_MAIN = 0x73; // MAIN_HEAD ('s')
|
|
32
|
+
export const RAR4_TYPE_FILE = 0x74; // FILE_HEAD ('t')
|
|
33
|
+
/** RAR4 main-header flag: whole-archive headers are password-encrypted. */
|
|
34
|
+
export const RAR4_MHD_ENCRYPTVER = 0x0080; // MHD_PASSWORD
|
|
35
|
+
export function matchAt(bytes, sig, offset = 0) {
|
|
36
|
+
if (offset + sig.length > bytes.length)
|
|
37
|
+
return false;
|
|
38
|
+
for (let i = 0; i < sig.length; i += 1) {
|
|
39
|
+
if (bytes[offset + i] !== sig[i])
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/** First offset at or after `from` where `sig` occurs, or -1. */
|
|
45
|
+
export function indexOfSig(bytes, sig, from = 0) {
|
|
46
|
+
outer: for (let i = from; i + sig.length <= bytes.length; i += 1) {
|
|
47
|
+
for (let j = 0; j < sig.length; j += 1) {
|
|
48
|
+
if (bytes[i + j] !== sig[j])
|
|
49
|
+
continue outer;
|
|
50
|
+
}
|
|
51
|
+
return i;
|
|
52
|
+
}
|
|
53
|
+
return -1;
|
|
54
|
+
}
|
|
55
|
+
export function readU16LE(b, o) {
|
|
56
|
+
return (b[o] | (b[o + 1] << 8)) & 0xffff;
|
|
57
|
+
}
|
|
58
|
+
export function readU32LE(b, o) {
|
|
59
|
+
return ((b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)) >>> 0);
|
|
60
|
+
}
|
|
61
|
+
/** Little-endian u64 as a Number. 7z offsets never exceed 2^53 in practice. */
|
|
62
|
+
export function readU64LE(b, o) {
|
|
63
|
+
let hi = 0;
|
|
64
|
+
let lo = 0;
|
|
65
|
+
lo = (b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24)) >>> 0;
|
|
66
|
+
hi = (b[o + 4] | (b[o + 5] << 8) | (b[o + 6] << 16) | (b[o + 7] << 24)) >>> 0;
|
|
67
|
+
return hi * 0x1_0000_0000 + lo;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* RAR5 variable-width integer: 7 bits per byte, little-endian, high bit is the
|
|
71
|
+
* continuation flag. Returns null when the buffer ends mid-vint.
|
|
72
|
+
*/
|
|
73
|
+
export function readVint(b, o) {
|
|
74
|
+
let value = 0;
|
|
75
|
+
let shift = 0;
|
|
76
|
+
let i = o;
|
|
77
|
+
while (i < b.length && shift < 64) {
|
|
78
|
+
const byte = b[i];
|
|
79
|
+
value += (byte & 0x7f) * 2 ** shift;
|
|
80
|
+
i += 1;
|
|
81
|
+
if ((byte & 0x80) === 0)
|
|
82
|
+
return { value, length: i - o };
|
|
83
|
+
shift += 7;
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/archive/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated, injectable host for 7z-wasm (use-strict/7z-wasm 1.2.0 — 7-Zip 24.09
|
|
3
|
+
* compiled to WASM). License: GNU LGPL + unRAR restriction. The unRAR decoder
|
|
4
|
+
* bundled in the wasm may be used to EXTRACT RAR archives but NOT to build a
|
|
5
|
+
* RAR-compatible archiver; see ./LICENSE-unrar.txt. This host therefore never
|
|
6
|
+
* exposes (and salvage never issues) a RAR creation command.
|
|
7
|
+
*
|
|
8
|
+
* wasm size: 7zz.wasm is ~1.65 MB (uncompressed) — a single 7-Zip binary that
|
|
9
|
+
* lists and extracts 7z, RAR (via unRAR), ZIP, tar, gzip, bzip2, xz, etc.
|
|
10
|
+
*
|
|
11
|
+
* Loading mirrors pdf/qpdf-host.ts and video/libav-host.ts: Node's default
|
|
12
|
+
* loader resolves the CJS/UMD wrapper from node_modules; a browser host calls
|
|
13
|
+
* setSevenZipLoader() with the wrapper factory (and locateFile/wasmBinary
|
|
14
|
+
* pointing at R2) before any salvage. Only the *factory* is cached — each
|
|
15
|
+
* salvage run gets its own module instance because 7-Zip's `main` calls exit()
|
|
16
|
+
* (with noExitRuntime the same instance is reused across the list + per-entry
|
|
17
|
+
* extract calls of a single run, but not across runs).
|
|
18
|
+
*/
|
|
19
|
+
/** The slice of the Emscripten module surface this package uses. */
|
|
20
|
+
export interface SevenZipFS {
|
|
21
|
+
writeFile(path: string, data: Uint8Array, opts?: {
|
|
22
|
+
flags?: string;
|
|
23
|
+
}): void;
|
|
24
|
+
readFile(path: string, opts?: {
|
|
25
|
+
encoding?: 'binary' | 'utf8';
|
|
26
|
+
flags?: string;
|
|
27
|
+
}): Uint8Array;
|
|
28
|
+
readdir(path: string): string[];
|
|
29
|
+
stat(path: string, dontFollow?: boolean): {
|
|
30
|
+
size: number;
|
|
31
|
+
mode: number;
|
|
32
|
+
};
|
|
33
|
+
isFile(mode: number): boolean;
|
|
34
|
+
isDir(mode: number): boolean;
|
|
35
|
+
mkdir(path: string, mode?: number): unknown;
|
|
36
|
+
analyzePath?(path: string): {
|
|
37
|
+
exists: boolean;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface SevenZipModule {
|
|
41
|
+
FS: SevenZipFS;
|
|
42
|
+
callMain(args: string[]): void;
|
|
43
|
+
}
|
|
44
|
+
export interface SevenZipModuleOptions {
|
|
45
|
+
noExitRuntime?: boolean;
|
|
46
|
+
stdin?: () => number | null;
|
|
47
|
+
print?: (line: string) => void;
|
|
48
|
+
printErr?: (line: string) => void;
|
|
49
|
+
locateFile?: (url: string, scriptDirectory: string) => string;
|
|
50
|
+
wasmBinary?: ArrayBuffer | Uint8Array;
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
}
|
|
53
|
+
export interface SevenZipFactory {
|
|
54
|
+
(opts?: SevenZipModuleOptions): Promise<SevenZipModule>;
|
|
55
|
+
}
|
|
56
|
+
export interface SevenZipLoader {
|
|
57
|
+
factory: SevenZipFactory;
|
|
58
|
+
/** Extra options merged into every module instance (locateFile, wasmBinary…). */
|
|
59
|
+
factoryOpts?: SevenZipModuleOptions;
|
|
60
|
+
}
|
|
61
|
+
/** Inject how the 7z-wasm factory is obtained (browser hosts). */
|
|
62
|
+
export declare function setSevenZipLoader(load: () => Promise<SevenZipLoader>): void;
|
|
63
|
+
/** Drop the cached factory (tests, or after a wasm crash). */
|
|
64
|
+
export declare function resetSevenZipHost(): void;
|
|
65
|
+
/** stdout/stderr and exit code of one 7-Zip command. */
|
|
66
|
+
export interface SevenZipResult {
|
|
67
|
+
code: number;
|
|
68
|
+
stdout: string;
|
|
69
|
+
stderr: string;
|
|
70
|
+
}
|
|
71
|
+
export interface SevenZipSession {
|
|
72
|
+
fs: SevenZipFS;
|
|
73
|
+
/** Run one 7-Zip command; captures stdout/stderr and never throws. */
|
|
74
|
+
run(args: string[]): SevenZipResult;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a fresh 7-Zip module and hand a session to `fn`. stdin returns EOF so a
|
|
78
|
+
* password prompt on an encrypted archive fails fast instead of hanging.
|
|
79
|
+
*/
|
|
80
|
+
export declare function withSevenZip<T>(fn: (session: SevenZipSession) => Promise<T> | T): Promise<T>;
|
|
81
|
+
/** Eagerly resolve the factory (used by salvage to surface load failures honestly). */
|
|
82
|
+
export declare function ensureSevenZip(): Promise<void>;
|
|
83
|
+
//# sourceMappingURL=host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/archive/host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU,CAAC;IAC5F,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5C,WAAW,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;CACjD;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,UAAU,CAAC;IACf,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,KAAK,MAAM,CAAC;IAC9D,UAAU,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC;IACtC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,IAAI,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,iFAAiF;IACjF,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAKD,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAG3E;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAyBD,wDAAwD;AACxD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,UAAU,CAAC;IACf,sEAAsE;IACtE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA+BlG;AAED,uFAAuF;AACvF,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated, injectable host for 7z-wasm (use-strict/7z-wasm 1.2.0 — 7-Zip 24.09
|
|
3
|
+
* compiled to WASM). License: GNU LGPL + unRAR restriction. The unRAR decoder
|
|
4
|
+
* bundled in the wasm may be used to EXTRACT RAR archives but NOT to build a
|
|
5
|
+
* RAR-compatible archiver; see ./LICENSE-unrar.txt. This host therefore never
|
|
6
|
+
* exposes (and salvage never issues) a RAR creation command.
|
|
7
|
+
*
|
|
8
|
+
* wasm size: 7zz.wasm is ~1.65 MB (uncompressed) — a single 7-Zip binary that
|
|
9
|
+
* lists and extracts 7z, RAR (via unRAR), ZIP, tar, gzip, bzip2, xz, etc.
|
|
10
|
+
*
|
|
11
|
+
* Loading mirrors pdf/qpdf-host.ts and video/libav-host.ts: Node's default
|
|
12
|
+
* loader resolves the CJS/UMD wrapper from node_modules; a browser host calls
|
|
13
|
+
* setSevenZipLoader() with the wrapper factory (and locateFile/wasmBinary
|
|
14
|
+
* pointing at R2) before any salvage. Only the *factory* is cached — each
|
|
15
|
+
* salvage run gets its own module instance because 7-Zip's `main` calls exit()
|
|
16
|
+
* (with noExitRuntime the same instance is reused across the list + per-entry
|
|
17
|
+
* extract calls of a single run, but not across runs).
|
|
18
|
+
*/
|
|
19
|
+
let loaderOverride = null;
|
|
20
|
+
let factoryPromise = null;
|
|
21
|
+
/** Inject how the 7z-wasm factory is obtained (browser hosts). */
|
|
22
|
+
export function setSevenZipLoader(load) {
|
|
23
|
+
loaderOverride = load;
|
|
24
|
+
factoryPromise = null;
|
|
25
|
+
}
|
|
26
|
+
/** Drop the cached factory (tests, or after a wasm crash). */
|
|
27
|
+
export function resetSevenZipHost() {
|
|
28
|
+
factoryPromise = null;
|
|
29
|
+
}
|
|
30
|
+
async function defaultNodeLoader() {
|
|
31
|
+
const isNode = typeof process !== 'undefined' && !!process.versions?.node;
|
|
32
|
+
if (!isNode) {
|
|
33
|
+
throw new Error('archive host: no loader configured. In the browser, call setSevenZipLoader() with the ' +
|
|
34
|
+
'7z-wasm factory and a locateFile/wasmBinary for 7zz.wasm before listing or extracting.');
|
|
35
|
+
}
|
|
36
|
+
const { createRequire } = await import('node:module');
|
|
37
|
+
const require = createRequire(import.meta.url);
|
|
38
|
+
const mod = require('7z-wasm');
|
|
39
|
+
const factory = typeof mod === 'function' ? mod : mod.default;
|
|
40
|
+
return { factory };
|
|
41
|
+
}
|
|
42
|
+
function getLoader() {
|
|
43
|
+
factoryPromise ??= (loaderOverride ?? defaultNodeLoader)().catch((e) => {
|
|
44
|
+
factoryPromise = null;
|
|
45
|
+
throw e;
|
|
46
|
+
});
|
|
47
|
+
return factoryPromise;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a fresh 7-Zip module and hand a session to `fn`. stdin returns EOF so a
|
|
51
|
+
* password prompt on an encrypted archive fails fast instead of hanging.
|
|
52
|
+
*/
|
|
53
|
+
export async function withSevenZip(fn) {
|
|
54
|
+
const { factory, factoryOpts } = await getLoader();
|
|
55
|
+
const outBuf = [];
|
|
56
|
+
const errBuf = [];
|
|
57
|
+
const module = await factory({
|
|
58
|
+
noExitRuntime: true,
|
|
59
|
+
stdin: () => null,
|
|
60
|
+
print: (line) => outBuf.push(line),
|
|
61
|
+
printErr: (line) => errBuf.push(line),
|
|
62
|
+
...factoryOpts,
|
|
63
|
+
});
|
|
64
|
+
const session = {
|
|
65
|
+
fs: module.FS,
|
|
66
|
+
run(args) {
|
|
67
|
+
outBuf.length = 0;
|
|
68
|
+
errBuf.length = 0;
|
|
69
|
+
let code = 0;
|
|
70
|
+
try {
|
|
71
|
+
module.callMain(args);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
// Emscripten throws the raw exit status (a number) on exit(n), or an
|
|
75
|
+
// ExitStatus-like object; either way a non-zero code is a failure.
|
|
76
|
+
if (typeof e === 'number')
|
|
77
|
+
code = e;
|
|
78
|
+
else if (e && typeof e === 'object' && 'status' in e)
|
|
79
|
+
code = Number(e.status) || 1;
|
|
80
|
+
else
|
|
81
|
+
code = 1;
|
|
82
|
+
}
|
|
83
|
+
return { code, stdout: outBuf.join('\n'), stderr: errBuf.join('\n') };
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
return fn(session);
|
|
87
|
+
}
|
|
88
|
+
/** Eagerly resolve the factory (used by salvage to surface load failures honestly). */
|
|
89
|
+
export async function ensureSevenZip() {
|
|
90
|
+
await getLoader();
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/archive/host.ts"],"names":[],"mappings":"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"}
|