* Build the final ParsedDocument with lazy object loading.
(
version: string,
xref: Map<number, XRefEntry>,
trailer: PdfDict,
recoveredViaBruteForce: boolean,
)
| 424 | * Build the final ParsedDocument with lazy object loading. |
| 425 | */ |
| 426 | private buildDocument( |
| 427 | version: string, |
| 428 | xref: Map<number, XRefEntry>, |
| 429 | trailer: PdfDict, |
| 430 | recoveredViaBruteForce: boolean, |
| 431 | ): ParsedDocument { |
| 432 | // Object cache: "objNum genNum" -> PdfObject (null = known-unparseable) |
| 433 | const cache = new Map<string, PdfObject | null>(); |
| 434 | |
| 435 | const lenient = this.options.lenient ?? true; |
| 436 | |
| 437 | const recoveryOptions = { |
| 438 | recoveryMode: lenient, |
| 439 | onWarning: (message: string, position: number) => { |
| 440 | this.warnings.push(`Object parse warning at offset ${position}: ${message}`); |
| 441 | }, |
| 442 | }; |
| 443 | |
| 444 | // Object stream cache: streamObjNum -> ObjectStreamParser |
| 445 | const objectStreamCache = new Map<number, ObjectStreamParser>(); |
| 446 | |
| 447 | // ───────────────────────────────────────────────────────────────────────────── |
| 448 | // Encryption setup |
| 449 | // ───────────────────────────────────────────────────────────────────────────── |
| 450 | |
| 451 | let securityHandler: StandardSecurityHandler | null = null; |
| 452 | let encryptionDict: EncryptionDict | null = null; |
| 453 | |
| 454 | const isEncrypted = isEncryptedTrailer(trailer); |
| 455 | |
| 456 | if (isEncrypted) { |
| 457 | try { |
| 458 | // Get /Encrypt dictionary |
| 459 | const encryptRef = trailer.getRef("Encrypt"); |
| 460 | |
| 461 | let encryptDictObj: PdfDict | null = null; |
| 462 | |
| 463 | if (encryptRef) { |
| 464 | // Need to load the encrypt dict without decryption |
| 465 | const entry = xref.get(encryptRef.objectNumber); |
| 466 | |
| 467 | if (entry?.type === "uncompressed") { |
| 468 | const parser = new IndirectObjectParser(this.scanner); |
| 469 | const result = parser.parseObjectAt(entry.offset); |
| 470 | |
| 471 | if (result.value instanceof PdfDict) { |
| 472 | encryptDictObj = result.value; |
| 473 | } |
| 474 | } |
| 475 | } else { |
| 476 | // Direct dictionary (rare but valid) |
| 477 | encryptDictObj = trailer.getDict("Encrypt") ?? null; |
| 478 | } |
| 479 | |
| 480 | if (encryptDictObj) { |
| 481 | encryptionDict = parseEncryptionDict(encryptDictObj); |
| 482 | |
| 483 | // Get file ID from trailer |
no test coverage detected