@intactfile/engines 0.1.0 → 0.3.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.
Files changed (113) hide show
  1. package/dist/archive/index.d.ts +5 -13
  2. package/dist/archive/index.d.ts.map +1 -1
  3. package/dist/archive/index.js +4 -1
  4. package/dist/archive/index.js.map +1 -1
  5. package/dist/audio/index.d.ts +11 -0
  6. package/dist/audio/index.d.ts.map +1 -0
  7. package/dist/audio/index.js +11 -0
  8. package/dist/audio/index.js.map +1 -0
  9. package/dist/audio/mp3.d.ts +22 -0
  10. package/dist/audio/mp3.d.ts.map +1 -0
  11. package/dist/audio/mp3.js +141 -0
  12. package/dist/audio/mp3.js.map +1 -0
  13. package/dist/audio/wav.d.ts +23 -0
  14. package/dist/audio/wav.d.ts.map +1 -0
  15. package/dist/audio/wav.js +86 -0
  16. package/dist/audio/wav.js.map +1 -0
  17. package/dist/bytes-util.d.ts +17 -0
  18. package/dist/bytes-util.d.ts.map +1 -0
  19. package/dist/bytes-util.js +46 -0
  20. package/dist/bytes-util.js.map +1 -0
  21. package/dist/detect/index.d.ts +1 -1
  22. package/dist/detect/index.d.ts.map +1 -1
  23. package/dist/detect/index.js +77 -0
  24. package/dist/detect/index.js.map +1 -1
  25. package/dist/heic/format.d.ts +87 -0
  26. package/dist/heic/format.d.ts.map +1 -0
  27. package/dist/heic/format.js +241 -0
  28. package/dist/heic/format.js.map +1 -0
  29. package/dist/index.d.ts +14 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +14 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/jpeg/index.d.ts +2 -8
  34. package/dist/jpeg/index.d.ts.map +1 -1
  35. package/dist/jpeg/index.js +4 -1
  36. package/dist/jpeg/index.js.map +1 -1
  37. package/dist/license.d.ts +63 -0
  38. package/dist/license.d.ts.map +1 -0
  39. package/dist/license.js +167 -0
  40. package/dist/license.js.map +1 -0
  41. package/dist/office-legacy/diagnose.d.ts +24 -0
  42. package/dist/office-legacy/diagnose.d.ts.map +1 -0
  43. package/dist/office-legacy/diagnose.js +111 -0
  44. package/dist/office-legacy/diagnose.js.map +1 -0
  45. package/dist/office-legacy/format.d.ts +89 -0
  46. package/dist/office-legacy/format.d.ts.map +1 -0
  47. package/dist/office-legacy/format.js +281 -0
  48. package/dist/office-legacy/format.js.map +1 -0
  49. package/dist/office-legacy/index.d.ts +9 -0
  50. package/dist/office-legacy/index.d.ts.map +1 -0
  51. package/dist/office-legacy/index.js +18 -0
  52. package/dist/office-legacy/index.js.map +1 -0
  53. package/dist/office-legacy/rebuild.d.ts +8 -0
  54. package/dist/office-legacy/rebuild.d.ts.map +1 -0
  55. package/dist/office-legacy/rebuild.js +234 -0
  56. package/dist/office-legacy/rebuild.js.map +1 -0
  57. package/dist/office-legacy/repair.d.ts +40 -0
  58. package/dist/office-legacy/repair.d.ts.map +1 -0
  59. package/dist/office-legacy/repair.js +161 -0
  60. package/dist/office-legacy/repair.js.map +1 -0
  61. package/dist/pdf/index.d.ts +5 -6
  62. package/dist/pdf/index.d.ts.map +1 -1
  63. package/dist/pdf/index.js +4 -1
  64. package/dist/pdf/index.js.map +1 -1
  65. package/dist/png/index.d.ts +1 -7
  66. package/dist/png/index.d.ts.map +1 -1
  67. package/dist/png/index.js +3 -1
  68. package/dist/png/index.js.map +1 -1
  69. package/dist/psd/diagnose.d.ts +33 -0
  70. package/dist/psd/diagnose.d.ts.map +1 -0
  71. package/dist/psd/diagnose.js +176 -0
  72. package/dist/psd/diagnose.js.map +1 -0
  73. package/dist/psd/format.d.ts +106 -0
  74. package/dist/psd/format.d.ts.map +1 -0
  75. package/dist/psd/format.js +238 -0
  76. package/dist/psd/format.js.map +1 -0
  77. package/dist/psd/index.d.ts +8 -0
  78. package/dist/psd/index.d.ts.map +1 -0
  79. package/dist/psd/index.js +13 -0
  80. package/dist/psd/index.js.map +1 -0
  81. package/dist/psd/repair.d.ts +36 -0
  82. package/dist/psd/repair.d.ts.map +1 -0
  83. package/dist/psd/repair.js +451 -0
  84. package/dist/psd/repair.js.map +1 -0
  85. package/dist/raw/diagnose.d.ts +29 -0
  86. package/dist/raw/diagnose.d.ts.map +1 -0
  87. package/dist/raw/diagnose.js +95 -0
  88. package/dist/raw/diagnose.js.map +1 -0
  89. package/dist/raw/format.d.ts +47 -0
  90. package/dist/raw/format.d.ts.map +1 -0
  91. package/dist/raw/format.js +213 -0
  92. package/dist/raw/format.js.map +1 -0
  93. package/dist/raw/index.d.ts +7 -0
  94. package/dist/raw/index.d.ts.map +1 -0
  95. package/dist/raw/index.js +13 -0
  96. package/dist/raw/index.js.map +1 -0
  97. package/dist/raw/repair.d.ts +46 -0
  98. package/dist/raw/repair.d.ts.map +1 -0
  99. package/dist/raw/repair.js +94 -0
  100. package/dist/raw/repair.js.map +1 -0
  101. package/dist/sqlite/index.d.ts +8 -1
  102. package/dist/sqlite/index.d.ts.map +1 -1
  103. package/dist/sqlite/index.js +4 -1
  104. package/dist/sqlite/index.js.map +1 -1
  105. package/dist/video/avi.d.ts +23 -0
  106. package/dist/video/avi.d.ts.map +1 -0
  107. package/dist/video/avi.js +122 -0
  108. package/dist/video/avi.js.map +1 -0
  109. package/dist/video/index.d.ts +15 -2
  110. package/dist/video/index.d.ts.map +1 -1
  111. package/dist/video/index.js +10 -2
  112. package/dist/video/index.js.map +1 -1
  113. package/package.json +18 -2
