catalog.js 37 KB

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