@vaadin-component-factory/vcf-pdf-viewer 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +1 -1
  2. package/package.json +42 -26
  3. package/{src/display → pdfjs/dist}/display_utils.js +344 -139
  4. package/{src/display → pdfjs/dist}/fetch_stream.js +115 -97
  5. package/pdfjs/dist/l10n_utils.js +140 -0
  6. package/{src/shared → pdfjs/dist}/message_handler.js +243 -259
  7. package/{src/display → pdfjs/dist}/network.js +149 -87
  8. package/{src/display/content_disposition.js → pdfjs/dist/network_utils.js} +167 -55
  9. package/{src/display → pdfjs/dist}/node_stream.js +133 -98
  10. package/pdfjs/dist/pdf.js +12778 -0
  11. package/pdfjs/dist/pdf_link_service.js +638 -0
  12. package/pdfjs/dist/pdf_rendering_queue.js +199 -0
  13. package/pdfjs/dist/pdf_thumbnail_viewer.js +819 -0
  14. package/pdfjs/dist/pdf_viewer.js +3598 -0
  15. package/pdfjs/dist/ui_utils.js +1033 -0
  16. package/{src/shared → pdfjs/dist}/util.js +301 -287
  17. package/pdfjs/dist/worker.js +62813 -0
  18. package/src/vcf-pdf-viewer.js +98 -46
  19. package/theme/lumo/vcf-pdf-viewer-styles.js +4 -4
  20. package/theme/material/vcf-pdf-viewer-styles.js +4 -4
  21. package/theme/material/vcf-pdf-viewer.js +2 -2
  22. package/src/core/.eslintrc +0 -13
  23. package/src/core/annotation.js +0 -2948
  24. package/src/core/arithmetic_decoder.js +0 -182
  25. package/src/core/ascii_85_stream.js +0 -98
  26. package/src/core/ascii_hex_stream.js +0 -79
  27. package/src/core/base_stream.js +0 -110
  28. package/src/core/bidi.js +0 -438
  29. package/src/core/calibri_factors.js +0 -308
  30. package/src/core/catalog.js +0 -1459
  31. package/src/core/ccitt.js +0 -1062
  32. package/src/core/ccitt_stream.js +0 -60
  33. package/src/core/cff_font.js +0 -116
  34. package/src/core/cff_parser.js +0 -1949
  35. package/src/core/charsets.js +0 -119
  36. package/src/core/chunked_stream.js +0 -557
  37. package/src/core/cmap.js +0 -1039
  38. package/src/core/colorspace.js +0 -1533
  39. package/src/core/core_utils.js +0 -464
  40. package/src/core/crypto.js +0 -1900
  41. package/src/core/decode_stream.js +0 -170
  42. package/src/core/decrypt_stream.js +0 -59
  43. package/src/core/default_appearance.js +0 -99
  44. package/src/core/document.js +0 -1456
  45. package/src/core/encodings.js +0 -301
  46. package/src/core/evaluator.js +0 -4601
  47. package/src/core/file_spec.js +0 -108
  48. package/src/core/flate_stream.js +0 -402
  49. package/src/core/font_renderer.js +0 -882
  50. package/src/core/fonts.js +0 -3260
  51. package/src/core/fonts_utils.js +0 -221
  52. package/src/core/function.js +0 -1257
  53. package/src/core/glyf.js +0 -706
  54. package/src/core/glyphlist.js +0 -4558
  55. package/src/core/helvetica_factors.js +0 -353
  56. package/src/core/image.js +0 -802
  57. package/src/core/image_utils.js +0 -291
  58. package/src/core/jbig2.js +0 -2572
  59. package/src/core/jbig2_stream.js +0 -73
  60. package/src/core/jpeg_stream.js +0 -105
  61. package/src/core/jpg.js +0 -1416
  62. package/src/core/jpx.js +0 -2343
  63. package/src/core/jpx_stream.js +0 -87
  64. package/src/core/liberationsans_widths.js +0 -221
  65. package/src/core/lzw_stream.js +0 -150
  66. package/src/core/metadata_parser.js +0 -146
  67. package/src/core/metrics.js +0 -2970
  68. package/src/core/murmurhash3.js +0 -139
  69. package/src/core/myriadpro_factors.js +0 -290
  70. package/src/core/name_number_tree.js +0 -153
  71. package/src/core/object_loader.js +0 -149
  72. package/src/core/opentype_file_builder.js +0 -154
  73. package/src/core/operator_list.js +0 -734
  74. package/src/core/parser.js +0 -1416
  75. package/src/core/pattern.js +0 -985
  76. package/src/core/pdf_manager.js +0 -217
  77. package/src/core/predictor_stream.js +0 -238
  78. package/src/core/primitives.js +0 -402
  79. package/src/core/ps_parser.js +0 -272
  80. package/src/core/run_length_stream.js +0 -61
  81. package/src/core/segoeui_factors.js +0 -308
  82. package/src/core/standard_fonts.js +0 -817
  83. package/src/core/stream.js +0 -103
  84. package/src/core/struct_tree.js +0 -335
  85. package/src/core/to_unicode_map.js +0 -103
  86. package/src/core/type1_font.js +0 -421
  87. package/src/core/type1_parser.js +0 -776
  88. package/src/core/unicode.js +0 -1649
  89. package/src/core/worker.js +0 -848
  90. package/src/core/worker_stream.js +0 -135
  91. package/src/core/writer.js +0 -278
  92. package/src/core/xfa/bind.js +0 -652
  93. package/src/core/xfa/builder.js +0 -207
  94. package/src/core/xfa/config.js +0 -1926
  95. package/src/core/xfa/connection_set.js +0 -202
  96. package/src/core/xfa/data.js +0 -82
  97. package/src/core/xfa/datasets.js +0 -76
  98. package/src/core/xfa/factory.js +0 -111
  99. package/src/core/xfa/fonts.js +0 -181
  100. package/src/core/xfa/formcalc_lexer.js +0 -385
  101. package/src/core/xfa/formcalc_parser.js +0 -1340
  102. package/src/core/xfa/html_utils.js +0 -639
  103. package/src/core/xfa/layout.js +0 -383
  104. package/src/core/xfa/locale_set.js +0 -345
  105. package/src/core/xfa/namespaces.js +0 -81
  106. package/src/core/xfa/parser.js +0 -184
  107. package/src/core/xfa/setup.js +0 -38
  108. package/src/core/xfa/signature.js +0 -40
  109. package/src/core/xfa/som.js +0 -338
  110. package/src/core/xfa/stylesheet.js +0 -40
  111. package/src/core/xfa/template.js +0 -6260
  112. package/src/core/xfa/text.js +0 -290
  113. package/src/core/xfa/unknown.js +0 -29
  114. package/src/core/xfa/utils.js +0 -217
  115. package/src/core/xfa/xdp.js +0 -59
  116. package/src/core/xfa/xfa_object.js +0 -1130
  117. package/src/core/xfa/xhtml.js +0 -543
  118. package/src/core/xfa_fonts.js +0 -208
  119. package/src/core/xml_parser.js +0 -507
  120. package/src/core/xref.js +0 -899
  121. package/src/display/annotation_layer.js +0 -2107
  122. package/src/display/annotation_storage.js +0 -113
  123. package/src/display/api.js +0 -3292
  124. package/src/display/base_factory.js +0 -180
  125. package/src/display/canvas.js +0 -2828
  126. package/src/display/font_loader.js +0 -484
  127. package/src/display/metadata.js +0 -41
  128. package/src/display/network_utils.js +0 -100
  129. package/src/display/node_utils.js +0 -83
  130. package/src/display/optional_content_config.js +0 -189
  131. package/src/display/pattern_helper.js +0 -659
  132. package/src/display/svg.js +0 -1709
  133. package/src/display/text_layer.js +0 -847
  134. package/src/display/transport_stream.js +0 -303
  135. package/src/display/worker_options.js +0 -40
  136. package/src/display/xfa_layer.js +0 -204
  137. package/src/doc_helper.js +0 -25
  138. package/src/images/logo.svg +0 -41
  139. package/src/interfaces.js +0 -169
  140. package/src/license_header.js +0 -14
  141. package/src/license_header_libre.js +0 -21
  142. package/src/pdf.image_decoders.js +0 -46
  143. package/src/pdf.js +0 -146
  144. package/src/pdf.sandbox.external.js +0 -181
  145. package/src/pdf.sandbox.js +0 -151
  146. package/src/pdf.scripting.js +0 -25
  147. package/src/pdf.worker.entry.js +0 -19
  148. package/src/pdf.worker.js +0 -23
  149. package/src/scripting_api/aform.js +0 -608
  150. package/src/scripting_api/app.js +0 -621
  151. package/src/scripting_api/color.js +0 -129
  152. package/src/scripting_api/common.js +0 -58
  153. package/src/scripting_api/console.js +0 -38
  154. package/src/scripting_api/constants.js +0 -208
  155. package/src/scripting_api/doc.js +0 -1195
  156. package/src/scripting_api/error.js +0 -23
  157. package/src/scripting_api/event.js +0 -232
  158. package/src/scripting_api/field.js +0 -620
  159. package/src/scripting_api/fullscreen.js +0 -145
  160. package/src/scripting_api/initialization.js +0 -223
  161. package/src/scripting_api/pdf_object.js +0 -24
  162. package/src/scripting_api/print_params.js +0 -146
  163. package/src/scripting_api/proxy.js +0 -139
  164. package/src/scripting_api/thermometer.js +0 -69
  165. package/src/scripting_api/util.js +0 -581
  166. package/src/shared/.eslintrc +0 -13
  167. package/src/shared/cffStandardStrings.js +0 -311
  168. package/src/shared/compatibility.js +0 -114
  169. package/src/shared/fonts_utils.js +0 -429
  170. package/src/shared/is_node.js +0 -27
  171. package/src/shared/scripting_utils.js +0 -85
  172. package/src/worker_loader.js +0 -32