@@ -1,18 +1,10 @@
1
- /**
2
- * Archive engine subpath export (`@intactfile/engines/archive`) — RAR/7z
3
- * SALVAGE extraction (recover intact entries from a damaged archive), not deep
4
- * repair. Kept out of the root export so browser bundles that never touch
5
- * archives never pull in the 7z-wasm dependency; even here, the wasm only loads
6
- * on the first salvageArchive call. diagnoseArchive is pure byte-sniffing and
7
- * loads no wasm.
8
- *
9
- * License note: extraction (including RAR via 7-Zip's unRAR-derived decoder) is
10
- * permitted; RAR CREATION is not and is never performed. The unRAR license text
11
- * ships next to this module at ./LICENSE-unrar.txt.
12
- */
13
1
  export { diagnoseArchive } from './diagnose.js';
14
2
  export type { ArchiveDiagnosis, ArchiveFormat, ArchiveDamageClass } from './diagnose.js';
15
- export { salvageArchive, parseSltListing } from './salvage.js';
3
+ export declare const salvageArchive: (src: import("../byte-source.js").ByteSource, opts?: import("./salvage.js").SalvageOptions | undefined) => Promise<{
4
+ files: import("./salvage.js").SalvagedFile[];
5
+ report: import("./salvage.js").SalvageReport;
6
+ }>;
7
+ export { parseSltListing } from './salvage.js';
16
8
  export type { SalvagedFile, SalvageStatus, SalvageOutcome, SalvageReport, SalvageEntrySummary, SalvageOptions, } from './salvage.js';
17
9
  export { withSevenZip, ensureSevenZip, setSevenZipLoader, resetSevenZipHost, } from './host.js';
18
10
  export type { SevenZipLoader, SevenZipFactory, SevenZipModule, SevenZipModuleOptions, SevenZipSession, SevenZipResult, SevenZipFS, } from './host.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/archive/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,cAAc,EACd,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/archive/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEzF,eAAO,MAAM,cAAc;;;EAAwB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,cAAc,GACf,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,cAAc,EACd,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,cAAc,EACd,UAAU,GACX,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,0EAA0E;AAC1E,eAAO,MAAM,kBAAkB,sBAAsB,CAAC"}
@@ -10,8 +10,11 @@
10
10
  * permitted; RAR CREATION is not and is never performed. The unRAR license text
11
11
  * ships next to this module at ./LICENSE-unrar.txt.
12
12
  */
13
+ import { gate } from '../license.js';
14
+ import { salvageArchive as _salvageArchive } from './salvage.js';
13
15
  export { diagnoseArchive } from './diagnose.js';
