obj.js 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478
  1. /* Copyright 2017 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. 'use strict';
  16. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  17. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  18. var sharedUtil = require('../shared/util.js');
  19. var corePrimitives = require('./primitives.js');
  20. var coreCrypto = require('./crypto.js');
  21. var coreParser = require('./parser.js');
  22. var coreChunkedStream = require('./chunked_stream.js');
  23. var coreColorSpace = require('./colorspace.js');
  24. var InvalidPDFException = sharedUtil.InvalidPDFException;
  25. var MissingDataException = sharedUtil.MissingDataException;
  26. var XRefParseException = sharedUtil.XRefParseException;
  27. var assert = sharedUtil.assert;
  28. var bytesToString = sharedUtil.bytesToString;
  29. var createPromiseCapability = sharedUtil.createPromiseCapability;
  30. var error = sharedUtil.error;
  31. var info = sharedUtil.info;
  32. var isArray = sharedUtil.isArray;
  33. var isBool = sharedUtil.isBool;
  34. var isInt = sharedUtil.isInt;
  35. var isString = sharedUtil.isString;
  36. var shadow = sharedUtil.shadow;
  37. var stringToPDFString = sharedUtil.stringToPDFString;
  38. var stringToUTF8String = sharedUtil.stringToUTF8String;
  39. var warn = sharedUtil.warn;
  40. var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl;
  41. var Util = sharedUtil.Util;
  42. var Dict = corePrimitives.Dict;
  43. var Ref = corePrimitives.Ref;
  44. var RefSet = corePrimitives.RefSet;
  45. var RefSetCache = corePrimitives.RefSetCache;
  46. var isName = corePrimitives.isName;
  47. var isCmd = corePrimitives.isCmd;
  48. var isDict = corePrimitives.isDict;
  49. var isRef = corePrimitives.isRef;
  50. var isRefsEqual = corePrimitives.isRefsEqual;
  51. var isStream = corePrimitives.isStream;
  52. var CipherTransformFactory = coreCrypto.CipherTransformFactory;
  53. var Lexer = coreParser.Lexer;
  54. var Parser = coreParser.Parser;
  55. var ChunkedStream = coreChunkedStream.ChunkedStream;
  56. var ColorSpace = coreColorSpace.ColorSpace;
  57. var Catalog = function CatalogClosure() {
  58. function Catalog(pdfManager, xref, pageFactory) {
  59. this.pdfManager = pdfManager;
  60. this.xref = xref;
  61. this.catDict = xref.getCatalogObj();
  62. assert(isDict(this.catDict), 'catalog object is not a dictionary');
  63. this.fontCache = new RefSetCache();
  64. this.builtInCMapCache = Object.create(null);
  65. this.pageKidsCountCache = new RefSetCache();
  66. this.pageFactory = pageFactory;
  67. this.pagePromises = [];
  68. }
  69. Catalog.prototype = {
  70. get metadata() {
  71. var streamRef = this.catDict.getRaw('Metadata');
  72. if (!isRef(streamRef)) {
  73. return shadow(this, 'metadata', null);
  74. }
  75. var encryptMetadata = !this.xref.encrypt ? false : this.xref.encrypt.encryptMetadata;
  76. var stream = this.xref.fetch(streamRef, !encryptMetadata);
  77. var metadata;
  78. if (stream && isDict(stream.dict)) {
  79. var type = stream.dict.get('Type');
  80. var subtype = stream.dict.get('Subtype');
  81. if (isName(type, 'Metadata') && isName(subtype, 'XML')) {
  82. try {
  83. metadata = stringToUTF8String(bytesToString(stream.getBytes()));
  84. } catch (e) {
  85. if (e instanceof MissingDataException) {
  86. throw e;
  87. }
  88. info('Skipping invalid metadata.');
  89. }
  90. }
  91. }
  92. return shadow(this, 'metadata', metadata);
  93. },
  94. get toplevelPagesDict() {
  95. var pagesObj = this.catDict.get('Pages');
  96. assert(isDict(pagesObj), 'invalid top-level pages dictionary');
  97. return shadow(this, 'toplevelPagesDict', pagesObj);
  98. },
  99. get documentOutline() {
  100. var obj = null;
  101. try {
  102. obj = this.readDocumentOutline();
  103. } catch (ex) {
  104. if (ex instanceof MissingDataException) {
  105. throw ex;
  106. }
  107. warn('Unable to read document outline');
  108. }
  109. return shadow(this, 'documentOutline', obj);
  110. },
  111. readDocumentOutline: function Catalog_readDocumentOutline() {
  112. var obj = this.catDict.get('Outlines');
  113. if (!isDict(obj)) {
  114. return null;
  115. }
  116. obj = obj.getRaw('First');
  117. if (!isRef(obj)) {
  118. return null;
  119. }
  120. var root = { items: [] };
  121. var queue = [{
  122. obj: obj,
  123. parent: root
  124. }];
  125. var processed = new RefSet();
  126. processed.put(obj);
  127. var xref = this.xref,
  128. blackColor = new Uint8Array(3);
  129. while (queue.length > 0) {
  130. var i = queue.shift();
  131. var outlineDict = xref.fetchIfRef(i.obj);
  132. if (outlineDict === null) {
  133. continue;
  134. }
  135. assert(outlineDict.has('Title'), 'Invalid outline item');
  136. var data = {
  137. url: null,
  138. dest: null
  139. };
  140. Catalog.parseDestDictionary({
  141. destDict: outlineDict,
  142. resultObj: data,
  143. docBaseUrl: this.pdfManager.docBaseUrl
  144. });
  145. var title = outlineDict.get('Title');
  146. var flags = outlineDict.get('F') || 0;
  147. var color = outlineDict.getArray('C'),
  148. rgbColor = blackColor;
  149. if (isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
  150. rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
  151. }
  152. var outlineItem = {
  153. dest: data.dest,
  154. url: data.url,
  155. unsafeUrl: data.unsafeUrl,
  156. newWindow: data.newWindow,
  157. title: stringToPDFString(title),
  158. color: rgbColor,
  159. count: outlineDict.get('Count'),
  160. bold: !!(flags & 2),
  161. italic: !!(flags & 1),
  162. items: []
  163. };
  164. i.parent.items.push(outlineItem);
  165. obj = outlineDict.getRaw('First');
  166. if (isRef(obj) && !processed.has(obj)) {
  167. queue.push({
  168. obj: obj,
  169. parent: outlineItem
  170. });
  171. processed.put(obj);
  172. }
  173. obj = outlineDict.getRaw('Next');
  174. if (isRef(obj) && !processed.has(obj)) {
  175. queue.push({
  176. obj: obj,
  177. parent: i.parent
  178. });
  179. processed.put(obj);
  180. }
  181. }
  182. return root.items.length > 0 ? root.items : null;
  183. },
  184. get numPages() {
  185. var obj = this.toplevelPagesDict.get('Count');
  186. assert(isInt(obj), 'page count in top level pages object is not an integer');
  187. return shadow(this, 'num', obj);
  188. },
  189. get destinations() {
  190. function fetchDestination(dest) {
  191. return isDict(dest) ? dest.get('D') : dest;
  192. }
  193. var xref = this.xref;
  194. var dests = {},
  195. nameTreeRef,
  196. nameDictionaryRef;
  197. var obj = this.catDict.get('Names');
  198. if (obj && obj.has('Dests')) {
  199. nameTreeRef = obj.getRaw('Dests');
  200. } else if (this.catDict.has('Dests')) {
  201. nameDictionaryRef = this.catDict.get('Dests');
  202. }
  203. if (nameDictionaryRef) {
  204. obj = nameDictionaryRef;
  205. obj.forEach(function catalogForEach(key, value) {
  206. if (!value) {
  207. return;
  208. }
  209. dests[key] = fetchDestination(value);
  210. });
  211. }
  212. if (nameTreeRef) {
  213. var nameTree = new NameTree(nameTreeRef, xref);
  214. var names = nameTree.getAll();
  215. for (var name in names) {
  216. dests[name] = fetchDestination(names[name]);
  217. }
  218. }
  219. return shadow(this, 'destinations', dests);
  220. },
  221. getDestination: function Catalog_getDestination(destinationId) {
  222. function fetchDestination(dest) {
  223. return isDict(dest) ? dest.get('D') : dest;
  224. }
  225. var xref = this.xref;
  226. var dest = null,
  227. nameTreeRef,
  228. nameDictionaryRef;
  229. var obj = this.catDict.get('Names');
  230. if (obj && obj.has('Dests')) {
  231. nameTreeRef = obj.getRaw('Dests');
  232. } else if (this.catDict.has('Dests')) {
  233. nameDictionaryRef = this.catDict.get('Dests');
  234. }
  235. if (nameDictionaryRef) {
  236. var value = nameDictionaryRef.get(destinationId);
  237. if (value) {
  238. dest = fetchDestination(value);
  239. }
  240. }
  241. if (nameTreeRef) {
  242. var nameTree = new NameTree(nameTreeRef, xref);
  243. dest = fetchDestination(nameTree.get(destinationId));
  244. }
  245. return dest;
  246. },
  247. get pageLabels() {
  248. var obj = null;
  249. try {
  250. obj = this.readPageLabels();
  251. } catch (ex) {
  252. if (ex instanceof MissingDataException) {
  253. throw ex;
  254. }
  255. warn('Unable to read page labels.');
  256. }
  257. return shadow(this, 'pageLabels', obj);
  258. },
  259. readPageLabels: function Catalog_readPageLabels() {
  260. var obj = this.catDict.getRaw('PageLabels');
  261. if (!obj) {
  262. return null;
  263. }
  264. var pageLabels = new Array(this.numPages);
  265. var style = null;
  266. var prefix = '';
  267. var numberTree = new NumberTree(obj, this.xref);
  268. var nums = numberTree.getAll();
  269. var currentLabel = '',
  270. currentIndex = 1;
  271. for (var i = 0, ii = this.numPages; i < ii; i++) {
  272. if (i in nums) {
  273. var labelDict = nums[i];
  274. assert(isDict(labelDict), 'The PageLabel is not a dictionary.');
  275. var type = labelDict.get('Type');
  276. assert(!type || isName(type, 'PageLabel'), 'Invalid type in PageLabel dictionary.');
  277. var s = labelDict.get('S');
  278. assert(!s || isName(s), 'Invalid style in PageLabel dictionary.');
  279. style = s ? s.name : null;
  280. var p = labelDict.get('P');
  281. assert(!p || isString(p), 'Invalid prefix in PageLabel dictionary.');
  282. prefix = p ? stringToPDFString(p) : '';
  283. var st = labelDict.get('St');
  284. assert(!st || isInt(st) && st >= 1, 'Invalid start in PageLabel dictionary.');
  285. currentIndex = st || 1;
  286. }
  287. switch (style) {
  288. case 'D':
  289. currentLabel = currentIndex;
  290. break;
  291. case 'R':
  292. case 'r':
  293. currentLabel = Util.toRoman(currentIndex, style === 'r');
  294. break;
  295. case 'A':
  296. case 'a':
  297. var LIMIT = 26;
  298. var A_UPPER_CASE = 0x41,
  299. A_LOWER_CASE = 0x61;
  300. var baseCharCode = style === 'a' ? A_LOWER_CASE : A_UPPER_CASE;
  301. var letterIndex = currentIndex - 1;
  302. var character = String.fromCharCode(baseCharCode + letterIndex % LIMIT);
  303. var charBuf = [];
  304. for (var j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) {
  305. charBuf.push(character);
  306. }
  307. currentLabel = charBuf.join('');
  308. break;
  309. default:
  310. assert(!style, 'Invalid style "' + style + '" in PageLabel dictionary.');
  311. }
  312. pageLabels[i] = prefix + currentLabel;
  313. currentLabel = '';
  314. currentIndex++;
  315. }
  316. return pageLabels;
  317. },
  318. get attachments() {
  319. var xref = this.xref;
  320. var attachments = null,
  321. nameTreeRef;
  322. var obj = this.catDict.get('Names');
  323. if (obj) {
  324. nameTreeRef = obj.getRaw('EmbeddedFiles');
  325. }
  326. if (nameTreeRef) {
  327. var nameTree = new NameTree(nameTreeRef, xref);
  328. var names = nameTree.getAll();
  329. for (var name in names) {
  330. var fs = new FileSpec(names[name], xref);
  331. if (!attachments) {
  332. attachments = Object.create(null);
  333. }
  334. attachments[stringToPDFString(name)] = fs.serializable;
  335. }
  336. }
  337. return shadow(this, 'attachments', attachments);
  338. },
  339. get javaScript() {
  340. var xref = this.xref;
  341. var obj = this.catDict.get('Names');
  342. var javaScript = [];
  343. function appendIfJavaScriptDict(jsDict) {
  344. var type = jsDict.get('S');
  345. if (!isName(type, 'JavaScript')) {
  346. return;
  347. }
  348. var js = jsDict.get('JS');
  349. if (isStream(js)) {
  350. js = bytesToString(js.getBytes());
  351. } else if (!isString(js)) {
  352. return;
  353. }
  354. javaScript.push(stringToPDFString(js));
  355. }
  356. if (obj && obj.has('JavaScript')) {
  357. var nameTree = new NameTree(obj.getRaw('JavaScript'), xref);
  358. var names = nameTree.getAll();
  359. for (var name in names) {
  360. var jsDict = names[name];
  361. if (isDict(jsDict)) {
  362. appendIfJavaScriptDict(jsDict);
  363. }
  364. }
  365. }
  366. var openactionDict = this.catDict.get('OpenAction');
  367. if (isDict(openactionDict, 'Action')) {
  368. var actionType = openactionDict.get('S');
  369. if (isName(actionType, 'Named')) {
  370. var action = openactionDict.get('N');
  371. if (isName(action, 'Print')) {
  372. javaScript.push('print({});');
  373. }
  374. } else {
  375. appendIfJavaScriptDict(openactionDict);
  376. }
  377. }
  378. return shadow(this, 'javaScript', javaScript);
  379. },
  380. cleanup: function Catalog_cleanup() {
  381. var _this = this;
  382. this.pageKidsCountCache.clear();
  383. var promises = [];
  384. this.fontCache.forEach(function (promise) {
  385. promises.push(promise);
  386. });
  387. return Promise.all(promises).then(function (translatedFonts) {
  388. for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
  389. var font = translatedFonts[i].dict;
  390. delete font.translated;
  391. }
  392. _this.fontCache.clear();
  393. _this.builtInCMapCache = Object.create(null);
  394. });
  395. },
  396. getPage: function Catalog_getPage(pageIndex) {
  397. var _this2 = this;
  398. if (!(pageIndex in this.pagePromises)) {
  399. this.pagePromises[pageIndex] = this.getPageDict(pageIndex).then(function (_ref) {
  400. var _ref2 = _slicedToArray(_ref, 2),
  401. dict = _ref2[0],
  402. ref = _ref2[1];
  403. return _this2.pageFactory.createPage(pageIndex, dict, ref, _this2.fontCache, _this2.builtInCMapCache);
  404. });
  405. }
  406. return this.pagePromises[pageIndex];
  407. },
  408. getPageDict: function Catalog_getPageDict(pageIndex) {
  409. var capability = createPromiseCapability();
  410. var nodesToVisit = [this.catDict.getRaw('Pages')];
  411. var count,
  412. currentPageIndex = 0;
  413. var xref = this.xref,
  414. pageKidsCountCache = this.pageKidsCountCache;
  415. function next() {
  416. while (nodesToVisit.length) {
  417. var currentNode = nodesToVisit.pop();
  418. if (isRef(currentNode)) {
  419. count = pageKidsCountCache.get(currentNode);
  420. if (count > 0 && currentPageIndex + count < pageIndex) {
  421. currentPageIndex += count;
  422. continue;
  423. }
  424. xref.fetchAsync(currentNode).then(function (obj) {
  425. if (isDict(obj, 'Page') || isDict(obj) && !obj.has('Kids')) {
  426. if (pageIndex === currentPageIndex) {
  427. if (currentNode && !pageKidsCountCache.has(currentNode)) {
  428. pageKidsCountCache.put(currentNode, 1);
  429. }
  430. capability.resolve([obj, currentNode]);
  431. } else {
  432. currentPageIndex++;
  433. next();
  434. }
  435. return;
  436. }
  437. nodesToVisit.push(obj);
  438. next();
  439. }, capability.reject);
  440. return;
  441. }
  442. assert(isDict(currentNode), 'page dictionary kid reference points to wrong type of object');
  443. count = currentNode.get('Count');
  444. var objId = currentNode.objId;
  445. if (objId && !pageKidsCountCache.has(objId)) {
  446. pageKidsCountCache.put(objId, count);
  447. }
  448. if (currentPageIndex + count <= pageIndex) {
  449. currentPageIndex += count;
  450. continue;
  451. }
  452. var kids = currentNode.get('Kids');
  453. assert(isArray(kids), 'page dictionary kids object is not an array');
  454. for (var last = kids.length - 1; last >= 0; last--) {
  455. nodesToVisit.push(kids[last]);
  456. }
  457. }
  458. capability.reject('Page index ' + pageIndex + ' not found.');
  459. }
  460. next();
  461. return capability.promise;
  462. },
  463. getPageIndex: function Catalog_getPageIndex(pageRef) {
  464. var xref = this.xref;
  465. function pagesBeforeRef(kidRef) {
  466. var total = 0;
  467. var parentRef;
  468. return xref.fetchAsync(kidRef).then(function (node) {
  469. if (isRefsEqual(kidRef, pageRef) && !isDict(node, 'Page') && !(isDict(node) && !node.has('Type') && node.has('Contents'))) {
  470. throw new Error('The reference does not point to a /Page Dict.');
  471. }
  472. if (!node) {
  473. return null;
  474. }
  475. assert(isDict(node), 'node must be a Dict.');
  476. parentRef = node.getRaw('Parent');
  477. return node.getAsync('Parent');
  478. }).then(function (parent) {
  479. if (!parent) {
  480. return null;
  481. }
  482. assert(isDict(parent), 'parent must be a Dict.');
  483. return parent.getAsync('Kids');
  484. }).then(function (kids) {
  485. if (!kids) {
  486. return null;
  487. }
  488. var kidPromises = [];
  489. var found = false;
  490. for (var i = 0; i < kids.length; i++) {
  491. var kid = kids[i];
  492. assert(isRef(kid), 'kid must be a Ref.');
  493. if (kid.num === kidRef.num) {
  494. found = true;
  495. break;
  496. }
  497. kidPromises.push(xref.fetchAsync(kid).then(function (kid) {
  498. if (kid.has('Count')) {
  499. var count = kid.get('Count');
  500. total += count;
  501. } else {
  502. total++;
  503. }
  504. }));
  505. }
  506. if (!found) {
  507. error('kid ref not found in parents kids');
  508. }
  509. return Promise.all(kidPromises).then(function () {
  510. return [total, parentRef];
  511. });
  512. });
  513. }
  514. var total = 0;
  515. function next(ref) {
  516. return pagesBeforeRef(ref).then(function (args) {
  517. if (!args) {
  518. return total;
  519. }
  520. var count = args[0];
  521. var parentRef = args[1];
  522. total += count;
  523. return next(parentRef);
  524. });
  525. }
  526. return next(pageRef);
  527. }
  528. };
  529. Catalog.parseDestDictionary = function Catalog_parseDestDictionary(params) {
  530. function addDefaultProtocolToUrl(url) {
  531. if (url.indexOf('www.') === 0) {
  532. return 'http://' + url;
  533. }
  534. return url;
  535. }
  536. function tryConvertUrlEncoding(url) {
  537. try {
  538. return stringToUTF8String(url);
  539. } catch (e) {
  540. return url;
  541. }
  542. }
  543. var destDict = params.destDict;
  544. if (!isDict(destDict)) {
  545. warn('Catalog_parseDestDictionary: "destDict" must be a dictionary.');
  546. return;
  547. }
  548. var resultObj = params.resultObj;
  549. if ((typeof resultObj === 'undefined' ? 'undefined' : _typeof(resultObj)) !== 'object') {
  550. warn('Catalog_parseDestDictionary: "resultObj" must be an object.');
  551. return;
  552. }
  553. var docBaseUrl = params.docBaseUrl || null;
  554. var action = destDict.get('A'),
  555. url,
  556. dest;
  557. if (isDict(action)) {
  558. var linkType = action.get('S').name;
  559. switch (linkType) {
  560. case 'URI':
  561. url = action.get('URI');
  562. if (isName(url)) {
  563. url = '/' + url.name;
  564. } else if (isString(url)) {
  565. url = addDefaultProtocolToUrl(url);
  566. }
  567. break;
  568. case 'GoTo':
  569. dest = action.get('D');
  570. break;
  571. case 'Launch':
  572. case 'GoToR':
  573. var urlDict = action.get('F');
  574. if (isDict(urlDict)) {
  575. url = urlDict.get('F') || null;
  576. } else if (isString(urlDict)) {
  577. url = urlDict;
  578. }
  579. var remoteDest = action.get('D');
  580. if (remoteDest) {
  581. if (isName(remoteDest)) {
  582. remoteDest = remoteDest.name;
  583. }
  584. if (isString(url)) {
  585. var baseUrl = url.split('#')[0];
  586. if (isString(remoteDest)) {
  587. url = baseUrl + '#' + remoteDest;
  588. } else if (isArray(remoteDest)) {
  589. url = baseUrl + '#' + JSON.stringify(remoteDest);
  590. }
  591. }
  592. }
  593. var newWindow = action.get('NewWindow');
  594. if (isBool(newWindow)) {
  595. resultObj.newWindow = newWindow;
  596. }
  597. break;
  598. case 'Named':
  599. var namedAction = action.get('N');
  600. if (isName(namedAction)) {
  601. resultObj.action = namedAction.name;
  602. }
  603. break;
  604. case 'JavaScript':
  605. var jsAction = action.get('JS'),
  606. js;
  607. if (isStream(jsAction)) {
  608. js = bytesToString(jsAction.getBytes());
  609. } else if (isString(jsAction)) {
  610. js = jsAction;
  611. }
  612. if (js) {
  613. var URL_OPEN_METHODS = ['app.launchURL', 'window.open'];
  614. var regex = new RegExp('^\\s*(' + URL_OPEN_METHODS.join('|').split('.').join('\\.') + ')\\((?:\'|\")([^\'\"]*)(?:\'|\")(?:,\\s*(\\w+)\\)|\\))', 'i');
  615. var jsUrl = regex.exec(stringToPDFString(js));
  616. if (jsUrl && jsUrl[2]) {
  617. url = jsUrl[2];
  618. if (jsUrl[3] === 'true' && jsUrl[1] === 'app.launchURL') {
  619. resultObj.newWindow = true;
  620. }
  621. break;
  622. }
  623. }
  624. default:
  625. warn('Catalog_parseDestDictionary: Unrecognized link type "' + linkType + '".');
  626. break;
  627. }
  628. } else if (destDict.has('Dest')) {
  629. dest = destDict.get('Dest');
  630. }
  631. if (isString(url)) {
  632. url = tryConvertUrlEncoding(url);
  633. var absoluteUrl = createValidAbsoluteUrl(url, docBaseUrl);
  634. if (absoluteUrl) {
  635. resultObj.url = absoluteUrl.href;
  636. }
  637. resultObj.unsafeUrl = url;
  638. }
  639. if (dest) {
  640. if (isName(dest)) {
  641. dest = dest.name;
  642. }
  643. if (isString(dest) || isArray(dest)) {
  644. resultObj.dest = dest;
  645. }
  646. }
  647. };
  648. return Catalog;
  649. }();
  650. var XRef = function XRefClosure() {
  651. function XRef(stream, pdfManager) {
  652. this.stream = stream;
  653. this.pdfManager = pdfManager;
  654. this.entries = [];
  655. this.xrefstms = Object.create(null);
  656. this.cache = [];
  657. this.stats = {
  658. streamTypes: [],
  659. fontTypes: []
  660. };
  661. }
  662. XRef.prototype = {
  663. setStartXRef: function XRef_setStartXRef(startXRef) {
  664. this.startXRefQueue = [startXRef];
  665. },
  666. parse: function XRef_parse(recoveryMode) {
  667. var trailerDict;
  668. if (!recoveryMode) {
  669. trailerDict = this.readXRef();
  670. } else {
  671. warn('Indexing all PDF objects');
  672. trailerDict = this.indexObjects();
  673. }
  674. trailerDict.assignXref(this);
  675. this.trailer = trailerDict;
  676. var encrypt = trailerDict.get('Encrypt');
  677. if (isDict(encrypt)) {
  678. var ids = trailerDict.get('ID');
  679. var fileId = ids && ids.length ? ids[0] : '';
  680. encrypt.suppressEncryption = true;
  681. this.encrypt = new CipherTransformFactory(encrypt, fileId, this.pdfManager.password);
  682. }
  683. if (!(this.root = trailerDict.get('Root'))) {
  684. error('Invalid root reference');
  685. }
  686. },
  687. processXRefTable: function XRef_processXRefTable(parser) {
  688. if (!('tableState' in this)) {
  689. this.tableState = {
  690. entryNum: 0,
  691. streamPos: parser.lexer.stream.pos,
  692. parserBuf1: parser.buf1,
  693. parserBuf2: parser.buf2
  694. };
  695. }
  696. var obj = this.readXRefTable(parser);
  697. if (!isCmd(obj, 'trailer')) {
  698. error('Invalid XRef table: could not find trailer dictionary');
  699. }
  700. var dict = parser.getObj();
  701. if (!isDict(dict) && dict.dict) {
  702. dict = dict.dict;
  703. }
  704. if (!isDict(dict)) {
  705. error('Invalid XRef table: could not parse trailer dictionary');
  706. }
  707. delete this.tableState;
  708. return dict;
  709. },
  710. readXRefTable: function XRef_readXRefTable(parser) {
  711. var stream = parser.lexer.stream;
  712. var tableState = this.tableState;
  713. stream.pos = tableState.streamPos;
  714. parser.buf1 = tableState.parserBuf1;
  715. parser.buf2 = tableState.parserBuf2;
  716. var obj;
  717. while (true) {
  718. if (!('firstEntryNum' in tableState) || !('entryCount' in tableState)) {
  719. if (isCmd(obj = parser.getObj(), 'trailer')) {
  720. break;
  721. }
  722. tableState.firstEntryNum = obj;
  723. tableState.entryCount = parser.getObj();
  724. }
  725. var first = tableState.firstEntryNum;
  726. var count = tableState.entryCount;
  727. if (!isInt(first) || !isInt(count)) {
  728. error('Invalid XRef table: wrong types in subsection header');
  729. }
  730. for (var i = tableState.entryNum; i < count; i++) {
  731. tableState.streamPos = stream.pos;
  732. tableState.entryNum = i;
  733. tableState.parserBuf1 = parser.buf1;
  734. tableState.parserBuf2 = parser.buf2;
  735. var entry = {};
  736. entry.offset = parser.getObj();
  737. entry.gen = parser.getObj();
  738. var type = parser.getObj();
  739. if (isCmd(type, 'f')) {
  740. entry.free = true;
  741. } else if (isCmd(type, 'n')) {
  742. entry.uncompressed = true;
  743. }
  744. if (!isInt(entry.offset) || !isInt(entry.gen) || !(entry.free || entry.uncompressed)) {
  745. error('Invalid entry in XRef subsection: ' + first + ', ' + count);
  746. }
  747. if (i === 0 && entry.free && first === 1) {
  748. first = 0;
  749. }
  750. if (!this.entries[i + first]) {
  751. this.entries[i + first] = entry;
  752. }
  753. }
  754. tableState.entryNum = 0;
  755. tableState.streamPos = stream.pos;
  756. tableState.parserBuf1 = parser.buf1;
  757. tableState.parserBuf2 = parser.buf2;
  758. delete tableState.firstEntryNum;
  759. delete tableState.entryCount;
  760. }
  761. if (this.entries[0] && !this.entries[0].free) {
  762. error('Invalid XRef table: unexpected first object');
  763. }
  764. return obj;
  765. },
  766. processXRefStream: function XRef_processXRefStream(stream) {
  767. if (!('streamState' in this)) {
  768. var streamParameters = stream.dict;
  769. var byteWidths = streamParameters.get('W');
  770. var range = streamParameters.get('Index');
  771. if (!range) {
  772. range = [0, streamParameters.get('Size')];
  773. }
  774. this.streamState = {
  775. entryRanges: range,
  776. byteWidths: byteWidths,
  777. entryNum: 0,
  778. streamPos: stream.pos
  779. };
  780. }
  781. this.readXRefStream(stream);
  782. delete this.streamState;
  783. return stream.dict;
  784. },
  785. readXRefStream: function XRef_readXRefStream(stream) {
  786. var i, j;
  787. var streamState = this.streamState;
  788. stream.pos = streamState.streamPos;
  789. var byteWidths = streamState.byteWidths;
  790. var typeFieldWidth = byteWidths[0];
  791. var offsetFieldWidth = byteWidths[1];
  792. var generationFieldWidth = byteWidths[2];
  793. var entryRanges = streamState.entryRanges;
  794. while (entryRanges.length > 0) {
  795. var first = entryRanges[0];
  796. var n = entryRanges[1];
  797. if (!isInt(first) || !isInt(n)) {
  798. error('Invalid XRef range fields: ' + first + ', ' + n);
  799. }
  800. if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) || !isInt(generationFieldWidth)) {
  801. error('Invalid XRef entry fields length: ' + first + ', ' + n);
  802. }
  803. for (i = streamState.entryNum; i < n; ++i) {
  804. streamState.entryNum = i;
  805. streamState.streamPos = stream.pos;
  806. var type = 0,
  807. offset = 0,
  808. generation = 0;
  809. for (j = 0; j < typeFieldWidth; ++j) {
  810. type = type << 8 | stream.getByte();
  811. }
  812. if (typeFieldWidth === 0) {
  813. type = 1;
  814. }
  815. for (j = 0; j < offsetFieldWidth; ++j) {
  816. offset = offset << 8 | stream.getByte();
  817. }
  818. for (j = 0; j < generationFieldWidth; ++j) {
  819. generation = generation << 8 | stream.getByte();
  820. }
  821. var entry = {};
  822. entry.offset = offset;
  823. entry.gen = generation;
  824. switch (type) {
  825. case 0:
  826. entry.free = true;
  827. break;
  828. case 1:
  829. entry.uncompressed = true;
  830. break;
  831. case 2:
  832. break;
  833. default:
  834. error('Invalid XRef entry type: ' + type);
  835. }
  836. if (!this.entries[first + i]) {
  837. this.entries[first + i] = entry;
  838. }
  839. }
  840. streamState.entryNum = 0;
  841. streamState.streamPos = stream.pos;
  842. entryRanges.splice(0, 2);
  843. }
  844. },
  845. indexObjects: function XRef_indexObjects() {
  846. var TAB = 0x9,
  847. LF = 0xA,
  848. CR = 0xD,
  849. SPACE = 0x20;
  850. var PERCENT = 0x25,
  851. LT = 0x3C;
  852. function readToken(data, offset) {
  853. var token = '',
  854. ch = data[offset];
  855. while (ch !== LF && ch !== CR && ch !== LT) {
  856. if (++offset >= data.length) {
  857. break;
  858. }
  859. token += String.fromCharCode(ch);
  860. ch = data[offset];
  861. }
  862. return token;
  863. }
  864. function skipUntil(data, offset, what) {
  865. var length = what.length,
  866. dataLength = data.length;
  867. var skipped = 0;
  868. while (offset < dataLength) {
  869. var i = 0;
  870. while (i < length && data[offset + i] === what[i]) {
  871. ++i;
  872. }
  873. if (i >= length) {
  874. break;
  875. }
  876. offset++;
  877. skipped++;
  878. }
  879. return skipped;
  880. }
  881. var objRegExp = /^(\d+)\s+(\d+)\s+obj\b/;
  882. var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
  883. var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]);
  884. var endobjBytes = new Uint8Array([101, 110, 100, 111, 98, 106]);
  885. var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
  886. this.entries.length = 0;
  887. var stream = this.stream;
  888. stream.pos = 0;
  889. var buffer = stream.getBytes();
  890. var position = stream.start,
  891. length = buffer.length;
  892. var trailers = [],
  893. xrefStms = [];
  894. while (position < length) {
  895. var ch = buffer[position];
  896. if (ch === TAB || ch === LF || ch === CR || ch === SPACE) {
  897. ++position;
  898. continue;
  899. }
  900. if (ch === PERCENT) {
  901. do {
  902. ++position;
  903. if (position >= length) {
  904. break;
  905. }
  906. ch = buffer[position];
  907. } while (ch !== LF && ch !== CR);
  908. continue;
  909. }
  910. var token = readToken(buffer, position);
  911. var m;
  912. if (token.indexOf('xref') === 0 && (token.length === 4 || /\s/.test(token[4]))) {
  913. position += skipUntil(buffer, position, trailerBytes);
  914. trailers.push(position);
  915. position += skipUntil(buffer, position, startxrefBytes);
  916. } else if (m = objRegExp.exec(token)) {
  917. if (typeof this.entries[m[1]] === 'undefined') {
  918. this.entries[m[1]] = {
  919. offset: position - stream.start,
  920. gen: m[2] | 0,
  921. uncompressed: true
  922. };
  923. }
  924. var contentLength = skipUntil(buffer, position, endobjBytes) + 7;
  925. var content = buffer.subarray(position, position + contentLength);
  926. var xrefTagOffset = skipUntil(content, 0, xrefBytes);
  927. if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) {
  928. xrefStms.push(position - stream.start);
  929. this.xrefstms[position - stream.start] = 1;
  930. }
  931. position += contentLength;
  932. } else if (token.indexOf('trailer') === 0 && (token.length === 7 || /\s/.test(token[7]))) {
  933. trailers.push(position);
  934. position += skipUntil(buffer, position, startxrefBytes);
  935. } else {
  936. position += token.length + 1;
  937. }
  938. }
  939. var i, ii;
  940. for (i = 0, ii = xrefStms.length; i < ii; ++i) {
  941. this.startXRefQueue.push(xrefStms[i]);
  942. this.readXRef(true);
  943. }
  944. var dict;
  945. for (i = 0, ii = trailers.length; i < ii; ++i) {
  946. stream.pos = trailers[i];
  947. var parser = new Parser(new Lexer(stream), true, this, true);
  948. var obj = parser.getObj();
  949. if (!isCmd(obj, 'trailer')) {
  950. continue;
  951. }
  952. dict = parser.getObj();
  953. if (!isDict(dict)) {
  954. continue;
  955. }
  956. if (dict.has('ID')) {
  957. return dict;
  958. }
  959. }
  960. if (dict) {
  961. return dict;
  962. }
  963. throw new InvalidPDFException('Invalid PDF structure');
  964. },
  965. readXRef: function XRef_readXRef(recoveryMode) {
  966. var stream = this.stream;
  967. try {
  968. while (this.startXRefQueue.length) {
  969. var startXRef = this.startXRefQueue[0];
  970. stream.pos = startXRef + stream.start;
  971. var parser = new Parser(new Lexer(stream), true, this);
  972. var obj = parser.getObj();
  973. var dict;
  974. if (isCmd(obj, 'xref')) {
  975. dict = this.processXRefTable(parser);
  976. if (!this.topDict) {
  977. this.topDict = dict;
  978. }
  979. obj = dict.get('XRefStm');
  980. if (isInt(obj)) {
  981. var pos = obj;
  982. if (!(pos in this.xrefstms)) {
  983. this.xrefstms[pos] = 1;
  984. this.startXRefQueue.push(pos);
  985. }
  986. }
  987. } else if (isInt(obj)) {
  988. if (!isInt(parser.getObj()) || !isCmd(parser.getObj(), 'obj') || !isStream(obj = parser.getObj())) {
  989. error('Invalid XRef stream');
  990. }
  991. dict = this.processXRefStream(obj);
  992. if (!this.topDict) {
  993. this.topDict = dict;
  994. }
  995. if (!dict) {
  996. error('Failed to read XRef stream');
  997. }
  998. } else {
  999. error('Invalid XRef stream header');
  1000. }
  1001. obj = dict.get('Prev');
  1002. if (isInt(obj)) {
  1003. this.startXRefQueue.push(obj);
  1004. } else if (isRef(obj)) {
  1005. this.startXRefQueue.push(obj.num);
  1006. }
  1007. this.startXRefQueue.shift();
  1008. }
  1009. return this.topDict;
  1010. } catch (e) {
  1011. if (e instanceof MissingDataException) {
  1012. throw e;
  1013. }
  1014. info('(while reading XRef): ' + e);
  1015. }
  1016. if (recoveryMode) {
  1017. return;
  1018. }
  1019. throw new XRefParseException();
  1020. },
  1021. getEntry: function XRef_getEntry(i) {
  1022. var xrefEntry = this.entries[i];
  1023. if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
  1024. return xrefEntry;
  1025. }
  1026. return null;
  1027. },
  1028. fetchIfRef: function XRef_fetchIfRef(obj, suppressEncryption) {
  1029. if (!isRef(obj)) {
  1030. return obj;
  1031. }
  1032. return this.fetch(obj, suppressEncryption);
  1033. },
  1034. fetch: function XRef_fetch(ref, suppressEncryption) {
  1035. assert(isRef(ref), 'ref object is not a reference');
  1036. var num = ref.num;
  1037. if (num in this.cache) {
  1038. var cacheEntry = this.cache[num];
  1039. if (cacheEntry instanceof Dict && !cacheEntry.objId) {
  1040. cacheEntry.objId = ref.toString();
  1041. }
  1042. return cacheEntry;
  1043. }
  1044. var xrefEntry = this.getEntry(num);
  1045. if (xrefEntry === null) {
  1046. return this.cache[num] = null;
  1047. }
  1048. if (xrefEntry.uncompressed) {
  1049. xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
  1050. } else {
  1051. xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
  1052. }
  1053. if (isDict(xrefEntry)) {
  1054. xrefEntry.objId = ref.toString();
  1055. } else if (isStream(xrefEntry)) {
  1056. xrefEntry.dict.objId = ref.toString();
  1057. }
  1058. return xrefEntry;
  1059. },
  1060. fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry, suppressEncryption) {
  1061. var gen = ref.gen;
  1062. var num = ref.num;
  1063. if (xrefEntry.gen !== gen) {
  1064. error('inconsistent generation in XRef');
  1065. }
  1066. var stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start);
  1067. var parser = new Parser(new Lexer(stream), true, this);
  1068. var obj1 = parser.getObj();
  1069. var obj2 = parser.getObj();
  1070. var obj3 = parser.getObj();
  1071. if (!isInt(obj1) || parseInt(obj1, 10) !== num || !isInt(obj2) || parseInt(obj2, 10) !== gen || !isCmd(obj3)) {
  1072. error('bad XRef entry');
  1073. }
  1074. if (!isCmd(obj3, 'obj')) {
  1075. if (obj3.cmd.indexOf('obj') === 0) {
  1076. num = parseInt(obj3.cmd.substring(3), 10);
  1077. if (!isNaN(num)) {
  1078. return num;
  1079. }
  1080. }
  1081. error('bad XRef entry');
  1082. }
  1083. if (this.encrypt && !suppressEncryption) {
  1084. xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
  1085. } else {
  1086. xrefEntry = parser.getObj();
  1087. }
  1088. if (!isStream(xrefEntry)) {
  1089. this.cache[num] = xrefEntry;
  1090. }
  1091. return xrefEntry;
  1092. },
  1093. fetchCompressed: function XRef_fetchCompressed(xrefEntry, suppressEncryption) {
  1094. var tableOffset = xrefEntry.offset;
  1095. var stream = this.fetch(new Ref(tableOffset, 0));
  1096. if (!isStream(stream)) {
  1097. error('bad ObjStm stream');
  1098. }
  1099. var first = stream.dict.get('First');
  1100. var n = stream.dict.get('N');
  1101. if (!isInt(first) || !isInt(n)) {
  1102. error('invalid first and n parameters for ObjStm stream');
  1103. }
  1104. var parser = new Parser(new Lexer(stream), false, this);
  1105. parser.allowStreams = true;
  1106. var i,
  1107. entries = [],
  1108. num,
  1109. nums = [];
  1110. for (i = 0; i < n; ++i) {
  1111. num = parser.getObj();
  1112. if (!isInt(num)) {
  1113. error('invalid object number in the ObjStm stream: ' + num);
  1114. }
  1115. nums.push(num);
  1116. var offset = parser.getObj();
  1117. if (!isInt(offset)) {
  1118. error('invalid object offset in the ObjStm stream: ' + offset);
  1119. }
  1120. }
  1121. for (i = 0; i < n; ++i) {
  1122. entries.push(parser.getObj());
  1123. if (isCmd(parser.buf1, 'endobj')) {
  1124. parser.shift();
  1125. }
  1126. num = nums[i];
  1127. var entry = this.entries[num];
  1128. if (entry && entry.offset === tableOffset && entry.gen === i) {
  1129. this.cache[num] = entries[i];
  1130. }
  1131. }
  1132. xrefEntry = entries[xrefEntry.gen];
  1133. if (xrefEntry === undefined) {
  1134. error('bad XRef entry for compressed object');
  1135. }
  1136. return xrefEntry;
  1137. },
  1138. fetchIfRefAsync: function XRef_fetchIfRefAsync(obj, suppressEncryption) {
  1139. if (!isRef(obj)) {
  1140. return Promise.resolve(obj);
  1141. }
  1142. return this.fetchAsync(obj, suppressEncryption);
  1143. },
  1144. fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
  1145. var streamManager = this.stream.manager;
  1146. var xref = this;
  1147. return new Promise(function tryFetch(resolve, reject) {
  1148. try {
  1149. resolve(xref.fetch(ref, suppressEncryption));
  1150. } catch (e) {
  1151. if (e instanceof MissingDataException) {
  1152. streamManager.requestRange(e.begin, e.end).then(function () {
  1153. tryFetch(resolve, reject);
  1154. }, reject);
  1155. return;
  1156. }
  1157. reject(e);
  1158. }
  1159. });
  1160. },
  1161. getCatalogObj: function XRef_getCatalogObj() {
  1162. return this.root;
  1163. }
  1164. };
  1165. return XRef;
  1166. }();
  1167. var NameOrNumberTree = function NameOrNumberTreeClosure() {
  1168. function NameOrNumberTree(root, xref) {
  1169. throw new Error('Cannot initialize NameOrNumberTree.');
  1170. }
  1171. NameOrNumberTree.prototype = {
  1172. getAll: function NameOrNumberTree_getAll() {
  1173. var dict = Object.create(null);
  1174. if (!this.root) {
  1175. return dict;
  1176. }
  1177. var xref = this.xref;
  1178. var processed = new RefSet();
  1179. processed.put(this.root);
  1180. var queue = [this.root];
  1181. while (queue.length > 0) {
  1182. var i, n;
  1183. var obj = xref.fetchIfRef(queue.shift());
  1184. if (!isDict(obj)) {
  1185. continue;
  1186. }
  1187. if (obj.has('Kids')) {
  1188. var kids = obj.get('Kids');
  1189. for (i = 0, n = kids.length; i < n; i++) {
  1190. var kid = kids[i];
  1191. assert(!processed.has(kid), 'Duplicate entry in "' + this._type + '" tree.');
  1192. queue.push(kid);
  1193. processed.put(kid);
  1194. }
  1195. continue;
  1196. }
  1197. var entries = obj.get(this._type);
  1198. if (isArray(entries)) {
  1199. for (i = 0, n = entries.length; i < n; i += 2) {
  1200. dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]);
  1201. }
  1202. }
  1203. }
  1204. return dict;
  1205. },
  1206. get: function NameOrNumberTree_get(key) {
  1207. if (!this.root) {
  1208. return null;
  1209. }
  1210. var xref = this.xref;
  1211. var kidsOrEntries = xref.fetchIfRef(this.root);
  1212. var loopCount = 0;
  1213. var MAX_LEVELS = 10;
  1214. var l, r, m;
  1215. while (kidsOrEntries.has('Kids')) {
  1216. if (++loopCount > MAX_LEVELS) {
  1217. warn('Search depth limit reached for "' + this._type + '" tree.');
  1218. return null;
  1219. }
  1220. var kids = kidsOrEntries.get('Kids');
  1221. if (!isArray(kids)) {
  1222. return null;
  1223. }
  1224. l = 0;
  1225. r = kids.length - 1;
  1226. while (l <= r) {
  1227. m = l + r >> 1;
  1228. var kid = xref.fetchIfRef(kids[m]);
  1229. var limits = kid.get('Limits');
  1230. if (key < xref.fetchIfRef(limits[0])) {
  1231. r = m - 1;
  1232. } else if (key > xref.fetchIfRef(limits[1])) {
  1233. l = m + 1;
  1234. } else {
  1235. kidsOrEntries = xref.fetchIfRef(kids[m]);
  1236. break;
  1237. }
  1238. }
  1239. if (l > r) {
  1240. return null;
  1241. }
  1242. }
  1243. var entries = kidsOrEntries.get(this._type);
  1244. if (isArray(entries)) {
  1245. l = 0;
  1246. r = entries.length - 2;
  1247. while (l <= r) {
  1248. m = l + r & ~1;
  1249. var currentKey = xref.fetchIfRef(entries[m]);
  1250. if (key < currentKey) {
  1251. r = m - 2;
  1252. } else if (key > currentKey) {
  1253. l = m + 2;
  1254. } else {
  1255. return xref.fetchIfRef(entries[m + 1]);
  1256. }
  1257. }
  1258. }
  1259. return null;
  1260. }
  1261. };
  1262. return NameOrNumberTree;
  1263. }();
  1264. var NameTree = function NameTreeClosure() {
  1265. function NameTree(root, xref) {
  1266. this.root = root;
  1267. this.xref = xref;
  1268. this._type = 'Names';
  1269. }
  1270. Util.inherit(NameTree, NameOrNumberTree, {});
  1271. return NameTree;
  1272. }();
  1273. var NumberTree = function NumberTreeClosure() {
  1274. function NumberTree(root, xref) {
  1275. this.root = root;
  1276. this.xref = xref;
  1277. this._type = 'Nums';
  1278. }
  1279. Util.inherit(NumberTree, NameOrNumberTree, {});
  1280. return NumberTree;
  1281. }();
  1282. var FileSpec = function FileSpecClosure() {
  1283. function FileSpec(root, xref) {
  1284. if (!root || !isDict(root)) {
  1285. return;
  1286. }
  1287. this.xref = xref;
  1288. this.root = root;
  1289. if (root.has('FS')) {
  1290. this.fs = root.get('FS');
  1291. }
  1292. this.description = root.has('Desc') ? stringToPDFString(root.get('Desc')) : '';
  1293. if (root.has('RF')) {
  1294. warn('Related file specifications are not supported');
  1295. }
  1296. this.contentAvailable = true;
  1297. if (!root.has('EF')) {
  1298. this.contentAvailable = false;
  1299. warn('Non-embedded file specifications are not supported');
  1300. }
  1301. }
  1302. function pickPlatformItem(dict) {
  1303. if (dict.has('UF')) {
  1304. return dict.get('UF');
  1305. } else if (dict.has('F')) {
  1306. return dict.get('F');
  1307. } else if (dict.has('Unix')) {
  1308. return dict.get('Unix');
  1309. } else if (dict.has('Mac')) {
  1310. return dict.get('Mac');
  1311. } else if (dict.has('DOS')) {
  1312. return dict.get('DOS');
  1313. }
  1314. return null;
  1315. }
  1316. FileSpec.prototype = {
  1317. get filename() {
  1318. if (!this._filename && this.root) {
  1319. var filename = pickPlatformItem(this.root) || 'unnamed';
  1320. this._filename = stringToPDFString(filename).replace(/\\\\/g, '\\').replace(/\\\//g, '/').replace(/\\/g, '/');
  1321. }
  1322. return this._filename;
  1323. },
  1324. get content() {
  1325. if (!this.contentAvailable) {
  1326. return null;
  1327. }
  1328. if (!this.contentRef && this.root) {
  1329. this.contentRef = pickPlatformItem(this.root.get('EF'));
  1330. }
  1331. var content = null;
  1332. if (this.contentRef) {
  1333. var xref = this.xref;
  1334. var fileObj = xref.fetchIfRef(this.contentRef);
  1335. if (fileObj && isStream(fileObj)) {
  1336. content = fileObj.getBytes();
  1337. } else {
  1338. warn('Embedded file specification points to non-existing/invalid ' + 'content');
  1339. }
  1340. } else {
  1341. warn('Embedded file specification does not have a content');
  1342. }
  1343. return content;
  1344. },
  1345. get serializable() {
  1346. return {
  1347. filename: this.filename,
  1348. content: this.content
  1349. };
  1350. }
  1351. };
  1352. return FileSpec;
  1353. }();
  1354. var ObjectLoader = function () {
  1355. function mayHaveChildren(value) {
  1356. return isRef(value) || isDict(value) || isArray(value) || isStream(value);
  1357. }
  1358. function addChildren(node, nodesToVisit) {
  1359. var value;
  1360. if (isDict(node) || isStream(node)) {
  1361. var map;
  1362. if (isDict(node)) {
  1363. map = node.map;
  1364. } else {
  1365. map = node.dict.map;
  1366. }
  1367. for (var key in map) {
  1368. value = map[key];
  1369. if (mayHaveChildren(value)) {
  1370. nodesToVisit.push(value);
  1371. }
  1372. }
  1373. } else if (isArray(node)) {
  1374. for (var i = 0, ii = node.length; i < ii; i++) {
  1375. value = node[i];
  1376. if (mayHaveChildren(value)) {
  1377. nodesToVisit.push(value);
  1378. }
  1379. }
  1380. }
  1381. }
  1382. function ObjectLoader(obj, keys, xref) {
  1383. this.obj = obj;
  1384. this.keys = keys;
  1385. this.xref = xref;
  1386. this.refSet = null;
  1387. this.capability = null;
  1388. }
  1389. ObjectLoader.prototype = {
  1390. load: function ObjectLoader_load() {
  1391. var keys = this.keys;
  1392. this.capability = createPromiseCapability();
  1393. if (!(this.xref.stream instanceof ChunkedStream) || this.xref.stream.getMissingChunks().length === 0) {
  1394. this.capability.resolve();
  1395. return this.capability.promise;
  1396. }
  1397. this.refSet = new RefSet();
  1398. var nodesToVisit = [];
  1399. for (var i = 0; i < keys.length; i++) {
  1400. nodesToVisit.push(this.obj[keys[i]]);
  1401. }
  1402. this._walk(nodesToVisit);
  1403. return this.capability.promise;
  1404. },
  1405. _walk: function ObjectLoader_walk(nodesToVisit) {
  1406. var _this3 = this;
  1407. var nodesToRevisit = [];
  1408. var pendingRequests = [];
  1409. while (nodesToVisit.length) {
  1410. var currentNode = nodesToVisit.pop();
  1411. if (isRef(currentNode)) {
  1412. if (this.refSet.has(currentNode)) {
  1413. continue;
  1414. }
  1415. try {
  1416. var ref = currentNode;
  1417. this.refSet.put(ref);
  1418. currentNode = this.xref.fetch(currentNode);
  1419. } catch (e) {
  1420. if (!(e instanceof MissingDataException)) {
  1421. throw e;
  1422. }
  1423. nodesToRevisit.push(currentNode);
  1424. pendingRequests.push({
  1425. begin: e.begin,
  1426. end: e.end
  1427. });
  1428. }
  1429. }
  1430. if (currentNode && currentNode.getBaseStreams) {
  1431. var baseStreams = currentNode.getBaseStreams();
  1432. var foundMissingData = false;
  1433. for (var i = 0; i < baseStreams.length; i++) {
  1434. var stream = baseStreams[i];
  1435. if (stream.getMissingChunks && stream.getMissingChunks().length) {
  1436. foundMissingData = true;
  1437. pendingRequests.push({
  1438. begin: stream.start,
  1439. end: stream.end
  1440. });
  1441. }
  1442. }
  1443. if (foundMissingData) {
  1444. nodesToRevisit.push(currentNode);
  1445. }
  1446. }
  1447. addChildren(currentNode, nodesToVisit);
  1448. }
  1449. if (pendingRequests.length) {
  1450. this.xref.stream.manager.requestRanges(pendingRequests).then(function () {
  1451. nodesToVisit = nodesToRevisit;
  1452. for (var i = 0; i < nodesToRevisit.length; i++) {
  1453. var node = nodesToRevisit[i];
  1454. if (isRef(node)) {
  1455. _this3.refSet.remove(node);
  1456. }
  1457. }
  1458. _this3._walk(nodesToVisit);
  1459. }, this.capability.reject);
  1460. return;
  1461. }
  1462. this.refSet = null;
  1463. this.capability.resolve();
  1464. }
  1465. };
  1466. return ObjectLoader;
  1467. }();
  1468. exports.Catalog = Catalog;
  1469. exports.ObjectLoader = ObjectLoader;
  1470. exports.XRef = XRef;
  1471. exports.FileSpec = FileSpec;