@@ -1,1416 +0,0 @@
1
- /* Copyright 2012 Mozilla Foundation
2
- *
3
- * Licensed under the Apache License, Version 2.0 (the "License");
4
- * you may not use this file except in compliance with the License.
5
- * You may obtain a copy of the License at
6
- *
7
- * http://www.apache.org/licenses/LICENSE-2.0
8
- *
9
- * Unless required by applicable law or agreed to in writing, software
10
- * distributed under the License is distributed on an "AS IS" BASIS,
11
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- * See the License for the specific language governing permissions and
13
- * limitations under the License.
14
- */
15
-
16
- import {
17
- assert,
18
- bytesToString,
19
- FormatError,
20
- info,
21
- isNum,
22
- StreamType,
23
- warn,
24
- } from "../shared/util.js";
25
- import {
26
- Cmd,
27
- Dict,
28
- EOF,
29
- isCmd,
30
- isDict,
31
- isEOF,
32
- isName,
33
- Name,
34
- Ref,
35
- } from "./primitives.js";
36
- import {
37
- isWhiteSpace,
38
- MissingDataException,
39
- ParserEOFException,
40
- } from "./core_utils.js";
41
- import { Ascii85Stream } from "./ascii_85_stream.js";
42
- import { AsciiHexStream } from "./ascii_hex_stream.js";
43
- import { CCITTFaxStream } from "./ccitt_stream.js";
44
- import { FlateStream } from "./flate_stream.js";
45
- import { Jbig2Stream } from "./jbig2_stream.js";
46
- import { JpegStream } from "./jpeg_stream.js";
47
- import { JpxStream } from "./jpx_stream.js";
48
- import { LZWStream } from "./lzw_stream.js";
49
- import { NullStream } from "./stream.js";
50
- import { PredictorStream } from "./predictor_stream.js";
51
- import { RunLengthStream } from "./run_length_stream.js";
52
-
53
- const MAX_LENGTH_TO_CACHE = 1000;
54
- const MAX_ADLER32_LENGTH = 5552;
55
-
56
- function computeAdler32(bytes) {
57
- const bytesLength = bytes.length;
58
- if (
59
- typeof PDFJSDev === "undefined" ||
60
- PDFJSDev.test("!PRODUCTION || TESTING")
61
- ) {
62
- assert(
63
- bytesLength < MAX_ADLER32_LENGTH,
64
- 'computeAdler32: Unsupported "bytes" length.'
65
- );
66
- }
67
- let a = 1,
68
- b = 0;
69
- for (let i = 0; i < bytesLength; ++i) {
70
- // No modulo required in the loop if `bytesLength < 5552`.
71
- a += bytes[i] & 0xff;
72
- b += a;
73
- }
74
- return (b % 65521 << 16) | a % 65521;
75
- }
76
-
77
- class Parser {
78
- constructor({ lexer, xref, allowStreams = false, recoveryMode = false }) {
79
- this.lexer = lexer;
80
- this.xref = xref;
81
- this.allowStreams = allowStreams;
82
- this.recoveryMode = recoveryMode;
83
-
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 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 MissingDataException) {
109
- throw e;
110
- }
111
- // Upon failure, the caller should reset this.lexer.pos to a known good
112
- // state and call this.shift() twice to reset the buffers.
113
- return false;
114
- }
115
- }
116
-
117
- getObj(cipherTransform = null) {
118
- const buf1 = this.buf1;
119
- this.shift();
120
-
121
- if (buf1 instanceof Cmd) {
122
- switch (buf1.cmd) {
123
- case "BI": // inline image
124
- return this.makeInlineImage(cipherTransform);
125
- case "[": // array
126
- const array = [];
127
- while (!isCmd(this.buf1, "]") && !isEOF(this.buf1)) {
128
- array.push(this.getObj(cipherTransform));
129
- }
130
- if (isEOF(this.buf1)) {
131
- if (this.recoveryMode) {
132
- return array;
133
- }
134
- throw new ParserEOFException("End of file inside array.");
135
- }
136
- this.shift();
137
- return array;
138
- case "<<": // dictionary or stream
139
- const dict = new Dict(this.xref);
140
- while (!isCmd(this.buf1, ">>") && !isEOF(this.buf1)) {
141
- if (!isName(this.buf1)) {
142
- info("Malformed dictionary: key must be a name object");
143
- this.shift();
144
- continue;
145
- }
146
-
147
- const key = this.buf1.name;
148
- this.shift();
149
- if (isEOF(this.buf1)) {
150
- break;
151
- }
152
- dict.set(key, this.getObj(cipherTransform));
153
- }
154
- if (isEOF(this.buf1)) {
155
- if (this.recoveryMode) {
156
- return dict;
157
- }
158
- throw new ParserEOFException("End of file inside dictionary.");
159
- }
160
-
161
- // Stream objects are not allowed inside content streams or
162
- // object streams.
163
- if (isCmd(this.buf2, "stream")) {
164
- return this.allowStreams
165
- ? this.makeStream(dict, cipherTransform)
166
- : dict;
167
- }
168
- this.shift();
169
- return dict;
170
- default:
171
- // simple object
172
- return buf1;
173
- }
174
- }
175
-
176
- if (Number.isInteger(buf1)) {
177
- // indirect reference or integer
178
- if (Number.isInteger(this.buf1) && isCmd(this.buf2, "R")) {
179
- const ref = Ref.get(buf1, this.buf1);
180
- this.shift();
181
- this.shift();
182
- return ref;
183
- }
184
- return buf1;
185
- }
186
-
187
- if (typeof buf1 === "string") {
188
- if (cipherTransform) {
189
- return cipherTransform.decryptString(buf1);
190
- }
191
- return buf1;
192
- }
193
-
194
- // simple object
195
- return buf1;
196
- }
197
-
198
- /**
199
- * Find the end of the stream by searching for the /EI\s/.
200
- * @returns {number} The inline stream length.
201
- */
202
- findDefaultInlineStreamEnd(stream) {
203
- const E = 0x45,
204
- I = 0x49,
205
- SPACE = 0x20,
206
- LF = 0xa,
207
- CR = 0xd,
208
- NUL = 0x0;
209
- const lexer = this.lexer,
210
- startPos = stream.pos,
211
- n = 10;
212
- let state = 0,
213
- ch,
214
- maybeEIPos;
215
- while ((ch = stream.getByte()) !== -1) {
216
- if (state === 0) {
217
- state = ch === E ? 1 : 0;
218
- } else if (state === 1) {
219
- state = ch === I ? 2 : 0;
220
- } else {
221
- assert(state === 2, "findDefaultInlineStreamEnd - invalid state.");
222
- if (ch === SPACE || ch === LF || ch === CR) {
223
- maybeEIPos = stream.pos;
224
- // Let's check that the next `n` bytes are ASCII... just to be sure.
225
- const followingBytes = stream.peekBytes(n);
226
- for (let i = 0, ii = followingBytes.length; i < ii; i++) {
227
- ch = followingBytes[i];
228
- if (ch === NUL && followingBytes[i + 1] !== NUL) {
229
- // NUL bytes are not supposed to occur *outside* of inline
230
- // images, but some PDF generators violate that assumption,
231
- // thus breaking the EI detection heuristics used below.
232
- //
233
- // However, we can't unconditionally treat NUL bytes as "ASCII",
234
- // since that *could* result in inline images being truncated.
235
- //
236
- // To attempt to address this, we'll still treat any *sequence*
237
- // of NUL bytes as non-ASCII, but for a *single* NUL byte we'll
238
- // continue checking the `followingBytes` (fixes issue8823.pdf).
239
- continue;
240
- }
241
- if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7f)) {
242
- // Not a LF, CR, SPACE or any visible ASCII character, i.e.
243
- // it's binary stuff. Resetting the state.
244
- state = 0;
245
- break;
246
- }
247
- }
248
-
249
- if (state !== 2) {
250
- continue;
251
- }
252
- // Check that the "EI" sequence isn't part of the image data, since
253
- // that would cause the image to be truncated (fixes issue11124.pdf).
254
- if (lexer.knownCommands) {
255
- const nextObj = lexer.peekObj();
256
- if (nextObj instanceof Cmd && !lexer.knownCommands[nextObj.cmd]) {
257
- // Not a valid command, i.e. the inline image data *itself*
258
- // contains an "EI" sequence. Resetting the state.
259
- state = 0;
260
- }
261
- } else {
262
- warn(
263
- "findDefaultInlineStreamEnd - `lexer.knownCommands` is undefined."
264
- );
265
- }
266
-
267
- if (state === 2) {
268
- break; // Finished!
269
- }
270
- } else {
271
- state = 0;
272
- }
273
- }
274
- }
275
-
276
- if (ch === -1) {
277
- warn(
278
- "findDefaultInlineStreamEnd: " +
279
- "Reached the end of the stream without finding a valid EI marker"
280
- );
281
- if (maybeEIPos) {
282
- warn('... trying to recover by using the last "EI" occurrence.');
283
- stream.skip(-(stream.pos - maybeEIPos)); // Reset the stream position.
284
- }
285
- }
286
-
287
- let endOffset = 4;
288
- stream.skip(-endOffset); // Set the stream position to just before "EI".
289
- ch = stream.peekByte();
290
- stream.skip(endOffset); // ... and remember to reset the stream position.
291
-
292
- // Ensure that we don't accidentally truncate the inline image, when the
293
- // data is immediately followed by the "EI" marker (fixes issue10388.pdf).
294
- if (!isWhiteSpace(ch)) {
295
- endOffset--;
296
- }
297
- return stream.pos - endOffset - startPos;
298
- }
299
-
300
- /**
301
- * Find the EOI (end-of-image) marker 0xFFD9 of the stream.
302
- * @returns {number} The inline stream length.
303
- */
304
- findDCTDecodeInlineStreamEnd(stream) {
305
- const startPos = stream.pos;
306
- let foundEOI = false,
307
- b,
308
- markerLength;
309
- while ((b = stream.getByte()) !== -1) {
310
- if (b !== 0xff) {
311
- // Not a valid marker.
312
- continue;
313
- }
314
- switch (stream.getByte()) {
315
- case 0x00: // Byte stuffing.
316
- // 0xFF00 appears to be a very common byte sequence in JPEG images.
317
- break;
318
-
319
- case 0xff: // Fill byte.
320
- // Avoid skipping a valid marker, resetting the stream position.
321
- stream.skip(-1);
322
- break;
323
-
324
- case 0xd9: // EOI
325
- foundEOI = true;
326
- break;
327
-
328
- case 0xc0: // SOF0
329
- case 0xc1: // SOF1
330
- case 0xc2: // SOF2
331
- case 0xc3: // SOF3
332
- /* falls through */
333
- case 0xc5: // SOF5
334
- case 0xc6: // SOF6
335
- case 0xc7: // SOF7
336
- /* falls through */
337
- case 0xc9: // SOF9
338
- case 0xca: // SOF10
339
- case 0xcb: // SOF11
340
- /* falls through */
341
- case 0xcd: // SOF13
342
- case 0xce: // SOF14
343
- case 0xcf: // SOF15
344
- /* falls through */
345
- case 0xc4: // DHT
346
- case 0xcc: // DAC
347
- /* falls through */
348
- case 0xda: // SOS
349
- case 0xdb: // DQT
350
- case 0xdc: // DNL
351
- case 0xdd: // DRI
352
- case 0xde: // DHP
353
- case 0xdf: // EXP
354
- /* falls through */
355
- case 0xe0: // APP0
356
- case 0xe1: // APP1
357
- case 0xe2: // APP2
358
- case 0xe3: // APP3
359
- case 0xe4: // APP4
360
- case 0xe5: // APP5
361
- case 0xe6: // APP6
362
- case 0xe7: // APP7
363
- case 0xe8: // APP8
364
- case 0xe9: // APP9
365
- case 0xea: // APP10
366
- case 0xeb: // APP11
367
- case 0xec: // APP12
368
- case 0xed: // APP13
369
- case 0xee: // APP14
370
- case 0xef: // APP15
371
- /* falls through */
372
- case 0xfe: // COM
373
- // The marker should be followed by the length of the segment.
374
- markerLength = stream.getUint16();
375
- if (markerLength > 2) {
376
- // |markerLength| contains the byte length of the marker segment,
377
- // including its own length (2 bytes) and excluding the marker.
378
- stream.skip(markerLength - 2); // Jump to the next marker.
379
- } else {
380
- // The marker length is invalid, resetting the stream position.
381
- stream.skip(-2);
382
- }
383
- break;
384
- }
385
- if (foundEOI) {
386
- break;
387
- }
388
- }
389
- const length = stream.pos - startPos;
390
- if (b === -1) {
391
- warn(
392
- "Inline DCTDecode image stream: " +
393
- "EOI marker not found, searching for /EI/ instead."
394
- );
395
- stream.skip(-length); // Reset the stream position.
396
- return this.findDefaultInlineStreamEnd(stream);
397
- }
398
- this.inlineStreamSkipEI(stream);
399
- return length;
400
- }
401
-
402
- /**
403
- * Find the EOD (end-of-data) marker '~>' (i.e. TILDE + GT) of the stream.
404
- * @returns {number} The inline stream length.
405
- */
406
- findASCII85DecodeInlineStreamEnd(stream) {
407
- const TILDE = 0x7e,
408
- GT = 0x3e;
409
- const startPos = stream.pos;
410
- let ch;
411
- while ((ch = stream.getByte()) !== -1) {
412
- if (ch === TILDE) {
413
- const tildePos = stream.pos;
414
-
415
- ch = stream.peekByte();
416
- // Handle corrupt PDF documents which contains whitespace "inside" of
417
- // the EOD marker (fixes issue10614.pdf).
418
- while (isWhiteSpace(ch)) {
419
- stream.skip();
420
- ch = stream.peekByte();
421
- }
422
- if (ch === GT) {
423
- stream.skip();
424
- break;
425
- }
426
- // Handle corrupt PDF documents which contains truncated EOD markers,
427
- // where the '>' character is missing (fixes issue11385.pdf).
428
- if (stream.pos > tildePos) {
429
- const maybeEI = stream.peekBytes(2);
430
- if (maybeEI[0] === /* E = */ 0x45 && maybeEI[1] === /* I = */ 0x49) {
431
- break;
432
- }
433
- }
434
- }
435
- }
436
- const length = stream.pos - startPos;
437
- if (ch === -1) {
438
- warn(
439
- "Inline ASCII85Decode image stream: " +
440
- "EOD marker not found, searching for /EI/ instead."
441
- );
442
- stream.skip(-length); // Reset the stream position.
443
- return this.findDefaultInlineStreamEnd(stream);
444
- }
445
- this.inlineStreamSkipEI(stream);
446
- return length;
447
- }
448
-
449
- /**
450
- * Find the EOD (end-of-data) marker '>' (i.e. GT) of the stream.
451
- * @returns {number} The inline stream length.
452
- */
453
- findASCIIHexDecodeInlineStreamEnd(stream) {
454
- const GT = 0x3e;
455
- const startPos = stream.pos;
456
- let ch;
457
- while ((ch = stream.getByte()) !== -1) {
458
- if (ch === GT) {
459
- break;
460
- }
461
- }
462
- const length = stream.pos - startPos;
463
- if (ch === -1) {
464
- warn(
465
- "Inline ASCIIHexDecode image stream: " +
466
- "EOD marker not found, searching for /EI/ instead."
467
- );
468
- stream.skip(-length); // Reset the stream position.
469
- return this.findDefaultInlineStreamEnd(stream);
470
- }
471
- this.inlineStreamSkipEI(stream);
472
- return length;
473
- }
474
-
475
- /**
476
- * Skip over the /EI/ for streams where we search for an EOD marker.
477
- */
478
- inlineStreamSkipEI(stream) {
479
- const E = 0x45,
480
- I = 0x49;
481
- let state = 0,
482
- ch;
483
- while ((ch = stream.getByte()) !== -1) {
484
- if (state === 0) {
485
- state = ch === E ? 1 : 0;
486
- } else if (state === 1) {
487
- state = ch === I ? 2 : 0;
488
- } else if (state === 2) {
489
- break;
490
- }
491
- }
492
- }
493
-
494
- makeInlineImage(cipherTransform) {
495
- const lexer = this.lexer;
496
- const stream = lexer.stream;
497
-
498
- // Parse dictionary.
499
- const dict = new Dict(this.xref);
500
- let dictLength;
501
- while (!isCmd(this.buf1, "ID") && !isEOF(this.buf1)) {
502
- if (!isName(this.buf1)) {
503
- throw new FormatError("Dictionary key must be a name object");
504
- }
505
- const key = this.buf1.name;
506
- this.shift();
507
- if (isEOF(this.buf1)) {
508
- break;
509
- }
510
- dict.set(key, this.getObj(cipherTransform));
511
- }
512
- if (lexer.beginInlineImagePos !== -1) {
513
- dictLength = stream.pos - lexer.beginInlineImagePos;
514
- }
515
-
516
- // Extract the name of the first (i.e. the current) image filter.
517
- const filter = dict.get("Filter", "F");
518
- let filterName;
519
- if (isName(filter)) {
520
- filterName = filter.name;
521
- } else if (Array.isArray(filter)) {
522
- const filterZero = this.xref.fetchIfRef(filter[0]);
523
- if (isName(filterZero)) {
524
- filterName = filterZero.name;
525
- }
526
- }
527
-
528
- // Parse image stream.
529
- const startPos = stream.pos;
530
- let length;
531
- if (filterName === "DCTDecode" || filterName === "DCT") {
532
- length = this.findDCTDecodeInlineStreamEnd(stream);
533
- } else if (filterName === "ASCII85Decode" || filterName === "A85") {
534
- length = this.findASCII85DecodeInlineStreamEnd(stream);
535
- } else if (filterName === "ASCIIHexDecode" || filterName === "AHx") {
536
- length = this.findASCIIHexDecodeInlineStreamEnd(stream);
537
- } else {
538
- length = this.findDefaultInlineStreamEnd(stream);
539
- }
540
- let imageStream = stream.makeSubStream(startPos, length, dict);
541
-
542
- // Cache all images below the MAX_LENGTH_TO_CACHE threshold by their
543
- // adler32 checksum.
544
- let cacheKey;
545
- if (length < MAX_LENGTH_TO_CACHE && dictLength < MAX_ADLER32_LENGTH) {
546
- const imageBytes = imageStream.getBytes();
547
- imageStream.reset();
548
-
549
- const initialStreamPos = stream.pos;
550
- // Set the stream position to the beginning of the dictionary data...
551
- stream.pos = lexer.beginInlineImagePos;
552
- // ... and fetch the bytes of the *entire* dictionary.
553
- const dictBytes = stream.getBytes(dictLength);
554
- // Finally, don't forget to reset the stream position.
555
- stream.pos = initialStreamPos;
556
-
557
- cacheKey = computeAdler32(imageBytes) + "_" + computeAdler32(dictBytes);
558
-
559
- const cacheEntry = this.imageCache[cacheKey];
560
- if (cacheEntry !== undefined) {
561
- this.buf2 = Cmd.get("EI");
562
- this.shift();
563
-
564
- cacheEntry.reset();
565
- return cacheEntry;
566
- }
567
- }
568
-
569
- if (cipherTransform) {
570
- imageStream = cipherTransform.createStream(imageStream, length);
571
- }
572
-
573
- imageStream = this.filter(imageStream, dict, length);
574
- imageStream.dict = dict;
575
- if (cacheKey !== undefined) {
576
- imageStream.cacheKey = `inline_${length}_${cacheKey}`;
577
- this.imageCache[cacheKey] = imageStream;
578
- }
579
-
580
- this.buf2 = Cmd.get("EI");
581
- this.shift();
582
-
583
- return imageStream;
584
- }
585
-
586
- _findStreamLength(startPos, signature) {
587
- const { stream } = this.lexer;
588
- stream.pos = startPos;
589
-
590
- const SCAN_BLOCK_LENGTH = 2048;
591
- const signatureLength = signature.length;
592
-
593
- while (stream.pos < stream.end) {
594
- const scanBytes = stream.peekBytes(SCAN_BLOCK_LENGTH);
595
- const scanLength = scanBytes.length - signatureLength;
596
-
597
- if (scanLength <= 0) {
598
- break;
599
- }
600
- let pos = 0;
601
- while (pos < scanLength) {
602
- let j = 0;
603
- while (j < signatureLength && scanBytes[pos + j] === signature[j]) {
604
- j++;
605
- }
606
- if (j >= signatureLength) {
607
- // `signature` found.
608
- stream.pos += pos;
609
- return stream.pos - startPos;
610
- }
611
- pos++;
612
- }
613
- stream.pos += scanLength;
614
- }
615
- return -1;
616
- }
617
-
618
- makeStream(dict, cipherTransform) {
619
- const lexer = this.lexer;
620
- let stream = lexer.stream;
621
-
622
- // Get the stream's start position.
623
- lexer.skipToNextLine();
624
- const startPos = stream.pos - 1;
625
-
626
- // Get the length.
627
- let length = dict.get("Length");
628
- if (!Number.isInteger(length)) {
629
- info(`Bad length "${length}" in stream`);
630
- length = 0;
631
- }
632
-
633
- // Skip over the stream data.
634
- stream.pos = startPos + length;
635
- lexer.nextChar();
636
-
637
- // Shift '>>' and check whether the new object marks the end of the stream.
638
- if (this.tryShift() && isCmd(this.buf2, "endstream")) {
639
- this.shift(); // 'stream'
640
- } else {
641
- // Bad stream length, scanning for endstream command.
642
- const ENDSTREAM_SIGNATURE = new Uint8Array([
643
- 0x65, 0x6e, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
644
- ]);
645
- let actualLength = this._findStreamLength(startPos, ENDSTREAM_SIGNATURE);
646
- if (actualLength < 0) {
647
- // Only allow limited truncation of the endstream signature,
648
- // to prevent false positives.
649
- const MAX_TRUNCATION = 1;
650
- // Check if the PDF generator included truncated endstream commands,
651
- // such as e.g. "endstrea" (fixes issue10004.pdf).
652
- for (let i = 1; i <= MAX_TRUNCATION; i++) {
653
- const end = ENDSTREAM_SIGNATURE.length - i;
654
- const TRUNCATED_SIGNATURE = ENDSTREAM_SIGNATURE.slice(0, end);
655
-
656
- const maybeLength = this._findStreamLength(
657
- startPos,
658
- TRUNCATED_SIGNATURE
659
- );
660
- if (maybeLength >= 0) {
661
- // Ensure that the byte immediately following the truncated
662
- // endstream command is a space, to prevent false positives.
663
- const lastByte = stream.peekBytes(end + 1)[end];
664
- if (!isWhiteSpace(lastByte)) {
665
- break;
666
- }
667
- info(
668
- `Found "${bytesToString(TRUNCATED_SIGNATURE)}" when ` +
669
- "searching for endstream command."
670
- );
671
- actualLength = maybeLength;
672
- break;
673
- }
674
- }
675
-
676
- if (actualLength < 0) {
677
- throw new FormatError("Missing endstream command.");
678
- }
679
- }
680
- length = actualLength;
681
-
682
- lexer.nextChar();
683
- this.shift();
684
- this.shift();
685
- }
686
- this.shift(); // 'endstream'
687
-
688
- stream = stream.makeSubStream(startPos, length, dict);
689
- if (cipherTransform) {
690
- stream = cipherTransform.createStream(stream, length);
691
- }
692
- stream = this.filter(stream, dict, length);
693
- stream.dict = dict;
694
- return stream;
695
- }
696
-
697
- filter(stream, dict, length) {
698
- let filter = dict.get("Filter", "F");
699
- let params = dict.get("DecodeParms", "DP");
700
-
701
- if (isName(filter)) {
702
- if (Array.isArray(params)) {
703
- warn(
704
- "/DecodeParms should not contain an Array, " +
705
- "when /Filter contains a Name."
706
- );
707
- }
708
- return this.makeFilter(stream, filter.name, length, params);
709
- }
710
-
711
- let maybeLength = length;
712
- if (Array.isArray(filter)) {
713
- const filterArray = filter;
714
- const paramsArray = params;
715
- for (let i = 0, ii = filterArray.length; i < ii; ++i) {
716
- filter = this.xref.fetchIfRef(filterArray[i]);
717
- if (!isName(filter)) {
718
- throw new FormatError(`Bad filter name "${filter}"`);
719
- }
720
-
721
- params = null;
722
- if (Array.isArray(paramsArray) && i in paramsArray) {
723
- params = this.xref.fetchIfRef(paramsArray[i]);
724
- }
725
- stream = this.makeFilter(stream, filter.name, maybeLength, params);
726
- // After the first stream the `length` variable is invalid.
727
- maybeLength = null;
728
- }
729
- }
730
- return stream;
731
- }
732
-
733
- makeFilter(stream, name, maybeLength, params) {
734
- // Since the 'Length' entry in the stream dictionary can be completely
735
- // wrong, e.g. zero for non-empty streams, only skip parsing the stream
736
- // when we can be absolutely certain that it actually is empty.
737
- if (maybeLength === 0) {
738
- warn(`Empty "${name}" stream.`);
739
- return new NullStream();
740
- }
741
-
742
- try {
743
- const xrefStreamStats = this.xref.stats.streamTypes;
744
- if (name === "FlateDecode" || name === "Fl") {
745
- xrefStreamStats[StreamType.FLATE] = true;
746
- if (params) {
747
- return new PredictorStream(
748
- new FlateStream(stream, maybeLength),
749
- maybeLength,
750
- params
751
- );
752
- }
753
- return new FlateStream(stream, maybeLength);
754
- }
755
- if (name === "LZWDecode" || name === "LZW") {
756
- xrefStreamStats[StreamType.LZW] = true;
757
- let earlyChange = 1;
758
- if (params) {
759
- if (params.has("EarlyChange")) {
760
- earlyChange = params.get("EarlyChange");
761
- }
762
- return new PredictorStream(
763
- new LZWStream(stream, maybeLength, earlyChange),
764
- maybeLength,
765
- params
766
- );
767
- }
768
- return new LZWStream(stream, maybeLength, earlyChange);
769
- }
770
- if (name === "DCTDecode" || name === "DCT") {
771
- xrefStreamStats[StreamType.DCT] = true;
772
- return new JpegStream(stream, maybeLength, params);
773
- }
774
- if (name === "JPXDecode" || name === "JPX") {
775
- xrefStreamStats[StreamType.JPX] = true;
776
- return new JpxStream(stream, maybeLength, params);
777
- }
778
- if (name === "ASCII85Decode" || name === "A85") {
779
- xrefStreamStats[StreamType.A85] = true;
780
- return new Ascii85Stream(stream, maybeLength);
781
- }
782
- if (name === "ASCIIHexDecode" || name === "AHx") {
783
- xrefStreamStats[StreamType.AHX] = true;
784
- return new AsciiHexStream(stream, maybeLength);
785
- }
786
- if (name === "CCITTFaxDecode" || name === "CCF") {
787
- xrefStreamStats[StreamType.CCF] = true;
788
- return new CCITTFaxStream(stream, maybeLength, params);
789
- }
790
- if (name === "RunLengthDecode" || name === "RL") {
791
- xrefStreamStats[StreamType.RLX] = true;
792
- return new RunLengthStream(stream, maybeLength);
793
- }
794
- if (name === "JBIG2Decode") {
795
- xrefStreamStats[StreamType.JBIG] = true;
796
- return new Jbig2Stream(stream, maybeLength, params);
797
- }
798
- warn(`Filter "${name}" is not supported.`);
799
- return stream;
800
- } catch (ex) {
801
- if (ex instanceof MissingDataException) {
802
- throw ex;
803
- }
804
- warn(`Invalid stream: "${ex}"`);
805
- return new NullStream();
806
- }
807
- }
808
- }
809
-
810
- // A '1' in this array means the character is white space. A '1' or
811
- // '2' means the character ends a name or command.
812
- // prettier-ignore
813
- const specialChars = [
814
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
815
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
816
- 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
817
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
818
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
819
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
820
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
821
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
822
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
823
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
824
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
825
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
826
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
827
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
828
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
829
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
830
- ];
831
-
832
- function toHexDigit(ch) {
833
- if (ch >= /* '0' = */ 0x30 && ch /* '9' = */ <= 0x39) {
834
- return ch & 0x0f;
835
- }
836
- if (
837
- (ch >= /* 'A' = */ 0x41 && ch <= /* 'F' = */ 0x46) ||
838
- (ch >= /* 'a' = */ 0x61 && ch <= /* 'f' = */ 0x66)
839
- ) {
840
- return (ch & 0x0f) + 9;
841
- }
842
- return -1;
843
- }
844
-
845
- class Lexer {
846
- constructor(stream, knownCommands = null) {
847
- this.stream = stream;
848
- this.nextChar();
849
-
850
- // While lexing, we build up many strings one char at a time. Using += for
851
- // this can result in lots of garbage strings. It's better to build an
852
- // array of single-char strings and then join() them together at the end.
853
- // And reusing a single array (i.e. |this.strBuf|) over and over for this
854
- // purpose uses less memory than using a new array for each string.
855
- this.strBuf = [];
856
-
857
- // The PDFs might have "glued" commands with other commands, operands or
858
- // literals, e.g. "q1". The knownCommands is a dictionary of the valid
859
- // commands and their prefixes. The prefixes are built the following way:
860
- // if there a command that is a prefix of the other valid command or
861
- // literal (e.g. 'f' and 'false') the following prefixes must be included,
862
- // 'fa', 'fal', 'fals'. The prefixes are not needed, if the command has no
863
- // other commands or literals as a prefix. The knowCommands is optional.
864
- this.knownCommands = knownCommands;
865
-
866
- this._hexStringNumWarn = 0;
867
- this.beginInlineImagePos = -1;
868
- }
869
-
870
- nextChar() {
871
- return (this.currentChar = this.stream.getByte());
872
- }
873
-
874
- peekChar() {
875
- return this.stream.peekByte();
876
- }
877
-
878
- getNumber() {
879
- let ch = this.currentChar;
880
- let eNotation = false;
881
- let divideBy = 0; // Different from 0 if it's a floating point value.
882
- let sign = 0;
883
-
884
- if (ch === /* '-' = */ 0x2d) {
885
- sign = -1;
886
- ch = this.nextChar();
887
-
888
- if (ch === /* '-' = */ 0x2d) {
889
- // Ignore double negative (this is consistent with Adobe Reader).
890
- ch = this.nextChar();
891
- }
892
- } else if (ch === /* '+' = */ 0x2b) {
893
- sign = 1;
894
- ch = this.nextChar();
895
- }
896
- if (ch === /* LF = */ 0x0a || ch === /* CR = */ 0x0d) {
897
- // Ignore line-breaks (this is consistent with Adobe Reader).
898
- do {
899
- ch = this.nextChar();
900
- } while (ch === 0x0a || ch === 0x0d);
901
- }
902
- if (ch === /* '.' = */ 0x2e) {
903
- divideBy = 10;
904
- ch = this.nextChar();
905
- }
906
- if (ch < /* '0' = */ 0x30 || ch > /* '9' = */ 0x39) {
907
- if (
908
- divideBy === 10 &&
909
- sign === 0 &&
910
- (isWhiteSpace(ch) || ch === /* EOF = */ -1)
911
- ) {
912
- // This is consistent with Adobe Reader (fixes issue9252.pdf).
913
- warn("Lexer.getNumber - treating a single decimal point as zero.");
914
- return 0;
915
- }
916
- throw new FormatError(
917
- `Invalid number: ${String.fromCharCode(ch)} (charCode ${ch})`
918
- );
919
- }
920
-
921
- sign = sign || 1;
922
- let baseValue = ch - 0x30; // '0'
923
- let powerValue = 0;
924
- let powerValueSign = 1;
925
-
926
- while ((ch = this.nextChar()) >= 0) {
927
- if (ch >= /* '0' = */ 0x30 && ch <= /* '9' = */ 0x39) {
928
- const currentDigit = ch - 0x30; // '0'
929
- if (eNotation) {
930
- // We are after an 'e' or 'E'.
931
- powerValue = powerValue * 10 + currentDigit;
932
- } else {
933
- if (divideBy !== 0) {
934
- // We are after a point.
935
- divideBy *= 10;
936
- }
937
- baseValue = baseValue * 10 + currentDigit;
938
- }
939
- } else if (ch === /* '.' = */ 0x2e) {
940
- if (divideBy === 0) {
941
- divideBy = 1;
942
- } else {
943
- // A number can have only one dot.
944
- break;
945
- }
946
- } else if (ch === /* '-' = */ 0x2d) {
947
- // Ignore minus signs in the middle of numbers to match
948
- // Adobe's behavior.
949
- warn("Badly formatted number: minus sign in the middle");
950
- } else if (ch === /* 'E' = */ 0x45 || ch === /* 'e' = */ 0x65) {
951
- // 'E' can be either a scientific notation or the beginning of a new
952
- // operator.
953
- ch = this.peekChar();
954
- if (ch === /* '+' = */ 0x2b || ch === /* '-' = */ 0x2d) {
955
- powerValueSign = ch === 0x2d ? -1 : 1;
956
- this.nextChar(); // Consume the sign character.
957
- } else if (ch < /* '0' = */ 0x30 || ch > /* '9' = */ 0x39) {
958
- // The 'E' must be the beginning of a new operator.
959
- break;
960
- }
961
- eNotation = true;
962
- } else {
963
- // The last character doesn't belong to us.
964
- break;
965
- }
966
- }
967
-
968
- if (divideBy !== 0) {
969
- baseValue /= divideBy;
970
- }
971
- if (eNotation) {
972
- baseValue *= 10 ** (powerValueSign * powerValue);
973
- }
974
- return sign * baseValue;
975
- }
976
-
977
- getString() {
978
- let numParen = 1;
979
- let done = false;
980
- const strBuf = this.strBuf;
981
- strBuf.length = 0;
982
-
983
- let ch = this.nextChar();
984
- while (true) {
985
- let charBuffered = false;
986
- switch (ch | 0) {
987
- case -1:
988
- warn("Unterminated string");
989
- done = true;
990
- break;
991
- case 0x28: // '('
992
- ++numParen;
993
- strBuf.push("(");
994
- break;
995
- case 0x29: // ')'
996
- if (--numParen === 0) {
997
- this.nextChar(); // consume strings ')'
998
- done = true;
999
- } else {
1000
- strBuf.push(")");
1001
- }
1002
- break;
1003
- case 0x5c: // '\\'
1004
- ch = this.nextChar();
1005
- switch (ch) {
1006
- case -1:
1007
- warn("Unterminated string");
1008
- done = true;
1009
- break;
1010
- case 0x6e: // 'n'
1011
- strBuf.push("\n");
1012
- break;
1013
- case 0x72: // 'r'
1014
- strBuf.push("\r");
1015
- break;
1016
- case 0x74: // 't'
1017
- strBuf.push("\t");
1018
- break;
1019
- case 0x62: // 'b'
1020
- strBuf.push("\b");
1021
- break;
1022
- case 0x66: // 'f'
1023
- strBuf.push("\f");
1024
- break;
1025
- case 0x5c: // '\'
1026
- case 0x28: // '('
1027
- case 0x29: // ')'
1028
- strBuf.push(String.fromCharCode(ch));
1029
- break;
1030
- case 0x30: // '0'
1031
- case 0x31: // '1'
1032
- case 0x32: // '2'
1033
- case 0x33: // '3'
1034
- case 0x34: // '4'
1035
- case 0x35: // '5'
1036
- case 0x36: // '6'
1037
- case 0x37: // '7'
1038
- let x = ch & 0x0f;
1039
- ch = this.nextChar();
1040
- charBuffered = true;
1041
- if (ch >= /* '0' = */ 0x30 && ch <= /* '7' = */ 0x37) {
1042
- x = (x << 3) + (ch & 0x0f);
1043
- ch = this.nextChar();
1044
- if (ch >= /* '0' = */ 0x30 && ch /* '7' = */ <= 0x37) {
1045
- charBuffered = false;
1046
- x = (x << 3) + (ch & 0x0f);
1047
- }
1048
- }
1049
- strBuf.push(String.fromCharCode(x));
1050
- break;
1051
- case 0x0d: // CR
1052
- if (this.peekChar() === /* LF = */ 0x0a) {
1053
- this.nextChar();
1054
- }
1055
- break;
1056
- case 0x0a: // LF
1057
- break;
1058
- default:
1059
- strBuf.push(String.fromCharCode(ch));
1060
- break;
1061
- }
1062
- break;
1063
- default:
1064
- strBuf.push(String.fromCharCode(ch));
1065
- break;
1066
- }
1067
- if (done) {
1068
- break;
1069
- }
1070
- if (!charBuffered) {
1071
- ch = this.nextChar();
1072
- }
1073
- }
1074
- return strBuf.join("");
1075
- }
1076
-
1077
- getName() {
1078
- let ch, previousCh;
1079
- const strBuf = this.strBuf;
1080
- strBuf.length = 0;
1081
-
1082
- while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
1083
- if (ch === /* '#' = */ 0x23) {
1084
- ch = this.nextChar();
1085
- if (specialChars[ch]) {
1086
- warn(
1087
- "Lexer_getName: " +
1088
- "NUMBER SIGN (#) should be followed by a hexadecimal number."
1089
- );
1090
- strBuf.push("#");
1091
- break;
1092
- }
1093
- const x = toHexDigit(ch);
1094
- if (x !== -1) {
1095
- previousCh = ch;
1096
- ch = this.nextChar();
1097
- const x2 = toHexDigit(ch);
1098
- if (x2 === -1) {
1099
- warn(
1100
- `Lexer_getName: Illegal digit (${String.fromCharCode(ch)}) ` +
1101
- "in hexadecimal number."
1102
- );
1103
- strBuf.push("#", String.fromCharCode(previousCh));
1104
- if (specialChars[ch]) {
1105
- break;
1106
- }
1107
- strBuf.push(String.fromCharCode(ch));
1108
- continue;
1109
- }
1110
- strBuf.push(String.fromCharCode((x << 4) | x2));
1111
- } else {
1112
- strBuf.push("#", String.fromCharCode(ch));
1113
- }
1114
- } else {
1115
- strBuf.push(String.fromCharCode(ch));
1116
- }
1117
- }
1118
- if (strBuf.length > 127) {
1119
- warn(`Name token is longer than allowed by the spec: ${strBuf.length}`);
1120
- } else if (strBuf.length === 0) {
1121
- warn("Name token is empty.");
1122
- }
1123
- return Name.get(strBuf.join(""));
1124
- }
1125
-
1126
- /**
1127
- * @private
1128
- */
1129
- _hexStringWarn(ch) {
1130
- const MAX_HEX_STRING_NUM_WARN = 5;
1131
-
1132
- if (this._hexStringNumWarn++ === MAX_HEX_STRING_NUM_WARN) {
1133
- warn("getHexString - ignoring additional invalid characters.");
1134
- return;
1135
- }
1136
- if (this._hexStringNumWarn > MAX_HEX_STRING_NUM_WARN) {
1137
- // Limit the number of warning messages printed for a `this.getHexString`
1138
- // invocation, since corrupt PDF documents may otherwise spam the console
1139
- // enough to affect general performance negatively.
1140
- return;
1141
- }
1142
- warn(`getHexString - ignoring invalid character: ${ch}`);
1143
- }
1144
-
1145
- getHexString() {
1146
- const strBuf = this.strBuf;
1147
- strBuf.length = 0;
1148
- let ch = this.currentChar;
1149
- let isFirstHex = true;
1150
- let firstDigit, secondDigit;
1151
- this._hexStringNumWarn = 0;
1152
-
1153
- while (true) {
1154
- if (ch < 0) {
1155
- warn("Unterminated hex string");
1156
- break;
1157
- } else if (ch === /* '>' = */ 0x3e) {
1158
- this.nextChar();
1159
- break;
1160
- } else if (specialChars[ch] === 1) {
1161
- ch = this.nextChar();
1162
- continue;
1163
- } else {
1164
- if (isFirstHex) {
1165
- firstDigit = toHexDigit(ch);
1166
- if (firstDigit === -1) {
1167
- this._hexStringWarn(ch);
1168
- ch = this.nextChar();
1169
- continue;
1170
- }
1171
- } else {
1172
- secondDigit = toHexDigit(ch);
1173
- if (secondDigit === -1) {
1174
- this._hexStringWarn(ch);
1175
- ch = this.nextChar();
1176
- continue;
1177
- }
1178
- strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit));
1179
- }
1180
- isFirstHex = !isFirstHex;
1181
- ch = this.nextChar();
1182
- }
1183
- }
1184
- return strBuf.join("");
1185
- }
1186
-
1187
- getObj() {
1188
- // Skip whitespace and comments.
1189
- let comment = false;
1190
- let ch = this.currentChar;
1191
- while (true) {
1192
- if (ch < 0) {
1193
- return EOF;
1194
- }
1195
- if (comment) {
1196
- if (ch === /* LF = */ 0x0a || ch === /* CR = */ 0x0d) {
1197
- comment = false;
1198
- }
1199
- } else if (ch === /* '%' = */ 0x25) {
1200
- comment = true;
1201
- } else if (specialChars[ch] !== 1) {
1202
- break;
1203
- }
1204
- ch = this.nextChar();
1205
- }
1206
-
1207
- // Start reading a token.
1208
- switch (ch | 0) {
1209
- case 0x30: // '0'
1210
- case 0x31: // '1'
1211
- case 0x32: // '2'
1212
- case 0x33: // '3'
1213
- case 0x34: // '4'
1214
- case 0x35: // '5'
1215
- case 0x36: // '6'
1216
- case 0x37: // '7'
1217
- case 0x38: // '8'
1218
- case 0x39: // '9'
1219
- case 0x2b: // '+'
1220
- case 0x2d: // '-'
1221
- case 0x2e: // '.'
1222
- return this.getNumber();
1223
- case 0x28: // '('
1224
- return this.getString();
1225
- case 0x2f: // '/'
1226
- return this.getName();
1227
- // array punctuation
1228
- case 0x5b: // '['
1229
- this.nextChar();
1230
- return Cmd.get("[");
1231
- case 0x5d: // ']'
1232
- this.nextChar();
1233
- return Cmd.get("]");
1234
- // hex string or dict punctuation
1235
- case 0x3c: // '<'
1236
- ch = this.nextChar();
1237
- if (ch === 0x3c) {
1238
- // dict punctuation
1239
- this.nextChar();
1240
- return Cmd.get("<<");
1241
- }
1242
- return this.getHexString();
1243
- // dict punctuation
1244
- case 0x3e: // '>'
1245
- ch = this.nextChar();
1246
- if (ch === 0x3e) {
1247
- this.nextChar();
1248
- return Cmd.get(">>");
1249
- }
1250
- return Cmd.get(">");
1251
- case 0x7b: // '{'
1252
- this.nextChar();
1253
- return Cmd.get("{");
1254
- case 0x7d: // '}'
1255
- this.nextChar();
1256
- return Cmd.get("}");
1257
- case 0x29: // ')'
1258
- // Consume the current character in order to avoid permanently hanging
1259
- // the worker thread if `Lexer.getObject` is called from within a loop
1260
- // containing try-catch statements, since we would otherwise attempt
1261
- // to parse the *same* character over and over (fixes issue8061.pdf).
1262
- this.nextChar();
1263
- throw new FormatError(`Illegal character: ${ch}`);
1264
- }
1265
-
1266
- // Start reading a command.
1267
- let str = String.fromCharCode(ch);
1268
- const knownCommands = this.knownCommands;
1269
- let knownCommandFound = knownCommands && knownCommands[str] !== undefined;
1270
- while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
1271
- // Stop if a known command is found and next character does not make
1272
- // the string a command.
1273
- const possibleCommand = str + String.fromCharCode(ch);
1274
- if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
1275
- break;
1276
- }
1277
- if (str.length === 128) {
1278
- throw new FormatError(`Command token too long: ${str.length}`);
1279
- }
1280
- str = possibleCommand;
1281
- knownCommandFound = knownCommands && knownCommands[str] !== undefined;
1282
- }
1283
- if (str === "true") {
1284
- return true;
1285
- }
1286
- if (str === "false") {
1287
- return false;
1288
- }
1289
- if (str === "null") {
1290
- return null;
1291
- }
1292
-
1293
- if (str === "BI") {
1294
- // Keep track of the current stream position, since it's needed in order
1295
- // to correctly cache inline images; see `Parser.makeInlineImage`.
1296
- this.beginInlineImagePos = this.stream.pos;
1297
- }
1298
-
1299
- return Cmd.get(str);
1300
- }
1301
-
1302
- peekObj() {
1303
- const streamPos = this.stream.pos,
1304
- currentChar = this.currentChar,
1305
- beginInlineImagePos = this.beginInlineImagePos;
1306
-
1307
- let nextObj;
1308
- try {
1309
- nextObj = this.getObj();
1310
- } catch (ex) {
1311
- if (ex instanceof MissingDataException) {
1312
- throw ex;
1313
- }
1314
- warn(`peekObj: ${ex}`);
1315
- }
1316
- // Ensure that we reset *all* relevant `Lexer`-instance state.
1317
- this.stream.pos = streamPos;
1318
- this.currentChar = currentChar;
1319
- this.beginInlineImagePos = beginInlineImagePos;
1320
-
1321
- return nextObj;
1322
- }
1323
-
1324
- skipToNextLine() {
1325
- let ch = this.currentChar;
1326
- while (ch >= 0) {
1327
- if (ch === /* CR = */ 0x0d) {
1328
- ch = this.nextChar();
1329
- if (ch === /* LF = */ 0x0a) {
1330
- this.nextChar();
1331
- }
1332
- break;
1333
- } else if (ch === /* LF = */ 0x0a) {
1334
- this.nextChar();
1335
- break;
1336
- }
1337
- ch = this.nextChar();
1338
- }
1339
- }
1340
- }
1341
-
1342
- class Linearization {
1343
- static create(stream) {
1344
- function getInt(linDict, name, allowZeroValue = false) {
1345
- const obj = linDict.get(name);
1346
- if (Number.isInteger(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
1347
- return obj;
1348
- }
1349
- throw new Error(
1350
- `The "${name}" parameter in the linearization ` +
1351
- "dictionary is invalid."
1352
- );
1353
- }
1354
-
1355
- function getHints(linDict) {
1356
- const hints = linDict.get("H");
1357
- let hintsLength;
1358
-
1359
- if (
1360
- Array.isArray(hints) &&
1361
- ((hintsLength = hints.length) === 2 || hintsLength === 4)
1362
- ) {
1363
- for (let index = 0; index < hintsLength; index++) {
1364
- const hint = hints[index];
1365
- if (!(Number.isInteger(hint) && hint > 0)) {
1366
- throw new Error(
1367
- `Hint (${index}) in the linearization dictionary is invalid.`
1368
- );
1369
- }
1370
- }
1371
- return hints;
1372
- }
1373
- throw new Error("Hint array in the linearization dictionary is invalid.");
1374
- }
1375
-
1376
- const parser = new Parser({
1377
- lexer: new Lexer(stream),
1378
- xref: null,
1379
- });
1380
- const obj1 = parser.getObj();
1381
- const obj2 = parser.getObj();
1382
- const obj3 = parser.getObj();
1383
- const linDict = parser.getObj();
1384
- let obj, length;
1385
- if (
1386
- !(
1387
- Number.isInteger(obj1) &&
1388
- Number.isInteger(obj2) &&
1389
- isCmd(obj3, "obj") &&
1390
- isDict(linDict) &&
1391
- isNum((obj = linDict.get("Linearized"))) &&
1392
- obj > 0
1393
- )
1394
- ) {
1395
- return null; // No valid linearization dictionary found.
1396
- } else if ((length = getInt(linDict, "L")) !== stream.length) {
1397
- throw new Error(
1398
- 'The "L" parameter in the linearization dictionary ' +
1399
- "does not equal the stream length."
1400
- );
1401
- }
1402
- return {
1403
- length,
1404
- hints: getHints(linDict),
1405
- objectNumberFirst: getInt(linDict, "O"),
1406
- endFirst: getInt(linDict, "E"),
1407
- numPages: getInt(linDict, "N"),
1408
- mainXRefEntriesOffset: getInt(linDict, "T"),
1409
- pageFirst: linDict.has("P")
1410
- ? getInt(linDict, "P", /* allowZeroValue = */ true)
1411
- : 0,
1412
- };
1413
- }
1414
- }
1415
-
1416
- export { Lexer, Linearization, Parser };