@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,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level SQLite file-format primitives shared by diagnosis and recovery.
|
|
3
|
+
* Pure functions, no engine dependency. Everything here is derived from the
|
|
4
|
+
* public-domain SQLite file format spec (https://sqlite.org/fileformat2.html):
|
|
5
|
+
* the 100-byte database header, the b-tree page layout, varints and the record
|
|
6
|
+
* (serial-type) format. Kept dependency-free so it runs identically in Node and
|
|
7
|
+
* the browser.
|
|
8
|
+
*/
|
|
9
|
+
/** The 16-byte magic that opens every SQLite database: "SQLite format 3\0". */
|
|
10
|
+
export declare const SQLITE_MAGIC: Uint8Array<ArrayBuffer>;
|
|
11
|
+
export declare const HEADER_SIZE = 100;
|
|
12
|
+
/** B-tree page type bytes. */
|
|
13
|
+
export declare const PAGE_INTERIOR_INDEX = 2;
|
|
14
|
+
export declare const PAGE_INTERIOR_TABLE = 5;
|
|
15
|
+
export declare const PAGE_LEAF_INDEX = 10;
|
|
16
|
+
export declare const PAGE_LEAF_TABLE = 13;
|
|
17
|
+
/** Storage-class values decoded from a record. INTEGERs that fit in a JS number
|
|
18
|
+
* come back as `number`; wider 64-bit integers come back as `bigint`. */
|
|
19
|
+
export type SqlValue = null | number | bigint | string | Uint8Array;
|
|
20
|
+
export interface SqliteHeader {
|
|
21
|
+
pageSize: number;
|
|
22
|
+
/** Reserved bytes at the end of each page (usually 0). */
|
|
23
|
+
reservedBytes: number;
|
|
24
|
+
writeVersion: number;
|
|
25
|
+
readVersion: number;
|
|
26
|
+
fileChangeCounter: number;
|
|
27
|
+
/** In-header database size in pages (offset 28). Only trustworthy when valid. */
|
|
28
|
+
pageCount: number;
|
|
29
|
+
/** True when the in-header page count is authoritative (SQLite's own rule:
|
|
30
|
+
* change counter at offset 24 equals version-valid-for at offset 92). */
|
|
31
|
+
pageCountValid: boolean;
|
|
32
|
+
freelistTrunkPage: number;
|
|
33
|
+
freelistPageCount: number;
|
|
34
|
+
schemaCookie: number;
|
|
35
|
+
schemaFormat: number;
|
|
36
|
+
/** 1 = UTF-8, 2 = UTF-16le, 3 = UTF-16be. */
|
|
37
|
+
textEncoding: number;
|
|
38
|
+
versionValidFor: number;
|
|
39
|
+
sqliteVersion: number;
|
|
40
|
+
}
|
|
41
|
+
export declare function readU16(b: Uint8Array, off: number): number;
|
|
42
|
+
export declare function readU32(b: Uint8Array, off: number): number;
|
|
43
|
+
/** Does the buffer start with the SQLite magic string? */
|
|
44
|
+
export declare function hasMagic(b: Uint8Array): boolean;
|
|
45
|
+
/** True for a page size SQLite accepts: a power of two in [512, 65536]. The
|
|
46
|
+
* on-disk value 1 is the spec's stand-in for 65536. */
|
|
47
|
+
export declare function isValidPageSize(raw: number): boolean;
|
|
48
|
+
export declare function decodePageSize(raw: number): number;
|
|
49
|
+
/**
|
|
50
|
+
* Parse the 100-byte database header. Returns null when the magic is absent or
|
|
51
|
+
* the page size is structurally impossible; every other field is returned raw
|
|
52
|
+
* so the diagnosis layer can decide how damaged it is.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseHeader(b: Uint8Array): SqliteHeader | null;
|
|
55
|
+
/** Decoded big-endian variable-length integer and how many bytes it used. */
|
|
56
|
+
export interface Varint {
|
|
57
|
+
value: bigint;
|
|
58
|
+
length: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Read a SQLite varint (1-9 big-endian bytes; high bit is a continuation flag,
|
|
62
|
+
* except the 9th byte contributes all 8 bits). Returns a bigint so 64-bit
|
|
63
|
+
* rowids and integer serial types never lose precision.
|
|
64
|
+
*/
|
|
65
|
+
export declare function readVarint(b: Uint8Array, off: number): Varint;
|
|
66
|
+
/** Narrow a bigint to a JS number when it is exactly representable. */
|
|
67
|
+
export declare function toSafeInt(v: bigint): number | bigint;
|
|
68
|
+
export interface BtreePageHeader {
|
|
69
|
+
type: number;
|
|
70
|
+
firstFreeblock: number;
|
|
71
|
+
cellCount: number;
|
|
72
|
+
cellContentStart: number;
|
|
73
|
+
fragmentedFreeBytes: number;
|
|
74
|
+
/** Interior pages only; -1 on leaf pages. */
|
|
75
|
+
rightMostPointer: number;
|
|
76
|
+
/** Offset within the page where the cell-pointer array begins. */
|
|
77
|
+
cellPointerArrayOffset: number;
|
|
78
|
+
/** Offset within the page where the b-tree header begins (100 on page 1). */
|
|
79
|
+
headerOffset: number;
|
|
80
|
+
}
|
|
81
|
+
export declare function isBtreePageType(type: number): boolean;
|
|
82
|
+
export declare function isInterior(type: number): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Parse a b-tree page header. `pageNo` distinguishes page 1 (whose b-tree
|
|
85
|
+
* header sits after the 100-byte database header). Returns null when the type
|
|
86
|
+
* byte is not a b-tree page type.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseBtreePageHeader(page: Uint8Array, pageNo: number): BtreePageHeader | null;
|
|
89
|
+
/** Cell-content offsets (relative to page start) from the cell-pointer array. */
|
|
90
|
+
export declare function readCellPointers(page: Uint8Array, hdr: BtreePageHeader): number[];
|
|
91
|
+
export interface DecodedRecord {
|
|
92
|
+
/** One value per column, in storage order. */
|
|
93
|
+
values: SqlValue[];
|
|
94
|
+
/** Serial type codes, parallel to `values` (useful for honest reporting). */
|
|
95
|
+
serialTypes: number[];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Decode a record (the "payload" of a table-leaf cell) into typed values.
|
|
99
|
+
* `textEncoding` selects the decoder for TEXT columns. Returns null when the
|
|
100
|
+
* record header is self-inconsistent (a common symptom of bit-rot).
|
|
101
|
+
*/
|
|
102
|
+
export declare function decodeRecord(payload: Uint8Array, textEncoding: number): DecodedRecord | null;
|
|
103
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/sqlite/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Low-level SQLite file-format primitives shared by diagnosis and recovery.
|
|
3
|
+
* Pure functions, no engine dependency. Everything here is derived from the
|
|
4
|
+
* public-domain SQLite file format spec (https://sqlite.org/fileformat2.html):
|
|
5
|
+
* the 100-byte database header, the b-tree page layout, varints and the record
|
|
6
|
+
* (serial-type) format. Kept dependency-free so it runs identically in Node and
|
|
7
|
+
* the browser.
|
|
8
|
+
*/
|
|
9
|
+
/** The 16-byte magic that opens every SQLite database: "SQLite format 3\0". */
|
|
10
|
+
export const SQLITE_MAGIC = new Uint8Array([
|
|
11
|
+
0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00,
|
|
12
|
+
]);
|
|
13
|
+
export const HEADER_SIZE = 100;
|
|
14
|
+
/** B-tree page type bytes. */
|
|
15
|
+
export const PAGE_INTERIOR_INDEX = 0x02;
|
|
16
|
+
export const PAGE_INTERIOR_TABLE = 0x05;
|
|
17
|
+
export const PAGE_LEAF_INDEX = 0x0a;
|
|
18
|
+
export const PAGE_LEAF_TABLE = 0x0d;
|
|
19
|
+
export function readU16(b, off) {
|
|
20
|
+
return ((b[off] ?? 0) << 8) | (b[off + 1] ?? 0);
|
|
21
|
+
}
|
|
22
|
+
export function readU32(b, off) {
|
|
23
|
+
return ((b[off] ?? 0) * 0x1000000 +
|
|
24
|
+
((b[off + 1] ?? 0) << 16) +
|
|
25
|
+
((b[off + 2] ?? 0) << 8) +
|
|
26
|
+
(b[off + 3] ?? 0));
|
|
27
|
+
}
|
|
28
|
+
/** Does the buffer start with the SQLite magic string? */
|
|
29
|
+
export function hasMagic(b) {
|
|
30
|
+
if (b.length < SQLITE_MAGIC.length)
|
|
31
|
+
return false;
|
|
32
|
+
for (let i = 0; i < SQLITE_MAGIC.length; i++)
|
|
33
|
+
if (b[i] !== SQLITE_MAGIC[i])
|
|
34
|
+
return false;
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
/** True for a page size SQLite accepts: a power of two in [512, 65536]. The
|
|
38
|
+
* on-disk value 1 is the spec's stand-in for 65536. */
|
|
39
|
+
export function isValidPageSize(raw) {
|
|
40
|
+
const size = raw === 1 ? 65536 : raw;
|
|
41
|
+
return size >= 512 && size <= 65536 && (size & (size - 1)) === 0;
|
|
42
|
+
}
|
|
43
|
+
export function decodePageSize(raw) {
|
|
44
|
+
return raw === 1 ? 65536 : raw;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse the 100-byte database header. Returns null when the magic is absent or
|
|
48
|
+
* the page size is structurally impossible; every other field is returned raw
|
|
49
|
+
* so the diagnosis layer can decide how damaged it is.
|
|
50
|
+
*/
|
|
51
|
+
export function parseHeader(b) {
|
|
52
|
+
if (!hasMagic(b) || b.length < HEADER_SIZE)
|
|
53
|
+
return null;
|
|
54
|
+
const rawPageSize = readU16(b, 16);
|
|
55
|
+
if (!isValidPageSize(rawPageSize))
|
|
56
|
+
return null;
|
|
57
|
+
const fileChangeCounter = readU32(b, 24);
|
|
58
|
+
const versionValidFor = readU32(b, 92);
|
|
59
|
+
const pageCount = readU32(b, 28);
|
|
60
|
+
return {
|
|
61
|
+
pageSize: decodePageSize(rawPageSize),
|
|
62
|
+
writeVersion: b[18] ?? 0,
|
|
63
|
+
readVersion: b[19] ?? 0,
|
|
64
|
+
reservedBytes: b[20] ?? 0,
|
|
65
|
+
fileChangeCounter,
|
|
66
|
+
pageCount,
|
|
67
|
+
pageCountValid: pageCount > 0 && fileChangeCounter === versionValidFor,
|
|
68
|
+
freelistTrunkPage: readU32(b, 32),
|
|
69
|
+
freelistPageCount: readU32(b, 36),
|
|
70
|
+
schemaCookie: readU32(b, 40),
|
|
71
|
+
schemaFormat: readU32(b, 44),
|
|
72
|
+
textEncoding: readU32(b, 56),
|
|
73
|
+
versionValidFor,
|
|
74
|
+
sqliteVersion: readU32(b, 96),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Read a SQLite varint (1-9 big-endian bytes; high bit is a continuation flag,
|
|
79
|
+
* except the 9th byte contributes all 8 bits). Returns a bigint so 64-bit
|
|
80
|
+
* rowids and integer serial types never lose precision.
|
|
81
|
+
*/
|
|
82
|
+
export function readVarint(b, off) {
|
|
83
|
+
let value = 0n;
|
|
84
|
+
for (let i = 0; i < 8; i++) {
|
|
85
|
+
const byte = b[off + i];
|
|
86
|
+
if (byte === undefined)
|
|
87
|
+
return { value, length: i };
|
|
88
|
+
value = (value << 7n) | BigInt(byte & 0x7f);
|
|
89
|
+
if ((byte & 0x80) === 0)
|
|
90
|
+
return { value, length: i + 1 };
|
|
91
|
+
}
|
|
92
|
+
// 9th byte: all 8 bits contribute.
|
|
93
|
+
const ninth = b[off + 8];
|
|
94
|
+
if (ninth === undefined)
|
|
95
|
+
return { value, length: 8 };
|
|
96
|
+
value = (value << 8n) | BigInt(ninth);
|
|
97
|
+
return { value, length: 9 };
|
|
98
|
+
}
|
|
99
|
+
/** Narrow a bigint to a JS number when it is exactly representable. */
|
|
100
|
+
export function toSafeInt(v) {
|
|
101
|
+
return v >= BigInt(Number.MIN_SAFE_INTEGER) && v <= BigInt(Number.MAX_SAFE_INTEGER) ? Number(v) : v;
|
|
102
|
+
}
|
|
103
|
+
export function isBtreePageType(type) {
|
|
104
|
+
return (type === PAGE_INTERIOR_INDEX ||
|
|
105
|
+
type === PAGE_INTERIOR_TABLE ||
|
|
106
|
+
type === PAGE_LEAF_INDEX ||
|
|
107
|
+
type === PAGE_LEAF_TABLE);
|
|
108
|
+
}
|
|
109
|
+
export function isInterior(type) {
|
|
110
|
+
return type === PAGE_INTERIOR_INDEX || type === PAGE_INTERIOR_TABLE;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Parse a b-tree page header. `pageNo` distinguishes page 1 (whose b-tree
|
|
114
|
+
* header sits after the 100-byte database header). Returns null when the type
|
|
115
|
+
* byte is not a b-tree page type.
|
|
116
|
+
*/
|
|
117
|
+
export function parseBtreePageHeader(page, pageNo) {
|
|
118
|
+
const headerOffset = pageNo === 1 ? HEADER_SIZE : 0;
|
|
119
|
+
const type = page[headerOffset];
|
|
120
|
+
if (type === undefined || !isBtreePageType(type))
|
|
121
|
+
return null;
|
|
122
|
+
const interior = isInterior(type);
|
|
123
|
+
const cellCount = readU16(page, headerOffset + 3);
|
|
124
|
+
const rawContentStart = readU16(page, headerOffset + 5);
|
|
125
|
+
return {
|
|
126
|
+
type,
|
|
127
|
+
firstFreeblock: readU16(page, headerOffset + 1),
|
|
128
|
+
cellCount,
|
|
129
|
+
cellContentStart: rawContentStart === 0 ? 65536 : rawContentStart,
|
|
130
|
+
fragmentedFreeBytes: page[headerOffset + 7] ?? 0,
|
|
131
|
+
rightMostPointer: interior ? readU32(page, headerOffset + 8) : -1,
|
|
132
|
+
cellPointerArrayOffset: headerOffset + (interior ? 12 : 8),
|
|
133
|
+
headerOffset,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/** Cell-content offsets (relative to page start) from the cell-pointer array. */
|
|
137
|
+
export function readCellPointers(page, hdr) {
|
|
138
|
+
const out = [];
|
|
139
|
+
for (let i = 0; i < hdr.cellCount; i++) {
|
|
140
|
+
const ptr = readU16(page, hdr.cellPointerArrayOffset + i * 2);
|
|
141
|
+
if (ptr >= hdr.headerOffset && ptr < page.length)
|
|
142
|
+
out.push(ptr);
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Decode a record (the "payload" of a table-leaf cell) into typed values.
|
|
148
|
+
* `textEncoding` selects the decoder for TEXT columns. Returns null when the
|
|
149
|
+
* record header is self-inconsistent (a common symptom of bit-rot).
|
|
150
|
+
*/
|
|
151
|
+
export function decodeRecord(payload, textEncoding) {
|
|
152
|
+
if (payload.length === 0)
|
|
153
|
+
return null;
|
|
154
|
+
const first = readVarint(payload, 0);
|
|
155
|
+
const headerLength = Number(first.value);
|
|
156
|
+
if (headerLength <= 0 || headerLength > payload.length)
|
|
157
|
+
return null;
|
|
158
|
+
const serialTypes = [];
|
|
159
|
+
let p = first.length;
|
|
160
|
+
while (p < headerLength) {
|
|
161
|
+
const st = readVarint(payload, p);
|
|
162
|
+
if (st.length === 0)
|
|
163
|
+
return null;
|
|
164
|
+
serialTypes.push(Number(st.value));
|
|
165
|
+
p += st.length;
|
|
166
|
+
}
|
|
167
|
+
const values = [];
|
|
168
|
+
let body = headerLength;
|
|
169
|
+
for (const st of serialTypes) {
|
|
170
|
+
const [value, size] = decodeSerial(payload, body, st, textEncoding);
|
|
171
|
+
values.push(value);
|
|
172
|
+
body += size;
|
|
173
|
+
if (body > payload.length)
|
|
174
|
+
break; // Truncated body: keep what parsed.
|
|
175
|
+
}
|
|
176
|
+
return { values, serialTypes };
|
|
177
|
+
}
|
|
178
|
+
function decodeSerial(payload, off, st, textEncoding) {
|
|
179
|
+
switch (st) {
|
|
180
|
+
case 0:
|
|
181
|
+
return [null, 0];
|
|
182
|
+
case 1:
|
|
183
|
+
return [signedInt(payload, off, 1), 1];
|
|
184
|
+
case 2:
|
|
185
|
+
return [signedInt(payload, off, 2), 2];
|
|
186
|
+
case 3:
|
|
187
|
+
return [signedInt(payload, off, 3), 3];
|
|
188
|
+
case 4:
|
|
189
|
+
return [signedInt(payload, off, 4), 4];
|
|
190
|
+
case 5:
|
|
191
|
+
return [signedInt(payload, off, 6), 6];
|
|
192
|
+
case 6:
|
|
193
|
+
return [signedInt(payload, off, 8), 8];
|
|
194
|
+
case 7:
|
|
195
|
+
return [readFloat64(payload, off), 8];
|
|
196
|
+
case 8:
|
|
197
|
+
return [0, 0];
|
|
198
|
+
case 9:
|
|
199
|
+
return [1, 0];
|
|
200
|
+
default: {
|
|
201
|
+
if (st < 12)
|
|
202
|
+
return [null, 0]; // 10, 11 are reserved.
|
|
203
|
+
const len = Math.floor((st - (st % 2 === 0 ? 12 : 13)) / 2);
|
|
204
|
+
const slice = payload.subarray(off, off + len);
|
|
205
|
+
if (st % 2 === 0)
|
|
206
|
+
return [slice.slice(), len]; // BLOB
|
|
207
|
+
return [decodeText(slice, textEncoding), len]; // TEXT
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function signedInt(b, off, bytes) {
|
|
212
|
+
let v = 0n;
|
|
213
|
+
for (let i = 0; i < bytes; i++)
|
|
214
|
+
v = (v << 8n) | BigInt(b[off + i] ?? 0);
|
|
215
|
+
// Sign-extend from the top bit.
|
|
216
|
+
const bits = BigInt(bytes * 8);
|
|
217
|
+
if (v >= 1n << (bits - 1n))
|
|
218
|
+
v -= 1n << bits;
|
|
219
|
+
return toSafeInt(v);
|
|
220
|
+
}
|
|
221
|
+
function readFloat64(b, off) {
|
|
222
|
+
if (off + 8 > b.length)
|
|
223
|
+
return 0;
|
|
224
|
+
const view = new DataView(b.buffer, b.byteOffset + off, 8);
|
|
225
|
+
return view.getFloat64(0, false);
|
|
226
|
+
}
|
|
227
|
+
const utf8 = new TextDecoder('utf-8', { fatal: false });
|
|
228
|
+
const utf16le = new TextDecoder('utf-16le', { fatal: false });
|
|
229
|
+
const utf16be = new TextDecoder('utf-16be', { fatal: false });
|
|
230
|
+
function decodeText(bytes, textEncoding) {
|
|
231
|
+
if (textEncoding === 2)
|
|
232
|
+
return utf16le.decode(bytes);
|
|
233
|
+
if (textEncoding === 3)
|
|
234
|
+
return utf16be.decode(bytes);
|
|
235
|
+
return utf8.decode(bytes);
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/sqlite/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite engine subpath export (`@intactfile/engines/sqlite`). Kept out of the
|
|
3
|
+
* root export so browser bundles that never touch SQLite never pull in the
|
|
4
|
+
* writer host; even here the writer engine (node:sqlite by default, or an
|
|
5
|
+
* injected sqlite-wasm builder) is only loaded on the first recoverSqlite call.
|
|
6
|
+
*
|
|
7
|
+
* The niche this fills: SQLite's `.recover` (reconstruct a corrupt database
|
|
8
|
+
* into a fresh one) has no client-side/browser implementation in the wild. The
|
|
9
|
+
* recovery brain here is a dependency-free TypeScript b-tree/page scanner, so
|
|
10
|
+
* it runs the same in Node and the browser.
|
|
11
|
+
*/
|
|
12
|
+
export { diagnoseSqlite } from './diagnose.js';
|
|
13
|
+
export type { SqliteDiagnosis, SqliteDamageClass, DiagnoseSqliteOptions, } from './diagnose.js';
|
|
14
|
+
export { recoverSqlite, recoverSqliteBytes } from './recover.js';
|
|
15
|
+
export type { SqliteRecoveryReport, SqliteRecoveryOutcome, SqliteRecoveryStrategy, RecoveredTableReport, RecoverSqliteOptions, } from './recover.js';
|
|
16
|
+
export { buildFreshDatabase, setSqliteBuilderLoader, resetSqliteHost, } from './sqlite-host.js';
|
|
17
|
+
export type { SqliteBuilder, SqliteBuilderLoader, SqliteBuildSpec, SqliteBuildStatement, SqliteBuildResult, } from './sqlite-host.js';
|
|
18
|
+
export { parseWal } from './wal.js';
|
|
19
|
+
export type { WalOverlay } from './wal.js';
|
|
20
|
+
export { SQLITE_MAGIC, parseHeader, parseBtreePageHeader, decodeRecord, readVarint, hasMagic, isValidPageSize, } from './format.js';
|
|
21
|
+
export type { SqliteHeader, SqlValue, DecodedRecord, BtreePageHeader } from './format.js';
|
|
22
|
+
export { PageReader, parseSchema, parseCreateTableColumns, walkTableBtree, rawScanLeafPages, } from './scan.js';
|
|
23
|
+
export type { MasterEntry, RecoveredRow, OrphanRecord, TableColumns, TableWalkResult, } from './scan.js';
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACjE,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG3C,OAAO,EACL,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1F,OAAO,EACL,UAAU,EACV,WAAW,EACX,uBAAuB,EACvB,cAAc,EACd,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,GAChB,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite engine subpath export (`@intactfile/engines/sqlite`). Kept out of the
|
|
3
|
+
* root export so browser bundles that never touch SQLite never pull in the
|
|
4
|
+
* writer host; even here the writer engine (node:sqlite by default, or an
|
|
5
|
+
* injected sqlite-wasm builder) is only loaded on the first recoverSqlite call.
|
|
6
|
+
*
|
|
7
|
+
* The niche this fills: SQLite's `.recover` (reconstruct a corrupt database
|
|
8
|
+
* into a fresh one) has no client-side/browser implementation in the wild. The
|
|
9
|
+
* recovery brain here is a dependency-free TypeScript b-tree/page scanner, so
|
|
10
|
+
* it runs the same in Node and the browser.
|
|
11
|
+
*/
|
|
12
|
+
export { diagnoseSqlite } from './diagnose.js';
|
|
13
|
+
export { recoverSqlite, recoverSqliteBytes } from './recover.js';
|
|
14
|
+
export { buildFreshDatabase, setSqliteBuilderLoader, resetSqliteHost, } from './sqlite-host.js';
|
|
15
|
+
export { parseWal } from './wal.js';
|
|
16
|
+
// Low-level format + scan primitives (useful for tooling and tests).
|
|
17
|
+
export { SQLITE_MAGIC, parseHeader, parseBtreePageHeader, decodeRecord, readVarint, hasMagic, isValidPageSize, } from './format.js';
|
|
18
|
+
export { PageReader, parseSchema, parseCreateTableColumns, walkTableBtree, rawScanLeafPages, } from './scan.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sqlite/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAO/C,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASjE,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGpC,qEAAqE;AACrE,OAAO,EACL,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,UAAU,EACV,WAAW,EACX,uBAAuB,EACvB,cAAc,EACd,gBAAgB,GACjB,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite recovery: reconstruct as much data as possible from a damaged database
|
|
3
|
+
* into a brand-new, openable one. Mirrors the strategy of SQLite's own
|
|
4
|
+
* `.recover` shell command (walk raw pages, rebuild the schema, re-insert every
|
|
5
|
+
* decodable row, route the un-attributable rows to a lost_and_found table) but
|
|
6
|
+
* implemented as a dependency-free TypeScript page scanner (scan.ts) plus an
|
|
7
|
+
* injectable writer host (sqlite-host.ts).
|
|
8
|
+
*
|
|
9
|
+
* Honesty first (see docs/03): recovered output is never presented as pristine.
|
|
10
|
+
* SQLite's own guidance is that data pulled from a corrupt file is "always
|
|
11
|
+
* suspect"; truncated data that is physically gone is reported as lost, and
|
|
12
|
+
* anything reconstructed by the pointer-free scan is flagged as such.
|
|
13
|
+
*/
|
|
14
|
+
import type { ByteSource } from '../byte-source.js';
|
|
15
|
+
import { type SqliteDamageClass } from './diagnose.js';
|
|
16
|
+
export type SqliteRecoveryOutcome = 'success' | 'partial' | 'failed';
|
|
17
|
+
export type SqliteRecoveryStrategy = 'btree-walk' | 'raw-page-scan' | 'dump-fallback' | null;
|
|
18
|
+
export interface RecoveredTableReport {
|
|
19
|
+
name: string;
|
|
20
|
+
columns: number;
|
|
21
|
+
rowsRecovered: number;
|
|
22
|
+
/** Some/all rows came from the pointer-free raw scan (interior pages damaged). */
|
|
23
|
+
viaRawScan: boolean;
|
|
24
|
+
/** The b-tree walk reached every page it pointed at. */
|
|
25
|
+
complete: boolean;
|
|
26
|
+
/** Cells on intact pages that were too corrupted to decode. */
|
|
27
|
+
droppedCells: number;
|
|
28
|
+
}
|
|
29
|
+
export interface SqliteRecoveryReport {
|
|
30
|
+
outcome: SqliteRecoveryOutcome;
|
|
31
|
+
damageClass: SqliteDamageClass;
|
|
32
|
+
strategy: SqliteRecoveryStrategy;
|
|
33
|
+
tablesRecovered: number;
|
|
34
|
+
rowsRecovered: number;
|
|
35
|
+
/** Rows placed in lost_and_found because they matched no known table. */
|
|
36
|
+
orphanCount: number;
|
|
37
|
+
/** Rows dropped by the writer (constraint violations, e.g. duplicate rowids). */
|
|
38
|
+
rowsFailedInsert: number;
|
|
39
|
+
/** Cells that were present on intact pages but too corrupted to decode. */
|
|
40
|
+
cellsDropped: number;
|
|
41
|
+
tables: RecoveredTableReport[];
|
|
42
|
+
/** Honest, user-facing caveats about what recovery can and cannot promise. */
|
|
43
|
+
caveats: string[];
|
|
44
|
+
notes: string[];
|
|
45
|
+
walApplied: boolean;
|
|
46
|
+
bytesIn: number;
|
|
47
|
+
bytesOut: number;
|
|
48
|
+
}
|
|
49
|
+
export interface RecoverSqliteOptions {
|
|
50
|
+
/** Sibling `-wal` file. Its committed frames are overlaid before scanning. */
|
|
51
|
+
wal?: ByteSource | Uint8Array;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Recover a SQLite database into a fresh one. Returns the new database bytes
|
|
55
|
+
* (omitted only when nothing could be produced) and an honest report.
|
|
56
|
+
*/
|
|
57
|
+
export declare function recoverSqlite(src: ByteSource, opts?: RecoverSqliteOptions): Promise<{
|
|
58
|
+
db?: Uint8Array;
|
|
59
|
+
report: SqliteRecoveryReport;
|
|
60
|
+
}>;
|
|
61
|
+
/** Convenience wrapper for callers holding raw bytes. */
|
|
62
|
+
export declare function recoverSqliteBytes(bytes: Uint8Array, opts?: RecoverSqliteOptions): Promise<{
|
|
63
|
+
db?: Uint8Array;
|
|
64
|
+
report: SqliteRecoveryReport;
|
|
65
|
+
}>;
|
|
66
|
+
//# sourceMappingURL=recover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recover.d.ts","sourceRoot":"","sources":["../../src/sqlite/recover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAevE,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AACrE,MAAM,MAAM,sBAAsB,GAAG,YAAY,GAAG,eAAe,GAAG,eAAe,GAAG,IAAI,CAAC;AAE7F,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,UAAU,EAAE,OAAO,CAAC;IACpB,wDAAwD;IACxD,QAAQ,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,WAAW,EAAE,iBAAiB,CAAC;IAC/B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,gBAAgB,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,GAAG,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAC/B;AAeD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,UAAU,EACf,IAAI,GAAE,oBAAyB,GAC9B,OAAO,CAAC;IAAE,EAAE,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,CAAC,CA6O5D;AAuFD,yDAAyD;AACzD,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,EACjB,IAAI,CAAC,EAAE,oBAAoB,GAC1B,OAAO,CAAC;IAAE,EAAE,CAAC,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,oBAAoB,CAAA;CAAE,CAAC,CAE5D"}
|