@substrat-run/attachment-extractors 0.1.4 → 0.2.1

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/dist/pdf.d.ts ADDED
@@ -0,0 +1,171 @@
1
+ /**
2
+ * PDF → text (#1575): the text layer a PDF's pages draw, read without a dependency.
3
+ *
4
+ * **The bytes are a tenant's, so this is a hostile-input parser first and a PDF reader second.**
5
+ * Every structure a file can make large or circular has a bound of its own, and every bound
6
+ * ends the extraction legibly — `{ failed }` with a content-free reason, or the text read so
7
+ * far marked truncated — never a throw that escapes, and never a hang:
8
+ *
9
+ * - **Decompression** (`decodeStream`). Each stream's decoded size is counted as the decoder
10
+ * produces it, against `PDF_STREAM_MAX` for the stream (past it: a bomb, and the file
11
+ * fails) and against the extraction's inflate budget in total (past it: the text read so
12
+ * far is kept, truncated). A declared `/Length` or `/DL` is never trusted for either.
13
+ * - **The cross-reference chain** (`readXref`): at most `PDF_XREF_SECTIONS` sections, and a
14
+ * `/Prev` or `/XRefStm` that comes back to one already read is a loop, refused.
15
+ * - **Objects**: at most `PDF_OBJECTS_MAX` cross-reference entries, however large a `/Size`
16
+ * or a subsection count claims to be — nothing is allocated from a declared count. An object
17
+ * is parsed at most once (`objects`), and one whose resolution reaches itself — a `/Length`
18
+ * naming its own stream, a chain of references back to the start — resolves to null.
19
+ * - **Object streams** do not nest: an object stream must itself sit at a file offset, as the
20
+ * format requires, so one named as living in another object stream is refused.
21
+ * - **Nesting**: an array or dictionary at most `PDF_DEPTH_MAX` deep, a page tree at most
22
+ * `PDF_TREE_DEPTH_MAX` deep and never through one of its own ancestors, a form XObject at
23
+ * most `PDF_FORM_DEPTH_MAX` deep and never inside itself. Every walk is a loop with a depth
24
+ * counter or a recursion with one: none follows what the file says without counting.
25
+ * - **Memory** (`Retained`): what the extraction keeps — cached decoded streams, a page's
26
+ * joined content, parsed objects, cross-reference entries, CMap entries, font decoders — is
27
+ * charged before it is allocated, at most `PDF_RETAINED_FACTOR` × the inflate budget plus
28
+ * `PDF_RETAINED_BASE`. Every other allocation is bounded by a named constant: a token, a
29
+ * stream (`PDF_STREAM_MAX`), the text collected, the operand stack.
30
+ * - **Work**: a token or a direct object larger than `EXTRACTION_STRIDE` is refused, so the
31
+ * synchronous lexer never runs more than a stride between two checks of the signal, and
32
+ * every loop over the file — the lexer's, the byte searches, the decoders, the content
33
+ * interpreter — charges `Pace` and yields at a stride. Content is interpreted against a
34
+ * budget of its own (`PDF_INTERPRET_FACTOR` × the inflate budget), so a page tree that
35
+ * draws one form a thousand times cannot spend more than that.
36
+ *
37
+ * What it reads: the classic and the stream cross-reference forms, hybrid files, incremental
38
+ * updates, object streams, and — when the cross-reference data is unusable, as in a file
39
+ * edited by a tool that did not rewrite it — a scan for `N G obj` headers instead. Filters:
40
+ * Flate (with PNG predictors), LZW, ASCIIHex, ASCII85, RunLength. Image filters are not text
41
+ * and are skipped. Text is decoded through a font's `/ToUnicode` CMap where it has one, and
42
+ * through its encoding — WinAnsi, MacRoman, Standard, `/Differences` glyph names — where it
43
+ * has not. A composite font with no `/ToUnicode` names glyphs, not characters, so its text is
44
+ * unreadable and is not guessed at.
45
+ *
46
+ * What it does not: **encrypted files** are refused with that reason (their keys are derived
47
+ * with MD5 and RC4, which Web Crypto does not carry, and this package does not hand-roll a
48
+ * hash). **No OCR**: a scanned page has no text layer, so a scanned PDF extracts to nothing,
49
+ * which the kernel records `empty`.
50
+ */
51
+ import { type ExtractionSignal } from '@substrat-run/kernel';
52
+ import { Retained, Pace, type InflateBudget } from './shared.js';
53
+ /** Cross-reference entries one file may declare, across every section. */
54
+ export declare const PDF_OBJECTS_MAX = 200000;
55
+ /** Cross-reference sections followed through `/Prev` and `/XRefStm`. */
56
+ export declare const PDF_XREF_SECTIONS = 64;
57
+ /** Nesting of arrays and dictionaries inside one object. */
58
+ export declare const PDF_DEPTH_MAX = 32;
59
+ /** Depth of the page tree. */
60
+ export declare const PDF_TREE_DEPTH_MAX = 64;
61
+ /** Page-tree nodes visited, pages included. */
62
+ export declare const PDF_TREE_NODES_MAX = 50000;
63
+ /** Depth of form XObjects drawn inside one another. */
64
+ export declare const PDF_FORM_DEPTH_MAX = 8;
65
+ /** Bytes one stream may decode to: past it, the stream is a bomb and the file fails. */
66
+ export declare const PDF_STREAM_MAX: number;
67
+ /** Content bytes interpreted, as a multiple of the inflate budget. */
68
+ export declare const PDF_INTERPRET_FACTOR = 4;
69
+ /**
70
+ * What one PDF extraction may hold at once, as a multiple of its inflate budget (`Retained`):
71
+ * the decoded streams themselves (at most one inflate budget), and as much again for what is
72
+ * built from them — parsed objects, the cross-reference, CMaps, fonts, joined page content.
73
+ */
74
+ export declare const PDF_RETAINED_FACTOR = 2;
75
+ /** And a base the structures need whatever the inflate budget: fonts, the cross-reference, objects. */
76
+ export declare const PDF_RETAINED_BASE: number;
77
+ interface PdfName {
78
+ readonly kind: 'name';
79
+ readonly name: string;
80
+ }
81
+ interface PdfString {
82
+ readonly kind: 'str';
83
+ readonly bytes: Uint8Array;
84
+ }
85
+ interface PdfRef {
86
+ readonly kind: 'ref';
87
+ readonly num: number;
88
+ readonly gen: number;
89
+ }
90
+ interface PdfStream {
91
+ readonly kind: 'stream';
92
+ readonly dict: PdfDict;
93
+ readonly start: number;
94
+ readonly length: number;
95
+ /** The object number it was read as, for the decode cache; null for none. */
96
+ readonly num: number | null;
97
+ }
98
+ type PdfDict = Map<string, PdfValue>;
99
+ type PdfValue = null | boolean | number | PdfName | PdfString | PdfRef | PdfStream | PdfDict | PdfValue[];
100
+ /** What a decoder did: its bytes, and whether the extraction's budget ran out on the way. */
101
+ interface Decoded {
102
+ readonly data: Uint8Array;
103
+ /** True when the inflate budget, not the stream, ended the data. */
104
+ readonly exhausted: boolean;
105
+ }
106
+ /** LZW as PDF writes it (8-bit, early change by default). */
107
+ declare function lzw(raw: Uint8Array, early: boolean, budget: InflateBudget, pace: Pace): Promise<Decoded>;
108
+ declare function asciiHex(raw: Uint8Array, budget: InflateBudget, pace: Pace): Promise<Decoded>;
109
+ declare function ascii85(raw: Uint8Array, budget: InflateBudget, pace: Pace): Promise<Decoded>;
110
+ declare function runLength(raw: Uint8Array, budget: InflateBudget, pace: Pace): Promise<Decoded>;
111
+ /** Undo a PNG predictor (`/Predictor` 10–15), row by row, with each row's own filter byte. */
112
+ declare function unpredict(data: Uint8Array, parms: PdfDict | null, pace: Pace): Promise<Uint8Array>;
113
+ /**
114
+ * A glyph name → its text: the names writers use, `uniXXXX`, `uXXXX`, and composed accents.
115
+ * The patterns below are anchored with one quantifier each (or fixed-width groups), so none
116
+ * can backtrack past linear — and a name is at most `GLYPH_NAME_MAX` long besides.
117
+ */
118
+ declare function glyphText(name: string): string;
119
+ /**
120
+ * A PDF's text, in page order. `{ text, truncated }` like every extractor here; a file that is
121
+ * not a readable PDF throws `MalformedInput` and one that breaks a bound
122
+ * `ExtractionBoundExceeded`, which the extractor turns into `{ failed }`.
123
+ */
124
+ export declare function pdfExtract(body: Uint8Array, maxInflatedBytes: number, maxTextBytes: number, signal: ExtractionSignal,
125
+ /** The memory budget; the package's own tests pass one to read what was charged. */
126
+ retained?: Retained,
127
+ /** The work budget; the package's own tests pass one to count what was charged. */
128
+ pace?: Pace): Promise<{
129
+ text: string;
130
+ truncated: boolean;
131
+ }>;
132
+ /** The glyph-name and encoding tables, for the package's own tests. */
133
+ export declare const pdfTables: {
134
+ glyphText: typeof glyphText;
135
+ WIN_ANSI: (string | null)[];
136
+ MAC_ROMAN: (string | null)[];
137
+ STANDARD: (string | null)[];
138
+ };
139
+ /** The stream decoders, for the package's own tests: each judged on what it charges and keeps. */
140
+ export declare const pdfDecoders: {
141
+ unpredict: typeof unpredict;
142
+ asciiHex: typeof asciiHex;
143
+ ascii85: typeof ascii85;
144
+ runLength: typeof runLength;
145
+ lzw: typeof lzw;
146
+ };
147
+ /** The lexer, for the package's own tests: judged on what it charges for one token. */
148
+ /** The CMap parser, for the package's own tests. */
149
+ export declare const pdfCMap: (data: Uint8Array, pace: Pace, retained: Retained) => Promise<{
150
+ map: {
151
+ get(length: number, code: number): string | undefined;
152
+ };
153
+ }>;
154
+ /** What a font's decoder is charged, for the package's own tests. */
155
+ export declare const pdfFontCosts: {
156
+ simple: number;
157
+ difference: number;
158
+ composite: number;
159
+ decodePerByte: number;
160
+ };
161
+ /** A CodeMap with nothing parsed into it, for the package's own tests to define and seal directly. */
162
+ export declare const pdfCodeMap: (retained: Retained) => {
163
+ setChar(length: number, code: number, text: string): void;
164
+ seal(pace: Pace): Promise<unknown>;
165
+ get(length: number, code: number): string | undefined;
166
+ };
167
+ export declare const pdfLexer: (buf: Uint8Array, pace: Pace) => {
168
+ next(): unknown;
169
+ };
170
+ export {};
171
+ //# sourceMappingURL=pdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"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"}