catalog.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2021 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. "use strict";
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.Catalog = void 0;
  27. var _primitives = require("./primitives.js");
  28. var _core_utils = require("./core_utils.js");
  29. var _util = require("../shared/util.js");
  30. var _name_number_tree = require("./name_number_tree.js");
  31. var _colorspace = require("./colorspace.js");
  32. var _file_spec = require("./file_spec.js");
  33. var _image_utils = require("./image_utils.js");
  34. var _metadata_parser = require("./metadata_parser.js");
  35. var _struct_tree = require("./struct_tree.js");
  36. function fetchDestination(dest) {
  37. if (dest instanceof _primitives.Dict) {
  38. dest = dest.get("D");
  39. }
  40. return Array.isArray(dest) ? dest : null;
  41. }
  42. class Catalog {
  43. constructor(pdfManager, xref) {
  44. this.pdfManager = pdfManager;
  45. this.xref = xref;
  46. this._catDict = xref.getCatalogObj();
  47. if (!(0, _primitives.isDict)(this._catDict)) {
  48. throw new _util.FormatError("Catalog object is not a dictionary.");
  49. }
  50. this.fontCache = new _primitives.RefSetCache();
  51. this.builtInCMapCache = new Map();
  52. this.standardFontDataCache = new Map();
  53. this.globalImageCache = new _image_utils.GlobalImageCache();
  54. this.pageKidsCountCache = new _primitives.RefSetCache();
  55. this.pageIndexCache = new _primitives.RefSetCache();
  56. this.nonBlendModesSet = new _primitives.RefSet();
  57. }
  58. get version() {
  59. const version = this._catDict.get("Version");
  60. if (!(0, _primitives.isName)(version)) {
  61. return (0, _util.shadow)(this, "version", null);
  62. }
  63. return (0, _util.shadow)(this, "version", version.name);
  64. }
  65. get collection() {
  66. let collection = null;
  67. try {
  68. const obj = this._catDict.get("Collection");
  69. if ((0, _primitives.isDict)(obj) && obj.size > 0) {
  70. collection = obj;
  71. }
  72. } catch (ex) {
  73. if (ex instanceof _core_utils.MissingDataException) {
  74. throw ex;
  75. }
  76. (0, _util.info)("Cannot fetch Collection entry; assuming no collection is present.");
  77. }
  78. return (0, _util.shadow)(this, "collection", collection);
  79. }
  80. get acroForm() {
  81. let acroForm = null;
  82. try {
  83. const obj = this._catDict.get("AcroForm");
  84. if ((0, _primitives.isDict)(obj) && obj.size > 0) {
  85. acroForm = obj;
  86. }
  87. } catch (ex) {
  88. if (ex instanceof _core_utils.MissingDataException) {
  89. throw ex;
  90. }
  91. (0, _util.info)("Cannot fetch AcroForm entry; assuming no forms are present.");
  92. }
  93. return (0, _util.shadow)(this, "acroForm", acroForm);
  94. }
  95. get metadata() {
  96. const streamRef = this._catDict.getRaw("Metadata");
  97. if (!(0, _primitives.isRef)(streamRef)) {
  98. return (0, _util.shadow)(this, "metadata", null);
  99. }
  100. const suppressEncryption = !(this.xref.encrypt && this.xref.encrypt.encryptMetadata);
  101. const stream = this.xref.fetch(streamRef, suppressEncryption);
  102. let metadata = null;
  103. if ((0, _primitives.isStream)(stream) && (0, _primitives.isDict)(stream.dict)) {
  104. const type = stream.dict.get("Type");
  105. const subtype = stream.dict.get("Subtype");
  106. if ((0, _primitives.isName)(type, "Metadata") && (0, _primitives.isName)(subtype, "XML")) {
  107. try {
  108. const data = (0, _util.stringToUTF8String)(stream.getString());
  109. if (data) {
  110. metadata = new _metadata_parser.MetadataParser(data).serializable;
  111. }
  112. } catch (e) {
  113. if (e instanceof _core_utils.MissingDataException) {
  114. throw e;
  115. }
  116. (0, _util.info)("Skipping invalid metadata.");
  117. }
  118. }
  119. }
  120. return (0, _util.shadow)(this, "metadata", metadata);
  121. }
  122. get markInfo() {
  123. let markInfo = null;
  124. try {
  125. markInfo = this._readMarkInfo();
  126. } catch (ex) {
  127. if (ex instanceof _core_utils.MissingDataException) {
  128. throw ex;
  129. }
  130. (0, _util.warn)("Unable to read mark info.");
  131. }
  132. return (0, _util.shadow)(this, "markInfo", markInfo);
  133. }
  134. _readMarkInfo() {
  135. const obj = this._catDict.get("MarkInfo");
  136. if (!(0, _primitives.isDict)(obj)) {
  137. return null;
  138. }
  139. const markInfo = Object.assign(Object.create(null), {
  140. Marked: false,
  141. UserProperties: false,
  142. Suspects: false
  143. });
  144. for (const key in markInfo) {
  145. if (!obj.has(key)) {
  146. continue;
  147. }
  148. const value = obj.get(key);
  149. if (!(0, _util.isBool)(value)) {
  150. continue;
  151. }
  152. markInfo[key] = value;
  153. }
  154. return markInfo;
  155. }
  156. get structTreeRoot() {
  157. let structTree = null;
  158. try {
  159. structTree = this._readStructTreeRoot();
  160. } catch (ex) {
  161. if (ex instanceof _core_utils.MissingDataException) {
  162. throw ex;
  163. }
  164. (0, _util.warn)("Unable read to structTreeRoot info.");
  165. }
  166. return (0, _util.shadow)(this, "structTreeRoot", structTree);
  167. }
  168. _readStructTreeRoot() {
  169. const obj = this._catDict.get("StructTreeRoot");
  170. if (!(0, _primitives.isDict)(obj)) {
  171. return null;
  172. }
  173. const root = new _struct_tree.StructTreeRoot(obj);
  174. root.init();
  175. return root;
  176. }
  177. get toplevelPagesDict() {
  178. const pagesObj = this._catDict.get("Pages");
  179. if (!(0, _primitives.isDict)(pagesObj)) {
  180. throw new _util.FormatError("Invalid top-level pages dictionary.");
  181. }
  182. return (0, _util.shadow)(this, "toplevelPagesDict", pagesObj);
  183. }
  184. get documentOutline() {
  185. let obj = null;
  186. try {
  187. obj = this._readDocumentOutline();
  188. } catch (ex) {
  189. if (ex instanceof _core_utils.MissingDataException) {
  190. throw ex;
  191. }
  192. (0, _util.warn)("Unable to read document outline.");
  193. }
  194. return (0, _util.shadow)(this, "documentOutline", obj);
  195. }
  196. _readDocumentOutline() {
  197. let obj = this._catDict.get("Outlines");
  198. if (!(0, _primitives.isDict)(obj)) {
  199. return null;
  200. }
  201. obj = obj.getRaw("First");
  202. if (!(0, _primitives.isRef)(obj)) {
  203. return null;
  204. }
  205. const root = {
  206. items: []
  207. };
  208. const queue = [{
  209. obj,
  210. parent: root
  211. }];
  212. const processed = new _primitives.RefSet();
  213. processed.put(obj);
  214. const xref = this.xref,
  215. blackColor = new Uint8ClampedArray(3);
  216. while (queue.length > 0) {
  217. const i = queue.shift();
  218. const outlineDict = xref.fetchIfRef(i.obj);
  219. if (outlineDict === null) {
  220. continue;
  221. }
  222. if (!outlineDict.has("Title")) {
  223. throw new _util.FormatError("Invalid outline item encountered.");
  224. }
  225. const data = {
  226. url: null,
  227. dest: null
  228. };
  229. Catalog.parseDestDictionary({
  230. destDict: outlineDict,
  231. resultObj: data,
  232. docBaseUrl: this.pdfManager.docBaseUrl
  233. });
  234. const title = outlineDict.get("Title");
  235. const flags = outlineDict.get("F") || 0;
  236. const color = outlineDict.getArray("C");
  237. const count = outlineDict.get("Count");
  238. let rgbColor = blackColor;
  239. if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
  240. rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0);
  241. }
  242. const outlineItem = {
  243. dest: data.dest,
  244. url: data.url,
  245. unsafeUrl: data.unsafeUrl,
  246. newWindow: data.newWindow,
  247. title: (0, _util.stringToPDFString)(title),
  248. color: rgbColor,
  249. count: Number.isInteger(count) ? count : undefined,
  250. bold: !!(flags & 2),
  251. italic: !!(flags & 1),
  252. items: []
  253. };
  254. i.parent.items.push(outlineItem);
  255. obj = outlineDict.getRaw("First");
  256. if ((0, _primitives.isRef)(obj) && !processed.has(obj)) {
  257. queue.push({
  258. obj,
  259. parent: outlineItem
  260. });
  261. processed.put(obj);
  262. }
  263. obj = outlineDict.getRaw("Next");
  264. if ((0, _primitives.isRef)(obj) && !processed.has(obj)) {
  265. queue.push({
  266. obj,
  267. parent: i.parent
  268. });
  269. processed.put(obj);
  270. }
  271. }
  272. return root.items.length > 0 ? root.items : null;
  273. }
  274. get permissions() {
  275. let permissions = null;
  276. try {
  277. permissions = this._readPermissions();
  278. } catch (ex) {
  279. if (ex instanceof _core_utils.MissingDataException) {
  280. throw ex;
  281. }
  282. (0, _util.warn)("Unable to read permissions.");
  283. }
  284. return (0, _util.shadow)(this, "permissions", permissions);
  285. }
  286. _readPermissions() {
  287. const encrypt = this.xref.trailer.get("Encrypt");
  288. if (!(0, _primitives.isDict)(encrypt)) {
  289. return null;
  290. }
  291. let flags = encrypt.get("P");
  292. if (!(0, _util.isNum)(flags)) {
  293. return null;
  294. }
  295. flags += 2 ** 32;
  296. const permissions = [];
  297. for (const key in _util.PermissionFlag) {
  298. const value = _util.PermissionFlag[key];
  299. if (flags & value) {
  300. permissions.push(value);
  301. }
  302. }
  303. return permissions;
  304. }
  305. get optionalContentConfig() {
  306. let config = null;
  307. try {
  308. const properties = this._catDict.get("OCProperties");
  309. if (!properties) {
  310. return (0, _util.shadow)(this, "optionalContentConfig", null);
  311. }
  312. const defaultConfig = properties.get("D");
  313. if (!defaultConfig) {
  314. return (0, _util.shadow)(this, "optionalContentConfig", null);
  315. }
  316. const groupsData = properties.get("OCGs");
  317. if (!Array.isArray(groupsData)) {
  318. return (0, _util.shadow)(this, "optionalContentConfig", null);
  319. }
  320. const groups = [];
  321. const groupRefs = [];
  322. for (const groupRef of groupsData) {
  323. if (!(0, _primitives.isRef)(groupRef)) {
  324. continue;
  325. }
  326. groupRefs.push(groupRef);
  327. const group = this.xref.fetchIfRef(groupRef);
  328. groups.push({
  329. id: groupRef.toString(),
  330. name: (0, _util.isString)(group.get("Name")) ? (0, _util.stringToPDFString)(group.get("Name")) : null,
  331. intent: (0, _util.isString)(group.get("Intent")) ? (0, _util.stringToPDFString)(group.get("Intent")) : null
  332. });
  333. }
  334. config = this._readOptionalContentConfig(defaultConfig, groupRefs);
  335. config.groups = groups;
  336. } catch (ex) {
  337. if (ex instanceof _core_utils.MissingDataException) {
  338. throw ex;
  339. }
  340. (0, _util.warn)(`Unable to read optional content config: ${ex}`);
  341. }
  342. return (0, _util.shadow)(this, "optionalContentConfig", config);
  343. }
  344. _readOptionalContentConfig(config, contentGroupRefs) {
  345. function parseOnOff(refs) {
  346. const onParsed = [];
  347. if (Array.isArray(refs)) {
  348. for (const value of refs) {
  349. if (!(0, _primitives.isRef)(value)) {
  350. continue;
  351. }
  352. if (contentGroupRefs.includes(value)) {
  353. onParsed.push(value.toString());
  354. }
  355. }
  356. }
  357. return onParsed;
  358. }
  359. function parseOrder(refs, nestedLevels = 0) {
  360. if (!Array.isArray(refs)) {
  361. return null;
  362. }
  363. const order = [];
  364. for (const value of refs) {
  365. if ((0, _primitives.isRef)(value) && contentGroupRefs.includes(value)) {
  366. parsedOrderRefs.put(value);
  367. order.push(value.toString());
  368. continue;
  369. }
  370. const nestedOrder = parseNestedOrder(value, nestedLevels);
  371. if (nestedOrder) {
  372. order.push(nestedOrder);
  373. }
  374. }
  375. if (nestedLevels > 0) {
  376. return order;
  377. }
  378. const hiddenGroups = [];
  379. for (const groupRef of contentGroupRefs) {
  380. if (parsedOrderRefs.has(groupRef)) {
  381. continue;
  382. }
  383. hiddenGroups.push(groupRef.toString());
  384. }
  385. if (hiddenGroups.length) {
  386. order.push({
  387. name: null,
  388. order: hiddenGroups
  389. });
  390. }
  391. return order;
  392. }
  393. function parseNestedOrder(ref, nestedLevels) {
  394. if (++nestedLevels > MAX_NESTED_LEVELS) {
  395. (0, _util.warn)("parseNestedOrder - reached MAX_NESTED_LEVELS.");
  396. return null;
  397. }
  398. const value = xref.fetchIfRef(ref);
  399. if (!Array.isArray(value)) {
  400. return null;
  401. }
  402. const nestedName = xref.fetchIfRef(value[0]);
  403. if (typeof nestedName !== "string") {
  404. return null;
  405. }
  406. const nestedOrder = parseOrder(value.slice(1), nestedLevels);
  407. if (!nestedOrder || !nestedOrder.length) {
  408. return null;
  409. }
  410. return {
  411. name: (0, _util.stringToPDFString)(nestedName),
  412. order: nestedOrder
  413. };
  414. }
  415. const xref = this.xref,
  416. parsedOrderRefs = new _primitives.RefSet(),
  417. MAX_NESTED_LEVELS = 10;
  418. return {
  419. name: (0, _util.isString)(config.get("Name")) ? (0, _util.stringToPDFString)(config.get("Name")) : null,
  420. creator: (0, _util.isString)(config.get("Creator")) ? (0, _util.stringToPDFString)(config.get("Creator")) : null,
  421. baseState: (0, _primitives.isName)(config.get("BaseState")) ? config.get("BaseState").name : null,
  422. on: parseOnOff(config.get("ON")),
  423. off: parseOnOff(config.get("OFF")),
  424. order: parseOrder(config.get("Order")),
  425. groups: null
  426. };
  427. }
  428. get numPages() {
  429. const obj = this.toplevelPagesDict.get("Count");
  430. if (!Number.isInteger(obj)) {
  431. throw new _util.FormatError("Page count in top-level pages dictionary is not an integer.");
  432. }
  433. return (0, _util.shadow)(this, "numPages", obj);
  434. }
  435. get destinations() {
  436. const obj = this._readDests(),
  437. dests = Object.create(null);
  438. if (obj instanceof _name_number_tree.NameTree) {
  439. for (const [key, value] of obj.getAll()) {
  440. const dest = fetchDestination(value);
  441. if (dest) {
  442. dests[key] = dest;
  443. }
  444. }
  445. } else if (obj instanceof _primitives.Dict) {
  446. obj.forEach(function (key, value) {
  447. const dest = fetchDestination(value);
  448. if (dest) {
  449. dests[key] = dest;
  450. }
  451. });
  452. }
  453. return (0, _util.shadow)(this, "destinations", dests);
  454. }
  455. getDestination(id) {
  456. const obj = this._readDests();
  457. if (obj instanceof _name_number_tree.NameTree) {
  458. const dest = fetchDestination(obj.get(id));
  459. if (dest) {
  460. return dest;
  461. }
  462. const allDest = this.destinations[id];
  463. if (allDest) {
  464. (0, _util.warn)(`Found "${id}" at an incorrect position in the NameTree.`);
  465. return allDest;
  466. }
  467. } else if (obj instanceof _primitives.Dict) {
  468. const dest = fetchDestination(obj.get(id));
  469. if (dest) {
  470. return dest;
  471. }
  472. }
  473. return null;
  474. }
  475. _readDests() {
  476. const obj = this._catDict.get("Names");
  477. if (obj && obj.has("Dests")) {
  478. return new _name_number_tree.NameTree(obj.getRaw("Dests"), this.xref);
  479. } else if (this._catDict.has("Dests")) {
  480. return this._catDict.get("Dests");
  481. }
  482. return undefined;
  483. }
  484. get pageLabels() {
  485. let obj = null;
  486. try {
  487. obj = this._readPageLabels();
  488. } catch (ex) {
  489. if (ex instanceof _core_utils.MissingDataException) {
  490. throw ex;
  491. }
  492. (0, _util.warn)("Unable to read page labels.");
  493. }
  494. return (0, _util.shadow)(this, "pageLabels", obj);
  495. }
  496. _readPageLabels() {
  497. const obj = this._catDict.getRaw("PageLabels");
  498. if (!obj) {
  499. return null;
  500. }
  501. const pageLabels = new Array(this.numPages);
  502. let style = null,
  503. prefix = "";
  504. const numberTree = new _name_number_tree.NumberTree(obj, this.xref);
  505. const nums = numberTree.getAll();
  506. let currentLabel = "",
  507. currentIndex = 1;
  508. for (let i = 0, ii = this.numPages; i < ii; i++) {
  509. const labelDict = nums.get(i);
  510. if (labelDict !== undefined) {
  511. if (!(0, _primitives.isDict)(labelDict)) {
  512. throw new _util.FormatError("PageLabel is not a dictionary.");
  513. }
  514. if (labelDict.has("Type") && !(0, _primitives.isName)(labelDict.get("Type"), "PageLabel")) {
  515. throw new _util.FormatError("Invalid type in PageLabel dictionary.");
  516. }
  517. if (labelDict.has("S")) {
  518. const s = labelDict.get("S");
  519. if (!(0, _primitives.isName)(s)) {
  520. throw new _util.FormatError("Invalid style in PageLabel dictionary.");
  521. }
  522. style = s.name;
  523. } else {
  524. style = null;
  525. }
  526. if (labelDict.has("P")) {
  527. const p = labelDict.get("P");
  528. if (!(0, _util.isString)(p)) {
  529. throw new _util.FormatError("Invalid prefix in PageLabel dictionary.");
  530. }
  531. prefix = (0, _util.stringToPDFString)(p);
  532. } else {
  533. prefix = "";
  534. }
  535. if (labelDict.has("St")) {
  536. const st = labelDict.get("St");
  537. if (!(Number.isInteger(st) && st >= 1)) {
  538. throw new _util.FormatError("Invalid start in PageLabel dictionary.");
  539. }
  540. currentIndex = st;
  541. } else {
  542. currentIndex = 1;
  543. }
  544. }
  545. switch (style) {
  546. case "D":
  547. currentLabel = currentIndex;
  548. break;
  549. case "R":
  550. case "r":
  551. currentLabel = (0, _core_utils.toRomanNumerals)(currentIndex, style === "r");
  552. break;
  553. case "A":
  554. case "a":
  555. const LIMIT = 26;
  556. const A_UPPER_CASE = 0x41,
  557. A_LOWER_CASE = 0x61;
  558. const baseCharCode = style === "a" ? A_LOWER_CASE : A_UPPER_CASE;
  559. const letterIndex = currentIndex - 1;
  560. const character = String.fromCharCode(baseCharCode + letterIndex % LIMIT);
  561. const charBuf = [];
  562. for (let j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) {
  563. charBuf.push(character);
  564. }
  565. currentLabel = charBuf.join("");
  566. break;
  567. default:
  568. if (style) {
  569. throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`);
  570. }
  571. currentLabel = "";
  572. }
  573. pageLabels[i] = prefix + currentLabel;
  574. currentIndex++;
  575. }
  576. return pageLabels;
  577. }
  578. get pageLayout() {
  579. const obj = this._catDict.get("PageLayout");
  580. let pageLayout = "";
  581. if ((0, _primitives.isName)(obj)) {
  582. switch (obj.name) {
  583. case "SinglePage":
  584. case "OneColumn":
  585. case "TwoColumnLeft":
  586. case "TwoColumnRight":
  587. case "TwoPageLeft":
  588. case "TwoPageRight":
  589. pageLayout = obj.name;
  590. }
  591. }
  592. return (0, _util.shadow)(this, "pageLayout", pageLayout);
  593. }
  594. get pageMode() {
  595. const obj = this._catDict.get("PageMode");
  596. let pageMode = "UseNone";
  597. if ((0, _primitives.isName)(obj)) {
  598. switch (obj.name) {
  599. case "UseNone":
  600. case "UseOutlines":
  601. case "UseThumbs":
  602. case "FullScreen":
  603. case "UseOC":
  604. case "UseAttachments":
  605. pageMode = obj.name;
  606. }
  607. }
  608. return (0, _util.shadow)(this, "pageMode", pageMode);
  609. }
  610. get viewerPreferences() {
  611. const ViewerPreferencesValidators = {
  612. HideToolbar: _util.isBool,
  613. HideMenubar: _util.isBool,
  614. HideWindowUI: _util.isBool,
  615. FitWindow: _util.isBool,
  616. CenterWindow: _util.isBool,
  617. DisplayDocTitle: _util.isBool,
  618. NonFullScreenPageMode: _primitives.isName,
  619. Direction: _primitives.isName,
  620. ViewArea: _primitives.isName,
  621. ViewClip: _primitives.isName,
  622. PrintArea: _primitives.isName,
  623. PrintClip: _primitives.isName,
  624. PrintScaling: _primitives.isName,
  625. Duplex: _primitives.isName,
  626. PickTrayByPDFSize: _util.isBool,
  627. PrintPageRange: Array.isArray,
  628. NumCopies: Number.isInteger
  629. };
  630. const obj = this._catDict.get("ViewerPreferences");
  631. let prefs = null;
  632. if ((0, _primitives.isDict)(obj)) {
  633. for (const key in ViewerPreferencesValidators) {
  634. if (!obj.has(key)) {
  635. continue;
  636. }
  637. const value = obj.get(key);
  638. if (!ViewerPreferencesValidators[key](value)) {
  639. (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`);
  640. continue;
  641. }
  642. let prefValue;
  643. switch (key) {
  644. case "NonFullScreenPageMode":
  645. switch (value.name) {
  646. case "UseNone":
  647. case "UseOutlines":
  648. case "UseThumbs":
  649. case "UseOC":
  650. prefValue = value.name;
  651. break;
  652. default:
  653. prefValue = "UseNone";
  654. }
  655. break;
  656. case "Direction":
  657. switch (value.name) {
  658. case "L2R":
  659. case "R2L":
  660. prefValue = value.name;
  661. break;
  662. default:
  663. prefValue = "L2R";
  664. }
  665. break;
  666. case "ViewArea":
  667. case "ViewClip":
  668. case "PrintArea":
  669. case "PrintClip":
  670. switch (value.name) {
  671. case "MediaBox":
  672. case "CropBox":
  673. case "BleedBox":
  674. case "TrimBox":
  675. case "ArtBox":
  676. prefValue = value.name;
  677. break;
  678. default:
  679. prefValue = "CropBox";
  680. }
  681. break;
  682. case "PrintScaling":
  683. switch (value.name) {
  684. case "None":
  685. case "AppDefault":
  686. prefValue = value.name;
  687. break;
  688. default:
  689. prefValue = "AppDefault";
  690. }
  691. break;
  692. case "Duplex":
  693. switch (value.name) {
  694. case "Simplex":
  695. case "DuplexFlipShortEdge":
  696. case "DuplexFlipLongEdge":
  697. prefValue = value.name;
  698. break;
  699. default:
  700. prefValue = "None";
  701. }
  702. break;
  703. case "PrintPageRange":
  704. const length = value.length;
  705. if (length % 2 !== 0) {
  706. break;
  707. }
  708. const isValid = value.every((page, i, arr) => {
  709. return Number.isInteger(page) && page > 0 && (i === 0 || page >= arr[i - 1]) && page <= this.numPages;
  710. });
  711. if (isValid) {
  712. prefValue = value;
  713. }
  714. break;
  715. case "NumCopies":
  716. if (value > 0) {
  717. prefValue = value;
  718. }
  719. break;
  720. default:
  721. if (typeof value !== "boolean") {
  722. throw new _util.FormatError(`viewerPreferences - expected a boolean value for: ${key}`);
  723. }
  724. prefValue = value;
  725. }
  726. if (prefValue !== undefined) {
  727. if (!prefs) {
  728. prefs = Object.create(null);
  729. }
  730. prefs[key] = prefValue;
  731. } else {
  732. (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`);
  733. }
  734. }
  735. }
  736. return (0, _util.shadow)(this, "viewerPreferences", prefs);
  737. }
  738. get openAction() {
  739. const obj = this._catDict.get("OpenAction");
  740. const openAction = Object.create(null);
  741. if ((0, _primitives.isDict)(obj)) {
  742. const destDict = new _primitives.Dict(this.xref);
  743. destDict.set("A", obj);
  744. const resultObj = {
  745. url: null,
  746. dest: null,
  747. action: null
  748. };
  749. Catalog.parseDestDictionary({
  750. destDict,
  751. resultObj
  752. });
  753. if (Array.isArray(resultObj.dest)) {
  754. openAction.dest = resultObj.dest;
  755. } else if (resultObj.action) {
  756. openAction.action = resultObj.action;
  757. }
  758. } else if (Array.isArray(obj)) {
  759. openAction.dest = obj;
  760. }
  761. return (0, _util.shadow)(this, "openAction", (0, _util.objectSize)(openAction) > 0 ? openAction : null);
  762. }
  763. get attachments() {
  764. const obj = this._catDict.get("Names");
  765. let attachments = null;
  766. if (obj instanceof _primitives.Dict && obj.has("EmbeddedFiles")) {
  767. const nameTree = new _name_number_tree.NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
  768. for (const [key, value] of nameTree.getAll()) {
  769. const fs = new _file_spec.FileSpec(value, this.xref);
  770. if (!attachments) {
  771. attachments = Object.create(null);
  772. }
  773. attachments[(0, _util.stringToPDFString)(key)] = fs.serializable;
  774. }
  775. }
  776. return (0, _util.shadow)(this, "attachments", attachments);
  777. }
  778. get xfaImages() {
  779. const obj = this._catDict.get("Names");
  780. let xfaImages = null;
  781. if (obj instanceof _primitives.Dict && obj.has("XFAImages")) {
  782. const nameTree = new _name_number_tree.NameTree(obj.getRaw("XFAImages"), this.xref);
  783. for (const [key, value] of nameTree.getAll()) {
  784. if (!xfaImages) {
  785. xfaImages = new _primitives.Dict(this.xref);
  786. }
  787. xfaImages.set(key, value);
  788. }
  789. }
  790. return (0, _util.shadow)(this, "xfaImages", xfaImages);
  791. }
  792. _collectJavaScript() {
  793. const obj = this._catDict.get("Names");
  794. let javaScript = null;
  795. function appendIfJavaScriptDict(name, jsDict) {
  796. if (!(jsDict instanceof _primitives.Dict)) {
  797. return;
  798. }
  799. if (!(0, _primitives.isName)(jsDict.get("S"), "JavaScript")) {
  800. return;
  801. }
  802. let js = jsDict.get("JS");
  803. if ((0, _primitives.isStream)(js)) {
  804. js = js.getString();
  805. } else if (typeof js !== "string") {
  806. return;
  807. }
  808. if (javaScript === null) {
  809. javaScript = new Map();
  810. }
  811. javaScript.set(name, (0, _util.stringToPDFString)(js));
  812. }
  813. if (obj instanceof _primitives.Dict && obj.has("JavaScript")) {
  814. const nameTree = new _name_number_tree.NameTree(obj.getRaw("JavaScript"), this.xref);
  815. for (const [key, value] of nameTree.getAll()) {
  816. appendIfJavaScriptDict(key, value);
  817. }
  818. }
  819. const openAction = this._catDict.get("OpenAction");
  820. if (openAction) {
  821. appendIfJavaScriptDict("OpenAction", openAction);
  822. }
  823. return javaScript;
  824. }
  825. get javaScript() {
  826. const javaScript = this._collectJavaScript();
  827. return (0, _util.shadow)(this, "javaScript", javaScript ? [...javaScript.values()] : null);
  828. }
  829. get jsActions() {
  830. const javaScript = this._collectJavaScript();
  831. let actions = (0, _core_utils.collectActions)(this.xref, this._catDict, _util.DocumentActionEventType);
  832. if (javaScript) {
  833. if (!actions) {
  834. actions = Object.create(null);
  835. }
  836. for (const [key, val] of javaScript) {
  837. if (key in actions) {
  838. actions[key].push(val);
  839. } else {
  840. actions[key] = [val];
  841. }
  842. }
  843. }
  844. return (0, _util.shadow)(this, "jsActions", actions);
  845. }
  846. fontFallback(id, handler) {
  847. const promises = [];
  848. this.fontCache.forEach(function (promise) {
  849. promises.push(promise);
  850. });
  851. return Promise.all(promises).then(translatedFonts => {
  852. for (const translatedFont of translatedFonts) {
  853. if (translatedFont.loadedName === id) {
  854. translatedFont.fallback(handler);
  855. return;
  856. }
  857. }
  858. });
  859. }
  860. cleanup(manuallyTriggered = false) {
  861. (0, _primitives.clearPrimitiveCaches)();
  862. this.globalImageCache.clear(manuallyTriggered);
  863. this.pageKidsCountCache.clear();
  864. this.pageIndexCache.clear();
  865. this.nonBlendModesSet.clear();
  866. const promises = [];
  867. this.fontCache.forEach(function (promise) {
  868. promises.push(promise);
  869. });
  870. return Promise.all(promises).then(translatedFonts => {
  871. for (const {
  872. dict
  873. } of translatedFonts) {
  874. delete dict.cacheKey;
  875. }
  876. this.fontCache.clear();
  877. this.builtInCMapCache.clear();
  878. this.standardFontDataCache.clear();
  879. });
  880. }
  881. getPageDict(pageIndex) {
  882. const capability = (0, _util.createPromiseCapability)();
  883. const nodesToVisit = [this._catDict.getRaw("Pages")];
  884. const visitedNodes = new _primitives.RefSet();
  885. const xref = this.xref,
  886. pageKidsCountCache = this.pageKidsCountCache;
  887. let count,
  888. currentPageIndex = 0;
  889. function next() {
  890. while (nodesToVisit.length) {
  891. const currentNode = nodesToVisit.pop();
  892. if ((0, _primitives.isRef)(currentNode)) {
  893. count = pageKidsCountCache.get(currentNode);
  894. if (count > 0 && currentPageIndex + count < pageIndex) {
  895. currentPageIndex += count;
  896. continue;
  897. }
  898. if (visitedNodes.has(currentNode)) {
  899. capability.reject(new _util.FormatError("Pages tree contains circular reference."));
  900. return;
  901. }
  902. visitedNodes.put(currentNode);
  903. xref.fetchAsync(currentNode).then(function (obj) {
  904. if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Kids")) {
  905. if (pageIndex === currentPageIndex) {
  906. if (currentNode && !pageKidsCountCache.has(currentNode)) {
  907. pageKidsCountCache.put(currentNode, 1);
  908. }
  909. capability.resolve([obj, currentNode]);
  910. } else {
  911. currentPageIndex++;
  912. next();
  913. }
  914. return;
  915. }
  916. nodesToVisit.push(obj);
  917. next();
  918. }, capability.reject);
  919. return;
  920. }
  921. if (!(0, _primitives.isDict)(currentNode)) {
  922. capability.reject(new _util.FormatError("Page dictionary kid reference points to wrong type of object."));
  923. return;
  924. }
  925. count = currentNode.get("Count");
  926. if (Number.isInteger(count) && count >= 0) {
  927. const objId = currentNode.objId;
  928. if (objId && !pageKidsCountCache.has(objId)) {
  929. pageKidsCountCache.put(objId, count);
  930. }
  931. if (currentPageIndex + count <= pageIndex) {
  932. currentPageIndex += count;
  933. continue;
  934. }
  935. }
  936. const kids = currentNode.get("Kids");
  937. if (!Array.isArray(kids)) {
  938. if ((0, _primitives.isName)(currentNode.get("Type"), "Page") || !currentNode.has("Type") && currentNode.has("Contents")) {
  939. if (currentPageIndex === pageIndex) {
  940. capability.resolve([currentNode, null]);
  941. return;
  942. }
  943. currentPageIndex++;
  944. continue;
  945. }
  946. capability.reject(new _util.FormatError("Page dictionary kids object is not an array."));
  947. return;
  948. }
  949. for (let last = kids.length - 1; last >= 0; last--) {
  950. nodesToVisit.push(kids[last]);
  951. }
  952. }
  953. capability.reject(new Error(`Page index ${pageIndex} not found.`));
  954. }
  955. next();
  956. return capability.promise;
  957. }
  958. getPageIndex(pageRef) {
  959. const cachedPageIndex = this.pageIndexCache.get(pageRef);
  960. if (cachedPageIndex !== undefined) {
  961. return Promise.resolve(cachedPageIndex);
  962. }
  963. const xref = this.xref;
  964. function pagesBeforeRef(kidRef) {
  965. let total = 0,
  966. parentRef;
  967. return xref.fetchAsync(kidRef).then(function (node) {
  968. if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, "Page") && !((0, _primitives.isDict)(node) && !node.has("Type") && node.has("Contents"))) {
  969. throw new _util.FormatError("The reference does not point to a /Page dictionary.");
  970. }
  971. if (!node) {
  972. return null;
  973. }
  974. if (!(0, _primitives.isDict)(node)) {
  975. throw new _util.FormatError("Node must be a dictionary.");
  976. }
  977. parentRef = node.getRaw("Parent");
  978. return node.getAsync("Parent");
  979. }).then(function (parent) {
  980. if (!parent) {
  981. return null;
  982. }
  983. if (!(0, _primitives.isDict)(parent)) {
  984. throw new _util.FormatError("Parent must be a dictionary.");
  985. }
  986. return parent.getAsync("Kids");
  987. }).then(function (kids) {
  988. if (!kids) {
  989. return null;
  990. }
  991. const kidPromises = [];
  992. let found = false;
  993. for (let i = 0, ii = kids.length; i < ii; i++) {
  994. const kid = kids[i];
  995. if (!(0, _primitives.isRef)(kid)) {
  996. throw new _util.FormatError("Kid must be a reference.");
  997. }
  998. if ((0, _primitives.isRefsEqual)(kid, kidRef)) {
  999. found = true;
  1000. break;
  1001. }
  1002. kidPromises.push(xref.fetchAsync(kid).then(function (obj) {
  1003. if (!(0, _primitives.isDict)(obj)) {
  1004. throw new _util.FormatError("Kid node must be a dictionary.");
  1005. }
  1006. if (obj.has("Count")) {
  1007. total += obj.get("Count");
  1008. } else {
  1009. total++;
  1010. }
  1011. }));
  1012. }
  1013. if (!found) {
  1014. throw new _util.FormatError("Kid reference not found in parent's kids.");
  1015. }
  1016. return Promise.all(kidPromises).then(function () {
  1017. return [total, parentRef];
  1018. });
  1019. });
  1020. }
  1021. let total = 0;
  1022. const next = ref => pagesBeforeRef(ref).then(args => {
  1023. if (!args) {
  1024. this.pageIndexCache.put(pageRef, total);
  1025. return total;
  1026. }
  1027. const [count, parentRef] = args;
  1028. total += count;
  1029. return next(parentRef);
  1030. });
  1031. return next(pageRef);
  1032. }
  1033. static parseDestDictionary(params) {
  1034. function addDefaultProtocolToUrl(url) {
  1035. return url.startsWith("www.") ? `http://${url}` : url;
  1036. }
  1037. function tryConvertUrlEncoding(url) {
  1038. try {
  1039. return (0, _util.stringToUTF8String)(url);
  1040. } catch (e) {
  1041. return url;
  1042. }
  1043. }
  1044. const destDict = params.destDict;
  1045. if (!(0, _primitives.isDict)(destDict)) {
  1046. (0, _util.warn)("parseDestDictionary: `destDict` must be a dictionary.");
  1047. return;
  1048. }
  1049. const resultObj = params.resultObj;
  1050. if (typeof resultObj !== "object") {
  1051. (0, _util.warn)("parseDestDictionary: `resultObj` must be an object.");
  1052. return;
  1053. }
  1054. const docBaseUrl = params.docBaseUrl || null;
  1055. let action = destDict.get("A"),
  1056. url,
  1057. dest;
  1058. if (!(0, _primitives.isDict)(action)) {
  1059. if (destDict.has("Dest")) {
  1060. action = destDict.get("Dest");
  1061. } else {
  1062. action = destDict.get("AA");
  1063. if ((0, _primitives.isDict)(action)) {
  1064. if (action.has("D")) {
  1065. action = action.get("D");
  1066. } else if (action.has("U")) {
  1067. action = action.get("U");
  1068. }
  1069. }
  1070. }
  1071. }
  1072. if ((0, _primitives.isDict)(action)) {
  1073. const actionType = action.get("S");
  1074. if (!(0, _primitives.isName)(actionType)) {
  1075. (0, _util.warn)("parseDestDictionary: Invalid type in Action dictionary.");
  1076. return;
  1077. }
  1078. const actionName = actionType.name;
  1079. switch (actionName) {
  1080. case "URI":
  1081. url = action.get("URI");
  1082. if ((0, _primitives.isName)(url)) {
  1083. url = "/" + url.name;
  1084. } else if ((0, _util.isString)(url)) {
  1085. url = addDefaultProtocolToUrl(url);
  1086. }
  1087. break;
  1088. case "GoTo":
  1089. dest = action.get("D");
  1090. break;
  1091. case "Launch":
  1092. case "GoToR":
  1093. const urlDict = action.get("F");
  1094. if ((0, _primitives.isDict)(urlDict)) {
  1095. url = urlDict.get("F") || null;
  1096. } else if ((0, _util.isString)(urlDict)) {
  1097. url = urlDict;
  1098. }
  1099. let remoteDest = action.get("D");
  1100. if (remoteDest) {
  1101. if ((0, _primitives.isName)(remoteDest)) {
  1102. remoteDest = remoteDest.name;
  1103. }
  1104. if ((0, _util.isString)(url)) {
  1105. const baseUrl = url.split("#")[0];
  1106. if ((0, _util.isString)(remoteDest)) {
  1107. url = baseUrl + "#" + remoteDest;
  1108. } else if (Array.isArray(remoteDest)) {
  1109. url = baseUrl + "#" + JSON.stringify(remoteDest);
  1110. }
  1111. }
  1112. }
  1113. const newWindow = action.get("NewWindow");
  1114. if ((0, _util.isBool)(newWindow)) {
  1115. resultObj.newWindow = newWindow;
  1116. }
  1117. break;
  1118. case "Named":
  1119. const namedAction = action.get("N");
  1120. if ((0, _primitives.isName)(namedAction)) {
  1121. resultObj.action = namedAction.name;
  1122. }
  1123. break;
  1124. case "JavaScript":
  1125. const jsAction = action.get("JS");
  1126. let js;
  1127. if ((0, _primitives.isStream)(jsAction)) {
  1128. js = jsAction.getString();
  1129. } else if ((0, _util.isString)(jsAction)) {
  1130. js = jsAction;
  1131. }
  1132. if (js) {
  1133. const URL_OPEN_METHODS = ["app.launchURL", "window.open"];
  1134. const regex = new RegExp("^\\s*(" + URL_OPEN_METHODS.join("|").split(".").join("\\.") + ")\\((?:'|\")([^'\"]*)(?:'|\")(?:,\\s*(\\w+)\\)|\\))", "i");
  1135. const jsUrl = regex.exec((0, _util.stringToPDFString)(js));
  1136. if (jsUrl && jsUrl[2]) {
  1137. url = jsUrl[2];
  1138. if (jsUrl[3] === "true" && jsUrl[1] === "app.launchURL") {
  1139. resultObj.newWindow = true;
  1140. }
  1141. break;
  1142. }
  1143. }
  1144. default:
  1145. if (actionName === "JavaScript" || actionName === "ResetForm" || actionName === "SubmitForm") {
  1146. break;
  1147. }
  1148. (0, _util.warn)(`parseDestDictionary - unsupported action: "${actionName}".`);
  1149. break;
  1150. }
  1151. } else if (destDict.has("Dest")) {
  1152. dest = destDict.get("Dest");
  1153. }
  1154. if ((0, _util.isString)(url)) {
  1155. url = tryConvertUrlEncoding(url);
  1156. const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl);
  1157. if (absoluteUrl) {
  1158. resultObj.url = absoluteUrl.href;
  1159. }
  1160. resultObj.unsafeUrl = url;
  1161. }
  1162. if (dest) {
  1163. if ((0, _primitives.isName)(dest)) {
  1164. dest = dest.name;
  1165. }
  1166. if ((0, _util.isString)(dest) || Array.isArray(dest)) {
  1167. resultObj.dest = dest;
  1168. }
  1169. }
  1170. }
  1171. }
  1172. exports.Catalog = Catalog;