* Parse traditional xref table format. * Scanner must be positioned at "xref" keyword.
()
| 137 | * Scanner must be positioned at "xref" keyword. |
| 138 | */ |
| 139 | parseTable(): XRefData { |
| 140 | const entries = new Map<number, XRefEntry>(); |
| 141 | |
| 142 | // Consume "xref" keyword |
| 143 | this.expectKeyword("xref"); |
| 144 | this.skipWhitespaceFromCurrent(); |
| 145 | |
| 146 | // Read subsections until we hit "trailer" |
| 147 | // Skip whitespace before each check (some PDFs have extra newlines between entries and trailer) |
| 148 | while (true) { |
| 149 | this.skipWhitespaceFromCurrent(); |
| 150 | |
| 151 | if (this.peekKeyword("trailer")) { |
| 152 | break; |
| 153 | } |
| 154 | |
| 155 | this.parseSubsection(entries); |
| 156 | } |
| 157 | |
| 158 | // Consume "trailer" keyword |
| 159 | this.expectKeyword("trailer"); |
| 160 | this.skipWhitespaceFromCurrent(); |
| 161 | |
| 162 | // Parse trailer dictionary |
| 163 | const reader = new TokenReader(this.scanner); |
| 164 | const parser = new ObjectParser(reader); |
| 165 | const result = parser.parseObject(); |
| 166 | |
| 167 | if (result === null || result.object.type !== "dict") { |
| 168 | throw new XRefParseError("Invalid trailer dictionary"); |
| 169 | } |
| 170 | |
| 171 | const trailer = result.object; |
| 172 | |
| 173 | // Extract /Prev if present |
| 174 | const prevNum = trailer.getNumber("Prev"); |
| 175 | const prev = prevNum?.value; |
| 176 | |
| 177 | return { |
| 178 | entries, |
| 179 | trailer, |
| 180 | prev, |
| 181 | }; |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * Parse xref stream format (PDF 1.5+). |
no test coverage detected