14
- export { salvageArchive, parseSltListing } from './salvage.js';
16
+ export const salvageArchive = gate(_salvageArchive);
17
+ export { parseSltListing } from './salvage.js';
15
18
  export { withSevenZip, ensureSevenZip, setSevenZipLoader, resetSevenZipHost, } from './host.js';
16
19
  export { SIG_7Z, SIG_RAR4, SIG_RAR5, matchAt, indexOfSig, } from './format.js';
17
20
  /** Relative path (from this module) to the shipped unRAR license text. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/archive/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAU/D,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAWnB,OAAO,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/archive/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,cAAc,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAU/C,OAAO,EACL,YAAY,EACZ,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAWnB,OAAO,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,UAAU,GACX,MAAM,aAAa,CAAC;AAErB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,kBAAkB,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare const repairWav: (src: import("../byte-source.js").ByteSource) => Promise<{
2
+ audio: Uint8Array;
3
+ report: import("./wav.js").WavRepairReport;
4
+ }>;
5
+ export type { WavRepairReport, AudioOutcome } from "./wav.js";
6
+ export declare const repairMp3: (src: import("../byte-source.js").ByteSource) => Promise<{
7
+ audio: Uint8Array;
8
+ report: import("./mp3.js").Mp3RepairReport;
9
+ }>;
10
+ export type { Mp3RepairReport } from "./mp3.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,SAAS;;;EAAmB,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC9D,eAAO,MAAM,SAAS;;;EAAmB,CAAC;AAC1C,YAAY,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Audio engine subpath export (`@intactfile/engines/audio`). Pure-TS structural
3
+ * repair for WAV (RIFF) and MP3 (frame resync). Kept out of the root barrel so
4
+ * bundles that don't repair audio stay lean.
5
+ */
6
+ import { gate } from "../license.js";
7
+ import { repairWav as _repairWav } from "./wav.js";
8
+ import { repairMp3 as _repairMp3 } from "./mp3.js";
9
+ export const repairWav = gate(_repairWav);
10
+ export const repairMp3 = gate(_repairMp3);
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,SAAS,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;AAE1C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * MP3 repair — pure TS, structural. Strips a broken/leading ID3 tag and any
3
+ * garbage, resynchronises on valid MPEG audio frames, drops corrupt frames, and
4
+ * concatenates the survivors into a playable stream. Honest: 0 valid frames = failed.
5
+ */
6
+ import type { ByteSource } from "../byte-source.js";
7
+ import type { AudioOutcome } from "./wav.js";
8
+ export interface Mp3RepairReport {
9
+ outcome: AudioOutcome;
10
+ damageClass: string;
11
+ notes: string[];
12
+ bytesIn: number;
13
+ bytesOut: number;
14
+ framesFound: number;
15
+ framesKept: number;
16
+ leadingGarbageBytes: number;
17
+ }
18
+ export declare function repairMp3(src: ByteSource): Promise<{
19
+ audio: Uint8Array;
20
+ report: Mp3RepairReport;
21
+ }>;
22
+ //# sourceMappingURL=mp3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mp3.d.ts","sourceRoot":"","sources":["../../src/audio/mp3.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AA8DD,wBAAsB,SAAS,CAC7B,GAAG,EAAE,UAAU,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC,CAiFzD"}
@@ -0,0 +1,141 @@
1
+ import { readAll } from "../bytes-util.js";
2
+ // [version][layer] -> bitrate table (kbps); index 0 = free, 15 = bad (both skipped).
3
+ // version: 0=MPEG2.5, 2=MPEG2, 3=MPEG1 (1 = reserved). layer: 1=III, 2=II, 3=I.
4
+ const BR_MPEG1_L1 = [0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0];
5
+ const BR_MPEG1_L2 = [0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0];
6
+ const BR_MPEG1_L3 = [0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0];
7
+ const BR_MPEG2_L1 = [0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0];
8
+ const BR_MPEG2_L23 = [0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0];
9
+ const SR_MPEG1 = [44100, 48000, 32000];
10
+ const SR_MPEG2 = [22050, 24000, 16000];
11
+ const SR_MPEG25 = [11025, 12000, 8000];
12
+ /** Parse a 4-byte frame header at `o`; null if not a valid frame header. */
13
+ function parseHeader(b, o) {
14
+ if (o + 4 > b.length)
15
+ return null;
16
+ if (b[o] !== 0xff || ((b[o + 1] & 0xe0) !== 0xe0))
17
+ return null;
18
+ const version = (b[o + 1] >> 3) & 0x03; // 0=2.5,1=res,2=2,3=1
19
+ const layer = (b[o + 1] >> 1) & 0x03; // 0=res,1=III,2=II,3=I
20
+ if (version === 1 || layer === 0)
21
+ return null;
22
+ const brIdx = (b[o + 2] >> 4) & 0x0f;
23
+ const srIdx = (b[o + 2] >> 2) & 0x03;
24
+ const padding = (b[o + 2] >> 1) & 0x01;
25
+ if (brIdx === 0 || brIdx === 15 || srIdx === 3)
26
+ return null;
27
+ const mpeg1 = version === 3;
28
+ let brTable;
29
+ if (layer === 3)
30
+ brTable = mpeg1 ? BR_MPEG1_L1 : BR_MPEG2_L1;
31
+ else if (layer === 2)
32
+ brTable = mpeg1 ? BR_MPEG1_L2 : BR_MPEG2_L23;
33
+ else
34
+ brTable = mpeg1 ? BR_MPEG1_L3 : BR_MPEG2_L23;
35
+ const bitrate = (brTable[brIdx] ?? 0) * 1000;
36
+ const srTable = version === 3 ? SR_MPEG1 : version === 2 ? SR_MPEG2 : SR_MPEG25;
37
+ const sampleRate = srTable[srIdx] ?? 0;
38
+ if (bitrate === 0 || sampleRate === 0)
39
+ return null;
40
+ let length;
41
+ if (layer === 3) {
42
+ // Layer I
43
+ length = Math.floor((12 * bitrate) / sampleRate + padding) * 4;
44
+ }
45
+ else {
46
+ // Layer II & III
47
+ const coef = mpeg1 ? 144 : 72;
48
+ length = Math.floor((coef * bitrate) / sampleRate) + padding;
49
+ }
50
+ return length >= 4 ? { length } : null;
51
+ }
52
+ /** Length of a leading ID3v2 tag at offset 0, or 0 if none. */
53
+ function id3v2Length(b) {
54
+ if (b.length < 10 || b[0] !== 0x49 || b[1] !== 0x44 || b[2] !== 0x33)
55
+ return 0; // "ID3"
56
+ // syncsafe 28-bit size in bytes 6..9
57
+ const size = ((b[6] & 0x7f) << 21) | ((b[7] & 0x7f) << 14) | ((b[8] & 0x7f) << 7) | (b[9] & 0x7f);
58
+ const footer = (b[5] & 0x10) !== 0 ? 10 : 0;
59
+ return 10 + size + footer;
60
+ }
61
+ export async function repairMp3(src) {
62
+ const buf = await readAll(src);
63
+ const notes = [];
64
+ let pos = 0;
65
+ let leadingGarbage = 0;
66
+ const id3 = id3v2Length(buf);
67
+ if (id3 > 0 && id3 <= buf.length) {
68
+ pos = id3;
69
+ notes.push(`skipped a ${id3}-byte ID3v2 tag`);
70
+ }
71
+ const parts = [];
72
+ let framesFound = 0;
73
+ let framesKept = 0;
74
+ let firstFrameSeen = false;
75
+ while (pos < buf.length) {
76
+ const h = parseHeader(buf, pos);
77
+ if (h && pos + h.length <= buf.length) {
78
+ // Confirm the next boundary is EOF or another sync — rejects false positives.
79
+ const next = pos + h.length;
80
+ if (next === buf.length || (buf[next] === 0xff && (buf[next + 1] & 0xe0) === 0xe0)) {
81
+ parts.push(buf.subarray(pos, next));
82
+ framesFound++;
83
+ framesKept++;
84
+ firstFrameSeen = true;
85
+ pos = next;
86
+ continue;
87
+ }
88
+ }
89
+ // Not a valid frame here.
90
+ if (!firstFrameSeen)
91
+ leadingGarbage++;
92
+ else
93
+ framesFound++; // a corrupt/dropped frame region
94
+ pos++;
95
+ }
96
+ const bytesIn = buf.length;
97
+ if (framesKept === 0) {
98
+ return {
99
+ audio: new Uint8Array(0),
100
+ report: {
101
+ outcome: "failed",
102
+ damageClass: "no-frames",
103
+ notes,
104
+ bytesIn,
105
+ bytesOut: 0,
106
+ framesFound,
107
+ framesKept: 0,
108
+ leadingGarbageBytes: leadingGarbage,
109
+ },
110
+ };
111
+ }
112
+ let total = 0;
113
+ for (const p of parts)
114
+ total += p.length;
115
+ const out = new Uint8Array(total);
116
+ let w = 0;
117
+ for (const p of parts) {
118
+ out.set(p, w);
119
+ w += p.length;
120
+ }
121
+ if (leadingGarbage > 0)
122
+ notes.push(`dropped ${leadingGarbage} bytes of leading garbage`);
123
+ const dropped = framesFound - framesKept;
124
+ if (dropped > 0)
125
+ notes.push(`dropped ${dropped} corrupt frame region(s)`);
126
+ const outcome = leadingGarbage > 0 || dropped > 0 ? "partial" : "success";
127
+ return {
128
+ audio: out,
129
+ report: {
130
+ outcome,
131
+ damageClass: outcome === "success" ? "clean" : "resynced",
132
+ notes,
133
+ bytesIn,
134
+ bytesOut: out.length,
135
+ framesFound,
136
+ framesKept,
137
+ leadingGarbageBytes: leadingGarbage,
138
+ },
139
+ };
140
+ }
141
+ //# sourceMappingURL=mp3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mp3.js","sourceRoot":"","sources":["../../src/audio/mp3.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * WAV repair — pure TS, structural (RIFF). Rebuilds the RIFF/fmt/data headers
3
+ * when sizes are wrong or truncated and the PCM is intact. Honest: no 'fmt '
4
+ * means we can't know the format, so we fail rather than guess.
5
+ */
6
+ import type { ByteSource } from "../byte-source.js";
7
+ export type AudioOutcome = "success" | "partial" | "failed";
8
+ export interface WavRepairReport {
9
+ outcome: AudioOutcome;
10
+ damageClass: string;
11
+ notes: string[];
12
+ bytesIn: number;
13
+ bytesOut: number;
14
+ sampleRateHz: number;
15
+ channels: number;
16
+ bitsPerSample: number;
17
+ pcmBytes: number;
18
+ }
19
+ export declare function repairWav(src: ByteSource): Promise<{
20
+ audio: Uint8Array;
21
+ report: WavRepairReport;
22
+ }>;
23
+ //# sourceMappingURL=wav.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wav.d.ts","sourceRoot":"","sources":["../../src/audio/wav.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,YAAY,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,SAAS,CAC7B,GAAG,EAAE,UAAU,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,eAAe,CAAA;CAAE,CAAC,CAsFzD"}
@@ -0,0 +1,86 @@
1
+ import { indexOfAscii, readAll, u16le, u32le, writeAscii, writeU16le, writeU32le, } from "../bytes-util.js";
2
+ export async function repairWav(src) {
3
+ const buf = await readAll(src);
4
+ const notes = [];
5
+ const fail = (damageClass) => ({
6
+ audio: new Uint8Array(0),
7
+ report: {
8
+ outcome: "failed",
9
+ damageClass,
10
+ notes,
11
+ bytesIn: buf.length,
12
+ bytesOut: 0,
13
+ sampleRateHz: 0,
14
+ channels: 0,
15
+ bitsPerSample: 0,
16
+ pcmBytes: 0,
17
+ },
18
+ });
19
+ if (buf.length < 44)
20
+ return fail("too-small");
21
+ const fmtOff = indexOfAscii(buf, "fmt ", 0);
22
+ if (fmtOff < 0 || fmtOff + 24 > buf.length)
23
+ return fail("no-fmt");
24
+ const fmtBody = fmtOff + 8;
25
+ const audioFormat = u16le(buf, fmtBody) || 1;
26
+ const channels = u16le(buf, fmtBody + 2);
27
+ const sampleRate = u32le(buf, fmtBody + 4);
28
+ const bitsPerSample = u16le(buf, fmtBody + 14);
29
+ if (channels === 0 || sampleRate === 0 || bitsPerSample === 0)
30
+ return fail("bad-fmt-params");
31
+ const blockAlign = channels * (bitsPerSample >> 3) || 1;
32
+ const byteRate = sampleRate * blockAlign;
33
+ let damageClass = "header";
34
+ let pcm;
35
+ const dataOff = indexOfAscii(buf, "data", fmtOff + 8);
36
+ if (dataOff >= 0 && dataOff + 8 <= buf.length) {
37
+ const declared = u32le(buf, dataOff + 4);
38
+ const avail = buf.length - (dataOff + 8);
39
+ if (declared > avail) {
40
+ notes.push(`data chunk declares ${declared} bytes but only ${avail} are present — recovered what remained`);
41
+ damageClass = "truncated-data";
42
+ }
43
+ pcm = buf.subarray(dataOff + 8, dataOff + 8 + Math.min(declared || avail, avail));
44
+ }
45
+ else {
46
+ notes.push("no 'data' chunk header found — treated the bytes after fmt as PCM");
47
+ damageClass = "no-data-header";
48
+ pcm = buf.subarray(fmtBody + 16);
49
+ }
50
+ // Trim to whole sample frames.
51
+ pcm = pcm.subarray(0, pcm.length - (pcm.length % blockAlign));
52
+ if (pcm.length === 0)
53
+ return fail("no-pcm");
54
+ const out = new Uint8Array(44 + pcm.length);
55
+ writeAscii(out, 0, "RIFF");
56
+ writeU32le(out, 4, 36 + pcm.length);
57
+ writeAscii(out, 8, "WAVE");
58
+ writeAscii(out, 12, "fmt ");
59
+ writeU32le(out, 16, 16);
60
+ writeU16le(out, 20, audioFormat);
61
+ writeU16le(out, 22, channels);
62
+ writeU32le(out, 24, sampleRate);
63
+ writeU32le(out, 28, byteRate);
64
+ writeU16le(out, 32, blockAlign);
65
+ writeU16le(out, 34, bitsPerSample);
66
+ writeAscii(out, 36, "data");
67
+ writeU32le(out, 40, pcm.length);
68
+ out.set(pcm, 44);
69
+ notes.unshift("rebuilt RIFF/fmt/data headers");
70
+ const outcome = damageClass === "truncated-data" || damageClass === "no-data-header" ? "partial" : "success";
71
+ return {
72
+ audio: out,
73
+ report: {
74
+ outcome,
75
+ damageClass,
76
+ notes,
77
+ bytesIn: buf.length,
78
+ bytesOut: out.length,
79
+ sampleRateHz: sampleRate,
80
+ channels,
81
+ bitsPerSample,
82
+ pcmBytes: pcm.length,
83
+ },
84
+ };
85
+ }
86
+ //# sourceMappingURL=wav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wav.js","sourceRoot":"","sources":["../../src/audio/wav.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Small byte helpers shared by the pure-TS structural engines (WAV/MP3/AVI).
3
+ * Little-endian readers/writers + ASCII fourcc matching + a whole-source read.
4
+ */
5
+ import type { ByteSource } from "./byte-source.js";
6
+ /** Read the entire source into one buffer (chunked, tolerant of short reads). */
7
+ export declare function readAll(src: ByteSource): Promise<Uint8Array>;
8
+ export declare const u16le: (b: Uint8Array, o: number) => number;
9
+ export declare const u32le: (b: Uint8Array, o: number) => number;
10
+ export declare function writeU16le(b: Uint8Array, o: number, v: number): void;
11
+ export declare function writeU32le(b: Uint8Array, o: number, v: number): void;
12
+ export declare function writeAscii(b: Uint8Array, o: number, s: string): void;
13
+ /** True if the 4+ ASCII chars of `s` sit at offset `o`. */
14
+ export declare function matchAscii(b: Uint8Array, o: number, s: string): boolean;
15
+ /** First index of ASCII `s` in `b` at/after `from`, or -1. */
16
+ export declare function indexOfAscii(b: Uint8Array, s: string, from?: number): number;
17
+ //# sourceMappingURL=bytes-util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes-util.d.ts","sourceRoot":"","sources":["../src/bytes-util.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,iFAAiF;AACjF,wBAAsB,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAUlE;AAED,eAAO,MAAM,KAAK,GAAI,GAAG,UAAU,EAAE,GAAG,MAAM,KAAG,MAA8C,CAAC;AAEhG,eAAO,MAAM,KAAK,GAAI,GAAG,UAAU,EAAE,GAAG,MAAM,KAAG,MACmD,CAAC;AAErG,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAGpE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAKpE;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAGvE;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,MAAM,CAMvE"}
@@ -0,0 +1,46 @@
1
+ /** Read the entire source into one buffer (chunked, tolerant of short reads). */
2
+ export async function readAll(src) {
3
+ const out = new Uint8Array(src.size);
4
+ let off = 0;
5
+ while (off < src.size) {
6
+ const chunk = await src.read(off, Math.min(1 << 20, src.size - off));
7
+ if (chunk.length === 0)
8
+ break;
9
+ out.set(chunk, off);
10
+ off += chunk.length;
11
+ }
12
+ return off === out.length ? out : out.subarray(0, off);
13
+ }
14
+ export const u16le = (b, o) => (b[o] ?? 0) | ((b[o + 1] ?? 0) << 8);
15
+ export const u32le = (b, o) => (((b[o] ?? 0) | ((b[o + 1] ?? 0) << 8) | ((b[o + 2] ?? 0) << 16) | ((b[o + 3] ?? 0) << 24)) >>> 0);
16
+ export function writeU16le(b, o, v) {
17
+ b[o] = v & 0xff;
18
+ b[o + 1] = (v >>> 8) & 0xff;
19
+ }
20
+ export function writeU32le(b, o, v) {
21
+ b[o] = v & 0xff;
22
+ b[o + 1] = (v >>> 8) & 0xff;
23
+ b[o + 2] = (v >>> 16) & 0xff;
24
+ b[o + 3] = (v >>> 24) & 0xff;
25
+ }
26
+ export function writeAscii(b, o, s) {
27
+ for (let i = 0; i < s.length; i++)
28
+ b[o + i] = s.charCodeAt(i);
29
+ }
30
+ /** True if the 4+ ASCII chars of `s` sit at offset `o`. */
31
+ export function matchAscii(b, o, s) {
32
+ for (let i = 0; i < s.length; i++)
33
+ if (b[o + i] !== s.charCodeAt(i))
34
+ return false;
35
+ return true;
36
+ }
37
+ /** First index of ASCII `s` in `b` at/after `from`, or -1. */
38
+ export function indexOfAscii(b, s, from = 0) {
39
+ const last = b.length - s.length;
40
+ for (let i = Math.max(0, from); i <= last; i++) {
41
+ if (matchAscii(b, i, s))
42
+ return i;
43
+ }
44
+ return -1;
45
+ }
46
+ //# sourceMappingURL=bytes-util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes-util.js","sourceRoot":"","sources":["../src/bytes-util.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import type { ByteSource } from '../byte-source.js';
2
2
  import type { Confidence } from '../types.js';
