1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.Parser = exports.Linearization = exports.Lexer = void 0;
|
28 |
|
29 | var _util = require("../shared/util.js");
|
30 |
|
31 | var _primitives = require("./primitives.js");
|
32 |
|
33 | var _core_utils = require("./core_utils.js");
|
34 |
|
35 | var _ascii_85_stream = require("./ascii_85_stream.js");
|
36 |
|
37 | var _ascii_hex_stream = require("./ascii_hex_stream.js");
|
38 |
|
39 | var _ccitt_stream = require("./ccitt_stream.js");
|
40 |
|
41 | var _flate_stream = require("./flate_stream.js");
|
42 |
|
43 | var _jbig2_stream = require("./jbig2_stream.js");
|
44 |
|
45 | var _jpeg_stream = require("./jpeg_stream.js");
|
46 |
|
47 | var _jpx_stream = require("./jpx_stream.js");
|
48 |
|
49 | var _lzw_stream = require("./lzw_stream.js");
|
50 |
|
51 | var _stream = require("./stream.js");
|
52 |
|
53 | var _predictor_stream = require("./predictor_stream.js");
|
54 |
|
55 | var _run_length_stream = require("./run_length_stream.js");
|
56 |
|
57 | const MAX_LENGTH_TO_CACHE = 1000;
|
58 | const MAX_ADLER32_LENGTH = 5552;
|
59 |
|
60 | function computeAdler32(bytes) {
|
61 | const bytesLength = bytes.length;
|
62 | let a = 1,
|
63 | b = 0;
|
64 |
|
65 | for (let i = 0; i < bytesLength; ++i) {
|
66 | a += bytes[i] & 0xff;
|
67 | b += a;
|
68 | }
|
69 |
|
70 | return b % 65521 << 16 | a % 65521;
|
71 | }
|
72 |
|
73 | class Parser {
|
74 | constructor({
|
75 | lexer,
|
76 | xref,
|
77 | allowStreams = false,
|
78 | recoveryMode = false
|
79 | }) {
|
80 | this.lexer = lexer;
|
81 | this.xref = xref;
|
82 | this.allowStreams = allowStreams;
|
83 | this.recoveryMode = recoveryMode;
|
84 | this.imageCache = Object.create(null);
|
85 | this.refill();
|
86 | }
|
87 |
|
88 | refill() {
|
89 | this.buf1 = this.lexer.getObj();
|
90 | this.buf2 = this.lexer.getObj();
|
91 | }
|
92 |
|
93 | shift() {
|
94 | if (this.buf2 instanceof _primitives.Cmd && this.buf2.cmd === "ID") {
|
95 | this.buf1 = this.buf2;
|
96 | this.buf2 = null;
|
97 | } else {
|
98 | this.buf1 = this.buf2;
|
99 | this.buf2 = this.lexer.getObj();
|
100 | }
|
101 | }
|
102 |
|
103 | tryShift() {
|
104 | try {
|
105 | this.shift();
|
106 | return true;
|
107 | } catch (e) {
|
108 | if (e instanceof _core_utils.MissingDataException) {
|
109 | throw e;
|
110 | }
|
111 |
|
112 | return false;
|
113 | }
|
114 | }
|
115 |
|
116 | getObj(cipherTransform = null) {
|
117 | const buf1 = this.buf1;
|
118 | this.shift();
|
119 |
|
120 | if (buf1 instanceof _primitives.Cmd) {
|
121 | switch (buf1.cmd) {
|
122 | case "BI":
|
123 | return this.makeInlineImage(cipherTransform);
|
124 |
|
125 | case "[":
|
126 | const array = [];
|
127 |
|
128 | while (!(0, _primitives.isCmd)(this.buf1, "]") && this.buf1 !== _primitives.EOF) {
|
129 | array.push(this.getObj(cipherTransform));
|
130 | }
|
131 |
|
132 | if (this.buf1 === _primitives.EOF) {
|
133 | if (this.recoveryMode) {
|
134 | return array;
|
135 | }
|
136 |
|
137 | throw new _core_utils.ParserEOFException("End of file inside array.");
|
138 | }
|
139 |
|
140 | this.shift();
|
141 | return array;
|
142 |
|
143 | case "<<":
|
144 | const dict = new _primitives.Dict(this.xref);
|
145 |
|
146 | while (!(0, _primitives.isCmd)(this.buf1, ">>") && this.buf1 !== _primitives.EOF) {
|
147 | if (!(this.buf1 instanceof _primitives.Name)) {
|
148 | (0, _util.info)("Malformed dictionary: key must be a name object");
|
149 | this.shift();
|
150 | continue;
|
151 | }
|
152 |
|
153 | const key = this.buf1.name;
|
154 | this.shift();
|
155 |
|
156 | if (this.buf1 === _primitives.EOF) {
|
157 | break;
|
158 | }
|
159 |
|
160 | dict.set(key, this.getObj(cipherTransform));
|
161 | }
|
162 |
|
163 | if (this.buf1 === _primitives.EOF) {
|
164 | if (this.recoveryMode) {
|
165 | return dict;
|
166 | }
|
167 |
|
168 | throw new _core_utils.ParserEOFException("End of file inside dictionary.");
|
169 | }
|
170 |
|
171 | if ((0, _primitives.isCmd)(this.buf2, "stream")) {
|
172 | return this.allowStreams ? this.makeStream(dict, cipherTransform) : dict;
|
173 | }
|
174 |
|
175 | this.shift();
|
176 | return dict;
|
177 |
|
178 | default:
|
179 | return buf1;
|
180 | }
|
181 | }
|
182 |
|
183 | if (Number.isInteger(buf1)) {
|
184 | if (Number.isInteger(this.buf1) && (0, _primitives.isCmd)(this.buf2, "R")) {
|
185 | const ref = _primitives.Ref.get(buf1, this.buf1);
|
186 |
|
187 | this.shift();
|
188 | this.shift();
|
189 | return ref;
|
190 | }
|
191 |
|
192 | return buf1;
|
193 | }
|
194 |
|
195 | if (typeof buf1 === "string") {
|
196 | if (cipherTransform) {
|
197 | return cipherTransform.decryptString(buf1);
|
198 | }
|
199 |
|
200 | return buf1;
|
201 | }
|
202 |
|
203 | return buf1;
|
204 | }
|
205 |
|
206 | findDefaultInlineStreamEnd(stream) {
|
207 | const E = 0x45,
|
208 | I = 0x49,
|
209 | SPACE = 0x20,
|
210 | LF = 0xa,
|
211 | CR = 0xd,
|
212 | NUL = 0x0;
|
213 | const lexer = this.lexer,
|
214 | startPos = stream.pos,
|
215 | n = 10;
|
216 | let state = 0,
|
217 | ch,
|
218 | maybeEIPos;
|
219 |
|
220 | while ((ch = stream.getByte()) !== -1) {
|
221 | if (state === 0) {
|
222 | state = ch === E ? 1 : 0;
|
223 | } else if (state === 1) {
|
224 | state = ch === I ? 2 : 0;
|
225 | } else {
|
226 | (0, _util.assert)(state === 2, "findDefaultInlineStreamEnd - invalid state.");
|
227 |
|
228 | if (ch === SPACE || ch === LF || ch === CR) {
|
229 | maybeEIPos = stream.pos;
|
230 | const followingBytes = stream.peekBytes(n);
|
231 |
|
232 | for (let i = 0, ii = followingBytes.length; i < ii; i++) {
|
233 | ch = followingBytes[i];
|
234 |
|
235 | if (ch === NUL && followingBytes[i + 1] !== NUL) {
|
236 | continue;
|
237 | }
|
238 |
|
239 | if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7f)) {
|
240 | state = 0;
|
241 | break;
|
242 | }
|
243 | }
|
244 |
|
245 | if (state !== 2) {
|
246 | continue;
|
247 | }
|
248 |
|
249 | if (lexer.knownCommands) {
|
250 | const nextObj = lexer.peekObj();
|
251 |
|
252 | if (nextObj instanceof _primitives.Cmd && !lexer.knownCommands[nextObj.cmd]) {
|
253 | state = 0;
|
254 | }
|
255 | } else {
|
256 | (0, _util.warn)("findDefaultInlineStreamEnd - `lexer.knownCommands` is undefined.");
|
257 | }
|
258 |
|
259 | if (state === 2) {
|
260 | break;
|
261 | }
|
262 | } else {
|
263 | state = 0;
|
264 | }
|
265 | }
|
266 | }
|
267 |
|
268 | if (ch === -1) {
|
269 | (0, _util.warn)("findDefaultInlineStreamEnd: " + "Reached the end of the stream without finding a valid EI marker");
|
270 |
|
271 | if (maybeEIPos) {
|
272 | (0, _util.warn)('... trying to recover by using the last "EI" occurrence.');
|
273 | stream.skip(-(stream.pos - maybeEIPos));
|
274 | }
|
275 | }
|
276 |
|
277 | let endOffset = 4;
|
278 | stream.skip(-endOffset);
|
279 | ch = stream.peekByte();
|
280 | stream.skip(endOffset);
|
281 |
|
282 | if (!(0, _core_utils.isWhiteSpace)(ch)) {
|
283 | endOffset--;
|
284 | }
|
285 |
|
286 | return stream.pos - endOffset - startPos;
|
287 | }
|
288 |
|
289 | findDCTDecodeInlineStreamEnd(stream) {
|
290 | const startPos = stream.pos;
|
291 | let foundEOI = false,
|
292 | b,
|
293 | markerLength;
|
294 |
|
295 | while ((b = stream.getByte()) !== -1) {
|
296 | if (b !== 0xff) {
|
297 | continue;
|
298 | }
|
299 |
|
300 | switch (stream.getByte()) {
|
301 | case 0x00:
|
302 | break;
|
303 |
|
304 | case 0xff:
|
305 | stream.skip(-1);
|
306 | break;
|
307 |
|
308 | case 0xd9:
|
309 | foundEOI = true;
|
310 | break;
|
311 |
|
312 | case 0xc0:
|
313 | case 0xc1:
|
314 | case 0xc2:
|
315 | case 0xc3:
|
316 | case 0xc5:
|
317 | case 0xc6:
|
318 | case 0xc7:
|
319 | case 0xc9:
|
320 | case 0xca:
|
321 | case 0xcb:
|
322 | case 0xcd:
|
323 | case 0xce:
|
324 | case 0xcf:
|
325 | case 0xc4:
|
326 | case 0xcc:
|
327 | case 0xda:
|
328 | case 0xdb:
|
329 | case 0xdc:
|
330 | case 0xdd:
|
331 | case 0xde:
|
332 | case 0xdf:
|
333 | case 0xe0:
|
334 | case 0xe1:
|
335 | case 0xe2:
|
336 | case 0xe3:
|
337 | case 0xe4:
|
338 | case 0xe5:
|
339 | case 0xe6:
|
340 | case 0xe7:
|
341 | case 0xe8:
|
342 | case 0xe9:
|
343 | case 0xea:
|
344 | case 0xeb:
|
345 | case 0xec:
|
346 | case 0xed:
|
347 | case 0xee:
|
348 | case 0xef:
|
349 | case 0xfe:
|
350 | markerLength = stream.getUint16();
|
351 |
|
352 | if (markerLength > 2) {
|
353 | stream.skip(markerLength - 2);
|
354 | } else {
|
355 | stream.skip(-2);
|
356 | }
|
357 |
|
358 | break;
|
359 | }
|
360 |
|
361 | if (foundEOI) {
|
362 | break;
|
363 | }
|
364 | }
|
365 |
|
366 | const length = stream.pos - startPos;
|
367 |
|
368 | if (b === -1) {
|
369 | (0, _util.warn)("Inline DCTDecode image stream: " + "EOI marker not found, searching for /EI/ instead.");
|
370 | stream.skip(-length);
|
371 | return this.findDefaultInlineStreamEnd(stream);
|
372 | }
|
373 |
|
374 | this.inlineStreamSkipEI(stream);
|
375 | return length;
|
376 | }
|
377 |
|
378 | findASCII85DecodeInlineStreamEnd(stream) {
|
379 | const TILDE = 0x7e,
|
380 | GT = 0x3e;
|
381 | const startPos = stream.pos;
|
382 | let ch;
|
383 |
|
384 | while ((ch = stream.getByte()) !== -1) {
|
385 | if (ch === TILDE) {
|
386 | const tildePos = stream.pos;
|
387 | ch = stream.peekByte();
|
388 |
|
389 | while ((0, _core_utils.isWhiteSpace)(ch)) {
|
390 | stream.skip();
|
391 | ch = stream.peekByte();
|
392 | }
|
393 |
|
394 | if (ch === GT) {
|
395 | stream.skip();
|
396 | break;
|
397 | }
|
398 |
|
399 | if (stream.pos > tildePos) {
|
400 | const maybeEI = stream.peekBytes(2);
|
401 |
|
402 | if (maybeEI[0] === 0x45 && maybeEI[1] === 0x49) {
|
403 | break;
|
404 | }
|
405 | }
|
406 | }
|
407 | }
|
408 |
|
409 | const length = stream.pos - startPos;
|
410 |
|
411 | if (ch === -1) {
|
412 | (0, _util.warn)("Inline ASCII85Decode image stream: " + "EOD marker not found, searching for /EI/ instead.");
|
413 | stream.skip(-length);
|
414 | return this.findDefaultInlineStreamEnd(stream);
|
415 | }
|
416 |
|
417 | this.inlineStreamSkipEI(stream);
|
418 | return length;
|
419 | }
|
420 |
|
421 | findASCIIHexDecodeInlineStreamEnd(stream) {
|
422 | const GT = 0x3e;
|
423 | const startPos = stream.pos;
|
424 | let ch;
|
425 |
|
426 | while ((ch = stream.getByte()) !== -1) {
|
427 | if (ch === GT) {
|
428 | break;
|
429 | }
|
430 | }
|
431 |
|
432 | const length = stream.pos - startPos;
|
433 |
|
434 | if (ch === -1) {
|
435 | (0, _util.warn)("Inline ASCIIHexDecode image stream: " + "EOD marker not found, searching for /EI/ instead.");
|
436 | stream.skip(-length);
|
437 | return this.findDefaultInlineStreamEnd(stream);
|
438 | }
|
439 |
|
440 | this.inlineStreamSkipEI(stream);
|
441 | return length;
|
442 | }
|
443 |
|
444 | inlineStreamSkipEI(stream) {
|
445 | const E = 0x45,
|
446 | I = 0x49;
|
447 | let state = 0,
|
448 | ch;
|
449 |
|
450 | while ((ch = stream.getByte()) !== -1) {
|
451 | if (state === 0) {
|
452 | state = ch === E ? 1 : 0;
|
453 | } else if (state === 1) {
|
454 | state = ch === I ? 2 : 0;
|
455 | } else if (state === 2) {
|
456 | break;
|
457 | }
|
458 | }
|
459 | }
|
460 |
|
461 | makeInlineImage(cipherTransform) {
|
462 | const lexer = this.lexer;
|
463 | const stream = lexer.stream;
|
464 | const dict = new _primitives.Dict(this.xref);
|
465 | let dictLength;
|
466 |
|
467 | while (!(0, _primitives.isCmd)(this.buf1, "ID") && this.buf1 !== _primitives.EOF) {
|
468 | if (!(this.buf1 instanceof _primitives.Name)) {
|
469 | throw new _util.FormatError("Dictionary key must be a name object");
|
470 | }
|
471 |
|
472 | const key = this.buf1.name;
|
473 | this.shift();
|
474 |
|
475 | if (this.buf1 === _primitives.EOF) {
|
476 | break;
|
477 | }
|
478 |
|
479 | dict.set(key, this.getObj(cipherTransform));
|
480 | }
|
481 |
|
482 | if (lexer.beginInlineImagePos !== -1) {
|
483 | dictLength = stream.pos - lexer.beginInlineImagePos;
|
484 | }
|
485 |
|
486 | const filter = dict.get("F", "Filter");
|
487 | let filterName;
|
488 |
|
489 | if (filter instanceof _primitives.Name) {
|
490 | filterName = filter.name;
|
491 | } else if (Array.isArray(filter)) {
|
492 | const filterZero = this.xref.fetchIfRef(filter[0]);
|
493 |
|
494 | if (filterZero instanceof _primitives.Name) {
|
495 | filterName = filterZero.name;
|
496 | }
|
497 | }
|
498 |
|
499 | const startPos = stream.pos;
|
500 | let length;
|
501 |
|
502 | switch (filterName) {
|
503 | case "DCT":
|
504 | case "DCTDecode":
|
505 | length = this.findDCTDecodeInlineStreamEnd(stream);
|
506 | break;
|
507 |
|
508 | case "A85":
|
509 | case "ASCII85Decode":
|
510 | length = this.findASCII85DecodeInlineStreamEnd(stream);
|
511 | break;
|
512 |
|
513 | case "AHx":
|
514 | case "ASCIIHexDecode":
|
515 | length = this.findASCIIHexDecodeInlineStreamEnd(stream);
|
516 | break;
|
517 |
|
518 | default:
|
519 | length = this.findDefaultInlineStreamEnd(stream);
|
520 | }
|
521 |
|
522 | let imageStream = stream.makeSubStream(startPos, length, dict);
|
523 | let cacheKey;
|
524 |
|
525 | if (length < MAX_LENGTH_TO_CACHE && dictLength < MAX_ADLER32_LENGTH) {
|
526 | const imageBytes = imageStream.getBytes();
|
527 | imageStream.reset();
|
528 | const initialStreamPos = stream.pos;
|
529 | stream.pos = lexer.beginInlineImagePos;
|
530 | const dictBytes = stream.getBytes(dictLength);
|
531 | stream.pos = initialStreamPos;
|
532 | cacheKey = computeAdler32(imageBytes) + "_" + computeAdler32(dictBytes);
|
533 | const cacheEntry = this.imageCache[cacheKey];
|
534 |
|
535 | if (cacheEntry !== undefined) {
|
536 | this.buf2 = _primitives.Cmd.get("EI");
|
537 | this.shift();
|
538 | cacheEntry.reset();
|
539 | return cacheEntry;
|
540 | }
|
541 | }
|
542 |
|
543 | if (cipherTransform) {
|
544 | imageStream = cipherTransform.createStream(imageStream, length);
|
545 | }
|
546 |
|
547 | imageStream = this.filter(imageStream, dict, length);
|
548 | imageStream.dict = dict;
|
549 |
|
550 | if (cacheKey !== undefined) {
|
551 | imageStream.cacheKey = `inline_${length}_${cacheKey}`;
|
552 | this.imageCache[cacheKey] = imageStream;
|
553 | }
|
554 |
|
555 | this.buf2 = _primitives.Cmd.get("EI");
|
556 | this.shift();
|
557 | return imageStream;
|
558 | }
|
559 |
|
560 | _findStreamLength(startPos, signature) {
|
561 | const {
|
562 | stream
|
563 | } = this.lexer;
|
564 | stream.pos = startPos;
|
565 | const SCAN_BLOCK_LENGTH = 2048;
|
566 | const signatureLength = signature.length;
|
567 |
|
568 | while (stream.pos < stream.end) {
|
569 | const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH);
|
570 | const scanLength = scanBytes.length - signatureLength;
|
571 |
|
572 | if (scanLength <= 0) {
|
573 | break;
|
574 | }
|
575 |
|
576 | let pos = 0;
|
577 |
|
578 | while (pos < scanLength) {
|
579 | let j = 0;
|
580 |
|
581 | while (j < signatureLength && scanBytes[pos + j] === signature[j]) {
|
582 | j++;
|
583 | }
|
584 |
|
585 | if (j >= signatureLength) {
|
586 | stream.pos += pos;
|
587 | return stream.pos - startPos;
|
588 | }
|
589 |
|
590 | pos++;
|
591 | }
|
592 |
|
593 | stream.pos += scanLength;
|
594 | }
|
595 |
|
596 | return -1;
|
597 | }
|
598 |
|
599 | makeStream(dict, cipherTransform) {
|
600 | const lexer = this.lexer;
|
601 | let stream = lexer.stream;
|
602 | lexer.skipToNextLine();
|
603 | const startPos = stream.pos - 1;
|
604 | let length = dict.get("Length");
|
605 |
|
606 | if (!Number.isInteger(length)) {
|
607 | (0, _util.info)(`Bad length "${length && length.toString()}" in stream.`);
|
608 | length = 0;
|
609 | }
|
610 |
|
611 | stream.pos = startPos + length;
|
612 | lexer.nextChar();
|
613 |
|
614 | if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, "endstream")) {
|
615 | this.shift();
|
616 | } else {
|
617 | const ENDSTREAM_SIGNATURE = new Uint8Array([0x65, 0x6e, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d]);
|
618 |
|
619 | let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE);
|
620 |
|
621 | if (actualLength < 0) {
|
622 | const MAX_TRUNCATION = 1;
|
623 |
|
624 | for (let i = 1; i <= MAX_TRUNCATION; i++) {
|
625 | const end = ENDSTREAM_SIGNATURE.length - i;
|
626 | const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end);
|
627 |
|
628 | const maybeLength = this._findStreamLength(startPos, TRUNCATED_SIGNATURE);
|
629 |
|
630 | if (maybeLength >= 0) {
|
631 | const lastByte = stream.peekBytes(end + 1)[end];
|
632 |
|
633 | if (!(0, _core_utils.isWhiteSpace)(lastByte)) {
|
634 | break;
|
635 | }
|
636 |
|
637 | (0, _util.info)(`Found "${(0, _util.bytesToString)(TRUNCATED_SIGNATURE)}" when ` + "searching for endstream command.");
|
638 | actualLength = maybeLength;
|
639 | break;
|
640 | }
|
641 | }
|
642 |
|
643 | if (actualLength < 0) {
|
644 | throw new _util.FormatError("Missing endstream command.");
|
645 | }
|
646 | }
|
647 |
|
648 | length = actualLength;
|
649 | lexer.nextChar();
|
650 | this.shift();
|
651 | this.shift();
|
652 | }
|
653 |
|
654 | this.shift();
|
655 | stream = stream.makeSubStream(startPos, length, dict);
|
656 |
|
657 | if (cipherTransform) {
|
658 | stream = cipherTransform.createStream(stream, length);
|
659 | }
|
660 |
|
661 | stream = this.filter(stream, dict, length);
|
662 | stream.dict = dict;
|
663 | return stream;
|
664 | }
|
665 |
|
666 | filter(stream, dict, length) {
|
667 | let filter = dict.get("F", "Filter");
|
668 | let params = dict.get("DP", "DecodeParms");
|
669 |
|
670 | if (filter instanceof _primitives.Name) {
|
671 | if (Array.isArray(params)) {
|
672 | (0, _util.warn)("/DecodeParms should not be an Array, when /Filter is a Name.");
|
673 | }
|
674 |
|
675 | return this.makeFilter(stream, filter.name, length, params);
|
676 | }
|
677 |
|
678 | let maybeLength = length;
|
679 |
|
680 | if (Array.isArray(filter)) {
|
681 | const filterArray = filter;
|
682 | const paramsArray = params;
|
683 |
|
684 | for (let i = 0, ii = filterArray.length; i < ii; ++i) {
|
685 | filter = this.xref.fetchIfRef(filterArray[i]);
|
686 |
|
687 | if (!(filter instanceof _primitives.Name)) {
|
688 | throw new _util.FormatError(`Bad filter name "${filter}"`);
|
689 | }
|
690 |
|
691 | params = null;
|
692 |
|
693 | if (Array.isArray(paramsArray) && i in paramsArray) {
|
694 | params = this.xref.fetchIfRef(paramsArray[i]);
|
695 | }
|
696 |
|
697 | stream = this.makeFilter(stream, filter.name, maybeLength, params);
|
698 | maybeLength = null;
|
699 | }
|
700 | }
|
701 |
|
702 | return stream;
|
703 | }
|
704 |
|
705 | makeFilter(stream, name, maybeLength, params) {
|
706 | if (maybeLength === 0) {
|
707 | (0, _util.warn)(`Empty "${name}" stream.`);
|
708 | return new _stream.NullStream();
|
709 | }
|
710 |
|
711 | const xrefStats = this.xref.stats;
|
712 |
|
713 | try {
|
714 | switch (name) {
|
715 | case "Fl":
|
716 | case "FlateDecode":
|
717 | xrefStats.addStreamType(_util.StreamType.FLATE);
|
718 |
|
719 | if (params) {
|
720 | return new _predictor_stream.PredictorStream(new _flate_stream.FlateStream(stream, maybeLength), maybeLength, params);
|
721 | }
|
722 |
|
723 | return new _flate_stream.FlateStream(stream, maybeLength);
|
724 |
|
725 | case "LZW":
|
726 | case "LZWDecode":
|
727 | xrefStats.addStreamType(_util.StreamType.LZW);
|
728 | let earlyChange = 1;
|
729 |
|
730 | if (params) {
|
731 | if (params.has("EarlyChange")) {
|
732 | earlyChange = params.get("EarlyChange");
|
733 | }
|
734 |
|
735 | return new _predictor_stream.PredictorStream(new _lzw_stream.LZWStream(stream, maybeLength, earlyChange), maybeLength, params);
|
736 | }
|
737 |
|
738 | return new _lzw_stream.LZWStream(stream, maybeLength, earlyChange);
|
739 |
|
740 | case "DCT":
|
741 | case "DCTDecode":
|
742 | xrefStats.addStreamType(_util.StreamType.DCT);
|
743 | return new _jpeg_stream.JpegStream(stream, maybeLength, params);
|
744 |
|
745 | case "JPX":
|
746 | case "JPXDecode":
|
747 | xrefStats.addStreamType(_util.StreamType.JPX);
|
748 | return new _jpx_stream.JpxStream(stream, maybeLength, params);
|
749 |
|
750 | case "A85":
|
751 | case "ASCII85Decode":
|
752 | xrefStats.addStreamType(_util.StreamType.A85);
|
753 | return new _ascii_85_stream.Ascii85Stream(stream, maybeLength);
|
754 |
|
755 | case "AHx":
|
756 | case "ASCIIHexDecode":
|
757 | xrefStats.addStreamType(_util.StreamType.AHX);
|
758 | return new _ascii_hex_stream.AsciiHexStream(stream, maybeLength);
|
759 |
|
760 | case "CCF":
|
761 | case "CCITTFaxDecode":
|
762 | xrefStats.addStreamType(_util.StreamType.CCF);
|
763 | return new _ccitt_stream.CCITTFaxStream(stream, maybeLength, params);
|
764 |
|
765 | case "RL":
|
766 | case "RunLengthDecode":
|
767 | xrefStats.addStreamType(_util.StreamType.RLX);
|
768 | return new _run_length_stream.RunLengthStream(stream, maybeLength);
|
769 |
|
770 | case "JBIG2Decode":
|
771 | xrefStats.addStreamType(_util.StreamType.JBIG);
|
772 | return new _jbig2_stream.Jbig2Stream(stream, maybeLength, params);
|
773 | }
|
774 |
|
775 | (0, _util.warn)(`Filter "${name}" is not supported.`);
|
776 | return stream;
|
777 | } catch (ex) {
|
778 | if (ex instanceof _core_utils.MissingDataException) {
|
779 | throw ex;
|
780 | }
|
781 |
|
782 | (0, _util.warn)(`Invalid stream: "${ex}"`);
|
783 | return new _stream.NullStream();
|
784 | }
|
785 | }
|
786 |
|
787 | }
|
788 |
|
789 | exports.Parser = Parser;
|
790 | const specialChars = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
791 |
|
792 | function toHexDigit(ch) {
|
793 | if (ch >= 0x30 && ch <= 0x39) {
|
794 | return ch & 0x0f;
|
795 | }
|
796 |
|
797 | if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) {
|
798 | return (ch & 0x0f) + 9;
|
799 | }
|
800 |
|
801 | return -1;
|
802 | }
|
803 |
|
804 | class Lexer {
|
805 | constructor(stream, knownCommands = null) {
|
806 | this.stream = stream;
|
807 | this.nextChar();
|
808 | this.strBuf = [];
|
809 | this.knownCommands = knownCommands;
|
810 | this._hexStringNumWarn = 0;
|
811 | this.beginInlineImagePos = -1;
|
812 | }
|
813 |
|
814 | nextChar() {
|
815 | return this.currentChar = this.stream.getByte();
|
816 | }
|
817 |
|
818 | peekChar() {
|
819 | return this.stream.peekByte();
|
820 | }
|
821 |
|
822 | getNumber() {
|
823 | let ch = this.currentChar;
|
824 | let eNotation = false;
|
825 | let divideBy = 0;
|
826 | let sign = 0;
|
827 |
|
828 | if (ch === 0x2d) {
|
829 | sign = -1;
|
830 | ch = this.nextChar();
|
831 |
|
832 | if (ch === 0x2d) {
|
833 | ch = this.nextChar();
|
834 | }
|
835 | } else if (ch === 0x2b) {
|
836 | sign = 1;
|
837 | ch = this.nextChar();
|
838 | }
|
839 |
|
840 | if (ch === 0x0a || ch === 0x0d) {
|
841 | do {
|
842 | ch = this.nextChar();
|
843 | } while (ch === 0x0a || ch === 0x0d);
|
844 | }
|
845 |
|
846 | if (ch === 0x2e) {
|
847 | divideBy = 10;
|
848 | ch = this.nextChar();
|
849 | }
|
850 |
|
851 | if (ch < 0x30 || ch > 0x39) {
|
852 | if ((0, _core_utils.isWhiteSpace)(ch) || ch === -1) {
|
853 | if (divideBy === 10 && sign === 0) {
|
854 | (0, _util.warn)("Lexer.getNumber - treating a single decimal point as zero.");
|
855 | return 0;
|
856 | }
|
857 |
|
858 | if (divideBy === 0 && sign === -1) {
|
859 | (0, _util.warn)("Lexer.getNumber - treating a single minus sign as zero.");
|
860 | return 0;
|
861 | }
|
862 | }
|
863 |
|
864 | throw new _util.FormatError(`Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`);
|
865 | }
|
866 |
|
867 | sign = sign || 1;
|
868 | let baseValue = ch - 0x30;
|
869 | let powerValue = 0;
|
870 | let powerValueSign = 1;
|
871 |
|
872 | while ((ch = this.nextChar()) >= 0) {
|
873 | if (ch >= 0x30 && ch <= 0x39) {
|
874 | const currentDigit = ch - 0x30;
|
875 |
|
876 | if (eNotation) {
|
877 | powerValue = powerValue * 10 + currentDigit;
|
878 | } else {
|
879 | if (divideBy !== 0) {
|
880 | divideBy *= 10;
|
881 | }
|
882 |
|
883 | baseValue = baseValue * 10 + currentDigit;
|
884 | }
|
885 | } else if (ch === 0x2e) {
|
886 | if (divideBy === 0) {
|
887 | divideBy = 1;
|
888 | } else {
|
889 | break;
|
890 | }
|
891 | } else if (ch === 0x2d) {
|
892 | (0, _util.warn)("Badly formatted number: minus sign in the middle");
|
893 | } else if (ch === 0x45 || ch === 0x65) {
|
894 | ch = this.peekChar();
|
895 |
|
896 | if (ch === 0x2b || ch === 0x2d) {
|
897 | powerValueSign = ch === 0x2d ? -1 : 1;
|
898 | this.nextChar();
|
899 | } else if (ch < 0x30 || ch > 0x39) {
|
900 | break;
|
901 | }
|
902 |
|
903 | eNotation = true;
|
904 | } else {
|
905 | break;
|
906 | }
|
907 | }
|
908 |
|
909 | if (divideBy !== 0) {
|
910 | baseValue /= divideBy;
|
911 | }
|
912 |
|
913 | if (eNotation) {
|
914 | baseValue *= 10 ** (powerValueSign * powerValue);
|
915 | }
|
916 |
|
917 | return sign * baseValue;
|
918 | }
|
919 |
|
920 | getString() {
|
921 | let numParen = 1;
|
922 | let done = false;
|
923 | const strBuf = this.strBuf;
|
924 | strBuf.length = 0;
|
925 | let ch = this.nextChar();
|
926 |
|
927 | while (true) {
|
928 | let charBuffered = false;
|
929 |
|
930 | switch (ch | 0) {
|
931 | case -1:
|
932 | (0, _util.warn)("Unterminated string");
|
933 | done = true;
|
934 | break;
|
935 |
|
936 | case 0x28:
|
937 | ++numParen;
|
938 | strBuf.push("(");
|
939 | break;
|
940 |
|
941 | case 0x29:
|
942 | if (--numParen === 0) {
|
943 | this.nextChar();
|
944 | done = true;
|
945 | } else {
|
946 | strBuf.push(")");
|
947 | }
|
948 |
|
949 | break;
|
950 |
|
951 | case 0x5c:
|
952 | ch = this.nextChar();
|
953 |
|
954 | switch (ch) {
|
955 | case -1:
|
956 | (0, _util.warn)("Unterminated string");
|
957 | done = true;
|
958 | break;
|
959 |
|
960 | case 0x6e:
|
961 | strBuf.push("\n");
|
962 | break;
|
963 |
|
964 | case 0x72:
|
965 | strBuf.push("\r");
|
966 | break;
|
967 |
|
968 | case 0x74:
|
969 | strBuf.push("\t");
|
970 | break;
|
971 |
|
972 | case 0x62:
|
973 | strBuf.push("\b");
|
974 | break;
|
975 |
|
976 | case 0x66:
|
977 | strBuf.push("\f");
|
978 | break;
|
979 |
|
980 | case 0x5c:
|
981 | case 0x28:
|
982 | case 0x29:
|
983 | strBuf.push(String.fromCharCode(ch));
|
984 | break;
|
985 |
|
986 | case 0x30:
|
987 | case 0x31:
|
988 | case 0x32:
|
989 | case 0x33:
|
990 | case 0x34:
|
991 | case 0x35:
|
992 | case 0x36:
|
993 | case 0x37:
|
994 | let x = ch & 0x0f;
|
995 | ch = this.nextChar();
|
996 | charBuffered = true;
|
997 |
|
998 | if (ch >= 0x30 && ch <= 0x37) {
|
999 | x = (x << 3) + (ch & 0x0f);
|
1000 | ch = this.nextChar();
|
1001 |
|
1002 | if (ch >= 0x30 && ch <= 0x37) {
|
1003 | charBuffered = false;
|
1004 | x = (x << 3) + (ch & 0x0f);
|
1005 | }
|
1006 | }
|
1007 |
|
1008 | strBuf.push(String.fromCharCode(x));
|
1009 | break;
|
1010 |
|
1011 | case 0x0d:
|
1012 | if (this.peekChar() === 0x0a) {
|
1013 | this.nextChar();
|
1014 | }
|
1015 |
|
1016 | break;
|
1017 |
|
1018 | case 0x0a:
|
1019 | break;
|
1020 |
|
1021 | default:
|
1022 | strBuf.push(String.fromCharCode(ch));
|
1023 | break;
|
1024 | }
|
1025 |
|
1026 | break;
|
1027 |
|
1028 | default:
|
1029 | strBuf.push(String.fromCharCode(ch));
|
1030 | break;
|
1031 | }
|
1032 |
|
1033 | if (done) {
|
1034 | break;
|
1035 | }
|
1036 |
|
1037 | if (!charBuffered) {
|
1038 | ch = this.nextChar();
|
1039 | }
|
1040 | }
|
1041 |
|
1042 | return strBuf.join("");
|
1043 | }
|
1044 |
|
1045 | getName() {
|
1046 | let ch, previousCh;
|
1047 | const strBuf = this.strBuf;
|
1048 | strBuf.length = 0;
|
1049 |
|
1050 | while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
|
1051 | if (ch === 0x23) {
|
1052 | ch = this.nextChar();
|
1053 |
|
1054 | if (specialChars[ch]) {
|
1055 | (0, _util.warn)("Lexer_getName: " + "NUMBER SIGN (#) should be followed by a hexadecimal number.");
|
1056 | strBuf.push("#");
|
1057 | break;
|
1058 | }
|
1059 |
|
1060 | const x = toHexDigit(ch);
|
1061 |
|
1062 | if (x !== -1) {
|
1063 | previousCh = ch;
|
1064 | ch = this.nextChar();
|
1065 | const x2 = toHexDigit(ch);
|
1066 |
|
1067 | if (x2 === -1) {
|
1068 | (0, _util.warn)(`Lexer_getName: Illegal digit (${String.fromCharCode(ch)}) ` + "in hexadecimal number.");
|
1069 | strBuf.push("#", String.fromCharCode(previousCh));
|
1070 |
|
1071 | if (specialChars[ch]) {
|
1072 | break;
|
1073 | }
|
1074 |
|
1075 | strBuf.push(String.fromCharCode(ch));
|
1076 | continue;
|
1077 | }
|
1078 |
|
1079 | strBuf.push(String.fromCharCode(x << 4 | x2));
|
1080 | } else {
|
1081 | strBuf.push("#", String.fromCharCode(ch));
|
1082 | }
|
1083 | } else {
|
1084 | strBuf.push(String.fromCharCode(ch));
|
1085 | }
|
1086 | }
|
1087 |
|
1088 | if (strBuf.length > 127) {
|
1089 | (0, _util.warn)(`Name token is longer than allowed by the spec: ${strBuf.length}`);
|
1090 | }
|
1091 |
|
1092 | return _primitives.Name.get(strBuf.join(""));
|
1093 | }
|
1094 |
|
1095 | _hexStringWarn(ch) {
|
1096 | const MAX_HEX_STRING_NUM_WARN = 5;
|
1097 |
|
1098 | if (this._hexStringNumWarn++ === MAX_HEX_STRING_NUM_WARN) {
|
1099 | (0, _util.warn)("getHexString - ignoring additional invalid characters.");
|
1100 | return;
|
1101 | }
|
1102 |
|
1103 | if (this._hexStringNumWarn > MAX_HEX_STRING_NUM_WARN) {
|
1104 | return;
|
1105 | }
|
1106 |
|
1107 | (0, _util.warn)(`getHexString - ignoring invalid character: ${ch}`);
|
1108 | }
|
1109 |
|
1110 | getHexString() {
|
1111 | const strBuf = this.strBuf;
|
1112 | strBuf.length = 0;
|
1113 | let ch = this.currentChar;
|
1114 | let isFirstHex = true;
|
1115 | let firstDigit, secondDigit;
|
1116 | this._hexStringNumWarn = 0;
|
1117 |
|
1118 | while (true) {
|
1119 | if (ch < 0) {
|
1120 | (0, _util.warn)("Unterminated hex string");
|
1121 | break;
|
1122 | } else if (ch === 0x3e) {
|
1123 | this.nextChar();
|
1124 | break;
|
1125 | } else if (specialChars[ch] === 1) {
|
1126 | ch = this.nextChar();
|
1127 | continue;
|
1128 | } else {
|
1129 | if (isFirstHex) {
|
1130 | firstDigit = toHexDigit(ch);
|
1131 |
|
1132 | if (firstDigit === -1) {
|
1133 | this._hexStringWarn(ch);
|
1134 |
|
1135 | ch = this.nextChar();
|
1136 | continue;
|
1137 | }
|
1138 | } else {
|
1139 | secondDigit = toHexDigit(ch);
|
1140 |
|
1141 | if (secondDigit === -1) {
|
1142 | this._hexStringWarn(ch);
|
1143 |
|
1144 | ch = this.nextChar();
|
1145 | continue;
|
1146 | }
|
1147 |
|
1148 | strBuf.push(String.fromCharCode(firstDigit << 4 | secondDigit));
|
1149 | }
|
1150 |
|
1151 | isFirstHex = !isFirstHex;
|
1152 | ch = this.nextChar();
|
1153 | }
|
1154 | }
|
1155 |
|
1156 | return strBuf.join("");
|
1157 | }
|
1158 |
|
1159 | getObj() {
|
1160 | let comment = false;
|
1161 | let ch = this.currentChar;
|
1162 |
|
1163 | while (true) {
|
1164 | if (ch < 0) {
|
1165 | return _primitives.EOF;
|
1166 | }
|
1167 |
|
1168 | if (comment) {
|
1169 | if (ch === 0x0a || ch === 0x0d) {
|
1170 | comment = false;
|
1171 | }
|
1172 | } else if (ch === 0x25) {
|
1173 | comment = true;
|
1174 | } else if (specialChars[ch] !== 1) {
|
1175 | break;
|
1176 | }
|
1177 |
|
1178 | ch = this.nextChar();
|
1179 | }
|
1180 |
|
1181 | switch (ch | 0) {
|
1182 | case 0x30:
|
1183 | case 0x31:
|
1184 | case 0x32:
|
1185 | case 0x33:
|
1186 | case 0x34:
|
1187 | case 0x35:
|
1188 | case 0x36:
|
1189 | case 0x37:
|
1190 | case 0x38:
|
1191 | case 0x39:
|
1192 | case 0x2b:
|
1193 | case 0x2d:
|
1194 | case 0x2e:
|
1195 | return this.getNumber();
|
1196 |
|
1197 | case 0x28:
|
1198 | return this.getString();
|
1199 |
|
1200 | case 0x2f:
|
1201 | return this.getName();
|
1202 |
|
1203 | case 0x5b:
|
1204 | this.nextChar();
|
1205 | return _primitives.Cmd.get("[");
|
1206 |
|
1207 | case 0x5d:
|
1208 | this.nextChar();
|
1209 | return _primitives.Cmd.get("]");
|
1210 |
|
1211 | case 0x3c:
|
1212 | ch = this.nextChar();
|
1213 |
|
1214 | if (ch === 0x3c) {
|
1215 | this.nextChar();
|
1216 | return _primitives.Cmd.get("<<");
|
1217 | }
|
1218 |
|
1219 | return this.getHexString();
|
1220 |
|
1221 | case 0x3e:
|
1222 | ch = this.nextChar();
|
1223 |
|
1224 | if (ch === 0x3e) {
|
1225 | this.nextChar();
|
1226 | return _primitives.Cmd.get(">>");
|
1227 | }
|
1228 |
|
1229 | return _primitives.Cmd.get(">");
|
1230 |
|
1231 | case 0x7b:
|
1232 | this.nextChar();
|
1233 | return _primitives.Cmd.get("{");
|
1234 |
|
1235 | case 0x7d:
|
1236 | this.nextChar();
|
1237 | return _primitives.Cmd.get("}");
|
1238 |
|
1239 | case 0x29:
|
1240 | this.nextChar();
|
1241 | throw new _util.FormatError(`Illegal character: ${ch}`);
|
1242 | }
|
1243 |
|
1244 | let str = String.fromCharCode(ch);
|
1245 |
|
1246 | if (ch < 0x20 || ch > 0x7f) {
|
1247 | const nextCh = this.peekChar();
|
1248 |
|
1249 | if (nextCh >= 0x20 && nextCh <= 0x7f) {
|
1250 | this.nextChar();
|
1251 | return _primitives.Cmd.get(str);
|
1252 | }
|
1253 | }
|
1254 |
|
1255 | const knownCommands = this.knownCommands;
|
1256 | let knownCommandFound = knownCommands && knownCommands[str] !== undefined;
|
1257 |
|
1258 | while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
|
1259 | const possibleCommand = str + String.fromCharCode(ch);
|
1260 |
|
1261 | if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
|
1262 | break;
|
1263 | }
|
1264 |
|
1265 | if (str.length === 128) {
|
1266 | throw new _util.FormatError(`Command token too long: ${str.length}`);
|
1267 | }
|
1268 |
|
1269 | str = possibleCommand;
|
1270 | knownCommandFound = knownCommands && knownCommands[str] !== undefined;
|
1271 | }
|
1272 |
|
1273 | if (str === "true") {
|
1274 | return true;
|
1275 | }
|
1276 |
|
1277 | if (str === "false") {
|
1278 | return false;
|
1279 | }
|
1280 |
|
1281 | if (str === "null") {
|
1282 | return null;
|
1283 | }
|
1284 |
|
1285 | if (str === "BI") {
|
1286 | this.beginInlineImagePos = this.stream.pos;
|
1287 | }
|
1288 |
|
1289 | return _primitives.Cmd.get(str);
|
1290 | }
|
1291 |
|
1292 | peekObj() {
|
1293 | const streamPos = this.stream.pos,
|
1294 | currentChar = this.currentChar,
|
1295 | beginInlineImagePos = this.beginInlineImagePos;
|
1296 | let nextObj;
|
1297 |
|
1298 | try {
|
1299 | nextObj = this.getObj();
|
1300 | } catch (ex) {
|
1301 | if (ex instanceof _core_utils.MissingDataException) {
|
1302 | throw ex;
|
1303 | }
|
1304 |
|
1305 | (0, _util.warn)(`peekObj: ${ex}`);
|
1306 | }
|
1307 |
|
1308 | this.stream.pos = streamPos;
|
1309 | this.currentChar = currentChar;
|
1310 | this.beginInlineImagePos = beginInlineImagePos;
|
1311 | return nextObj;
|
1312 | }
|
1313 |
|
1314 | skipToNextLine() {
|
1315 | let ch = this.currentChar;
|
1316 |
|
1317 | while (ch >= 0) {
|
1318 | if (ch === 0x0d) {
|
1319 | ch = this.nextChar();
|
1320 |
|
1321 | if (ch === 0x0a) {
|
1322 | this.nextChar();
|
1323 | }
|
1324 |
|
1325 | break;
|
1326 | } else if (ch === 0x0a) {
|
1327 | this.nextChar();
|
1328 | break;
|
1329 | }
|
1330 |
|
1331 | ch = this.nextChar();
|
1332 | }
|
1333 | }
|
1334 |
|
1335 | }
|
1336 |
|
1337 | exports.Lexer = Lexer;
|
1338 |
|
1339 | class Linearization {
|
1340 | static create(stream) {
|
1341 | function getInt(linDict, name, allowZeroValue = false) {
|
1342 | const obj = linDict.get(name);
|
1343 |
|
1344 | if (Number.isInteger(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
|
1345 | return obj;
|
1346 | }
|
1347 |
|
1348 | throw new Error(`The "${name}" parameter in the linearization ` + "dictionary is invalid.");
|
1349 | }
|
1350 |
|
1351 | function getHints(linDict) {
|
1352 | const hints = linDict.get("H");
|
1353 | let hintsLength;
|
1354 |
|
1355 | if (Array.isArray(hints) && ((hintsLength = hints.length) === 2 || hintsLength === 4)) {
|
1356 | for (let index = 0; index < hintsLength; index++) {
|
1357 | const hint = hints[index];
|
1358 |
|
1359 | if (!(Number.isInteger(hint) && hint > 0)) {
|
1360 | throw new Error(`Hint (${index}) in the linearization dictionary is invalid.`);
|
1361 | }
|
1362 | }
|
1363 |
|
1364 | return hints;
|
1365 | }
|
1366 |
|
1367 | throw new Error("Hint array in the linearization dictionary is invalid.");
|
1368 | }
|
1369 |
|
1370 | const parser = new Parser({
|
1371 | lexer: new Lexer(stream),
|
1372 | xref: null
|
1373 | });
|
1374 | const obj1 = parser.getObj();
|
1375 | const obj2 = parser.getObj();
|
1376 | const obj3 = parser.getObj();
|
1377 | const linDict = parser.getObj();
|
1378 | let obj, length;
|
1379 |
|
1380 | if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && (0, _primitives.isCmd)(obj3, "obj") && linDict instanceof _primitives.Dict && typeof (obj = linDict.get("Linearized")) === "number" && obj > 0)) {
|
1381 | return null;
|
1382 | } else if ((length = getInt(linDict, "L")) !== stream.length) {
|
1383 | throw new Error('The "L" parameter in the linearization dictionary ' + "does not equal the stream length.");
|
1384 | }
|
1385 |
|
1386 | return {
|
1387 | length,
|
1388 | hints: getHints(linDict),
|
1389 | objectNumberFirst: getInt(linDict, "O"),
|
1390 | endFirst: getInt(linDict, "E"),
|
1391 | numPages: getInt(linDict, "N"),
|
1392 | mainXRefEntriesOffset: getInt(linDict, "T"),
|
1393 | pageFirst: linDict.has("P") ? getInt(linDict, "P", true) : 0
|
1394 | };
|
1395 | }
|
1396 |
|
1397 | }
|
1398 |
|
1399 | exports.Linearization = Linearization; |
\ | No newline at end of file |