@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,350 @@
|
|
|
1
|
+
import { MemorySource } from '../byte-source.js';
|
|
2
|
+
import { diagnoseVideo } from './diagnose.js';
|
|
3
|
+
import { getLibAV, resetLibAVHost, withLibAV } from './libav-host.js';
|
|
4
|
+
// AVFormatContext flag bits (libavformat/avformat.h).
|
|
5
|
+
export const AVFMT_FLAG_GENPTS = 0x0001;
|
|
6
|
+
export const AVFMT_FLAG_IGNIDX = 0x0002;
|
|
7
|
+
/** AVPacket flag: demuxer marked the packet as corrupt. */
|
|
8
|
+
const AV_PKT_FLAG_CORRUPT = 0x0002;
|
|
9
|
+
const AV_OPT_SEARCH_CHILDREN = 1;
|
|
10
|
+
/** Ordered ladder: the first strategy is tried first. */
|
|
11
|
+
export const REMUX_STRATEGIES = [
|
|
12
|
+
{
|
|
13
|
+
id: 'copy-faststart',
|
|
14
|
+
label: 'stream copy + faststart',
|
|
15
|
+
description: 'Copies all streams untouched and moves the index to the front of the file.',
|
|
16
|
+
demuxFlags: 0,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 'genpts-copy',
|
|
20
|
+
label: 'timestamp regeneration + stream copy',
|
|
21
|
+
description: 'Regenerates missing presentation timestamps (+genpts) and ignores the broken container ' +
|
|
22
|
+
'index (+ignidx) before copying the streams.',
|
|
23
|
+
demuxFlags: AVFMT_FLAG_GENPTS | AVFMT_FLAG_IGNIDX,
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
/** Map input container to output: mkv stays mkv, webm stays webm, rest → mp4. */
|
|
27
|
+
export function outputContainerFor(diagnosis) {
|
|
28
|
+
if (diagnosis.container === 'mkv')
|
|
29
|
+
return 'mkv';
|
|
30
|
+
if (diagnosis.container === 'webm')
|
|
31
|
+
return 'webm';
|
|
32
|
+
return 'mp4';
|
|
33
|
+
}
|
|
34
|
+
const FORMAT_NAMES = {
|
|
35
|
+
mp4: 'mp4',
|
|
36
|
+
mkv: 'matroska',
|
|
37
|
+
webm: 'webm',
|
|
38
|
+
};
|
|
39
|
+
/** Pure planning step: what to run for a given diagnosis (unit-testable). */
|
|
40
|
+
export function planRemux(diagnosis) {
|
|
41
|
+
const output = outputContainerFor(diagnosis);
|
|
42
|
+
const plan = {
|
|
43
|
+
attempt: true,
|
|
44
|
+
skipReason: null,
|
|
45
|
+
stripPrefixBytes: diagnosis.dataOffset,
|
|
46
|
+
output,
|
|
47
|
+
formatName: FORMAT_NAMES[output],
|
|
48
|
+
movflags: output === 'mp4' ? '+faststart' : null,
|
|
49
|
+
strategies: REMUX_STRATEGIES,
|
|
50
|
+
};
|
|
51
|
+
if (diagnosis.damageClass === 'not-video') {
|
|
52
|
+
plan.attempt = false;
|
|
53
|
+
plan.skipReason = 'input is not recognizable as a video container; remux not attempted';
|
|
54
|
+
}
|
|
55
|
+
else if (diagnosis.damageClass === 'missing-moov') {
|
|
56
|
+
plan.attempt = false;
|
|
57
|
+
plan.skipReason =
|
|
58
|
+
'no moov index: a stream-copy remux has no sample table to copy from. Repairing this file ' +
|
|
59
|
+
'requires moov reconstruction from the raw mdat payload (planned as a separate engine); ' +
|
|
60
|
+
'no output was produced rather than pretending success.';
|
|
61
|
+
}
|
|
62
|
+
return plan;
|
|
63
|
+
}
|
|
64
|
+
class StrategyError extends Error {
|
|
65
|
+
}
|
|
66
|
+
export async function remuxVideo(src, opts = {}) {
|
|
67
|
+
const diagnosis = opts.diagnosis ?? (await diagnoseVideo(src));
|
|
68
|
+
const plan = planRemux(diagnosis);
|
|
69
|
+
const notes = [...diagnosis.notes];
|
|
70
|
+
const attempts = [];
|
|
71
|
+
const report = (outcome, video, strategy, run) => ({
|
|
72
|
+
video,
|
|
73
|
+
report: {
|
|
74
|
+
outcome,
|
|
75
|
+
damageClass: diagnosis.damageClass,
|
|
76
|
+
container: diagnosis.container,
|
|
77
|
+
outputContainer: plan.attempt ? plan.output : null,
|
|
78
|
+
strategy,
|
|
79
|
+
streamsFound: run?.streamsFound ?? 0,
|
|
80
|
+
streamsCopied: run?.streamsCopied ?? 0,
|
|
81
|
+
packetsCopied: run?.packetsCopied ?? 0,
|
|
82
|
+
corruptPackets: run?.corruptPackets ?? 0,
|
|
83
|
+
stoppedEarly: run?.stoppedEarly ?? false,
|
|
84
|
+
durationSeconds: run?.durationSeconds ?? null,
|
|
85
|
+
recoveredSeconds: run?.recoveredSeconds ?? null,
|
|
86
|
+
attempts,
|
|
87
|
+
notes,
|
|
88
|
+
bytesIn: src.size,
|
|
89
|
+
bytesOut: video.length,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
if (!plan.attempt) {
|
|
93
|
+
notes.push(plan.skipReason);
|
|
94
|
+
return report('failed', new Uint8Array(0), null, null);
|
|
95
|
+
}
|
|
96
|
+
if (plan.stripPrefixBytes > 0) {
|
|
97
|
+
notes.push(`stripping ${plan.stripPrefixBytes} bytes of garbage prefix before remuxing`);
|
|
98
|
+
}
|
|
99
|
+
const bytes = await src.read(plan.stripPrefixBytes, src.size - plan.stripPrefixBytes);
|
|
100
|
+
// Load failures (no loader configured, wasm fetch failed) are reported as a
|
|
101
|
+
// failed repair with an explicit engine note, not thrown at the caller.
|
|
102
|
+
try {
|
|
103
|
+
await getLibAV();
|
|
104
|
+
}
|
|
105
|
+
catch (e) {
|
|
106
|
+
notes.push(`video engine unavailable: ${e instanceof Error ? e.message : String(e)}`);
|
|
107
|
+
return report('failed', new Uint8Array(0), null, null);
|
|
108
|
+
}
|
|
109
|
+
let winner = null;
|
|
110
|
+
for (const strategy of plan.strategies) {
|
|
111
|
+
try {
|
|
112
|
+
const run = await withLibAV((libav, runId) => runStrategy(libav, runId, bytes, plan, strategy));
|
|
113
|
+
attempts.push({ strategy: strategy.id, ok: true, packetsCopied: run.packetsCopied, error: null });
|
|
114
|
+
winner = { strategy: strategy.id, run };
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
119
|
+
attempts.push({ strategy: strategy.id, ok: false, packetsCopied: 0, error: message });
|
|
120
|
+
if (!(e instanceof StrategyError)) {
|
|
121
|
+
// Unexpected wasm-level failure: drop the cached instance so the next
|
|
122
|
+
// run starts from a clean runtime.
|
|
123
|
+
resetLibAVHost();
|
|
124
|
+
notes.push(`engine error during "${strategy.label}": ${message}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!winner) {
|
|
129
|
+
if (diagnosis.container === 'avi') {
|
|
130
|
+
notes.push('the bundled libav.js variant (webcodecs) has no AVI demuxer; AVI remux needs a custom ' +
|
|
131
|
+
'variant build (fragment demuxer-avi) or an injected loader that provides one');
|
|
132
|
+
}
|
|
133
|
+
notes.push('no remux strategy produced a usable output');
|
|
134
|
+
return report('failed', new Uint8Array(0), null, null);
|
|
135
|
+
}
|
|
136
|
+
const { run } = winner;
|
|
137
|
+
notes.push(`copied ${run.packetsCopied} packet(s) across ${run.streamsCopied} stream(s)`);
|
|
138
|
+
if (run.streamsCopied < run.streamsFound) {
|
|
139
|
+
notes.push(`${run.streamsFound - run.streamsCopied} non-audio/video stream(s) were not copied`);
|
|
140
|
+
}
|
|
141
|
+
// Verification: the produced container must re-diagnose as structurally clean.
|
|
142
|
+
const verify = await diagnoseVideo(new MemorySource(run.video));
|
|
143
|
+
if (verify.damageClass !== 'none') {
|
|
144
|
+
notes.push(`remuxed output re-diagnosed as "${verify.damageClass}"; not claiming success`);
|
|
145
|
+
return report('failed', run.video, winner.strategy, run);
|
|
146
|
+
}
|
|
147
|
+
let outcome = 'success';
|
|
148
|
+
if (diagnosis.damageClass === 'truncated-mdat') {
|
|
149
|
+
outcome = 'partial';
|
|
150
|
+
notes.push('input media data was truncated: recovered the frames before the cut; the rest is gone');
|
|
151
|
+
}
|
|
152
|
+
else if (run.stoppedEarly) {
|
|
153
|
+
outcome = 'partial';
|
|
154
|
+
notes.push('packet reading stopped before end-of-file; recovered the readable part');
|
|
155
|
+
}
|
|
156
|
+
else if (run.corruptPackets > 0) {
|
|
157
|
+
outcome = 'partial';
|
|
158
|
+
notes.push(`${run.corruptPackets} packet(s) were flagged corrupt by the demuxer`);
|
|
159
|
+
}
|
|
160
|
+
else if (run.durationSeconds !== null &&
|
|
161
|
+
run.recoveredSeconds !== null &&
|
|
162
|
+
run.recoveredSeconds < run.durationSeconds * 0.85) {
|
|
163
|
+
// The container claims more content than the packets delivered (e.g. an
|
|
164
|
+
// MKV cut mid-cluster, which the demuxer ends without an error): honest
|
|
165
|
+
// partial, not success.
|
|
166
|
+
outcome = 'partial';
|
|
167
|
+
notes.push(`recovered ${run.recoveredSeconds.toFixed(2)}s of a declared ${run.durationSeconds.toFixed(2)}s — ` +
|
|
168
|
+
'the media data ends before the declared duration (likely truncation)');
|
|
169
|
+
}
|
|
170
|
+
return report(outcome, run.video, winner.strategy, run);
|
|
171
|
+
}
|
|
172
|
+
async function runStrategy(libav, runId, bytes, plan, strategy) {
|
|
173
|
+
const inName = `in-${runId}.bin`;
|
|
174
|
+
const outName = `out-${runId}.${plan.output}`;
|
|
175
|
+
// Explicit teardown state: every wasm-side resource is released exactly once,
|
|
176
|
+
// whether the run succeeds or throws.
|
|
177
|
+
let fmtCtx = 0;
|
|
178
|
+
let outCtx = 0;
|
|
179
|
+
let pbCtx = 0;
|
|
180
|
+
let pktPtr = 0;
|
|
181
|
+
let inWritten = false;
|
|
182
|
+
let outWritten = false;
|
|
183
|
+
try {
|
|
184
|
+
await libav.writeFile(inName, bytes);
|
|
185
|
+
inWritten = true;
|
|
186
|
+
const fmt = await libav.avformat_open_input_js(inName, 0, 0);
|
|
187
|
+
if (!fmt)
|
|
188
|
+
throw new StrategyError('demuxer could not open the input (no readable container structure)');
|
|
189
|
+
fmtCtx = fmt;
|
|
190
|
+
if (strategy.demuxFlags !== 0) {
|
|
191
|
+
const flags = await libav.AVFormatContext_flags(fmt);
|
|
192
|
+
await libav.AVFormatContext_flags_s(fmt, flags | strategy.demuxFlags);
|
|
193
|
+
}
|
|
194
|
+
const fsi = await libav.avformat_find_stream_info(fmt, 0);
|
|
195
|
+
if (fsi < 0)
|
|
196
|
+
throw new StrategyError(`could not read stream info (${fsi})`);
|
|
197
|
+
const streamsFound = await libav.AVFormatContext_nb_streams(fmt);
|
|
198
|
+
const durationSeconds = await readDurationSeconds(libav, fmt);
|
|
199
|
+
// Map copyable (audio/video) streams to output indices.
|
|
200
|
+
const mapping = [];
|
|
201
|
+
const inStreams = [];
|
|
202
|
+
let outIndex = 0;
|
|
203
|
+
for (let i = 0; i < streamsFound; i += 1) {
|
|
204
|
+
const stream = await libav.AVFormatContext_streams_a(fmt, i);
|
|
205
|
+
const par = await libav.AVStream_codecpar(stream);
|
|
206
|
+
const codecType = await libav.AVCodecParameters_codec_type(par);
|
|
207
|
+
const copyable = codecType === libav.AVMEDIA_TYPE_VIDEO || codecType === libav.AVMEDIA_TYPE_AUDIO;
|
|
208
|
+
mapping.push(copyable ? outIndex++ : -1);
|
|
209
|
+
inStreams.push({
|
|
210
|
+
ptr: stream,
|
|
211
|
+
tbNum: await libav.AVStream_time_base_num(stream),
|
|
212
|
+
tbDen: await libav.AVStream_time_base_den(stream),
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const streamsCopied = outIndex;
|
|
216
|
+
if (streamsCopied === 0)
|
|
217
|
+
throw new StrategyError('no audio/video streams found to copy');
|
|
218
|
+
const oc = await libav.avformat_alloc_output_context2_js(0, plan.formatName, outName);
|
|
219
|
+
if (!oc)
|
|
220
|
+
throw new StrategyError(`could not create ${plan.formatName} output context`);
|
|
221
|
+
outCtx = oc;
|
|
222
|
+
const outStreams = [];
|
|
223
|
+
for (let i = 0; i < streamsFound; i += 1) {
|
|
224
|
+
if (mapping[i] === -1)
|
|
225
|
+
continue;
|
|
226
|
+
const outStream = await libav.avformat_new_stream(oc, 0);
|
|
227
|
+
if (!outStream)
|
|
228
|
+
throw new StrategyError('could not allocate output stream');
|
|
229
|
+
const inPar = await libav.AVStream_codecpar(inStreams[i].ptr);
|
|
230
|
+
const outPar = await libav.AVStream_codecpar(outStream);
|
|
231
|
+
const copied = await libav.avcodec_parameters_copy(outPar, inPar);
|
|
232
|
+
if (copied < 0)
|
|
233
|
+
throw new StrategyError(`could not copy codec parameters (${copied})`);
|
|
234
|
+
await libav.AVCodecParameters_codec_tag_s(outPar, 0);
|
|
235
|
+
}
|
|
236
|
+
if (plan.movflags !== null) {
|
|
237
|
+
await libav.av_opt_set(oc, 'movflags', plan.movflags, AV_OPT_SEARCH_CHILDREN);
|
|
238
|
+
}
|
|
239
|
+
const pb = await libav.avio_open2_js(outName, libav.AVIO_FLAG_WRITE, 0, 0);
|
|
240
|
+
if (!pb)
|
|
241
|
+
throw new StrategyError('could not open the output for writing');
|
|
242
|
+
pbCtx = pb;
|
|
243
|
+
outWritten = true;
|
|
244
|
+
await libav.AVFormatContext_pb_s(oc, pb);
|
|
245
|
+
const wroteHeader = await libav.avformat_write_header(oc, 0);
|
|
246
|
+
if (wroteHeader < 0)
|
|
247
|
+
throw new StrategyError(`muxer rejected the streams (write_header ${wroteHeader})`);
|
|
248
|
+
// Output time bases are final only after write_header.
|
|
249
|
+
for (let i = 0, o = 0; i < streamsFound; i += 1) {
|
|
250
|
+
if (mapping[i] === -1)
|
|
251
|
+
continue;
|
|
252
|
+
const outStream = await libav.AVFormatContext_streams_a(oc, o++);
|
|
253
|
+
outStreams.push({
|
|
254
|
+
tbNum: await libav.AVStream_time_base_num(outStream),
|
|
255
|
+
tbDen: await libav.AVStream_time_base_den(outStream),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const pkt = await libav.av_packet_alloc();
|
|
259
|
+
pktPtr = pkt;
|
|
260
|
+
let packetsCopied = 0;
|
|
261
|
+
let corruptPackets = 0;
|
|
262
|
+
let stoppedEarly = false;
|
|
263
|
+
let recoveredSeconds = null;
|
|
264
|
+
for (;;) {
|
|
265
|
+
const read = await libav.av_read_frame(fmt, pkt);
|
|
266
|
+
if (read < 0) {
|
|
267
|
+
stoppedEarly = read !== libav.AVERROR_EOF;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
const inIndex = await libav.AVPacket_stream_index(pkt);
|
|
271
|
+
const outIdx = mapping[inIndex] ?? -1;
|
|
272
|
+
if (outIdx === -1) {
|
|
273
|
+
await libav.av_packet_unref(pkt);
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const flags = await libav.AVPacket_flags(pkt);
|
|
277
|
+
if (flags & AV_PKT_FLAG_CORRUPT)
|
|
278
|
+
corruptPackets += 1;
|
|
279
|
+
const inTb = inStreams[inIndex];
|
|
280
|
+
const outTb = outStreams[outIdx];
|
|
281
|
+
// Recovered timeline: end of the last packet in input time-base seconds.
|
|
282
|
+
const ptsHi = await libav.AVPacket_ptshi(pkt);
|
|
283
|
+
if (ptsHi >= 0 && inTb.tbDen > 0) {
|
|
284
|
+
const pts = ptsHi * 4294967296 + ((await libav.AVPacket_pts(pkt)) >>> 0);
|
|
285
|
+
const durHi = await libav.AVPacket_durationhi(pkt);
|
|
286
|
+
const dur = durHi >= 0 ? durHi * 4294967296 + ((await libav.AVPacket_duration(pkt)) >>> 0) : 0;
|
|
287
|
+
const end = ((pts + dur) * inTb.tbNum) / inTb.tbDen;
|
|
288
|
+
if (recoveredSeconds === null || end > recoveredSeconds)
|
|
289
|
+
recoveredSeconds = end;
|
|
290
|
+
}
|
|
291
|
+
await libav.av_packet_rescale_ts_js(pkt, inTb.tbNum, inTb.tbDen, outTb.tbNum, outTb.tbDen);
|
|
292
|
+
await libav.AVPacket_stream_index_s(pkt, outIdx);
|
|
293
|
+
await libav.AVPacket_pos_s(pkt, -1);
|
|
294
|
+
await libav.AVPacket_poshi_s(pkt, -1);
|
|
295
|
+
const wrote = await libav.av_interleaved_write_frame(oc, pkt);
|
|
296
|
+
if (wrote < 0)
|
|
297
|
+
throw new StrategyError(`muxer rejected packet ${packetsCopied} (${wrote})`);
|
|
298
|
+
packetsCopied += 1;
|
|
299
|
+
}
|
|
300
|
+
if (packetsCopied === 0)
|
|
301
|
+
throw new StrategyError('no packets could be read from the damaged input');
|
|
302
|
+
const trailer = await libav.av_write_trailer(oc);
|
|
303
|
+
if (trailer < 0)
|
|
304
|
+
throw new StrategyError(`could not finalize the output (write_trailer ${trailer})`);
|
|
305
|
+
// Close the demuxer and the output pb BEFORE reading the file back:
|
|
306
|
+
// avio_close flushes the last buffered bytes into MEMFS.
|
|
307
|
+
await libav.avformat_close_input_js(fmt);
|
|
308
|
+
fmtCtx = 0;
|
|
309
|
+
await libav.avio_close(pb);
|
|
310
|
+
pbCtx = 0;
|
|
311
|
+
const video = await libav.readFile(outName);
|
|
312
|
+
if (video.length === 0)
|
|
313
|
+
throw new StrategyError('muxer produced an empty file');
|
|
314
|
+
return { video, streamsFound, streamsCopied, packetsCopied, corruptPackets, stoppedEarly, durationSeconds, recoveredSeconds };
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
if (pktPtr)
|
|
318
|
+
await quietly(() => libav.av_packet_free_js(pktPtr));
|
|
319
|
+
if (fmtCtx)
|
|
320
|
+
await quietly(() => libav.avformat_close_input_js(fmtCtx));
|
|
321
|
+
if (pbCtx)
|
|
322
|
+
await quietly(() => libav.avio_close(pbCtx));
|
|
323
|
+
if (outCtx)
|
|
324
|
+
await quietly(() => libav.avformat_free_context(outCtx));
|
|
325
|
+
if (inWritten)
|
|
326
|
+
await quietly(() => libav.unlink(inName));
|
|
327
|
+
if (outWritten)
|
|
328
|
+
await quietly(() => libav.unlink(outName));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
async function quietly(step) {
|
|
332
|
+
try {
|
|
333
|
+
await step();
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// best-effort cleanup
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/** AVFormatContext.duration is int64 microseconds (AV_TIME_BASE). */
|
|
340
|
+
async function readDurationSeconds(libav, fmt) {
|
|
341
|
+
const lo = await libav.AVFormatContext_duration(fmt);
|
|
342
|
+
const hi = await libav.AVFormatContext_durationhi(fmt);
|
|
343
|
+
if (hi < 0)
|
|
344
|
+
return null; // AV_NOPTS_VALUE or negative
|
|
345
|
+
const us = hi * 4294967296 + (lo >>> 0);
|
|
346
|
+
if (us <= 0)
|
|
347
|
+
return null;
|
|
348
|
+
return us / 1_000_000;
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=remux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remux.js","sourceRoot":"","sources":["../../src/video/remux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ByteSource } from '../byte-source.js';
|
|
2
|
+
import type { Confidence } from '../types.js';
|
|
3
|
+
import { type EocdResult, type ScanResult } from './scan.js';
|
|
4
|
+
export type DamageClass = 'none' | 'missing-eocd' | 'broken-central-directory' | 'truncated' | 'garbage-prefix' | 'unknown';
|
|
5
|
+
export type { Confidence };
|
|
6
|
+
export interface ZipDiagnosis {
|
|
7
|
+
damageClass: DamageClass;
|
|
8
|
+
entriesFound: number;
|
|
9
|
+
entriesRecoverable: number;
|
|
10
|
+
confidence: Confidence;
|
|
11
|
+
notes: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface ZipAnalysis {
|
|
14
|
+
scan: ScanResult;
|
|
15
|
+
eocd: EocdResult | null;
|
|
16
|
+
damageClass: DamageClass;
|
|
17
|
+
notes: string[];
|
|
18
|
+
}
|
|
19
|
+
/** Structural analysis shared by diagnoseZip and repairZip. */
|
|
20
|
+
export declare function analyzeZip(src: ByteSource): Promise<ZipAnalysis>;
|
|
21
|
+
export declare function diagnoseZip(src: ByteSource): Promise<ZipDiagnosis>;
|
|
22
|
+
//# sourceMappingURL=diagnose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../../src/zip/diagnose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAA8B,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAGzF,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,cAAc,GACd,0BAA0B,GAC1B,WAAW,GACX,gBAAgB,GAChB,SAAS,CAAC;AAEd,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AA4BD,+DAA+D;AAC/D,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CA6DtE;AAWD,wBAAsB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAyBxE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { CDH_FIXED_SIZE, SIG_CDH, readU16, readU32 } from './format.js';
|
|
2
|
+
import { findEocd, scanLocalEntries } from './scan.js';
|
|
3
|
+
import { validateEntry } from './salvage.js';
|
|
4
|
+
async function checkCentralDirectory(src, cdOffset, expectedEntries) {
|
|
5
|
+
let off = cdOffset;
|
|
6
|
+
let parsed = 0;
|
|
7
|
+
const cap = Math.min(expectedEntries, 1_000_000);
|
|
8
|
+
while (parsed < cap) {
|
|
9
|
+
const b = await src.read(off, CDH_FIXED_SIZE);
|
|
10
|
+
if (b.length < CDH_FIXED_SIZE || readU32(b, 0) !== SIG_CDH)
|
|
11
|
+
break;
|
|
12
|
+
const nameLen = readU16(b, 28);
|
|
13
|
+
const extraLen = readU16(b, 30);
|
|
14
|
+
const commentLen = readU16(b, 32);
|
|
15
|
+
if (nameLen > 4096)
|
|
16
|
+
break;
|
|
17
|
+
off += CDH_FIXED_SIZE + nameLen + extraLen + commentLen;
|
|
18
|
+
parsed++;
|
|
19
|
+
}
|
|
20
|
+
return { valid: expectedEntries > 0 && parsed >= expectedEntries, entriesParsed: parsed };
|
|
21
|
+
}
|
|
22
|
+
/** Structural analysis shared by diagnoseZip and repairZip. */
|
|
23
|
+
export async function analyzeZip(src) {
|
|
24
|
+
const scan = await scanLocalEntries(src);
|
|
25
|
+
const eocd = await findEocd(src);
|
|
26
|
+
const notes = [...scan.notes, ...(eocd?.notes ?? [])];
|
|
27
|
+
let damageClass;
|
|
28
|
+
if (scan.entries.length === 0) {
|
|
29
|
+
if (!eocd && scan.firstCdhOffset === undefined) {
|
|
30
|
+
damageClass = 'unknown';
|
|
31
|
+
notes.push('no zip structures recognized');
|
|
32
|
+
}
|
|
33
|
+
else if (eocd && eocd.eocd.totalEntries === 0 && scan.firstCdhOffset === undefined) {
|
|
34
|
+
damageClass = 'none';
|
|
35
|
+
notes.push('archive is empty');
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
damageClass = 'unknown';
|
|
39
|
+
notes.push('central directory or EOCD present but no local file entries found');
|
|
40
|
+
}
|
|
41
|
+
return { scan, eocd, damageClass, notes };
|
|
42
|
+
}
|
|
43
|
+
if (scan.prefixOffset > 0) {
|
|
44
|
+
damageClass = 'garbage-prefix';
|
|
45
|
+
if (!eocd)
|
|
46
|
+
notes.push('EOCD is also missing');
|
|
47
|
+
if (scan.truncatedTail)
|
|
48
|
+
notes.push('archive also appears truncated');
|
|
49
|
+
return { scan, eocd, damageClass, notes };
|
|
50
|
+
}
|
|
51
|
+
if (!eocd) {
|
|
52
|
+
if (scan.truncatedTail) {
|
|
53
|
+
damageClass = 'truncated';
|
|
54
|
+
notes.push('file ends in the middle of an entry');
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
damageClass = 'missing-eocd';
|
|
58
|
+
if (scan.firstCdhOffset !== undefined)
|
|
59
|
+
notes.push('central directory present but EOCD missing');
|
|
60
|
+
else
|
|
61
|
+
notes.push('central directory and EOCD missing');
|
|
62
|
+
}
|
|
63
|
+
return { scan, eocd, damageClass, notes };
|
|
64
|
+
}
|
|
65
|
+
if (scan.truncatedTail) {
|
|
66
|
+
return { scan, eocd, damageClass: 'truncated', notes };
|
|
67
|
+
}
|
|
68
|
+
const cdOffset = eocd.zip64?.cdOffset ?? eocd.eocd.cdOffset;
|
|
69
|
+
const expected = eocd.zip64?.totalEntries ?? eocd.eocd.totalEntries;
|
|
70
|
+
const cd = await checkCentralDirectory(src, cdOffset, expected);
|
|
71
|
+
if (!cd.valid) {
|
|
72
|
+
damageClass = 'broken-central-directory';
|
|
73
|
+
notes.push(cd.entriesParsed === 0
|
|
74
|
+
? 'EOCD points to an unreadable central directory'
|
|
75
|
+
: `central directory readable only for ${cd.entriesParsed}/${expected} entries`);
|
|
76
|
+
return { scan, eocd, damageClass, notes };
|
|
77
|
+
}
|
|
78
|
+
if (scan.gaps > 0) {
|
|
79
|
+
notes.push(`${scan.gaps} unparseable gap(s) between entries`);
|
|
80
|
+
}
|
|
81
|
+
return { scan, eocd, damageClass: 'none', notes };
|
|
82
|
+
}
|
|
83
|
+
function rateConfidence(damage, found, recoverable) {
|
|
84
|
+
if (damage === 'unknown')
|
|
85
|
+
return 'low';
|
|
86
|
+
if (found === 0)
|
|
87
|
+
return damage === 'none' ? 'high' : 'low';
|
|
88
|
+
const ratio = recoverable / found;
|
|
89
|
+
if (damage === 'none')
|
|
90
|
+
return ratio === 1 ? 'high' : ratio >= 0.5 ? 'medium' : 'low';
|
|
91
|
+
if (damage === 'truncated')
|
|
92
|
+
return recoverable > 0 ? 'medium' : 'low';
|
|
93
|
+
return ratio >= 0.95 ? 'high' : ratio >= 0.5 ? 'medium' : 'low';
|
|
94
|
+
}
|
|
95
|
+
export async function diagnoseZip(src) {
|
|
96
|
+
const { scan, damageClass, notes } = await analyzeZip(src);
|
|
97
|
+
let recoverable = 0;
|
|
98
|
+
let corrupt = 0;
|
|
99
|
+
let encrypted = 0;
|
|
100
|
+
let unsupported = 0;
|
|
101
|
+
for (const entry of scan.entries) {
|
|
102
|
+
const v = await validateEntry(src, entry);
|
|
103
|
+
if (v.status === 'ok')
|
|
104
|
+
recoverable++;
|
|
105
|
+
else if (v.status === 'corrupt-data')
|
|
106
|
+
corrupt++;
|
|
107
|
+
else if (v.status === 'encrypted')
|
|
108
|
+
encrypted++;
|
|
109
|
+
else
|
|
110
|
+
unsupported++;
|
|
111
|
+
}
|
|
112
|
+
if (corrupt > 0)
|
|
113
|
+
notes.push(`${corrupt} entr${corrupt === 1 ? 'y' : 'ies'} with unrecoverable data corruption`);
|
|
114
|
+
if (encrypted > 0)
|
|
115
|
+
notes.push(`${encrypted} encrypted entr${encrypted === 1 ? 'y' : 'ies'} (cannot verify without password)`);
|
|
116
|
+
if (unsupported > 0)
|
|
117
|
+
notes.push(`${unsupported} entr${unsupported === 1 ? 'y' : 'ies'} with unsupported compression method`);
|
|
118
|
+
return {
|
|
119
|
+
damageClass,
|
|
120
|
+
entriesFound: scan.entries.length,
|
|
121
|
+
entriesRecoverable: recoverable,
|
|
122
|
+
confidence: rateConfidence(damageClass, scan.entries.length, recoverable),
|
|
123
|
+
notes,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../src/zip/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export declare const SIG_LFH = 67324752;
|
|
2
|
+
export declare const SIG_CDH = 33639248;
|
|
3
|
+
export declare const SIG_EOCD = 101010256;
|
|
4
|
+
export declare const SIG_DD = 134695760;
|
|
5
|
+
export declare const SIG_EOCD64 = 101075792;
|
|
6
|
+
export declare const SIG_EOCD64_LOC = 117853008;
|
|
7
|
+
export declare const LFH_FIXED_SIZE = 30;
|
|
8
|
+
export declare const CDH_FIXED_SIZE = 46;
|
|
9
|
+
export declare const EOCD_FIXED_SIZE = 22;
|
|
10
|
+
export declare const MAX_COMMENT = 65535;
|
|
11
|
+
export declare const FLAG_ENCRYPTED = 1;
|
|
12
|
+
export declare const FLAG_DATA_DESCRIPTOR = 8;
|
|
13
|
+
export declare const FLAG_UTF8 = 2048;
|
|
14
|
+
export declare const METHOD_STORE = 0;
|
|
15
|
+
export declare const METHOD_DEFLATE = 8;
|
|
16
|
+
export declare const U32_MAX = 4294967295;
|
|
17
|
+
export declare const U16_MAX = 65535;
|
|
18
|
+
export interface LocalHeader {
|
|
19
|
+
versionNeeded: number;
|
|
20
|
+
flags: number;
|
|
21
|
+
method: number;
|
|
22
|
+
dosTime: number;
|
|
23
|
+
dosDate: number;
|
|
24
|
+
crc32: number;
|
|
25
|
+
compressedSize: number;
|
|
26
|
+
uncompressedSize: number;
|
|
27
|
+
nameLength: number;
|
|
28
|
+
extraLength: number;
|
|
29
|
+
}
|
|
30
|
+
export interface Zip64Extra {
|
|
31
|
+
uncompressedSize?: number;
|
|
32
|
+
compressedSize?: number;
|
|
33
|
+
localHeaderOffset?: number;
|
|
34
|
+
/** Extra field is present but its declared length does not cover the fields the 0xFFFFFFFF markers require. */
|
|
35
|
+
malformed: boolean;
|
|
36
|
+
}
|
|
37
|
+
export interface Eocd {
|
|
38
|
+
offset: number;
|
|
39
|
+
diskNumber: number;
|
|
40
|
+
cdStartDisk: number;
|
|
41
|
+
entriesOnDisk: number;
|
|
42
|
+
totalEntries: number;
|
|
43
|
+
cdSize: number;
|
|
44
|
+
cdOffset: number;
|
|
45
|
+
commentLength: number;
|
|
46
|
+
}
|
|
47
|
+
export declare function readU16(b: Uint8Array, o: number): number;
|
|
48
|
+
export declare function readU32(b: Uint8Array, o: number): number;
|
|
49
|
+
export declare function readU64(b: Uint8Array, o: number): number;
|
|
50
|
+
/** Parse the 30 fixed bytes of a local file header (signature already verified or not required). */
|
|
51
|
+
export declare function parseLocalHeader(b: Uint8Array, o?: number): LocalHeader | null;
|
|
52
|
+
/** Cheap plausibility check to reject false-positive PK\x03\x04 matches inside compressed data. */
|
|
53
|
+
export declare function localHeaderLooksSane(h: LocalHeader): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Parse a zip64 extended-information extra field (id 0x0001) out of an LFH/CDH
|
|
56
|
+
* extra blob. Which 8-byte fields are present depends on which 32-bit header
|
|
57
|
+
* fields are 0xFFFFFFFF, in spec order: usize, csize, offset.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseZip64Extra(extra: Uint8Array, needs: {
|
|
60
|
+
uncompressedSize: boolean;
|
|
61
|
+
compressedSize: boolean;
|
|
62
|
+
localHeaderOffset?: boolean;
|
|
63
|
+
}): Zip64Extra | null;
|
|
64
|
+
export declare function parseEocd(b: Uint8Array, o: number, absoluteOffset: number): Eocd | null;
|
|
65
|
+
/** DOS timestamp for entries whose original date is unrecoverable. */
|
|
66
|
+
export declare const FALLBACK_DOS_DATE: number;
|
|
67
|
+
export declare const FALLBACK_DOS_TIME = 0;
|
|
68
|
+
/**
|
|
69
|
+
* The size actually occupied on disk can legitimately exceed the 32-bit size
|
|
70
|
+
* declared in the header when a writer (notably OneDrive/old Windows zips
|
|
71
|
+
* > 4 GiB) stored `size mod 2^32` without zip64 fields. The fix is
|
|
72
|
+
* deterministic: accept the actual size iff the difference is an exact
|
|
73
|
+
* multiple of 2^32.
|
|
74
|
+
*/
|
|
75
|
+
export declare function reconcileDeclaredSize(declared: number, actual: number): {
|
|
76
|
+
size: number;
|
|
77
|
+
wrapAroundFixed: boolean;
|
|
78
|
+
} | null;
|
|
79
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/zip/format.ts"],"names":[],"mappings":"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"}
|