@normativepdf/recover 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/LICENSE +21 -0
- package/README.ja.md +100 -0
- package/README.md +105 -0
- package/dist/cos.d.ts +97 -0
- package/dist/cos.d.ts.map +1 -0
- package/dist/cos.js +177 -0
- package/dist/cos.js.map +1 -0
- package/dist/document.d.ts +106 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +334 -0
- package/dist/document.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/dist/xref-walk.d.ts +114 -0
- package/dist/xref-walk.d.ts.map +1 -0
- package/dist/xref-walk.js +383 -0
- package/dist/xref-walk.js.map +1 -0
- package/package.json +70 -0
package/dist/document.js
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文書を開く 1 つの入口と、**その読みの射程**。
|
|
3
|
+
*
|
|
4
|
+
* normativepdf は §7.5 を条文どおりに読み、条文に反する文書を受け取らない。
|
|
5
|
+
* それは正しいが、消費者は「受け取らない」で終われない —— 監査の対象として持ち込まれる
|
|
6
|
+
* 文書こそ壊れているからである。そこで:
|
|
7
|
+
*
|
|
8
|
+
* 1. まず `parsePdf` に渡す。読めたらそれをそのまま使う(**方針を挟まない**)
|
|
9
|
+
* 2. 断られたら `xref-walk.ts` の回復方針で歩き、読めた節から文書を組み立てる
|
|
10
|
+
*
|
|
11
|
+
* この順番が肝で、2,947 検体のうち 2,930 件は 1 で読める。回復方針が当たるのは
|
|
12
|
+
* 残り 17 件だけであり、そこだけが「ライブラリの答え」ではなく「このパッケージの方針」になる。
|
|
13
|
+
* どちらだったかは `scope.recovered` が申告する。
|
|
14
|
+
*
|
|
15
|
+
* 🔴 **射程は判定ではない。** `scope` は「どこまで読んだか」であって、
|
|
16
|
+
* 「この文書が条文に適合しているか」ではない。適合の判定は validator が下す。
|
|
17
|
+
*/
|
|
18
|
+
import { ByteCursor, buildDocumentDecryptor, dictGet, PdfDocument, parseIndirectObject, parsePdf, TokenReader, } from 'normativepdf';
|
|
19
|
+
import { asDict, asRef, bytesOf } from './cos.js';
|
|
20
|
+
import { findOrigin, LATIN1, reconstructXref, walkXrefChain, } from './xref-walk.js';
|
|
21
|
+
const CONTEXT = 'document';
|
|
22
|
+
/** 目録(catalog)に届くか。届かない文書は「1 オブジェクトの文書」として扱えない。 */
|
|
23
|
+
async function catalogReachable(doc) {
|
|
24
|
+
try {
|
|
25
|
+
return (await doc.getCatalog()).kind === 'dict';
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** §7.5.2 のヘッダ版。無い文書では null(それを違反と呼ぶのは validator の仕事)。 */
|
|
32
|
+
function headerVersionOf(bytes, origin) {
|
|
33
|
+
const head = LATIN1.decode(bytes.subarray(origin, origin + 32));
|
|
34
|
+
return /^%PDF-(\d+\.\d+)/.exec(head)?.[1] ?? null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 節の trailer を新しい順に重ねる(§7.5.6)。増分更新の trailer は
|
|
38
|
+
* `/Root` などを繰り返すことになっているが、繰り返していない文書が実在するので、
|
|
39
|
+
* **古い節で埋める**。埋めたことは隠さない(重ねた結果しか使わないので、
|
|
40
|
+
* どの節から来たかを知りたい場合は `sections` を見ること)。
|
|
41
|
+
*/
|
|
42
|
+
function mergeTrailers(chain) {
|
|
43
|
+
const entries = new Map();
|
|
44
|
+
for (let i = chain.sections.length - 1; i >= 0; i -= 1) {
|
|
45
|
+
for (const [key, value] of chain.sections[i].trailer.entries) {
|
|
46
|
+
if (!entries.has(key))
|
|
47
|
+
entries.set(key, value);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { kind: 'dict', entries };
|
|
51
|
+
}
|
|
52
|
+
/** 新しい節が古い節を上書きする形で 1 枚の相互参照表にする(§7.5.4 / §7.5.6)。 */
|
|
53
|
+
function mergeXref(chain) {
|
|
54
|
+
const merged = new Map();
|
|
55
|
+
for (const section of chain.sections) {
|
|
56
|
+
for (const [objectNumber, entry] of section.entries)
|
|
57
|
+
merged.set(objectNumber, entry);
|
|
58
|
+
}
|
|
59
|
+
return merged;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `/Encrypt` 辞書を復号器なしで読む。§7.6.2 は「Encrypt 辞書の中の文字列」を
|
|
63
|
+
* 暗号化の対象から除いているので、生バイトから直接読むのが正しい読み方である。
|
|
64
|
+
*/
|
|
65
|
+
function readEncryptDict(bytes, origin, trailer, xref) {
|
|
66
|
+
const entry = dictGet(trailer, 'Encrypt');
|
|
67
|
+
if (entry === undefined)
|
|
68
|
+
return null;
|
|
69
|
+
if (entry.kind === 'dict')
|
|
70
|
+
return entry;
|
|
71
|
+
const ref = asRef(entry);
|
|
72
|
+
if (!ref)
|
|
73
|
+
return null;
|
|
74
|
+
const located = xref.get(ref.objectNumber);
|
|
75
|
+
if (located?.type !== 'in-use')
|
|
76
|
+
return null;
|
|
77
|
+
try {
|
|
78
|
+
const reader = new TokenReader(new ByteCursor(bytes, origin + located.offset));
|
|
79
|
+
return asDict(parseIndirectObject(reader).object);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** trailer `/ID` の第 1 要素(R ≤ 4 の鍵導出が要る・Algorithm 2 step e)。 */
|
|
86
|
+
function idFirstOf(trailer) {
|
|
87
|
+
const id = dictGet(trailer, 'ID');
|
|
88
|
+
if (id?.kind !== 'array')
|
|
89
|
+
return undefined;
|
|
90
|
+
return bytesOf(id.items[0]) ?? undefined;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 回復方針で歩いた節から `PdfDocument` を組み立てる。
|
|
94
|
+
*
|
|
95
|
+
* 版は 2 回組んで決める: ヘッダ版で 1 度組み、catalog `/Version` を読み、
|
|
96
|
+
* それが後の版ならその版で組み直す(§7.7.2 Table 29 / §7.5.2 NOTE 3)。
|
|
97
|
+
* 復号器も同じ理由で 2 段になる —— `/Encrypt` を解決するには文書が要る。
|
|
98
|
+
*/
|
|
99
|
+
async function buildFromChain(bytes, chain, options) {
|
|
100
|
+
const trailer = mergeTrailers(chain);
|
|
101
|
+
const xref = mergeXref(chain);
|
|
102
|
+
// 🔴 チェーンが辿り切れていない文書では、表に載っていないオブジェクトを数え上げて**穴だけ**埋める。
|
|
103
|
+
//
|
|
104
|
+
// 実測(`_wout/dss-pades-5sigs-doctimestamp.pdf`・`/Prev 0` で切れた 8 リビジョン 6 署名):
|
|
105
|
+
// 目録は読めるのに `/DSS` が指すオブジェクト 127 がどの節にも載っておらず、
|
|
106
|
+
// 失効情報が丸ごと見えなくなって **`revocation: revoked` が `unknown` に化けた**。
|
|
107
|
+
// 表にある定義は上書きしないので、意図的に free にされたオブジェクトが復活することはない。
|
|
108
|
+
let filledFromScan = 0;
|
|
109
|
+
if (chain.stop.kind !== 'complete') {
|
|
110
|
+
const scanned = reconstructXref(bytes, chain.origin);
|
|
111
|
+
if (scanned) {
|
|
112
|
+
for (const [objectNumber, entry] of scanned.entries) {
|
|
113
|
+
if (xref.has(objectNumber))
|
|
114
|
+
continue;
|
|
115
|
+
xref.set(objectNumber, entry);
|
|
116
|
+
filledFromScan += 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const headerVersion = headerVersionOf(bytes, chain.origin) ?? '1.0';
|
|
121
|
+
const plain = new PdfDocument(bytes, chain.origin, headerVersion, headerVersion, trailer, xref, chain.stop);
|
|
122
|
+
let decryptor;
|
|
123
|
+
const encryptEntry = dictGet(trailer, 'Encrypt');
|
|
124
|
+
const encrypted = encryptEntry !== undefined;
|
|
125
|
+
const encryptDict = readEncryptDict(bytes, chain.origin, trailer, xref);
|
|
126
|
+
if (encrypted && encryptDict) {
|
|
127
|
+
try {
|
|
128
|
+
decryptor = buildDocumentDecryptor(encryptDict, asRef(encryptEntry)?.objectNumber, idFirstOf(trailer), { password: options.password ?? '' });
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
// 🔴 鍵が導けなくても文書は返す。`/Encrypt` 辞書だけは §7.6.2 により読めるので、
|
|
132
|
+
// それだけで決まる規則(ISO 14289-1 7.16)は答えられる。復号器を付けない文書は
|
|
133
|
+
// オブジェクトを 1 つも渡さないので、暗号文を平文の顔で配ることにはならない。
|
|
134
|
+
options.onDebug?.(CONTEXT, `not authenticated: ${String(error)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const authenticated = !encrypted || decryptor !== undefined;
|
|
138
|
+
const staged = decryptor
|
|
139
|
+
? new PdfDocument(bytes, chain.origin, headerVersion, headerVersion, trailer, xref, chain.stop, decryptor)
|
|
140
|
+
: plain;
|
|
141
|
+
// catalog /Version がヘッダより後なら、そちらが実効版になる
|
|
142
|
+
let version = headerVersion;
|
|
143
|
+
try {
|
|
144
|
+
const catalog = asDict(await staged.getCatalog());
|
|
145
|
+
const declared = dictGet(catalog ?? { kind: 'dict', entries: new Map() }, 'Version');
|
|
146
|
+
if (declared?.kind === 'name' &&
|
|
147
|
+
/^\d+\.\d+$/.test(declared.value) &&
|
|
148
|
+
declared.value > version) {
|
|
149
|
+
version = declared.value;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// catalog に届かないこと自体は射程の話で、ここでは版を上げないだけ
|
|
154
|
+
}
|
|
155
|
+
const doc = version === headerVersion
|
|
156
|
+
? staged
|
|
157
|
+
: new PdfDocument(bytes, chain.origin, headerVersion, version, trailer, xref, chain.stop, decryptor);
|
|
158
|
+
return { doc, encrypted, authenticated, encryptDict, filledFromScan };
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 文書を開く。ライブラリが読めればそれを、断ったら回復方針で組み立てたものを返す。
|
|
162
|
+
* どちらも無理なら、**ライブラリが名指しした条文をそのまま**投げる。
|
|
163
|
+
*/
|
|
164
|
+
export async function openDocument(bytes, options = {}) {
|
|
165
|
+
const password = options.password ?? '';
|
|
166
|
+
let doc = null;
|
|
167
|
+
let refusal = null;
|
|
168
|
+
let refused = null;
|
|
169
|
+
try {
|
|
170
|
+
doc = await parsePdf(bytes, { password });
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
refused = error;
|
|
174
|
+
refusal = error instanceof Error ? error.message : String(error);
|
|
175
|
+
}
|
|
176
|
+
// 目録に届き、しかもチェーンが最後まで歩けた文書なら、それが答え。方針は挟まない。
|
|
177
|
+
//
|
|
178
|
+
// 🔴 **チェーンが途中で止まった文書はそのまま使わない。** ライブラリが返すのは
|
|
179
|
+
// 「チェーンが届いた範囲」で、そこには**ファイルが定義しているオブジェクトの一部しか無い**。
|
|
180
|
+
// `/Prev 0` の実検体(`dss-pades-5sigs-doctimestamp.pdf`)で測ると、署名 6 本のうち
|
|
181
|
+
// 5 本が消え、そのうち 1 本は失効した証明書で `invalid` と判定されていたものだった
|
|
182
|
+
// —— 反証がまるごと見えなくなる。監査の道具としては、これが最も避けたい向きの誤りである。
|
|
183
|
+
//
|
|
184
|
+
// そこで文書の組み立てだけは `startxref` の値も頼りに読み進める(`continuePastStop`)。
|
|
185
|
+
// リビジョンの一覧(`revision-diff`)は逆に、チェーンが言うとおりに厳密に読む。
|
|
186
|
+
// **「ファイルが定義しているオブジェクト」と「チェーンが辿れるリビジョン」は別の問いである。**
|
|
187
|
+
if (doc && doc.chainStop.kind === 'complete' && (await catalogReachable(doc))) {
|
|
188
|
+
// 節の数はライブラリが持っていないので、ここで歩いて数える。
|
|
189
|
+
// 2,950 検体で 87 ミリ秒(1 文書あたり 0.03 ミリ秒)—— 数えない理由にはならない。
|
|
190
|
+
const counted = await walkXrefChain(bytes, doc.origin);
|
|
191
|
+
return {
|
|
192
|
+
doc,
|
|
193
|
+
scope: {
|
|
194
|
+
recovered: false,
|
|
195
|
+
refusal: null,
|
|
196
|
+
chainStop: doc.chainStop,
|
|
197
|
+
newestSectionUnreadable: false,
|
|
198
|
+
sections: counted ? counted.sections.length : null,
|
|
199
|
+
continuedPastStop: false,
|
|
200
|
+
filledFromScan: 0,
|
|
201
|
+
reconstructed: false,
|
|
202
|
+
objects: doc.xref.size,
|
|
203
|
+
encrypted: doc.encryption !== undefined,
|
|
204
|
+
authenticated: true,
|
|
205
|
+
encryptDict: readEncryptDict(bytes, doc.origin, doc.trailer, doc.xref),
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// 🔴 ここから先がこのパッケージの方針である。2 つの理由でここに来る:
|
|
210
|
+
// 1. ライブラリが条文を名指しして受け取らなかった(構造が壊れている)
|
|
211
|
+
// 2. 読めたが**目録に届かない** —— `/Prev 0` などでチェーンが途中で止まり、
|
|
212
|
+
// 文書の本体が入っている節を読んでいない。「1 オブジェクトの文書」として
|
|
213
|
+
// 答えると、そこに何が書いてあるかを見ないまま「違反なし」を返すことになる
|
|
214
|
+
const origin = findOrigin(bytes);
|
|
215
|
+
const chain = await walkXrefChain(bytes, origin, {
|
|
216
|
+
continuePastStop: true,
|
|
217
|
+
onDebug: options.onDebug,
|
|
218
|
+
});
|
|
219
|
+
if (!chain) {
|
|
220
|
+
// 節が 1 つも読めない。ファイルの中のオブジェクトを数え上げて組み直す —— **推測である**。
|
|
221
|
+
const rebuilt = reconstructXref(bytes, origin);
|
|
222
|
+
if (!rebuilt) {
|
|
223
|
+
options.onDebug?.(CONTEXT, `no cross-reference section could be read: ${refusal ?? '(none)'}`);
|
|
224
|
+
if (refused)
|
|
225
|
+
throw refused;
|
|
226
|
+
throw new Error('no cross-reference section could be read');
|
|
227
|
+
}
|
|
228
|
+
options.onDebug?.(CONTEXT, `reconstructed ${rebuilt.entries.size} object(s) after: ${refusal}`);
|
|
229
|
+
const synthetic = {
|
|
230
|
+
origin,
|
|
231
|
+
sections: [
|
|
232
|
+
{
|
|
233
|
+
offset: origin,
|
|
234
|
+
kind: 'table',
|
|
235
|
+
entries: rebuilt.entries,
|
|
236
|
+
selfObjectNumber: null,
|
|
237
|
+
trailer: rebuilt.trailer,
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
stop: { kind: 'unreadable', offset: 0, reason: 'no cross-reference section could be read' },
|
|
241
|
+
truncated: true,
|
|
242
|
+
newestSectionUnreadable: true,
|
|
243
|
+
linearized: false,
|
|
244
|
+
continuedPastStop: false,
|
|
245
|
+
};
|
|
246
|
+
const rebuiltDoc = await buildFromChain(bytes, synthetic, { password });
|
|
247
|
+
return {
|
|
248
|
+
doc: rebuiltDoc.doc,
|
|
249
|
+
scope: {
|
|
250
|
+
recovered: true,
|
|
251
|
+
refusal,
|
|
252
|
+
chainStop: synthetic.stop,
|
|
253
|
+
newestSectionUnreadable: true,
|
|
254
|
+
sections: 0,
|
|
255
|
+
continuedPastStop: false,
|
|
256
|
+
filledFromScan: 0,
|
|
257
|
+
reconstructed: true,
|
|
258
|
+
objects: rebuiltDoc.doc.xref.size,
|
|
259
|
+
encrypted: rebuiltDoc.encrypted,
|
|
260
|
+
authenticated: rebuiltDoc.authenticated,
|
|
261
|
+
encryptDict: rebuiltDoc.encryptDict,
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const built = await buildFromChain(bytes, chain, { password });
|
|
266
|
+
// 組み立てても目録に届かず、ライブラリの答えのほうが読めていたなら、そちらを使う。
|
|
267
|
+
if (doc && !(await catalogReachable(built.doc))) {
|
|
268
|
+
return {
|
|
269
|
+
doc,
|
|
270
|
+
scope: {
|
|
271
|
+
recovered: false,
|
|
272
|
+
refusal: null,
|
|
273
|
+
chainStop: doc.chainStop,
|
|
274
|
+
newestSectionUnreadable: false,
|
|
275
|
+
// ここは既に歩いてある。ライブラリの答えを使うだけで、読んだ節は同じ。
|
|
276
|
+
sections: chain.sections.length,
|
|
277
|
+
continuedPastStop: false,
|
|
278
|
+
filledFromScan: 0,
|
|
279
|
+
reconstructed: false,
|
|
280
|
+
objects: doc.xref.size,
|
|
281
|
+
encrypted: doc.encryption !== undefined,
|
|
282
|
+
authenticated: true,
|
|
283
|
+
encryptDict: readEncryptDict(bytes, doc.origin, doc.trailer, doc.xref),
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
if (refusal)
|
|
288
|
+
options.onDebug?.(CONTEXT, `recovered after: ${refusal}`);
|
|
289
|
+
// 「回復した」= ライブラリの答えではなく、このパッケージが組み立てた、という意味。
|
|
290
|
+
// 断られた理由がパスワードだけ(鍵が導けないまま)なら、構造は壊れていないので言わない。
|
|
291
|
+
const structurallyRecovered = (refusal !== null && built.authenticated) ||
|
|
292
|
+
chain.newestSectionUnreadable ||
|
|
293
|
+
chain.continuedPastStop;
|
|
294
|
+
return {
|
|
295
|
+
doc: built.doc,
|
|
296
|
+
scope: {
|
|
297
|
+
recovered: structurallyRecovered,
|
|
298
|
+
refusal,
|
|
299
|
+
chainStop: chain.stop,
|
|
300
|
+
newestSectionUnreadable: chain.newestSectionUnreadable,
|
|
301
|
+
sections: chain.sections.length,
|
|
302
|
+
continuedPastStop: chain.continuedPastStop,
|
|
303
|
+
filledFromScan: built.filledFromScan,
|
|
304
|
+
reconstructed: false,
|
|
305
|
+
objects: built.doc.xref.size,
|
|
306
|
+
encrypted: built.encrypted,
|
|
307
|
+
authenticated: built.authenticated,
|
|
308
|
+
encryptDict: built.encryptDict,
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* 内部の申告を、出力に載せる形にする。落とすのは `encryptDict` だけ
|
|
314
|
+
* —— COS 辞書なので JSON にすると内部表現が出る。`/V` `/R` `/Filter` の値が
|
|
315
|
+
* 要るなら、呼び出し側がそこから取り出す。
|
|
316
|
+
*/
|
|
317
|
+
export function toReadingScope(scope) {
|
|
318
|
+
// 鍵の順は手で書く。分割代入の残りを広げると `chainStop` が末尾に回り、
|
|
319
|
+
// 読み手が最初に見る場所が変わってしまう。
|
|
320
|
+
return {
|
|
321
|
+
recovered: scope.recovered,
|
|
322
|
+
refusal: scope.refusal,
|
|
323
|
+
chainStop: { ...scope.chainStop },
|
|
324
|
+
newestSectionUnreadable: scope.newestSectionUnreadable,
|
|
325
|
+
sections: scope.sections,
|
|
326
|
+
continuedPastStop: scope.continuedPastStop,
|
|
327
|
+
filledFromScan: scope.filledFromScan,
|
|
328
|
+
reconstructed: scope.reconstructed,
|
|
329
|
+
objects: scope.objects,
|
|
330
|
+
encrypted: scope.encrypted,
|
|
331
|
+
authenticated: scope.authenticated,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@normativepdf/recover`
|
|
3
|
+
*
|
|
4
|
+
* 相互参照表が ISO 32000-2 §7.5 のとおりでない PDF を、読める範囲まで読む。
|
|
5
|
+
*
|
|
6
|
+
* normativepdf は §7.5 を条文どおりに読み、条文に反する文書は受け取らずに
|
|
7
|
+
* 例外を投げる(DESIGN §4.2「自前で検証器を持たない」)。受け取らなかった文書を
|
|
8
|
+
* どう読むかは、そこでは決めずに利用側へ残してある。それをここに置いた。
|
|
9
|
+
*
|
|
10
|
+
* 🔴 **このパッケージは適合を判定しない。** `DocumentScope` と `ReadingScope` が
|
|
11
|
+
* 答えるのは「どこまで読んだか」だけで、「条文に適合しているか」ではない。
|
|
12
|
+
* 適合の判定は利用する側が行う(ADR-0010)。
|
|
13
|
+
*/
|
|
14
|
+
export { asArray, asDict, asRef, asStream, boolOf, bytesOf, decodedBytes, dictOfStream, enumerateDicts, enumerateObjects, get, has, type IndirectEntry, integerOf, type Lookup, nameOf, numberOf, resolved, textOf, tryGet, tryResolve, } from './cos.js';
|
|
15
|
+
export { type DocumentScope, type OpenedDocument, type OpenOptions, openDocument, toReadingScope, } from './document.js';
|
|
16
|
+
export type { DebugSink, ReadingScope, XrefKind } from './types.js';
|
|
17
|
+
export { findOrigin, indexOfBytes, isDelimiter, isWhitespace, LATIN1, readToken, reconstructXref, skipWhitespace, type WalkedChain, type WalkedSection, type WalkOptions, walkXrefChain, } from './xref-walk.js';
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,OAAO,EACP,MAAM,EACN,KAAK,EACL,QAAQ,EACR,MAAM,EACN,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,GAAG,EACH,GAAG,EACH,KAAK,aAAa,EAClB,SAAS,EACT,KAAK,MAAM,EACX,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,MAAM,EACN,SAAS,EACT,eAAe,EACf,cAAc,EACd,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@normativepdf/recover`
|
|
3
|
+
*
|
|
4
|
+
* 相互参照表が ISO 32000-2 §7.5 のとおりでない PDF を、読める範囲まで読む。
|
|
5
|
+
*
|
|
6
|
+
* normativepdf は §7.5 を条文どおりに読み、条文に反する文書は受け取らずに
|
|
7
|
+
* 例外を投げる(DESIGN §4.2「自前で検証器を持たない」)。受け取らなかった文書を
|
|
8
|
+
* どう読むかは、そこでは決めずに利用側へ残してある。それをここに置いた。
|
|
9
|
+
*
|
|
10
|
+
* 🔴 **このパッケージは適合を判定しない。** `DocumentScope` と `ReadingScope` が
|
|
11
|
+
* 答えるのは「どこまで読んだか」だけで、「条文に適合しているか」ではない。
|
|
12
|
+
* 適合の判定は利用する側が行う(ADR-0010)。
|
|
13
|
+
*/
|
|
14
|
+
export { asArray, asDict, asRef, asStream, boolOf, bytesOf, decodedBytes, dictOfStream, enumerateDicts, enumerateObjects, get, has, integerOf, nameOf, numberOf, resolved, textOf, tryGet, tryResolve, } from './cos.js';
|
|
15
|
+
export { openDocument, toReadingScope, } from './document.js';
|
|
16
|
+
export { findOrigin, indexOfBytes, isDelimiter, isWhitespace, LATIN1, readToken, reconstructXref, skipWhitespace, walkXrefChain, } from './xref-walk.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,OAAO,EACP,MAAM,EACN,KAAK,EACL,QAAQ,EACR,MAAM,EACN,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,GAAG,EACH,GAAG,EAEH,SAAS,EAET,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAIL,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,MAAM,EACN,SAAS,EACT,eAAe,EACf,cAAc,EAId,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@normativepdf/recover` の型。
|
|
3
|
+
*
|
|
4
|
+
* `ReadingScope` は `DocumentScope`(`document.ts`)と対で意味を持つ ——
|
|
5
|
+
* 前者が外に出す形、後者が COS 辞書まで持つ内側の形である。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* デバッグ出力を受け取る関数。渡さなければ何も出力しない。
|
|
9
|
+
*
|
|
10
|
+
* 🔴 **stdout に書く関数を渡さないこと。** このパッケージを最初に使うのは
|
|
11
|
+
* MCP サーバで、そこでは stdout に書いたバイトが JSON-RPC のメッセージとして
|
|
12
|
+
* 読まれ、パースに失敗する。
|
|
13
|
+
*/
|
|
14
|
+
export type DebugSink = (context: string, message: string) => void;
|
|
15
|
+
/** Which form of cross-reference section a revision used */
|
|
16
|
+
export type XrefKind = 'table' | 'stream' | 'hybrid';
|
|
17
|
+
/**
|
|
18
|
+
* どこまで読んだか —— **判定ではなく、判定の射程**。
|
|
19
|
+
*
|
|
20
|
+
* 同じ規則を当てても、読めた範囲が違えば答えが違う。この構造体が無いと
|
|
21
|
+
* 「制約に違反していない」と「その対象を観測していない」が同じ顔をする。
|
|
22
|
+
* だから報告の**先頭**に置く(消費者の出力でも)。
|
|
23
|
+
*
|
|
24
|
+
* 🔴 `reconstructed: true` のとき、相互参照表は **このパッケージが組み直したもの**で
|
|
25
|
+
* あって、ファイルが持っているものではない。監査の読み手に伏せてよい事実ではない。
|
|
26
|
+
*
|
|
27
|
+
* `DocumentScope`(内部)から `encryptDict` を落としたもの。
|
|
28
|
+
* COS 辞書は JSON にすると内部表現が出るので外には出さない。
|
|
29
|
+
*/
|
|
30
|
+
export interface ReadingScope {
|
|
31
|
+
/** true = ライブラリがそのまま読んだのではなく、回復方針で組み立てた */
|
|
32
|
+
recovered: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 回復に入った理由 —— ライブラリが投げた、条文を名指しするエラーの文面。
|
|
35
|
+
*
|
|
36
|
+
* 🔴 **文面で分岐しないこと。** これは normativepdf のメッセージそのままで、
|
|
37
|
+
* 版が上がれば言い回しが変わる。分岐するなら `recovered` と `chainStop.kind`。
|
|
38
|
+
*/
|
|
39
|
+
refusal: string | null;
|
|
40
|
+
/** チェーンの歩きがどこで止まったか(§7.5.6) */
|
|
41
|
+
chainStop: {
|
|
42
|
+
kind: string;
|
|
43
|
+
offset?: number;
|
|
44
|
+
reason?: string;
|
|
45
|
+
};
|
|
46
|
+
/** 最後の `startxref` が読めず、古い入口から入った = 末尾のバイトは代表されていない */
|
|
47
|
+
newestSectionUnreadable: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* 読めた相互参照節の数。数えられなかったときは `null`。
|
|
50
|
+
* `0` は「節が 1 つも読めなかった」という観測結果のときだけ。
|
|
51
|
+
*/
|
|
52
|
+
sections: number | null;
|
|
53
|
+
/** チェーンが止まったあと、`startxref` の値も頼りに読み進めた */
|
|
54
|
+
continuedPastStop: boolean;
|
|
55
|
+
/** 表に載っていないオブジェクトを数え上げて埋めた数(表にある定義は上書きしない) */
|
|
56
|
+
filledFromScan: number;
|
|
57
|
+
/** 🔴 相互参照表を組み直した。ファイルが持っている表ではない */
|
|
58
|
+
reconstructed: boolean;
|
|
59
|
+
/** 相互参照表に載っているオブジェクトの数 */
|
|
60
|
+
objects: number;
|
|
61
|
+
/** trailer に `/Encrypt` がある(§7.6) */
|
|
62
|
+
encrypted: boolean;
|
|
63
|
+
/** 暗号化文書の鍵が導けた。false のときオブジェクトは 1 つも読めない(ADR-0008) */
|
|
64
|
+
authenticated: boolean;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEnE,4DAA4D;AAC5D,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+BAA+B;IAC/B,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,uDAAuD;IACvD,uBAAuB,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,0CAA0C;IAC1C,iBAAiB,EAAE,OAAO,CAAC;IAC3B,8CAA8C;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,aAAa,EAAE,OAAO,CAAC;CACxB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 相互参照チェーンの歩きと、その**回復方針**。
|
|
3
|
+
*
|
|
4
|
+
* normativepdf は §7.5 を条文どおりに読み、回復方針を持たない —— `readXrefSectionAt` の
|
|
5
|
+
* doc コメントが「自分で歩く消費者のために公開している。第 1 消費者は pdf-verify-mcp の
|
|
6
|
+
* revision diff」と名指ししているとおり、ここがその方針の置き場である。
|
|
7
|
+
*
|
|
8
|
+
* **なぜ 1 か所なのか**(2026-08-28 の実測。ADR-0010 が器を決めた):
|
|
9
|
+
* この方針は revision diff だけのものではない。文書を開く入口(`pdf-parser.ts`)も
|
|
10
|
+
* 同じ判断を要る —— コーパス 2,947 検体のうち 17 件は、入口の節や `startxref` が
|
|
11
|
+
* 条文に反していて `parsePdf` が受け取らない。方針が 2 か所にあると、
|
|
12
|
+
* 「この文書をどこまで読んだか」の答えがツールによって割れる。
|
|
13
|
+
*
|
|
14
|
+
* 方針は 4 つ:
|
|
15
|
+
* 1. 最後の `startxref` が読めなければ、古い入口を順に試す(試したことは申告する)
|
|
16
|
+
* 2. `/Prev` が正の整数でなければ、そこで打ち切る —— 「きれいに終わった」とは言わない
|
|
17
|
+
* 3. 巡回と `MAX_REVISIONS` で止める
|
|
18
|
+
* 4. 線形化(Annex F)の 2 節は 1 リビジョンに畳む
|
|
19
|
+
*
|
|
20
|
+
* ここに判定は書かない。どこまで読めたかを返すだけで、それをどう読むかは呼び出し側が決める。
|
|
21
|
+
*/
|
|
22
|
+
import { type CosDict, type XrefChainStop, type XrefEntry } from 'normativepdf';
|
|
23
|
+
import type { DebugSink, XrefKind } from './types.js';
|
|
24
|
+
export declare const LATIN1: import("util").TextDecoder;
|
|
25
|
+
/**
|
|
26
|
+
* 歩いて読めた 1 つの相互参照節。offset は絶対位置に直してあり、entries は
|
|
27
|
+
* 線形化の畳み込みのために可変にしてある。`trailer` は文書を組み立てる側が要る。
|
|
28
|
+
*/
|
|
29
|
+
export interface WalkedSection {
|
|
30
|
+
/** Absolute byte offset of the cross-reference section (`origin + offset`) */
|
|
31
|
+
offset: number;
|
|
32
|
+
kind: XrefKind;
|
|
33
|
+
entries: Map<number, XrefEntry>;
|
|
34
|
+
/** Object number of the cross-reference stream itself, when it is one */
|
|
35
|
+
selfObjectNumber: number | null;
|
|
36
|
+
/** Trailer dictionary of this section (§7.5.5 Table 15; Table 17 for streams) */
|
|
37
|
+
trailer: CosDict;
|
|
38
|
+
}
|
|
39
|
+
/** 歩いた結果。`sections` は古い順。 */
|
|
40
|
+
export interface WalkOptions {
|
|
41
|
+
/**
|
|
42
|
+
* チェーンが途中で止まったあと、**まだ読んでいない `startxref` の値**から読み続ける。
|
|
43
|
+
*
|
|
44
|
+
* 既定は false —— リビジョンの一覧(`revision-diff`)はチェーンが言うとおりに
|
|
45
|
+
* 読むべきで、続きを勝手に足すと「歩き切った」と同じ顔になる。
|
|
46
|
+
* true にするのは**文書を組み立てられないとき**だけである(目録に届かない、など)。
|
|
47
|
+
* そのときは「ここから先は `/Prev` ではなく `startxref` を頼りに読んだ」という
|
|
48
|
+
* 別の事実になるので、`continuedPastStop` で申告する。
|
|
49
|
+
*/
|
|
50
|
+
continuePastStop?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* 読めなかった節の申告先。既定は「どこにも出さない」。
|
|
53
|
+
* 🔴 stdout に書く実装を渡さないこと(`DebugSink`)。
|
|
54
|
+
*/
|
|
55
|
+
onDebug?: DebugSink;
|
|
56
|
+
}
|
|
57
|
+
export interface WalkedChain {
|
|
58
|
+
/** §7.5.2 の原点(`%PDF-` の位置)。節の offset は絶対、エントリの offset は原点相対 */
|
|
59
|
+
origin: number;
|
|
60
|
+
sections: WalkedSection[];
|
|
61
|
+
/**
|
|
62
|
+
* 歩きがどこで止まったか。normativepdf と同じ 5 値
|
|
63
|
+
* (`complete` / `prev-zero` / `unreadable` / `cyclic` / `malformed`)。
|
|
64
|
+
* 🔴 「終わりまで来た」と「これ以上行けなかった」は別の事実である。
|
|
65
|
+
*/
|
|
66
|
+
stop: XrefChainStop;
|
|
67
|
+
/** チェーンを最後まで辿れなかった(巡回・上限・辿れない `/Prev`) */
|
|
68
|
+
truncated: boolean;
|
|
69
|
+
/** 最後の `startxref` が読めず、古い入口から入った = 末尾のバイトはどの節にも代表されていない */
|
|
70
|
+
newestSectionUnreadable: boolean;
|
|
71
|
+
/** 線形化(Annex F)の 2 節を 1 リビジョンに畳んだ */
|
|
72
|
+
linearized: boolean;
|
|
73
|
+
/** 止まったあと、`startxref` の値から読み続けた(`continuePastStop`) */
|
|
74
|
+
continuedPastStop: boolean;
|
|
75
|
+
}
|
|
76
|
+
export declare function isWhitespace(byte: number): boolean;
|
|
77
|
+
export declare function isDelimiter(byte: number): boolean;
|
|
78
|
+
export declare function indexOfBytes(hay: Uint8Array, needle: string, from: number): number;
|
|
79
|
+
export declare function skipWhitespace(bytes: Uint8Array, index: number): number;
|
|
80
|
+
/** Read the next whitespace/delimiter-terminated token. */
|
|
81
|
+
export declare function readToken(bytes: Uint8Array, index: number): {
|
|
82
|
+
token: string;
|
|
83
|
+
next: number;
|
|
84
|
+
} | null;
|
|
85
|
+
/**
|
|
86
|
+
* §7.5.2 — "byte offsets shall be calculated from the PERCENT SIGN" of the
|
|
87
|
+
* `%PDF-` header, which need not be at byte 0. A file with no header at all is
|
|
88
|
+
* not dismissed here (that is the validator's verdict, not this module's): the
|
|
89
|
+
* origin falls back to 0 so the chain can still be described.
|
|
90
|
+
*/
|
|
91
|
+
export declare function findOrigin(bytes: Uint8Array): number;
|
|
92
|
+
/**
|
|
93
|
+
* Walk `startxref` → `/Prev` → … and return the revisions oldest first.
|
|
94
|
+
*
|
|
95
|
+
* Reading each section is normativepdf's job; everything below is the recovery
|
|
96
|
+
* policy that library deliberately leaves to its consumer.
|
|
97
|
+
*/
|
|
98
|
+
export declare function walkXrefChain(bytes: Uint8Array, origin?: number, options?: WalkOptions): Promise<WalkedChain | null>;
|
|
99
|
+
/**
|
|
100
|
+
* ファイルの中の `N G obj` を数え上げて、相互参照表を組み直す。
|
|
101
|
+
*
|
|
102
|
+
* 🔴 **これは推測である。** ファイルが持っていない表をこちらが作るのだから、
|
|
103
|
+
* 使った文書ではそう申告しなければならない(`DocumentScope.reconstructed`)。
|
|
104
|
+
* それでも refuse より良いのは、監査に持ち込まれる文書こそ壊れているからで、
|
|
105
|
+
* 「読めません」だけを返すと**中に何が書いてあるかを誰も見ないまま終わる**。
|
|
106
|
+
*
|
|
107
|
+
* 呼ぶのは `walkXrefChain` が 1 節も読めなかったときだけ。
|
|
108
|
+
* 後ろにある定義が前の定義を上書きする(増分更新は後ろが新しい・§7.5.6)。
|
|
109
|
+
*/
|
|
110
|
+
export declare function reconstructXref(bytes: Uint8Array, origin: number): {
|
|
111
|
+
entries: Map<number, XrefEntry>;
|
|
112
|
+
trailer: CosDict;
|
|
113
|
+
} | null;
|
|
114
|
+
//# sourceMappingURL=xref-walk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xref-walk.d.ts","sourceRoot":"","sources":["../src/xref-walk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAEL,KAAK,OAAO,EAOZ,KAAK,aAAa,EAClB,KAAK,SAAS,EAEf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAStD,eAAO,MAAM,MAAM,4BAA4B,CAAC;AAEhD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAChC,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,iFAAiF;IACjF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,6BAA6B;AAC7B,MAAM,WAAW,WAAW;IAC1B;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B;;;;OAIG;IACH,IAAI,EAAE,aAAa,CAAC;IACpB,0CAA0C;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,4DAA4D;IAC5D,uBAAuB,EAAE,OAAO,CAAC;IACjC,qCAAqC;IACrC,UAAU,EAAE,OAAO,CAAC;IACpB,uDAAuD;IACvD,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAMD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASlD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAajD;AAOD,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAElF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAevE;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CACvB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,MAAM,GACZ;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUxC;AAMD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAEpD;AAgFD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,UAAU,EACjB,MAAM,GAAE,MAA0B,EAClC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAyH7B;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,MAAM,GACb;IAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAwD9D"}
|