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

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 (174) hide show
  1. package/README.md +1 -1
  2. package/package.json +33 -18
  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/get.js +1857 -0
  6. package/pdfjs/dist/index.js +767 -0
  7. package/pdfjs/dist/l10n_utils.js +140 -0
  8. package/{src/shared → pdfjs/dist}/message_handler.js +243 -259
  9. package/{src/display → pdfjs/dist}/network.js +149 -87
  10. package/{src/display/content_disposition.js → pdfjs/dist/network_utils.js} +167 -55
  11. package/{src/display → pdfjs/dist}/node_stream.js +133 -98
  12. package/pdfjs/dist/pdf.js +12778 -0
  13. package/pdfjs/dist/pdf_link_service.js +638 -0
  14. package/pdfjs/dist/pdf_rendering_queue.js +199 -0
  15. package/pdfjs/dist/pdf_thumbnail_viewer.js +819 -0
  16. package/pdfjs/dist/pdf_viewer.js +3598 -0
  17. package/pdfjs/dist/typeof.js +100 -0
  18. package/pdfjs/dist/ui_utils.js +1033 -0
  19. package/{src/shared → pdfjs/dist}/util.js +301 -287
  20. package/pdfjs/dist/worker.js +62813 -0
  21. package/src/vcf-pdf-viewer.js +77 -27
  22. package/theme/lumo/vcf-pdf-viewer-styles.js +1 -1
  23. package/theme/material/vcf-pdf-viewer.js +2 -2
  24. package/src/core/.eslintrc +0 -13
  25. package/src/core/annotation.js +0 -2948
  26. package/src/core/arithmetic_decoder.js +0 -182
  27. package/src/core/ascii_85_stream.js +0 -98
  28. package/src/core/ascii_hex_stream.js +0 -79
  29. package/src/core/base_stream.js +0 -110
  30. package/src/core/bidi.js +0 -438
  31. package/src/core/calibri_factors.js +0 -308
  32. package/src/core/catalog.js +0 -1459
  33. package/src/core/ccitt.js +0 -1062
  34. package/src/core/ccitt_stream.js +0 -60
  35. package/src/core/cff_font.js +0 -116
  36. package/src/core/cff_parser.js +0 -1949
  37. package/src/core/charsets.js +0 -119
  38. package/src/core/chunked_stream.js +0 -557
  39. package/src/core/cmap.js +0 -1039
  40. package/src/core/colorspace.js +0 -1533
  41. package/src/core/core_utils.js +0 -464
  42. package/src/core/crypto.js +0 -1900
  43. package/src/core/decode_stream.js +0 -170
  44. package/src/core/decrypt_stream.js +0 -59
  45. package/src/core/default_appearance.js +0 -99
  46. package/src/core/document.js +0 -1456
  47. package/src/core/encodings.js +0 -301
  48. package/src/core/evaluator.js +0 -4601
  49. package/src/core/file_spec.js +0 -108
  50. package/src/core/flate_stream.js +0 -402
  51. package/src/core/font_renderer.js +0 -882
  52. package/src/core/fonts.js +0 -3260
  53. package/src/core/fonts_utils.js +0 -221
  54. package/src/core/function.js +0 -1257
  55. package/src/core/glyf.js +0 -706
  56. package/src/core/glyphlist.js +0 -4558
  57. package/src/core/helvetica_factors.js +0 -353
  58. package/src/core/image.js +0 -802
  59. package/src/core/image_utils.js +0 -291
  60. package/src/core/jbig2.js +0 -2572
  61. package/src/core/jbig2_stream.js +0 -73
  62. package/src/core/jpeg_stream.js +0 -105
  63. package/src/core/jpg.js +0 -1416
  64. package/src/core/jpx.js +0 -2343
  65. package/src/core/jpx_stream.js +0 -87
  66. package/src/core/liberationsans_widths.js +0 -221
  67. package/src/core/lzw_stream.js +0 -150
  68. package/src/core/metadata_parser.js +0 -146
  69. package/src/core/metrics.js +0 -2970
  70. package/src/core/murmurhash3.js +0 -139
  71. package/src/core/myriadpro_factors.js +0 -290
  72. package/src/core/name_number_tree.js +0 -153
  73. package/src/core/object_loader.js +0 -149
  74. package/src/core/opentype_file_builder.js +0 -154
  75. package/src/core/operator_list.js +0 -734
  76. package/src/core/parser.js +0 -1416
  77. package/src/core/pattern.js +0 -985
  78. package/src/core/pdf_manager.js +0 -217
  79. package/src/core/predictor_stream.js +0 -238
  80. package/src/core/primitives.js +0 -402
  81. package/src/core/ps_parser.js +0 -272
  82. package/src/core/run_length_stream.js +0 -61
  83. package/src/core/segoeui_factors.js +0 -308
  84. package/src/core/standard_fonts.js +0 -817
  85. package/src/core/stream.js +0 -103
  86. package/src/core/struct_tree.js +0 -335
  87. package/src/core/to_unicode_map.js +0 -103
  88. package/src/core/type1_font.js +0 -421
  89. package/src/core/type1_parser.js +0 -776
  90. package/src/core/unicode.js +0 -1649
  91. package/src/core/worker.js +0 -848
  92. package/src/core/worker_stream.js +0 -135
  93. package/src/core/writer.js +0 -278
  94. package/src/core/xfa/bind.js +0 -652
  95. package/src/core/xfa/builder.js +0 -207
  96. package/src/core/xfa/config.js +0 -1926
  97. package/src/core/xfa/connection_set.js +0 -202
  98. package/src/core/xfa/data.js +0 -82
  99. package/src/core/xfa/datasets.js +0 -76
  100. package/src/core/xfa/factory.js +0 -111
  101. package/src/core/xfa/fonts.js +0 -181
  102. package/src/core/xfa/formcalc_lexer.js +0 -385
  103. package/src/core/xfa/formcalc_parser.js +0 -1340
  104. package/src/core/xfa/html_utils.js +0 -639
  105. package/src/core/xfa/layout.js +0 -383
  106. package/src/core/xfa/locale_set.js +0 -345
  107. package/src/core/xfa/namespaces.js +0 -81
  108. package/src/core/xfa/parser.js +0 -184
  109. package/src/core/xfa/setup.js +0 -38
  110. package/src/core/xfa/signature.js +0 -40
  111. package/src/core/xfa/som.js +0 -338
  112. package/src/core/xfa/stylesheet.js +0 -40
  113. package/src/core/xfa/template.js +0 -6260
  114. package/src/core/xfa/text.js +0 -290
  115. package/src/core/xfa/unknown.js +0 -29
  116. package/src/core/xfa/utils.js +0 -217
  117. package/src/core/xfa/xdp.js +0 -59
  118. package/src/core/xfa/xfa_object.js +0 -1130
  119. package/src/core/xfa/xhtml.js +0 -543
  120. package/src/core/xfa_fonts.js +0 -208
  121. package/src/core/xml_parser.js +0 -507
  122. package/src/core/xref.js +0 -899
  123. package/src/display/annotation_layer.js +0 -2107
  124. package/src/display/annotation_storage.js +0 -113
  125. package/src/display/api.js +0 -3292
  126. package/src/display/base_factory.js +0 -180
  127. package/src/display/canvas.js +0 -2828
  128. package/src/display/font_loader.js +0 -484
  129. package/src/display/metadata.js +0 -41
  130. package/src/display/network_utils.js +0 -100
  131. package/src/display/node_utils.js +0 -83
  132. package/src/display/optional_content_config.js +0 -189
  133. package/src/display/pattern_helper.js +0 -659
  134. package/src/display/svg.js +0 -1709
  135. package/src/display/text_layer.js +0 -847
  136. package/src/display/transport_stream.js +0 -303
  137. package/src/display/worker_options.js +0 -40
  138. package/src/display/xfa_layer.js +0 -204
  139. package/src/doc_helper.js +0 -25
  140. package/src/images/logo.svg +0 -41
  141. package/src/interfaces.js +0 -169
  142. package/src/license_header.js +0 -14
  143. package/src/license_header_libre.js +0 -21
  144. package/src/pdf.image_decoders.js +0 -46
  145. package/src/pdf.js +0 -146
  146. package/src/pdf.sandbox.external.js +0 -181
  147. package/src/pdf.sandbox.js +0 -151
  148. package/src/pdf.scripting.js +0 -25
  149. package/src/pdf.worker.entry.js +0 -19
  150. package/src/pdf.worker.js +0 -23
  151. package/src/scripting_api/aform.js +0 -608
  152. package/src/scripting_api/app.js +0 -621
  153. package/src/scripting_api/color.js +0 -129
  154. package/src/scripting_api/common.js +0 -58
  155. package/src/scripting_api/console.js +0 -38
  156. package/src/scripting_api/constants.js +0 -208
  157. package/src/scripting_api/doc.js +0 -1195
  158. package/src/scripting_api/error.js +0 -23
  159. package/src/scripting_api/event.js +0 -232
  160. package/src/scripting_api/field.js +0 -620
  161. package/src/scripting_api/fullscreen.js +0 -145
  162. package/src/scripting_api/initialization.js +0 -223
  163. package/src/scripting_api/pdf_object.js +0 -24
  164. package/src/scripting_api/print_params.js +0 -146
  165. package/src/scripting_api/proxy.js +0 -139
  166. package/src/scripting_api/thermometer.js +0 -69
  167. package/src/scripting_api/util.js +0 -581
  168. package/src/shared/.eslintrc +0 -13
  169. package/src/shared/cffStandardStrings.js +0 -311
  170. package/src/shared/compatibility.js +0 -114
  171. package/src/shared/fonts_utils.js +0 -429
  172. package/src/shared/is_node.js +0 -27
  173. package/src/shared/scripting_utils.js +0 -85
  174. package/src/worker_loader.js +0 -32