3
- export type FileFormat = 'zip' | 'pdf' | 'mp4' | 'mov' | 'jpeg' | 'png' | 'wav' | 'avi' | 'riff' | 'mkv' | 'webm' | 'mp3' | 'unknown';
3
+ export type FileFormat = 'zip' | 'pdf' | 'mp4' | 'mov' | 'jpeg' | 'png' | 'wav' | 'avi' | 'riff' | 'mkv' | 'webm' | 'mp3' | 'raw' | 'psd' | 'cfbf' | 'unknown';
4
4
  export interface FormatDetection {
5
5
  format: FileFormat;
6
6
  /** Sub-container when known: docx/xlsx/pptx/ooxml/zip for zips, ftyp brand for mp4/mov, riff type for riff. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAW9C,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,KAAK,GACL,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,+GAA+G;IAC/G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAoDD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CA2G5E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa9C,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,KAAK,GACL,MAAM,GACN,KAAK,GACL,KAAK,GACL,KAAK,GACL,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,+GAA+G;IAC/G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAoDD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CA4K5E"}
@@ -1,3 +1,5 @@
1
+ import { findRawStart, rawIdAt } from '../raw/format.js';
2
+ import { findSignature as findPsdSignature } from '../psd/format.js';
1
3
  import { FLAG_DATA_DESCRIPTOR, LFH_FIXED_SIZE, SIG_EOCD, SIG_LFH, U32_MAX, parseLocalHeader, readU32, } from '../zip/format.js';
2
4
  const SCAN_WINDOW = 64 * 1024;
3
5
  function ascii(b, from, to) {
@@ -72,6 +74,25 @@ export async function detectFormat(src) {
72
74
  if (head[0] === 0xff && head[1] === 0xd8 && head[2] === 0xff) {
73
75
  return { format: 'jpeg', confidence: 'high', notes };
74
76
  }
77
+ // RAW photo containers: TIFF-family (CR2/NEF/ARW/DNG/generic TIFF) + Fujifilm
78
+ // RAF at offset 0. CR3 (ISO-BMFF, ftyp "crx ") is handled in the ftyp branch.
79
+ {
80
+ const rawId = rawIdAt(head, 0);
81
+ if (rawId && rawId.container !== 'cr3') {
82
+ return { format: 'raw', container: rawId.container, confidence: 'high', notes };
83
+ }
84
+ }
85
+ // PSD / PSB (Photoshop) — "8BPS"; version (2 bytes) distinguishes psd vs psb.
86
+ if (head[0] === 0x38 && head[1] === 0x42 && head[2] === 0x50 && head[3] === 0x53) {
87
+ const version = (head[4] << 8) | head[5];
88
+ return { format: 'psd', container: version === 2 ? 'psb' : 'psd', confidence: 'high', notes };
89
+ }
90
+ // CFBF / OLE2 (legacy Office .doc/.xls/.ppt/.msg) — D0 CF 11 E0 A1 B1 1A E1.
91
+ if (head[0] === 0xd0 && head[1] === 0xcf && head[2] === 0x11 && head[3] === 0xe0 &&
92
+ head[4] === 0xa1 && head[5] === 0xb1 && head[6] === 0x1a && head[7] === 0xe1) {
93
+ const win = src.size <= head.length ? head : await src.read(0, Math.min(src.size, SCAN_WINDOW));
94
+ return { format: 'cfbf', container: sniffCfbfContainer(win), confidence: 'high', notes };
95
+ }
75
96
  // RIFF (WAV / AVI)
76
97
  if (ascii(head, 0, 4) === 'RIFF' && head.length >= 12) {
77
98
  const kind = ascii(head, 8, 12);
@@ -107,6 +128,10 @@ export async function detectFormat(src) {
107
128
  // MP4 / MOV: ftyp box at start
108
129
  if (head.length >= 12 && ascii(head, 4, 8) === 'ftyp') {
109
130
  const brand = ascii(head, 8, 12);
131
+ // Canon CR3 RAW is ISO-BMFF with the "crx " major brand.
132
+ if (brand === 'crx ') {
133
+ return { format: 'raw', container: 'cr3', confidence: 'high', notes };
134
+ }
110
135
  const boxSize = readU32be(head, 0);
111
136
  if (boxSize < 8 || boxSize > src.size)
112
137
  notes.push('implausible ftyp box size');
@@ -129,6 +154,40 @@ export async function detectFormat(src) {
129
154
  notes.push(`PDF header found at offset ${pdfAt} (garbage prefix)`);
130
155
  return { format: 'pdf', confidence: pdfAt <= 1024 ? 'high' : 'medium', notes };
131
156
  }
157
+ // RAW header after a garbage prefix (TIFF/RAF at any offset, or ftyp "crx ").
158
+ const rawStart = findRawStart(window);
159
+ if (rawStart && rawStart.offset > 0) {
160
+ notes.push(`RAW header found at offset ${rawStart.offset} (garbage prefix)`);
161
+ return {
162
+ format: 'raw',
163
+ container: rawStart.container,
164
+ confidence: rawStart.offset <= 1024 ? 'high' : 'medium',
165
+ notes,
166
+ };
167
+ }
168
+ // PSD/PSB header after a garbage prefix.
169
+ const psdAt = findPsdSignature(window, SCAN_WINDOW);
170
+ if (psdAt > 0) {
171
+ const version = (window[psdAt + 4] << 8) | window[psdAt + 5];
172
+ notes.push(`8BPS signature found at offset ${psdAt} (garbage prefix)`);
173
+ return {
174
+ format: 'psd',
175
+ container: version === 2 ? 'psb' : 'psd',
176
+ confidence: psdAt <= 1024 ? 'high' : 'medium',
177
+ notes,
178
+ };
179
+ }
180
+ // CFBF header after a garbage prefix.
181
+ const cfbfAt = indexOfBytes(window, [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]);
182
+ if (cfbfAt > 0) {
183
+ notes.push(`CFBF signature found at offset ${cfbfAt} (garbage prefix)`);
184
+ return {
185
+ format: 'cfbf',
186
+ container: sniffCfbfContainer(window),
187
+ confidence: cfbfAt <= 1024 ? 'high' : 'medium',
188
+ notes,
189
+ };
190
+ }
132
191
  const ftypAt = indexOfBytes(window, [0x66, 0x74, 0x79, 0x70]); // 'ftyp'
133
192
  if (ftypAt >= 4) {
134
193
  const brand = ascii(window, ftypAt + 4, ftypAt + 8);
@@ -156,4 +215,22 @@ export async function detectFormat(src) {
156
215
  function readU32be(b, o) {
157
216
  return ((b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]) >>> 0;
158
217
  }
218
+ /** Find an ASCII string encoded as UTF-16LE (how CFBF stores directory names). */
219
+ function utf16leIndexOf(b, s) {
220
+ const needle = [];
221
+ for (let i = 0; i < s.length; i++) {
222
+ needle.push(s.charCodeAt(i) & 0xff, 0);
223
+ }
224
+ return indexOfBytes(b, needle);
225
+ }
226
+ /** Sniff the legacy-Office document type from the UTF-16 stream names in the bytes. */
227
+ function sniffCfbfContainer(b) {
228
+ if (utf16leIndexOf(b, 'WordDocument') !== -1)
229
+ return 'doc';
230
+ if (utf16leIndexOf(b, 'Workbook') !== -1 || utf16leIndexOf(b, 'Book') !== -1)
231
+ return 'xls';
232
+ if (utf16leIndexOf(b, 'PowerPoint Document') !== -1)
233
+ return 'ppt';
234
+ return 'ole';
235
+ }
159
236
  //# sourceMappingURL=index.js.map