* Recovery parsing using brute-force when normal parsing fails.
()
| 195 | * Recovery parsing using brute-force when normal parsing fails. |
| 196 | */ |
| 197 | private parseWithRecovery(): ParsedDocument { |
| 198 | // Try to get version even if header is malformed |
| 199 | let version = DEFAULT_VERSION; |
| 200 | |
| 201 | try { |
| 202 | version = this.parseHeader(); |
| 203 | } catch { |
| 204 | this.warnings.push("Could not parse header, using default version"); |
| 205 | } |
| 206 | |
| 207 | // Use brute-force parser to find objects |
| 208 | const bruteForce = new BruteForceParser(this.scanner); |
| 209 | |
| 210 | const result = bruteForce.recover(); |
| 211 | |
| 212 | if (result === null) { |
| 213 | throw new UnrecoverableParseError("Could not recover PDF structure: no objects found"); |
| 214 | } |
| 215 | |
| 216 | this.warnings.push(...result.warnings); |
| 217 | |
| 218 | // Build xref from recovered entries |
| 219 | const xref = new Map<number, XRefEntry>(); |
| 220 | |
| 221 | for (const [key, recoveredEntry] of result.xref.entries()) { |
| 222 | // Key is "objNum genNum" |
| 223 | const [objNumStr, genNumStr] = key.split(" "); |
| 224 | |
| 225 | const objNum = parseInt(objNumStr, 10); |
| 226 | const generation = parseInt(genNumStr, 10); |
| 227 | |
| 228 | if (recoveredEntry.type === "uncompressed") { |
| 229 | xref.set(objNum, { type: "uncompressed", offset: recoveredEntry.offset, generation }); |
| 230 | } else { |
| 231 | // Compressed entry from object stream |
| 232 | xref.set(objNum, { |
| 233 | type: "compressed", |
| 234 | streamObjNum: recoveredEntry.streamObjNum, |
| 235 | indexInStream: recoveredEntry.indexInStream, |
| 236 | }); |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | // Build trailer from recovered root |
| 241 | const trailer = new PdfDict([ |
| 242 | ["Root", result.trailer.Root], |
| 243 | ["Size", new PdfNumber(result.trailer.Size)], |
| 244 | ]); |
| 245 | |
| 246 | return this.buildDocument(version, xref, trailer, true); |
| 247 | } |
| 248 | |
| 249 | /** |
| 250 | * Parse PDF header and extract version. |
no test coverage detected