@@ -1,1459 +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
- clearPrimitiveCaches,
18
- Dict,
19
- isDict,
20
- isName,
21
- isRef,
22
- isRefsEqual,
23
- isStream,
24
- RefSet,
25
- RefSetCache,
26
- } from "./primitives.js";
27
- import {
28
- collectActions,
29
- MissingDataException,
30
- toRomanNumerals,
31
- } from "./core_utils.js";
32
- import {
33
- createPromiseCapability,
34
- createValidAbsoluteUrl,
35
- DocumentActionEventType,
36
- FormatError,
37
- info,
38
- isBool,
39
- isNum,
40
- isString,
41
- objectSize,
42
- PermissionFlag,
43
- shadow,
44
- stringToPDFString,
45
- stringToUTF8String,
46
- warn,
47
- } from "../shared/util.js";
48
- import { NameTree, NumberTree } from "./name_number_tree.js";
49
- import { ColorSpace } from "./colorspace.js";
50
- import { FileSpec } from "./file_spec.js";
51
- import { GlobalImageCache } from "./image_utils.js";
52
- import { MetadataParser } from "./metadata_parser.js";
53
- import { StructTreeRoot } from "./struct_tree.js";
54
-
55
- function fetchDestination(dest) {
56
- if (dest instanceof Dict) {
57
- dest = dest.get("D");
58
- }
59
- return Array.isArray(dest) ? dest : null;
60
- }
61
-
62
- class Catalog {
63
- constructor(pdfManager, xref) {
64
- this.pdfManager = pdfManager;
65
- this.xref = xref;
66
-
67
- this._catDict = xref.getCatalogObj();
68
- if (!isDict(this._catDict)) {
69
- throw new FormatError("Catalog object is not a dictionary.");
70
- }
71
-
72
- this.fontCache = new RefSetCache();
73
- this.builtInCMapCache = new Map();
74
- this.standardFontDataCache = new Map();
75
- this.globalImageCache = new GlobalImageCache();
76
- this.pageKidsCountCache = new RefSetCache();
77
- this.pageIndexCache = new RefSetCache();
78
- this.nonBlendModesSet = new RefSet();
79
- }
80
-
81
- get version() {
82
- const version = this._catDict.get("Version");
83
- if (!isName(version)) {
84
- return shadow(this, "version", null);
85
- }
86
- return shadow(this, "version", version.name);
87
- }
88
-
89
- get collection() {
90
- let collection = null;
91
- try {
92
- const obj = this._catDict.get("Collection");
93
- if (isDict(obj) && obj.size > 0) {
94
- collection = obj;
95
- }
96
- } catch (ex) {
97
- if (ex instanceof MissingDataException) {
98
- throw ex;
99
- }
100
- info("Cannot fetch Collection entry; assuming no collection is present.");
101
- }
102
- return shadow(this, "collection", collection);
103
- }
104
-
105
- get acroForm() {
106
- let acroForm = null;
107
- try {
108
- const obj = this._catDict.get("AcroForm");
109
- if (isDict(obj) && obj.size > 0) {
110
- acroForm = obj;
111
- }
112
- } catch (ex) {
113
- if (ex instanceof MissingDataException) {
114
- throw ex;
115
- }
116
- info("Cannot fetch AcroForm entry; assuming no forms are present.");
117
- }
118
- return shadow(this, "acroForm", acroForm);
119
- }
120
-
121
- get metadata() {
122
- const streamRef = this._catDict.getRaw("Metadata");
123
- if (!isRef(streamRef)) {
124
- return shadow(this, "metadata", null);
125
- }
126
-
127
- const suppressEncryption = !(
128
- this.xref.encrypt && this.xref.encrypt.encryptMetadata
129
- );
130
- const stream = this.xref.fetch(streamRef, suppressEncryption);
131
- let metadata = null;
132
-
133
- if (isStream(stream) && isDict(stream.dict)) {
134
- const type = stream.dict.get("Type");
135
- const subtype = stream.dict.get("Subtype");
136
-
137
- if (isName(type, "Metadata") && isName(subtype, "XML")) {
138
- // XXX: This should examine the charset the XML document defines,
139
- // however since there are currently no real means to decode arbitrary
140
- // charsets, let's just hope that the author of the PDF was reasonable
141
- // enough to stick with the XML default charset, which is UTF-8.
142
- try {
143
- const data = stringToUTF8String(stream.getString());
144
- if (data) {
145
- metadata = new MetadataParser(data).serializable;
146
- }
147
- } catch (e) {
148
- if (e instanceof MissingDataException) {
149
- throw e;
150
- }
151
- info("Skipping invalid metadata.");
152
- }
153
- }
154
- }
155
- return shadow(this, "metadata", metadata);
156
- }
157
-
158
- get markInfo() {
159
- let markInfo = null;
160
- try {
161
- markInfo = this._readMarkInfo();
162
- } catch (ex) {
163
- if (ex instanceof MissingDataException) {
164
- throw ex;
165
- }
166
- warn("Unable to read mark info.");
167
- }
168
- return shadow(this, "markInfo", markInfo);
169
- }
170
-
171
- /**
172
- * @private
173
- */
174
- _readMarkInfo() {
175
- const obj = this._catDict.get("MarkInfo");
176
- if (!isDict(obj)) {
177
- return null;
178
- }
179
-
180
- const markInfo = Object.assign(Object.create(null), {
181
- Marked: false,
182
- UserProperties: false,
183
- Suspects: false,
184
- });
185
- for (const key in markInfo) {
186
- if (!obj.has(key)) {
187
- continue;
188
- }
189
- const value = obj.get(key);
190
- if (!isBool(value)) {
191
- continue;
192
- }
193
- markInfo[key] = value;
194
- }
195
-
196
- return markInfo;
197
- }
198
-
199
- get structTreeRoot() {
200
- let structTree = null;
201
- try {
202
- structTree = this._readStructTreeRoot();
203
- } catch (ex) {
204
- if (ex instanceof MissingDataException) {
205
- throw ex;
206
- }
207
- warn("Unable read to structTreeRoot info.");
208
- }
209
- return shadow(this, "structTreeRoot", structTree);
210
- }
211
-
212
- /**
213
- * @private
214
- */
215
- _readStructTreeRoot() {
216
- const obj = this._catDict.get("StructTreeRoot");
217
- if (!isDict(obj)) {
218
- return null;
219
- }
220
- const root = new StructTreeRoot(obj);
221
- root.init();
222
- return root;
223
- }
224
-
225
- get toplevelPagesDict() {
226
- const pagesObj = this._catDict.get("Pages");
227
- if (!isDict(pagesObj)) {
228
- throw new FormatError("Invalid top-level pages dictionary.");
229
- }
230
- return shadow(this, "toplevelPagesDict", pagesObj);
231
- }
232
-
233
- get documentOutline() {
234
- let obj = null;
235
- try {
236
- obj = this._readDocumentOutline();
237
- } catch (ex) {
238
- if (ex instanceof MissingDataException) {
239
- throw ex;
240
- }
241
- warn("Unable to read document outline.");
242
- }
243
- return shadow(this, "documentOutline", obj);
244
- }
245
-
246
- /**
247
- * @private
248
- */
249
- _readDocumentOutline() {
250
- let obj = this._catDict.get("Outlines");
251
- if (!isDict(obj)) {
252
- return null;
253
- }
254
- obj = obj.getRaw("First");
255
- if (!isRef(obj)) {
256
- return null;
257
- }
258
-
259
- const root = { items: [] };
260
- const queue = [{ obj, parent: root }];
261
- // To avoid recursion, keep track of the already processed items.
262
- const processed = new RefSet();
263
- processed.put(obj);
264
- const xref = this.xref,
265
- blackColor = new Uint8ClampedArray(3);
266
-
267
- while (queue.length > 0) {
268
- const i = queue.shift();
269
- const outlineDict = xref.fetchIfRef(i.obj);
270
- if (outlineDict === null) {
271
- continue;
272
- }
273
- if (!outlineDict.has("Title")) {
274
- throw new FormatError("Invalid outline item encountered.");
275
- }
276
-
277
- const data = { url: null, dest: null };
278
- Catalog.parseDestDictionary({
279
- destDict: outlineDict,
280
- resultObj: data,
281
- docBaseUrl: this.pdfManager.docBaseUrl,
282
- });
283
- const title = outlineDict.get("Title");
284
- const flags = outlineDict.get("F") || 0;
285
- const color = outlineDict.getArray("C");
286
- const count = outlineDict.get("Count");
287
- let rgbColor = blackColor;
288
-
289
- // We only need to parse the color when it's valid, and non-default.
290
- if (
291
- Array.isArray(color) &&
292
- color.length === 3 &&
293
- (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)
294
- ) {
295
- rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
296
- }
297
-
298
- const outlineItem = {
299
- dest: data.dest,
300
- url: data.url,
301
- unsafeUrl: data.unsafeUrl,
302
- newWindow: data.newWindow,
303
- title: stringToPDFString(title),
304
- color: rgbColor,
305
- count: Number.isInteger(count) ? count : undefined,
306
- bold: !!(flags & 2),
307
- italic: !!(flags & 1),
308
- items: [],
309
- };
310
-
311
- i.parent.items.push(outlineItem);
312
- obj = outlineDict.getRaw("First");
313
- if (isRef(obj) && !processed.has(obj)) {
314
- queue.push({ obj, parent: outlineItem });
315
- processed.put(obj);
316
- }
317
- obj = outlineDict.getRaw("Next");
318
- if (isRef(obj) && !processed.has(obj)) {
319
- queue.push({ obj, parent: i.parent });
320
- processed.put(obj);
321
- }
322
- }
323
- return root.items.length > 0 ? root.items : null;
324
- }
325
-
326
- get permissions() {
327
- let permissions = null;
328
- try {
329
- permissions = this._readPermissions();
330
- } catch (ex) {
331
- if (ex instanceof MissingDataException) {
332
- throw ex;
333
- }
334
- warn("Unable to read permissions.");
335
- }
336
- return shadow(this, "permissions", permissions);
337
- }
338
-
339
- /**
340
- * @private
341
- */
342
- _readPermissions() {
343
- const encrypt = this.xref.trailer.get("Encrypt");
344
- if (!isDict(encrypt)) {
345
- return null;
346
- }
347
-
348
- let flags = encrypt.get("P");
349
- if (!isNum(flags)) {
350
- return null;
351
- }
352
-
353
- // PDF integer objects are represented internally in signed 2's complement
354
- // form. Therefore, convert the signed decimal integer to a signed 2's
355
- // complement binary integer so we can use regular bitwise operations on it.
356
- flags += 2 ** 32;
357
-
358
- const permissions = [];
359
- for (const key in PermissionFlag) {
360
- const value = PermissionFlag[key];
361
- if (flags & value) {
362
- permissions.push(value);
363
- }
364
- }
365
- return permissions;
366
- }
367
-
368
- get optionalContentConfig() {
369
- let config = null;
370
- try {
371
- const properties = this._catDict.get("OCProperties");
372
- if (!properties) {
373
- return shadow(this, "optionalContentConfig", null);
374
- }
375
- const defaultConfig = properties.get("D");
376
- if (!defaultConfig) {
377
- return shadow(this, "optionalContentConfig", null);
378
- }
379
- const groupsData = properties.get("OCGs");
380
- if (!Array.isArray(groupsData)) {
381
- return shadow(this, "optionalContentConfig", null);
382
- }
383
- const groups = [];
384
- const groupRefs = [];
385
- // Ensure all the optional content groups are valid.
386
- for (const groupRef of groupsData) {
387
- if (!isRef(groupRef)) {
388
- continue;
389
- }
390
- groupRefs.push(groupRef);
391
- const group = this.xref.fetchIfRef(groupRef);
392
- groups.push({
393
- id: groupRef.toString(),
394
- name: isString(group.get("Name"))
395
- ? stringToPDFString(group.get("Name"))
396
- : null,
397
- intent: isString(group.get("Intent"))
398
- ? stringToPDFString(group.get("Intent"))
399
- : null,
400
- });
401
- }
402
- config = this._readOptionalContentConfig(defaultConfig, groupRefs);
403
- config.groups = groups;
404
- } catch (ex) {
405
- if (ex instanceof MissingDataException) {
406
- throw ex;
407
- }
408
- warn(`Unable to read optional content config: ${ex}`);
409
- }
410
- return shadow(this, "optionalContentConfig", config);
411
- }
412
-
413
- _readOptionalContentConfig(config, contentGroupRefs) {
414
- function parseOnOff(refs) {
415
- const onParsed = [];
416
- if (Array.isArray(refs)) {
417
- for (const value of refs) {
418
- if (!isRef(value)) {
419
- continue;
420
- }
421
- if (contentGroupRefs.includes(value)) {
422
- onParsed.push(value.toString());
423
- }
424
- }
425
- }
426
- return onParsed;
427
- }
428
-
429
- function parseOrder(refs, nestedLevels = 0) {
430
- if (!Array.isArray(refs)) {
431
- return null;
432
- }
433
- const order = [];
434
-
435
- for (const value of refs) {
436
- if (isRef(value) && contentGroupRefs.includes(value)) {
437
- parsedOrderRefs.put(value); // Handle "hidden" groups, see below.
438
-
439
- order.push(value.toString());
440
- continue;
441
- }
442
- // Handle nested /Order arrays (see e.g. issue 9462 and bug 1240641).
443
- const nestedOrder = parseNestedOrder(value, nestedLevels);
444
- if (nestedOrder) {
445
- order.push(nestedOrder);
446
- }
447
- }
448
-
449
- if (nestedLevels > 0) {
450
- return order;
451
- }
452
- const hiddenGroups = [];
453
- for (const groupRef of contentGroupRefs) {
454
- if (parsedOrderRefs.has(groupRef)) {
455
- continue;
456
- }
457
- hiddenGroups.push(groupRef.toString());
458
- }
459
- if (hiddenGroups.length) {
460
- order.push({ name: null, order: hiddenGroups });
461
- }
462
-
463
- return order;
464
- }
465
-
466
- function parseNestedOrder(ref, nestedLevels) {
467
- if (++nestedLevels > MAX_NESTED_LEVELS) {
468
- warn("parseNestedOrder - reached MAX_NESTED_LEVELS.");
469
- return null;
470
- }
471
- const value = xref.fetchIfRef(ref);
472
- if (!Array.isArray(value)) {
473
- return null;
474
- }
475
- const nestedName = xref.fetchIfRef(value[0]);
476
- if (typeof nestedName !== "string") {
477
- return null;
478
- }
479
- const nestedOrder = parseOrder(value.slice(1), nestedLevels);
480
- if (!nestedOrder || !nestedOrder.length) {
481
- return null;
482
- }
483
- return { name: stringToPDFString(nestedName), order: nestedOrder };
484
- }
485
-
486
- const xref = this.xref,
487
- parsedOrderRefs = new RefSet(),
488
- MAX_NESTED_LEVELS = 10;
489
-
490
- return {
491
- name: isString(config.get("Name"))
492
- ? stringToPDFString(config.get("Name"))
493
- : null,
494
- creator: isString(config.get("Creator"))
495
- ? stringToPDFString(config.get("Creator"))
496
- : null,
497
- baseState: isName(config.get("BaseState"))
498
- ? config.get("BaseState").name
499
- : null,
500
- on: parseOnOff(config.get("ON")),
501
- off: parseOnOff(config.get("OFF")),
502
- order: parseOrder(config.get("Order")),
503
- groups: null,
504
- };
505
- }
506
-
507
- get numPages() {
508
- const obj = this.toplevelPagesDict.get("Count");
509
- if (!Number.isInteger(obj)) {
510
- throw new FormatError(
511
- "Page count in top-level pages dictionary is not an integer."
512
- );
513
- }
514
- return shadow(this, "numPages", obj);
515
- }
516
-
517
- get destinations() {
518
- const obj = this._readDests(),
519
- dests = Object.create(null);
520
- if (obj instanceof NameTree) {
521
- for (const [key, value] of obj.getAll()) {
522
- const dest = fetchDestination(value);
523
- if (dest) {
524
- dests[key] = dest;
525
- }
526
- }
527
- } else if (obj instanceof Dict) {
528
- obj.forEach(function (key, value) {
529
- const dest = fetchDestination(value);
530
- if (dest) {
531
- dests[key] = dest;
532
- }
533
- });
534
- }
535
- return shadow(this, "destinations", dests);
536
- }
537
-
538
- getDestination(id) {
539
- const obj = this._readDests();
540
- if (obj instanceof NameTree) {
541
- const dest = fetchDestination(obj.get(id));
542
- if (dest) {
543
- return dest;
544
- }
545
- // Fallback to checking the *entire* NameTree, in an attempt to handle
546
- // corrupt PDF documents with out-of-order NameTrees (fixes issue 10272).
547
- const allDest = this.destinations[id];
548
- if (allDest) {
549
- warn(`Found "${id}" at an incorrect position in the NameTree.`);
550
- return allDest;
551
- }
552
- } else if (obj instanceof Dict) {
553
- const dest = fetchDestination(obj.get(id));
554
- if (dest) {
555
- return dest;
556
- }
557
- }
558
- return null;
559
- }
560
-
561
- /**
562
- * @private
563
- */
564
- _readDests() {
565
- const obj = this._catDict.get("Names");
566
- if (obj && obj.has("Dests")) {
567
- return new NameTree(obj.getRaw("Dests"), this.xref);
568
- } else if (this._catDict.has("Dests")) {
569
- // Simple destination dictionary.
570
- return this._catDict.get("Dests");
571
- }
572
- return undefined;
573
- }
574
-
575
- get pageLabels() {
576
- let obj = null;
577
- try {
578
- obj = this._readPageLabels();
579
- } catch (ex) {
580
- if (ex instanceof MissingDataException) {
581
- throw ex;
582
- }
583
- warn("Unable to read page labels.");
584
- }
585
- return shadow(this, "pageLabels", obj);
586
- }
587
-
588
- /**
589
- * @private
590
- */
591
- _readPageLabels() {
592
- const obj = this._catDict.getRaw("PageLabels");
593
- if (!obj) {
594
- return null;
595
- }
596
-
597
- const pageLabels = new Array(this.numPages);
598
- let style = null,
599
- prefix = "";
600
-
601
- const numberTree = new NumberTree(obj, this.xref);
602
- const nums = numberTree.getAll();
603
- let currentLabel = "",
604
- currentIndex = 1;
605
-
606
- for (let i = 0, ii = this.numPages; i < ii; i++) {
607
- const labelDict = nums.get(i);
608
-
609
- if (labelDict !== undefined) {
610
- if (!isDict(labelDict)) {
611
- throw new FormatError("PageLabel is not a dictionary.");
612
- }
613
-
614
- if (
615
- labelDict.has("Type") &&
616
- !isName(labelDict.get("Type"), "PageLabel")
617
- ) {
618
- throw new FormatError("Invalid type in PageLabel dictionary.");
619
- }
620
-
621
- if (labelDict.has("S")) {
622
- const s = labelDict.get("S");
623
- if (!isName(s)) {
624
- throw new FormatError("Invalid style in PageLabel dictionary.");
625
- }
626
- style = s.name;
627
- } else {
628
- style = null;
629
- }
630
-
631
- if (labelDict.has("P")) {
632
- const p = labelDict.get("P");
633
- if (!isString(p)) {
634
- throw new FormatError("Invalid prefix in PageLabel dictionary.");
635
- }
636
- prefix = stringToPDFString(p);
637
- } else {
638
- prefix = "";
639
- }
640
-
641
- if (labelDict.has("St")) {
642
- const st = labelDict.get("St");
643
- if (!(Number.isInteger(st) && st >= 1)) {
644
- throw new FormatError("Invalid start in PageLabel dictionary.");
645
- }
646
- currentIndex = st;
647
- } else {
648
- currentIndex = 1;
649
- }
650
- }
651
-
652
- switch (style) {
653
- case "D":
654
- currentLabel = currentIndex;
655
- break;
656
- case "R":
657
- case "r":
658
- currentLabel = toRomanNumerals(currentIndex, style === "r");
659
- break;
660
- case "A":
661
- case "a":
662
- const LIMIT = 26; // Use only the characters A-Z, or a-z.
663
- const A_UPPER_CASE = 0x41,
664
- A_LOWER_CASE = 0x61;
665
-
666
- const baseCharCode = style === "a" ? A_LOWER_CASE : A_UPPER_CASE;
667
- const letterIndex = currentIndex - 1;
668
- const character = String.fromCharCode(
669
- baseCharCode + (letterIndex % LIMIT)
670
- );
671
- const charBuf = [];
672
- for (let j = 0, jj = (letterIndex / LIMIT) | 0; j <= jj; j++) {
673
- charBuf.push(character);
674
- }
675
- currentLabel = charBuf.join("");
676
- break;
677
- default:
678
- if (style) {
679
- throw new FormatError(
680
- `Invalid style "${style}" in PageLabel dictionary.`
681
- );
682
- }
683
- currentLabel = "";
684
- }
685
-
686
- pageLabels[i] = prefix + currentLabel;
687
- currentIndex++;
688
- }
689
- return pageLabels;
690
- }
691
-
692
- get pageLayout() {
693
- const obj = this._catDict.get("PageLayout");
694
- // Purposely use a non-standard default value, rather than 'SinglePage', to
695
- // allow differentiating between `undefined` and /SinglePage since that does
696
- // affect the Scroll mode (continuous/non-continuous) used in Adobe Reader.
697
- let pageLayout = "";
698
-
699
- if (isName(obj)) {
700
- switch (obj.name) {
701
- case "SinglePage":
702
- case "OneColumn":
703
- case "TwoColumnLeft":
704
- case "TwoColumnRight":
705
- case "TwoPageLeft":
706
- case "TwoPageRight":
707
- pageLayout = obj.name;
708
- }
709
- }
710
- return shadow(this, "pageLayout", pageLayout);
711
- }
712
-
713
- get pageMode() {
714
- const obj = this._catDict.get("PageMode");
715
- let pageMode = "UseNone"; // Default value.
716
-
717
- if (isName(obj)) {
718
- switch (obj.name) {
719
- case "UseNone":
720
- case "UseOutlines":
721
- case "UseThumbs":
722
- case "FullScreen":
723
- case "UseOC":
724
- case "UseAttachments":
725
- pageMode = obj.name;
726
- }
727
- }
728
- return shadow(this, "pageMode", pageMode);
729
- }
730
-
731
- get viewerPreferences() {
732
- const ViewerPreferencesValidators = {
733
- HideToolbar: isBool,
734
- HideMenubar: isBool,
735
- HideWindowUI: isBool,
736
- FitWindow: isBool,
737
- CenterWindow: isBool,
738
- DisplayDocTitle: isBool,
739
- NonFullScreenPageMode: isName,
740
- Direction: isName,
741
- ViewArea: isName,
742
- ViewClip: isName,
743
- PrintArea: isName,
744
- PrintClip: isName,
745
- PrintScaling: isName,
746
- Duplex: isName,
747
- PickTrayByPDFSize: isBool,
748
- PrintPageRange: Array.isArray,
749
- NumCopies: Number.isInteger,
750
- };
751
-
752
- const obj = this._catDict.get("ViewerPreferences");
753
- let prefs = null;
754
-
755
- if (isDict(obj)) {
756
- for (const key in ViewerPreferencesValidators) {
757
- if (!obj.has(key)) {
758
- continue;
759
- }
760
- const value = obj.get(key);
761
- // Make sure the (standard) value conforms to the specification.
762
- if (!ViewerPreferencesValidators[key](value)) {
763
- info(`Bad value in ViewerPreferences for "${key}".`);
764
- continue;
765
- }
766
- let prefValue;
767
-
768
- switch (key) {
769
- case "NonFullScreenPageMode":
770
- switch (value.name) {
771
- case "UseNone":
772
- case "UseOutlines":
773
- case "UseThumbs":
774
- case "UseOC":
775
- prefValue = value.name;
776
- break;
777
- default:
778
- prefValue = "UseNone";
779
- }
780
- break;
781
- case "Direction":
782
- switch (value.name) {
783
- case "L2R":
784
- case "R2L":
785
- prefValue = value.name;
786
- break;
787
- default:
788
- prefValue = "L2R";
789
- }
790
- break;
791
- case "ViewArea":
792
- case "ViewClip":
793
- case "PrintArea":
794
- case "PrintClip":
795
- switch (value.name) {
796
- case "MediaBox":
797
- case "CropBox":
798
- case "BleedBox":
799
- case "TrimBox":
800
- case "ArtBox":
801
- prefValue = value.name;
802
- break;
803
- default:
804
- prefValue = "CropBox";
805
- }
806
- break;
807
- case "PrintScaling":
808
- switch (value.name) {
809
- case "None":
810
- case "AppDefault":
811
- prefValue = value.name;
812
- break;
813
- default:
814
- prefValue = "AppDefault";
815
- }
816
- break;
817
- case "Duplex":
818
- switch (value.name) {
819
- case "Simplex":
820
- case "DuplexFlipShortEdge":
821
- case "DuplexFlipLongEdge":
822
- prefValue = value.name;
823
- break;
824
- default:
825
- prefValue = "None";
826
- }
827
- break;
828
- case "PrintPageRange":
829
- const length = value.length;
830
- if (length % 2 !== 0) {
831
- // The number of elements must be even.
832
- break;
833
- }
834
- const isValid = value.every((page, i, arr) => {
835
- return (
836
- Number.isInteger(page) &&
837
- page > 0 &&
838
- (i === 0 || page >= arr[i - 1]) &&
839
- page <= this.numPages
840
- );
841
- });
842
- if (isValid) {
843
- prefValue = value;
844
- }
845
- break;
846
- case "NumCopies":
847
- if (value > 0) {
848
- prefValue = value;
849
- }
850
- break;
851
- default:
852
- if (typeof value !== "boolean") {
853
- throw new FormatError(
854
- `viewerPreferences - expected a boolean value for: ${key}`
855
- );
856
- }
857
- prefValue = value;
858
- }
859
-
860
- if (prefValue !== undefined) {
861
- if (!prefs) {
862
- prefs = Object.create(null);
863
- }
864
- prefs[key] = prefValue;
865
- } else {
866
- info(`Bad value in ViewerPreferences for "${key}".`);
867
- }
868
- }
869
- }
870
- return shadow(this, "viewerPreferences", prefs);
871
- }
872
-
873
- get openAction() {
874
- const obj = this._catDict.get("OpenAction");
875
- const openAction = Object.create(null);
876
-
877
- if (isDict(obj)) {
878
- // Convert the OpenAction dictionary into a format that works with
879
- // `parseDestDictionary`, to avoid having to re-implement those checks.
880
- const destDict = new Dict(this.xref);
881
- destDict.set("A", obj);
882
-
883
- const resultObj = { url: null, dest: null, action: null };
884
- Catalog.parseDestDictionary({ destDict, resultObj });
885
-
886
- if (Array.isArray(resultObj.dest)) {
887
- openAction.dest = resultObj.dest;
888
- } else if (resultObj.action) {
889
- openAction.action = resultObj.action;
890
- }
891
- } else if (Array.isArray(obj)) {
892
- openAction.dest = obj;
893
- }
894
- return shadow(
895
- this,
896
- "openAction",
897
- objectSize(openAction) > 0 ? openAction : null
898
- );
899
- }
900
-
901
- get attachments() {
902
- const obj = this._catDict.get("Names");
903
- let attachments = null;
904
-
905
- if (obj instanceof Dict && obj.has("EmbeddedFiles")) {
906
- const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
907
- for (const [key, value] of nameTree.getAll()) {
908
- const fs = new FileSpec(value, this.xref);
909
- if (!attachments) {
910
- attachments = Object.create(null);
911
- }
912
- attachments[stringToPDFString(key)] = fs.serializable;
913
- }
914
- }
915
- return shadow(this, "attachments", attachments);
916
- }
917
-
918
- get xfaImages() {
919
- const obj = this._catDict.get("Names");
920
- let xfaImages = null;
921
-
922
- if (obj instanceof Dict && obj.has("XFAImages")) {
923
- const nameTree = new NameTree(obj.getRaw("XFAImages"), this.xref);
924
- for (const [key, value] of nameTree.getAll()) {
925
- if (!xfaImages) {
926
- xfaImages = new Dict(this.xref);
927
- }
928
- xfaImages.set(key, value);
929
- }
930
- }
931
- return shadow(this, "xfaImages", xfaImages);
932
- }
933
-
934
- _collectJavaScript() {
935
- const obj = this._catDict.get("Names");
936
- let javaScript = null;
937
-
938
- function appendIfJavaScriptDict(name, jsDict) {
939
- if (!(jsDict instanceof Dict)) {
940
- return;
941
- }
942
- if (!isName(jsDict.get("S"), "JavaScript")) {
943
- return;
944
- }
945
-
946
- let js = jsDict.get("JS");
947
- if (isStream(js)) {
948
- js = js.getString();
949
- } else if (typeof js !== "string") {
950
- return;
951
- }
952
-
953
- if (javaScript === null) {
954
- javaScript = new Map();
955
- }
956
- javaScript.set(name, stringToPDFString(js));
957
- }
958
-
959
- if (obj instanceof Dict && obj.has("JavaScript")) {
960
- const nameTree = new NameTree(obj.getRaw("JavaScript"), this.xref);
961
- for (const [key, value] of nameTree.getAll()) {
962
- appendIfJavaScriptDict(key, value);
963
- }
964
- }
965
- // Append OpenAction "JavaScript" actions, if any, to the JavaScript map.
966
- const openAction = this._catDict.get("OpenAction");
967
- if (openAction) {
968
- appendIfJavaScriptDict("OpenAction", openAction);
969
- }
970
-
971
- return javaScript;
972
- }
973
-
974
- get javaScript() {
975
- const javaScript = this._collectJavaScript();
976
- return shadow(
977
- this,
978
- "javaScript",
979
- javaScript ? [...javaScript.values()] : null
980
- );
981
- }
982
-
983
- get jsActions() {
984
- const javaScript = this._collectJavaScript();
985
- let actions = collectActions(
986
- this.xref,
987
- this._catDict,
988
- DocumentActionEventType
989
- );
990
-
991
- if (javaScript) {
992
- if (!actions) {
993
- actions = Object.create(null);
994
- }
995
- for (const [key, val] of javaScript) {
996
- if (key in actions) {
997
- actions[key].push(val);
998
- } else {
999
- actions[key] = [val];
1000
- }
1001
- }
1002
- }
1003
- return shadow(this, "jsActions", actions);
1004
- }
1005
-
1006
- fontFallback(id, handler) {
1007
- const promises = [];
1008
- this.fontCache.forEach(function (promise) {
1009
- promises.push(promise);
1010
- });
1011
-
1012
- return Promise.all(promises).then(translatedFonts => {
1013
- for (const translatedFont of translatedFonts) {
1014
- if (translatedFont.loadedName === id) {
1015
- translatedFont.fallback(handler);
1016
- return;
1017
- }
1018
- }
1019
- });
1020
- }
1021
-
1022
- cleanup(manuallyTriggered = false) {
1023
- clearPrimitiveCaches();
1024
- this.globalImageCache.clear(/* onlyData = */ manuallyTriggered);
1025
- this.pageKidsCountCache.clear();
1026
- this.pageIndexCache.clear();
1027
- this.nonBlendModesSet.clear();
1028
-
1029
- const promises = [];
1030
- this.fontCache.forEach(function (promise) {
1031
- promises.push(promise);
1032
- });
1033
-
1034
- return Promise.all(promises).then(translatedFonts => {
1035
- for (const { dict } of translatedFonts) {
1036
- delete dict.cacheKey;
1037
- }
1038
- this.fontCache.clear();
1039
- this.builtInCMapCache.clear();
1040
- this.standardFontDataCache.clear();
1041
- });
1042
- }
1043
-
1044
- getPageDict(pageIndex) {
1045
- const capability = createPromiseCapability();
1046
- const nodesToVisit = [this._catDict.getRaw("Pages")];
1047
- const visitedNodes = new RefSet();
1048
- const xref = this.xref,
1049
- pageKidsCountCache = this.pageKidsCountCache;
1050
- let count,
1051
- currentPageIndex = 0;
1052
-
1053
- function next() {
1054
- while (nodesToVisit.length) {
1055
- const currentNode = nodesToVisit.pop();
1056
-
1057
- if (isRef(currentNode)) {
1058
- count = pageKidsCountCache.get(currentNode);
1059
- // Skip nodes where the page can't be.
1060
- if (count > 0 && currentPageIndex + count < pageIndex) {
1061
- currentPageIndex += count;
1062
- continue;
1063
- }
1064
- // Prevent circular references in the /Pages tree.
1065
- if (visitedNodes.has(currentNode)) {
1066
- capability.reject(
1067
- new FormatError("Pages tree contains circular reference.")
1068
- );
1069
- return;
1070
- }
1071
- visitedNodes.put(currentNode);
1072
-
1073
- xref.fetchAsync(currentNode).then(function (obj) {
1074
- if (isDict(obj, "Page") || (isDict(obj) && !obj.has("Kids"))) {
1075
- if (pageIndex === currentPageIndex) {
1076
- // Cache the Page reference, since it can *greatly* improve
1077
- // performance by reducing redundant lookups in long documents
1078
- // where all nodes are found at *one* level of the tree.
1079
- if (currentNode && !pageKidsCountCache.has(currentNode)) {
1080
- pageKidsCountCache.put(currentNode, 1);
1081
- }
1082
- capability.resolve([obj, currentNode]);
1083
- } else {
1084
- currentPageIndex++;
1085
- next();
1086
- }
1087
- return;
1088
- }
1089
- nodesToVisit.push(obj);
1090
- next();
1091
- }, capability.reject);
1092
- return;
1093
- }
1094
-
1095
- // Must be a child page dictionary.
1096
- if (!isDict(currentNode)) {
1097
- capability.reject(
1098
- new FormatError(
1099
- "Page dictionary kid reference points to wrong type of object."
1100
- )
1101
- );
1102
- return;
1103
- }
1104
-
1105
- count = currentNode.get("Count");
1106
- if (Number.isInteger(count) && count >= 0) {
1107
- // Cache the Kids count, since it can reduce redundant lookups in
1108
- // documents where all nodes are found at *one* level of the tree.
1109
- const objId = currentNode.objId;
1110
- if (objId && !pageKidsCountCache.has(objId)) {
1111
- pageKidsCountCache.put(objId, count);
1112
- }
1113
- // Skip nodes where the page can't be.
1114
- if (currentPageIndex + count <= pageIndex) {
1115
- currentPageIndex += count;
1116
- continue;
1117
- }
1118
- }
1119
-
1120
- const kids = currentNode.get("Kids");
1121
- if (!Array.isArray(kids)) {
1122
- // Prevent errors in corrupt PDF documents that violate the
1123
- // specification by *inlining* Page dicts directly in the Kids
1124
- // array, rather than using indirect objects (fixes issue9540.pdf).
1125
- if (
1126
- isName(currentNode.get("Type"), "Page") ||
1127
- (!currentNode.has("Type") && currentNode.has("Contents"))
1128
- ) {
1129
- if (currentPageIndex === pageIndex) {
1130
- capability.resolve([currentNode, null]);
1131
- return;
1132
- }
1133
- currentPageIndex++;
1134
- continue;
1135
- }
1136
-
1137
- capability.reject(
1138
- new FormatError("Page dictionary kids object is not an array.")
1139
- );
1140
- return;
1141
- }
1142
-
1143
- // Always check all `Kids` nodes, to avoid getting stuck in an empty
1144
- // node further down in the tree (see issue5644.pdf, issue8088.pdf),
1145
- // and to ensure that we actually find the correct `Page` dict.
1146
- for (let last = kids.length - 1; last >= 0; last--) {
1147
- nodesToVisit.push(kids[last]);
1148
- }
1149
- }
1150
- capability.reject(new Error(`Page index ${pageIndex} not found.`));
1151
- }
1152
- next();
1153
- return capability.promise;
1154
- }
1155
-
1156
- getPageIndex(pageRef) {
1157
- const cachedPageIndex = this.pageIndexCache.get(pageRef);
1158
- if (cachedPageIndex !== undefined) {
1159
- return Promise.resolve(cachedPageIndex);
1160
- }
1161
-
1162
- // The page tree nodes have the count of all the leaves below them. To get
1163
- // how many pages are before we just have to walk up the tree and keep
1164
- // adding the count of siblings to the left of the node.
1165
- const xref = this.xref;
1166
-
1167
- function pagesBeforeRef(kidRef) {
1168
- let total = 0,
1169
- parentRef;
1170
-
1171
- return xref
1172
- .fetchAsync(kidRef)
1173
- .then(function (node) {
1174
- if (
1175
- isRefsEqual(kidRef, pageRef) &&
1176
- !isDict(node, "Page") &&
1177
- !(isDict(node) && !node.has("Type") && node.has("Contents"))
1178
- ) {
1179
- throw new FormatError(
1180
- "The reference does not point to a /Page dictionary."
1181
- );
1182
- }
1183
- if (!node) {
1184
- return null;
1185
- }
1186
- if (!isDict(node)) {
1187
- throw new FormatError("Node must be a dictionary.");
1188
- }
1189
- parentRef = node.getRaw("Parent");
1190
- return node.getAsync("Parent");
1191
- })
1192
- .then(function (parent) {
1193
- if (!parent) {
1194
- return null;
1195
- }
1196
- if (!isDict(parent)) {
1197
- throw new FormatError("Parent must be a dictionary.");
1198
- }
1199
- return parent.getAsync("Kids");
1200
- })
1201
- .then(function (kids) {
1202
- if (!kids) {
1203
- return null;
1204
- }
1205
-
1206
- const kidPromises = [];
1207
- let found = false;
1208
- for (let i = 0, ii = kids.length; i < ii; i++) {
1209
- const kid = kids[i];
1210
- if (!isRef(kid)) {
1211
- throw new FormatError("Kid must be a reference.");
1212
- }
1213
- if (isRefsEqual(kid, kidRef)) {
1214
- found = true;
1215
- break;
1216
- }
1217
- kidPromises.push(
1218
- xref.fetchAsync(kid).then(function (obj) {
1219
- if (!isDict(obj)) {
1220
- throw new FormatError("Kid node must be a dictionary.");
1221
- }
1222
- if (obj.has("Count")) {
1223
- total += obj.get("Count");
1224
- } else {
1225
- // Page leaf node.
1226
- total++;
1227
- }
1228
- })
1229
- );
1230
- }
1231
- if (!found) {
1232
- throw new FormatError("Kid reference not found in parent's kids.");
1233
- }
1234
- return Promise.all(kidPromises).then(function () {
1235
- return [total, parentRef];
1236
- });
1237
- });
1238
- }
1239
-
1240
- let total = 0;
1241
- const next = ref =>
1242
- pagesBeforeRef(ref).then(args => {
1243
- if (!args) {
1244
- this.pageIndexCache.put(pageRef, total);
1245
- return total;
1246
- }
1247
- const [count, parentRef] = args;
1248
- total += count;
1249
- return next(parentRef);
1250
- });
1251
-
1252
- return next(pageRef);
1253
- }
1254
-
1255
- /**
1256
- * @typedef ParseDestDictionaryParameters
1257
- * @property {Dict} destDict - The dictionary containing the destination.
1258
- * @property {Object} resultObj - The object where the parsed destination
1259
- * properties will be placed.
1260
- * @property {string} [docBaseUrl] - The document base URL that is used when
1261
- * attempting to recover valid absolute URLs from relative ones.
1262
- */
1263
-
1264
- /**
1265
- * Helper function used to parse the contents of destination dictionaries.
1266
- * @param {ParseDestDictionaryParameters} params
1267
- */
1268
- static parseDestDictionary(params) {
1269
- // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
1270
- function addDefaultProtocolToUrl(url) {
1271
- return url.startsWith("www.") ? `http://${url}` : url;
1272
- }
1273
-
1274
- // According to ISO 32000-1:2008, section 12.6.4.7, URIs should be encoded
1275
- // in 7-bit ASCII. Some bad PDFs use UTF-8 encoding; see Bugzilla 1122280.
1276
- function tryConvertUrlEncoding(url) {
1277
- try {
1278
- return stringToUTF8String(url);
1279
- } catch (e) {
1280
- return url;
1281
- }
1282
- }
1283
-
1284
- const destDict = params.destDict;
1285
- if (!isDict(destDict)) {
1286
- warn("parseDestDictionary: `destDict` must be a dictionary.");
1287
- return;
1288
- }
1289
- const resultObj = params.resultObj;
1290
- if (typeof resultObj !== "object") {
1291
- warn("parseDestDictionary: `resultObj` must be an object.");
1292
- return;
1293
- }
1294
- const docBaseUrl = params.docBaseUrl || null;
1295
-
1296
- let action = destDict.get("A"),
1297
- url,
1298
- dest;
1299
- if (!isDict(action)) {
1300
- if (destDict.has("Dest")) {
1301
- // A /Dest entry should *only* contain a Name or an Array, but some bad
1302
- // PDF generators ignore that and treat it as an /A entry.
1303
- action = destDict.get("Dest");
1304
- } else {
1305
- action = destDict.get("AA");
1306
- if (isDict(action)) {
1307
- if (action.has("D")) {
1308
- // MouseDown
1309
- action = action.get("D");
1310
- } else if (action.has("U")) {
1311
- // MouseUp
1312
- action = action.get("U");
1313
- }
1314
- }
1315
- }
1316
- }
1317
-
1318
- if (isDict(action)) {
1319
- const actionType = action.get("S");
1320
- if (!isName(actionType)) {
1321
- warn("parseDestDictionary: Invalid type in Action dictionary.");
1322
- return;
1323
- }
1324
- const actionName = actionType.name;
1325
-
1326
- switch (actionName) {
1327
- case "URI":
1328
- url = action.get("URI");
1329
- if (isName(url)) {
1330
- // Some bad PDFs do not put parentheses around relative URLs.
1331
- url = "/" + url.name;
1332
- } else if (isString(url)) {
1333
- url = addDefaultProtocolToUrl(url);
1334
- }
1335
- // TODO: pdf spec mentions urls can be relative to a Base
1336
- // entry in the dictionary.
1337
- break;
1338
-
1339
- case "GoTo":
1340
- dest = action.get("D");
1341
- break;
1342
-
1343
- case "Launch":
1344
- // We neither want, nor can, support arbitrary 'Launch' actions.
1345
- // However, in practice they are mostly used for linking to other PDF
1346
- // files, which we thus attempt to support (utilizing `docBaseUrl`).
1347
- /* falls through */
1348
-
1349
- case "GoToR":
1350
- const urlDict = action.get("F");
1351
- if (isDict(urlDict)) {
1352
- // We assume that we found a FileSpec dictionary
1353
- // and fetch the URL without checking any further.
1354
- url = urlDict.get("F") || null;
1355
- } else if (isString(urlDict)) {
1356
- url = urlDict;
1357
- }
1358
-
1359
- // NOTE: the destination is relative to the *remote* document.
1360
- let remoteDest = action.get("D");
1361
- if (remoteDest) {
1362
- if (isName(remoteDest)) {
1363
- remoteDest = remoteDest.name;
1364
- }
1365
- if (isString(url)) {
1366
- const baseUrl = url.split("#")[0];
1367
- if (isString(remoteDest)) {
1368
- url = baseUrl + "#" + remoteDest;
1369
- } else if (Array.isArray(remoteDest)) {
1370
- url = baseUrl + "#" + JSON.stringify(remoteDest);
1371
- }
1372
- }
1373
- }
1374
- // The 'NewWindow' property, equal to `LinkTarget.BLANK`.
1375
- const newWindow = action.get("NewWindow");
1376
- if (isBool(newWindow)) {
1377
- resultObj.newWindow = newWindow;
1378
- }
1379
- break;
1380
-
1381
- case "Named":
1382
- const namedAction = action.get("N");
1383
- if (isName(namedAction)) {
1384
- resultObj.action = namedAction.name;
1385
- }
1386
- break;
1387
-
1388
- case "JavaScript":
1389
- const jsAction = action.get("JS");
1390
- let js;
1391
-
1392
- if (isStream(jsAction)) {
1393
- js = jsAction.getString();
1394
- } else if (isString(jsAction)) {
1395
- js = jsAction;
1396
- }
1397
-
1398
- if (js) {
1399
- // Attempt to recover valid URLs from `JS` entries with certain
1400
- // white-listed formats:
1401
- // - window.open('http://example.com')
1402
- // - app.launchURL('http://example.com', true)
1403
- const URL_OPEN_METHODS = ["app.launchURL", "window.open"];
1404
- const regex = new RegExp(
1405
- "^\\s*(" +
1406
- URL_OPEN_METHODS.join("|").split(".").join("\\.") +
1407
- ")\\((?:'|\")([^'\"]*)(?:'|\")(?:,\\s*(\\w+)\\)|\\))",
1408
- "i"
1409
- );
1410
-
1411
- const jsUrl = regex.exec(stringToPDFString(js));
1412
- if (jsUrl && jsUrl[2]) {
1413
- url = jsUrl[2];
1414
-
1415
- if (jsUrl[3] === "true" && jsUrl[1] === "app.launchURL") {
1416
- resultObj.newWindow = true;
1417
- }
1418
- break;
1419
- }
1420
- }
1421
- /* falls through */
1422
- default:
1423
- if (
1424
- actionName === "JavaScript" ||
1425
- actionName === "ResetForm" ||
1426
- actionName === "SubmitForm"
1427
- ) {
1428
- // Don't bother the user with a warning for actions that require
1429
- // scripting support, since those will be handled separately.
1430
- break;
1431
- }
1432
- warn(`parseDestDictionary - unsupported action: "${actionName}".`);
1433
- break;
1434
- }
1435
- } else if (destDict.has("Dest")) {
1436
- // Simple destination.
1437
- dest = destDict.get("Dest");
1438
- }
1439
-
1440
- if (isString(url)) {
1441
- url = tryConvertUrlEncoding(url);
1442
- const absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl);
1443
- if (absoluteUrl) {
1444
- resultObj.url = absoluteUrl.href;
1445
- }
1446
- resultObj.unsafeUrl = url;
1447
- }
1448
- if (dest) {
1449
- if (isName(dest)) {
1450
- dest = dest.name;
1451
- }
1452
- if (isString(dest) || Array.isArray(dest)) {
1453
- resultObj.dest = dest;
1454
- }
1455
- }
1456
- }
1457
- }
1458
-
1459
- export { Catalog };