* Parse PDF header and extract version. * * Lenient handling (like pdf.js and PDFBox): * - Search first 1024 bytes for %PDF- * - Accept garbage before/after header * - Default to 1.4 if version unparseable
()
| 255 | * - Default to 1.4 if version unparseable |
| 256 | */ |
| 257 | parseHeader(): string { |
| 258 | const bytes = this.scanner.bytes; |
| 259 | const searchLimit = Math.min(bytes.length, HEADER_SEARCH_LIMIT); |
| 260 | |
| 261 | // Search for %PDF- marker |
| 262 | let headerPos = -1; |
| 263 | for (let i = 0; i <= searchLimit - PDF_HEADER.length; i++) { |
| 264 | if (this.matchesAt(i, PDF_HEADER)) { |
| 265 | headerPos = i; |
| 266 | break; |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | if (headerPos === -1) { |
| 271 | if (this.options.lenient) { |
| 272 | this.warnings.push("PDF header not found, using default version"); |
| 273 | return DEFAULT_VERSION; |
| 274 | } |
| 275 | throw new StructureError("PDF header not found"); |
| 276 | } |
| 277 | |
| 278 | if (headerPos > 0) { |
| 279 | this.warnings.push(`PDF header found at offset ${headerPos} (expected 0)`); |
| 280 | } |
| 281 | |
| 282 | // Read version string after %PDF- |
| 283 | const versionStart = headerPos + PDF_HEADER.length; |
| 284 | let version = ""; |
| 285 | |
| 286 | // Read characters until whitespace or non-version char (max 7 chars like pdf.js) |
| 287 | for (let i = 0; i < 7 && versionStart + i < bytes.length; i++) { |
| 288 | const byte = bytes[versionStart + i]; |
| 289 | |
| 290 | // Stop at whitespace or control chars |
| 291 | if (byte <= 0x20) { |
| 292 | break; |
| 293 | } |
| 294 | |
| 295 | version += String.fromCharCode(byte); |
| 296 | } |
| 297 | |
| 298 | // Validate version format |
| 299 | if (VERSION_PATTERN.test(version)) { |
| 300 | return version; |
| 301 | } |
| 302 | |
| 303 | // Try to extract just the version part (handle garbage after version) |
| 304 | const match = version.match(/^(\d\.\d)/); |
| 305 | if (match) { |
| 306 | this.warnings.push(`Version string has garbage after it: ${version}`); |
| 307 | return match[1]; |
| 308 | } |
| 309 | |
| 310 | if (this.options.lenient) { |
| 311 | this.warnings.push(`Invalid PDF version: ${version}, using default`); |
| 312 | return DEFAULT_VERSION; |
| 313 | } |
| 314 |
no test coverage detected