obj.js 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2020 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.FileSpec = exports.XRef = exports.ObjectLoader = exports.Catalog = void 0;
  27. var _util = require("../shared/util.js");
  28. var _primitives = require("./primitives.js");
  29. var _parser = require("./parser.js");
  30. var _core_utils = require("./core_utils.js");
  31. var _crypto = require("./crypto.js");
  32. var _colorspace = require("./colorspace.js");
  33. var _image_utils = require("./image_utils.js");
  34. function fetchDestination(dest) {
  35. return (0, _primitives.isDict)(dest) ? dest.get("D") : dest;
  36. }
  37. class Catalog {
  38. constructor(pdfManager, xref) {
  39. this.pdfManager = pdfManager;
  40. this.xref = xref;
  41. this.catDict = xref.getCatalogObj();
  42. if (!(0, _primitives.isDict)(this.catDict)) {
  43. throw new _util.FormatError("Catalog object is not a dictionary.");
  44. }
  45. this.fontCache = new _primitives.RefSetCache();
  46. this.builtInCMapCache = new Map();
  47. this.globalImageCache = new _image_utils.GlobalImageCache();
  48. this.pageKidsCountCache = new _primitives.RefSetCache();
  49. }
  50. get metadata() {
  51. const streamRef = this.catDict.getRaw("Metadata");
  52. if (!(0, _primitives.isRef)(streamRef)) {
  53. return (0, _util.shadow)(this, "metadata", null);
  54. }
  55. const suppressEncryption = !(this.xref.encrypt && this.xref.encrypt.encryptMetadata);
  56. const stream = this.xref.fetch(streamRef, suppressEncryption);
  57. let metadata;
  58. if (stream && (0, _primitives.isDict)(stream.dict)) {
  59. const type = stream.dict.get("Type");
  60. const subtype = stream.dict.get("Subtype");
  61. if ((0, _primitives.isName)(type, "Metadata") && (0, _primitives.isName)(subtype, "XML")) {
  62. try {
  63. metadata = (0, _util.stringToUTF8String)((0, _util.bytesToString)(stream.getBytes()));
  64. } catch (e) {
  65. if (e instanceof _core_utils.MissingDataException) {
  66. throw e;
  67. }
  68. (0, _util.info)("Skipping invalid metadata.");
  69. }
  70. }
  71. }
  72. return (0, _util.shadow)(this, "metadata", metadata);
  73. }
  74. get toplevelPagesDict() {
  75. const pagesObj = this.catDict.get("Pages");
  76. if (!(0, _primitives.isDict)(pagesObj)) {
  77. throw new _util.FormatError("Invalid top-level pages dictionary.");
  78. }
  79. return (0, _util.shadow)(this, "toplevelPagesDict", pagesObj);
  80. }
  81. get documentOutline() {
  82. let obj = null;
  83. try {
  84. obj = this._readDocumentOutline();
  85. } catch (ex) {
  86. if (ex instanceof _core_utils.MissingDataException) {
  87. throw ex;
  88. }
  89. (0, _util.warn)("Unable to read document outline.");
  90. }
  91. return (0, _util.shadow)(this, "documentOutline", obj);
  92. }
  93. _readDocumentOutline() {
  94. let obj = this.catDict.get("Outlines");
  95. if (!(0, _primitives.isDict)(obj)) {
  96. return null;
  97. }
  98. obj = obj.getRaw("First");
  99. if (!(0, _primitives.isRef)(obj)) {
  100. return null;
  101. }
  102. const root = {
  103. items: []
  104. };
  105. const queue = [{
  106. obj,
  107. parent: root
  108. }];
  109. const processed = new _primitives.RefSet();
  110. processed.put(obj);
  111. const xref = this.xref,
  112. blackColor = new Uint8ClampedArray(3);
  113. while (queue.length > 0) {
  114. const i = queue.shift();
  115. const outlineDict = xref.fetchIfRef(i.obj);
  116. if (outlineDict === null) {
  117. continue;
  118. }
  119. if (!outlineDict.has("Title")) {
  120. throw new _util.FormatError("Invalid outline item encountered.");
  121. }
  122. const data = {
  123. url: null,
  124. dest: null
  125. };
  126. Catalog.parseDestDictionary({
  127. destDict: outlineDict,
  128. resultObj: data,
  129. docBaseUrl: this.pdfManager.docBaseUrl
  130. });
  131. const title = outlineDict.get("Title");
  132. const flags = outlineDict.get("F") || 0;
  133. const color = outlineDict.getArray("C");
  134. const count = outlineDict.get("Count");
  135. let rgbColor = blackColor;
  136. if (Array.isArray(color) && color.length === 3 && (color[0] !== 0 || color[1] !== 0 || color[2] !== 0)) {
  137. rgbColor = _colorspace.ColorSpace.singletons.rgb.getRgb(color, 0);
  138. }
  139. const outlineItem = {
  140. dest: data.dest,
  141. url: data.url,
  142. unsafeUrl: data.unsafeUrl,
  143. newWindow: data.newWindow,
  144. title: (0, _util.stringToPDFString)(title),
  145. color: rgbColor,
  146. count: Number.isInteger(count) ? count : undefined,
  147. bold: !!(flags & 2),
  148. italic: !!(flags & 1),
  149. items: []
  150. };
  151. i.parent.items.push(outlineItem);
  152. obj = outlineDict.getRaw("First");
  153. if ((0, _primitives.isRef)(obj) && !processed.has(obj)) {
  154. queue.push({
  155. obj,
  156. parent: outlineItem
  157. });
  158. processed.put(obj);
  159. }
  160. obj = outlineDict.getRaw("Next");
  161. if ((0, _primitives.isRef)(obj) && !processed.has(obj)) {
  162. queue.push({
  163. obj,
  164. parent: i.parent
  165. });
  166. processed.put(obj);
  167. }
  168. }
  169. return root.items.length > 0 ? root.items : null;
  170. }
  171. get permissions() {
  172. let permissions = null;
  173. try {
  174. permissions = this._readPermissions();
  175. } catch (ex) {
  176. if (ex instanceof _core_utils.MissingDataException) {
  177. throw ex;
  178. }
  179. (0, _util.warn)("Unable to read permissions.");
  180. }
  181. return (0, _util.shadow)(this, "permissions", permissions);
  182. }
  183. _readPermissions() {
  184. const encrypt = this.xref.trailer.get("Encrypt");
  185. if (!(0, _primitives.isDict)(encrypt)) {
  186. return null;
  187. }
  188. let flags = encrypt.get("P");
  189. if (!(0, _util.isNum)(flags)) {
  190. return null;
  191. }
  192. flags += 2 ** 32;
  193. const permissions = [];
  194. for (const key in _util.PermissionFlag) {
  195. const value = _util.PermissionFlag[key];
  196. if (flags & value) {
  197. permissions.push(value);
  198. }
  199. }
  200. return permissions;
  201. }
  202. get numPages() {
  203. const obj = this.toplevelPagesDict.get("Count");
  204. if (!Number.isInteger(obj)) {
  205. throw new _util.FormatError("Page count in top-level pages dictionary is not an integer.");
  206. }
  207. return (0, _util.shadow)(this, "numPages", obj);
  208. }
  209. get destinations() {
  210. const obj = this._readDests(),
  211. dests = Object.create(null);
  212. if (obj instanceof NameTree) {
  213. const names = obj.getAll();
  214. for (const name in names) {
  215. dests[name] = fetchDestination(names[name]);
  216. }
  217. } else if (obj instanceof _primitives.Dict) {
  218. obj.forEach(function (key, value) {
  219. if (value) {
  220. dests[key] = fetchDestination(value);
  221. }
  222. });
  223. }
  224. return (0, _util.shadow)(this, "destinations", dests);
  225. }
  226. getDestination(destinationId) {
  227. const obj = this._readDests();
  228. if (obj instanceof NameTree || obj instanceof _primitives.Dict) {
  229. return fetchDestination(obj.get(destinationId) || null);
  230. }
  231. return null;
  232. }
  233. _readDests() {
  234. const obj = this.catDict.get("Names");
  235. if (obj && obj.has("Dests")) {
  236. return new NameTree(obj.getRaw("Dests"), this.xref);
  237. } else if (this.catDict.has("Dests")) {
  238. return this.catDict.get("Dests");
  239. }
  240. return undefined;
  241. }
  242. get pageLabels() {
  243. let obj = null;
  244. try {
  245. obj = this._readPageLabels();
  246. } catch (ex) {
  247. if (ex instanceof _core_utils.MissingDataException) {
  248. throw ex;
  249. }
  250. (0, _util.warn)("Unable to read page labels.");
  251. }
  252. return (0, _util.shadow)(this, "pageLabels", obj);
  253. }
  254. _readPageLabels() {
  255. const obj = this.catDict.getRaw("PageLabels");
  256. if (!obj) {
  257. return null;
  258. }
  259. const pageLabels = new Array(this.numPages);
  260. let style = null,
  261. prefix = "";
  262. const numberTree = new NumberTree(obj, this.xref);
  263. const nums = numberTree.getAll();
  264. let currentLabel = "",
  265. currentIndex = 1;
  266. for (let i = 0, ii = this.numPages; i < ii; i++) {
  267. if (i in nums) {
  268. const labelDict = nums[i];
  269. if (!(0, _primitives.isDict)(labelDict)) {
  270. throw new _util.FormatError("PageLabel is not a dictionary.");
  271. }
  272. if (labelDict.has("Type") && !(0, _primitives.isName)(labelDict.get("Type"), "PageLabel")) {
  273. throw new _util.FormatError("Invalid type in PageLabel dictionary.");
  274. }
  275. if (labelDict.has("S")) {
  276. const s = labelDict.get("S");
  277. if (!(0, _primitives.isName)(s)) {
  278. throw new _util.FormatError("Invalid style in PageLabel dictionary.");
  279. }
  280. style = s.name;
  281. } else {
  282. style = null;
  283. }
  284. if (labelDict.has("P")) {
  285. const p = labelDict.get("P");
  286. if (!(0, _util.isString)(p)) {
  287. throw new _util.FormatError("Invalid prefix in PageLabel dictionary.");
  288. }
  289. prefix = (0, _util.stringToPDFString)(p);
  290. } else {
  291. prefix = "";
  292. }
  293. if (labelDict.has("St")) {
  294. const st = labelDict.get("St");
  295. if (!(Number.isInteger(st) && st >= 1)) {
  296. throw new _util.FormatError("Invalid start in PageLabel dictionary.");
  297. }
  298. currentIndex = st;
  299. } else {
  300. currentIndex = 1;
  301. }
  302. }
  303. switch (style) {
  304. case "D":
  305. currentLabel = currentIndex;
  306. break;
  307. case "R":
  308. case "r":
  309. currentLabel = (0, _core_utils.toRomanNumerals)(currentIndex, style === "r");
  310. break;
  311. case "A":
  312. case "a":
  313. const LIMIT = 26;
  314. const A_UPPER_CASE = 0x41,
  315. A_LOWER_CASE = 0x61;
  316. const baseCharCode = style === "a" ? A_LOWER_CASE : A_UPPER_CASE;
  317. const letterIndex = currentIndex - 1;
  318. const character = String.fromCharCode(baseCharCode + letterIndex % LIMIT);
  319. const charBuf = [];
  320. for (let j = 0, jj = letterIndex / LIMIT | 0; j <= jj; j++) {
  321. charBuf.push(character);
  322. }
  323. currentLabel = charBuf.join("");
  324. break;
  325. default:
  326. if (style) {
  327. throw new _util.FormatError(`Invalid style "${style}" in PageLabel dictionary.`);
  328. }
  329. currentLabel = "";
  330. }
  331. pageLabels[i] = prefix + currentLabel;
  332. currentIndex++;
  333. }
  334. return pageLabels;
  335. }
  336. get pageLayout() {
  337. const obj = this.catDict.get("PageLayout");
  338. let pageLayout = "";
  339. if ((0, _primitives.isName)(obj)) {
  340. switch (obj.name) {
  341. case "SinglePage":
  342. case "OneColumn":
  343. case "TwoColumnLeft":
  344. case "TwoColumnRight":
  345. case "TwoPageLeft":
  346. case "TwoPageRight":
  347. pageLayout = obj.name;
  348. }
  349. }
  350. return (0, _util.shadow)(this, "pageLayout", pageLayout);
  351. }
  352. get pageMode() {
  353. const obj = this.catDict.get("PageMode");
  354. let pageMode = "UseNone";
  355. if ((0, _primitives.isName)(obj)) {
  356. switch (obj.name) {
  357. case "UseNone":
  358. case "UseOutlines":
  359. case "UseThumbs":
  360. case "FullScreen":
  361. case "UseOC":
  362. case "UseAttachments":
  363. pageMode = obj.name;
  364. }
  365. }
  366. return (0, _util.shadow)(this, "pageMode", pageMode);
  367. }
  368. get viewerPreferences() {
  369. const ViewerPreferencesValidators = {
  370. HideToolbar: _util.isBool,
  371. HideMenubar: _util.isBool,
  372. HideWindowUI: _util.isBool,
  373. FitWindow: _util.isBool,
  374. CenterWindow: _util.isBool,
  375. DisplayDocTitle: _util.isBool,
  376. NonFullScreenPageMode: _primitives.isName,
  377. Direction: _primitives.isName,
  378. ViewArea: _primitives.isName,
  379. ViewClip: _primitives.isName,
  380. PrintArea: _primitives.isName,
  381. PrintClip: _primitives.isName,
  382. PrintScaling: _primitives.isName,
  383. Duplex: _primitives.isName,
  384. PickTrayByPDFSize: _util.isBool,
  385. PrintPageRange: Array.isArray,
  386. NumCopies: Number.isInteger
  387. };
  388. const obj = this.catDict.get("ViewerPreferences");
  389. let prefs = null;
  390. if ((0, _primitives.isDict)(obj)) {
  391. for (const key in ViewerPreferencesValidators) {
  392. if (!obj.has(key)) {
  393. continue;
  394. }
  395. const value = obj.get(key);
  396. if (!ViewerPreferencesValidators[key](value)) {
  397. (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`);
  398. continue;
  399. }
  400. let prefValue;
  401. switch (key) {
  402. case "NonFullScreenPageMode":
  403. switch (value.name) {
  404. case "UseNone":
  405. case "UseOutlines":
  406. case "UseThumbs":
  407. case "UseOC":
  408. prefValue = value.name;
  409. break;
  410. default:
  411. prefValue = "UseNone";
  412. }
  413. break;
  414. case "Direction":
  415. switch (value.name) {
  416. case "L2R":
  417. case "R2L":
  418. prefValue = value.name;
  419. break;
  420. default:
  421. prefValue = "L2R";
  422. }
  423. break;
  424. case "ViewArea":
  425. case "ViewClip":
  426. case "PrintArea":
  427. case "PrintClip":
  428. switch (value.name) {
  429. case "MediaBox":
  430. case "CropBox":
  431. case "BleedBox":
  432. case "TrimBox":
  433. case "ArtBox":
  434. prefValue = value.name;
  435. break;
  436. default:
  437. prefValue = "CropBox";
  438. }
  439. break;
  440. case "PrintScaling":
  441. switch (value.name) {
  442. case "None":
  443. case "AppDefault":
  444. prefValue = value.name;
  445. break;
  446. default:
  447. prefValue = "AppDefault";
  448. }
  449. break;
  450. case "Duplex":
  451. switch (value.name) {
  452. case "Simplex":
  453. case "DuplexFlipShortEdge":
  454. case "DuplexFlipLongEdge":
  455. prefValue = value.name;
  456. break;
  457. default:
  458. prefValue = "None";
  459. }
  460. break;
  461. case "PrintPageRange":
  462. const length = value.length;
  463. if (length % 2 !== 0) {
  464. break;
  465. }
  466. const isValid = value.every((page, i, arr) => {
  467. return Number.isInteger(page) && page > 0 && (i === 0 || page >= arr[i - 1]) && page <= this.numPages;
  468. });
  469. if (isValid) {
  470. prefValue = value;
  471. }
  472. break;
  473. case "NumCopies":
  474. if (value > 0) {
  475. prefValue = value;
  476. }
  477. break;
  478. default:
  479. if (typeof value !== "boolean") {
  480. throw new _util.FormatError(`viewerPreferences - expected a boolean value for: ${key}`);
  481. }
  482. prefValue = value;
  483. }
  484. if (prefValue !== undefined) {
  485. if (!prefs) {
  486. prefs = Object.create(null);
  487. }
  488. prefs[key] = prefValue;
  489. } else {
  490. (0, _util.info)(`Bad value in ViewerPreferences for "${key}".`);
  491. }
  492. }
  493. }
  494. return (0, _util.shadow)(this, "viewerPreferences", prefs);
  495. }
  496. get openAction() {
  497. const obj = this.catDict.get("OpenAction");
  498. let openAction = null;
  499. if ((0, _primitives.isDict)(obj)) {
  500. const destDict = new _primitives.Dict(this.xref);
  501. destDict.set("A", obj);
  502. const resultObj = {
  503. url: null,
  504. dest: null,
  505. action: null
  506. };
  507. Catalog.parseDestDictionary({
  508. destDict,
  509. resultObj
  510. });
  511. if (Array.isArray(resultObj.dest)) {
  512. if (!openAction) {
  513. openAction = Object.create(null);
  514. }
  515. openAction.dest = resultObj.dest;
  516. } else if (resultObj.action) {
  517. if (!openAction) {
  518. openAction = Object.create(null);
  519. }
  520. openAction.action = resultObj.action;
  521. }
  522. } else if (Array.isArray(obj)) {
  523. if (!openAction) {
  524. openAction = Object.create(null);
  525. }
  526. openAction.dest = obj;
  527. }
  528. return (0, _util.shadow)(this, "openAction", openAction);
  529. }
  530. get attachments() {
  531. const obj = this.catDict.get("Names");
  532. let attachments = null;
  533. if (obj && obj.has("EmbeddedFiles")) {
  534. const nameTree = new NameTree(obj.getRaw("EmbeddedFiles"), this.xref);
  535. const names = nameTree.getAll();
  536. for (const name in names) {
  537. const fs = new FileSpec(names[name], this.xref);
  538. if (!attachments) {
  539. attachments = Object.create(null);
  540. }
  541. attachments[(0, _util.stringToPDFString)(name)] = fs.serializable;
  542. }
  543. }
  544. return (0, _util.shadow)(this, "attachments", attachments);
  545. }
  546. get javaScript() {
  547. const obj = this.catDict.get("Names");
  548. let javaScript = null;
  549. function appendIfJavaScriptDict(jsDict) {
  550. const type = jsDict.get("S");
  551. if (!(0, _primitives.isName)(type, "JavaScript")) {
  552. return;
  553. }
  554. let js = jsDict.get("JS");
  555. if ((0, _primitives.isStream)(js)) {
  556. js = (0, _util.bytesToString)(js.getBytes());
  557. } else if (!(0, _util.isString)(js)) {
  558. return;
  559. }
  560. if (!javaScript) {
  561. javaScript = [];
  562. }
  563. javaScript.push((0, _util.stringToPDFString)(js));
  564. }
  565. if (obj && obj.has("JavaScript")) {
  566. const nameTree = new NameTree(obj.getRaw("JavaScript"), this.xref);
  567. const names = nameTree.getAll();
  568. for (const name in names) {
  569. const jsDict = names[name];
  570. if ((0, _primitives.isDict)(jsDict)) {
  571. appendIfJavaScriptDict(jsDict);
  572. }
  573. }
  574. }
  575. const openAction = this.catDict.get("OpenAction");
  576. if ((0, _primitives.isDict)(openAction) && (0, _primitives.isName)(openAction.get("S"), "JavaScript")) {
  577. appendIfJavaScriptDict(openAction);
  578. }
  579. return (0, _util.shadow)(this, "javaScript", javaScript);
  580. }
  581. fontFallback(id, handler) {
  582. const promises = [];
  583. this.fontCache.forEach(function (promise) {
  584. promises.push(promise);
  585. });
  586. return Promise.all(promises).then(translatedFonts => {
  587. for (const translatedFont of translatedFonts) {
  588. if (translatedFont.loadedName === id) {
  589. translatedFont.fallback(handler);
  590. return;
  591. }
  592. }
  593. });
  594. }
  595. cleanup(manuallyTriggered = false) {
  596. (0, _primitives.clearPrimitiveCaches)();
  597. this.globalImageCache.clear(manuallyTriggered);
  598. this.pageKidsCountCache.clear();
  599. const promises = [];
  600. this.fontCache.forEach(function (promise) {
  601. promises.push(promise);
  602. });
  603. return Promise.all(promises).then(translatedFonts => {
  604. for (const {
  605. dict
  606. } of translatedFonts) {
  607. delete dict.translated;
  608. }
  609. this.fontCache.clear();
  610. this.builtInCMapCache.clear();
  611. });
  612. }
  613. getPageDict(pageIndex) {
  614. const capability = (0, _util.createPromiseCapability)();
  615. const nodesToVisit = [this.catDict.getRaw("Pages")];
  616. const visitedNodes = new _primitives.RefSet();
  617. const xref = this.xref,
  618. pageKidsCountCache = this.pageKidsCountCache;
  619. let count,
  620. currentPageIndex = 0;
  621. function next() {
  622. while (nodesToVisit.length) {
  623. const currentNode = nodesToVisit.pop();
  624. if ((0, _primitives.isRef)(currentNode)) {
  625. count = pageKidsCountCache.get(currentNode);
  626. if (count > 0 && currentPageIndex + count < pageIndex) {
  627. currentPageIndex += count;
  628. continue;
  629. }
  630. if (visitedNodes.has(currentNode)) {
  631. capability.reject(new _util.FormatError("Pages tree contains circular reference."));
  632. return;
  633. }
  634. visitedNodes.put(currentNode);
  635. xref.fetchAsync(currentNode).then(function (obj) {
  636. if ((0, _primitives.isDict)(obj, "Page") || (0, _primitives.isDict)(obj) && !obj.has("Kids")) {
  637. if (pageIndex === currentPageIndex) {
  638. if (currentNode && !pageKidsCountCache.has(currentNode)) {
  639. pageKidsCountCache.put(currentNode, 1);
  640. }
  641. capability.resolve([obj, currentNode]);
  642. } else {
  643. currentPageIndex++;
  644. next();
  645. }
  646. return;
  647. }
  648. nodesToVisit.push(obj);
  649. next();
  650. }, capability.reject);
  651. return;
  652. }
  653. if (!(0, _primitives.isDict)(currentNode)) {
  654. capability.reject(new _util.FormatError("Page dictionary kid reference points to wrong type of object."));
  655. return;
  656. }
  657. count = currentNode.get("Count");
  658. if (Number.isInteger(count) && count >= 0) {
  659. const objId = currentNode.objId;
  660. if (objId && !pageKidsCountCache.has(objId)) {
  661. pageKidsCountCache.put(objId, count);
  662. }
  663. if (currentPageIndex + count <= pageIndex) {
  664. currentPageIndex += count;
  665. continue;
  666. }
  667. }
  668. const kids = currentNode.get("Kids");
  669. if (!Array.isArray(kids)) {
  670. if ((0, _primitives.isName)(currentNode.get("Type"), "Page") || !currentNode.has("Type") && currentNode.has("Contents")) {
  671. if (currentPageIndex === pageIndex) {
  672. capability.resolve([currentNode, null]);
  673. return;
  674. }
  675. currentPageIndex++;
  676. continue;
  677. }
  678. capability.reject(new _util.FormatError("Page dictionary kids object is not an array."));
  679. return;
  680. }
  681. for (let last = kids.length - 1; last >= 0; last--) {
  682. nodesToVisit.push(kids[last]);
  683. }
  684. }
  685. capability.reject(new Error(`Page index ${pageIndex} not found.`));
  686. }
  687. next();
  688. return capability.promise;
  689. }
  690. getPageIndex(pageRef) {
  691. const xref = this.xref;
  692. function pagesBeforeRef(kidRef) {
  693. let total = 0,
  694. parentRef;
  695. return xref.fetchAsync(kidRef).then(function (node) {
  696. if ((0, _primitives.isRefsEqual)(kidRef, pageRef) && !(0, _primitives.isDict)(node, "Page") && !((0, _primitives.isDict)(node) && !node.has("Type") && node.has("Contents"))) {
  697. throw new _util.FormatError("The reference does not point to a /Page dictionary.");
  698. }
  699. if (!node) {
  700. return null;
  701. }
  702. if (!(0, _primitives.isDict)(node)) {
  703. throw new _util.FormatError("Node must be a dictionary.");
  704. }
  705. parentRef = node.getRaw("Parent");
  706. return node.getAsync("Parent");
  707. }).then(function (parent) {
  708. if (!parent) {
  709. return null;
  710. }
  711. if (!(0, _primitives.isDict)(parent)) {
  712. throw new _util.FormatError("Parent must be a dictionary.");
  713. }
  714. return parent.getAsync("Kids");
  715. }).then(function (kids) {
  716. if (!kids) {
  717. return null;
  718. }
  719. const kidPromises = [];
  720. let found = false;
  721. for (let i = 0, ii = kids.length; i < ii; i++) {
  722. const kid = kids[i];
  723. if (!(0, _primitives.isRef)(kid)) {
  724. throw new _util.FormatError("Kid must be a reference.");
  725. }
  726. if ((0, _primitives.isRefsEqual)(kid, kidRef)) {
  727. found = true;
  728. break;
  729. }
  730. kidPromises.push(xref.fetchAsync(kid).then(function (obj) {
  731. if (!(0, _primitives.isDict)(obj)) {
  732. throw new _util.FormatError("Kid node must be a dictionary.");
  733. }
  734. if (obj.has("Count")) {
  735. total += obj.get("Count");
  736. } else {
  737. total++;
  738. }
  739. }));
  740. }
  741. if (!found) {
  742. throw new _util.FormatError("Kid reference not found in parent's kids.");
  743. }
  744. return Promise.all(kidPromises).then(function () {
  745. return [total, parentRef];
  746. });
  747. });
  748. }
  749. let total = 0;
  750. function next(ref) {
  751. return pagesBeforeRef(ref).then(function (args) {
  752. if (!args) {
  753. return total;
  754. }
  755. const [count, parentRef] = args;
  756. total += count;
  757. return next(parentRef);
  758. });
  759. }
  760. return next(pageRef);
  761. }
  762. static parseDestDictionary(params) {
  763. function addDefaultProtocolToUrl(url) {
  764. return url.startsWith("www.") ? `http://${url}` : url;
  765. }
  766. function tryConvertUrlEncoding(url) {
  767. try {
  768. return (0, _util.stringToUTF8String)(url);
  769. } catch (e) {
  770. return url;
  771. }
  772. }
  773. const destDict = params.destDict;
  774. if (!(0, _primitives.isDict)(destDict)) {
  775. (0, _util.warn)("parseDestDictionary: `destDict` must be a dictionary.");
  776. return;
  777. }
  778. const resultObj = params.resultObj;
  779. if (typeof resultObj !== "object") {
  780. (0, _util.warn)("parseDestDictionary: `resultObj` must be an object.");
  781. return;
  782. }
  783. const docBaseUrl = params.docBaseUrl || null;
  784. let action = destDict.get("A"),
  785. url,
  786. dest;
  787. if (!(0, _primitives.isDict)(action) && destDict.has("Dest")) {
  788. action = destDict.get("Dest");
  789. }
  790. if ((0, _primitives.isDict)(action)) {
  791. const actionType = action.get("S");
  792. if (!(0, _primitives.isName)(actionType)) {
  793. (0, _util.warn)("parseDestDictionary: Invalid type in Action dictionary.");
  794. return;
  795. }
  796. const actionName = actionType.name;
  797. switch (actionName) {
  798. case "URI":
  799. url = action.get("URI");
  800. if ((0, _primitives.isName)(url)) {
  801. url = "/" + url.name;
  802. } else if ((0, _util.isString)(url)) {
  803. url = addDefaultProtocolToUrl(url);
  804. }
  805. break;
  806. case "GoTo":
  807. dest = action.get("D");
  808. break;
  809. case "Launch":
  810. case "GoToR":
  811. const urlDict = action.get("F");
  812. if ((0, _primitives.isDict)(urlDict)) {
  813. url = urlDict.get("F") || null;
  814. } else if ((0, _util.isString)(urlDict)) {
  815. url = urlDict;
  816. }
  817. let remoteDest = action.get("D");
  818. if (remoteDest) {
  819. if ((0, _primitives.isName)(remoteDest)) {
  820. remoteDest = remoteDest.name;
  821. }
  822. if ((0, _util.isString)(url)) {
  823. const baseUrl = url.split("#")[0];
  824. if ((0, _util.isString)(remoteDest)) {
  825. url = baseUrl + "#" + remoteDest;
  826. } else if (Array.isArray(remoteDest)) {
  827. url = baseUrl + "#" + JSON.stringify(remoteDest);
  828. }
  829. }
  830. }
  831. const newWindow = action.get("NewWindow");
  832. if ((0, _util.isBool)(newWindow)) {
  833. resultObj.newWindow = newWindow;
  834. }
  835. break;
  836. case "Named":
  837. const namedAction = action.get("N");
  838. if ((0, _primitives.isName)(namedAction)) {
  839. resultObj.action = namedAction.name;
  840. }
  841. break;
  842. case "JavaScript":
  843. const jsAction = action.get("JS");
  844. let js;
  845. if ((0, _primitives.isStream)(jsAction)) {
  846. js = (0, _util.bytesToString)(jsAction.getBytes());
  847. } else if ((0, _util.isString)(jsAction)) {
  848. js = jsAction;
  849. }
  850. if (js) {
  851. const URL_OPEN_METHODS = ["app.launchURL", "window.open"];
  852. const regex = new RegExp("^\\s*(" + URL_OPEN_METHODS.join("|").split(".").join("\\.") + ")\\((?:'|\")([^'\"]*)(?:'|\")(?:,\\s*(\\w+)\\)|\\))", "i");
  853. const jsUrl = regex.exec((0, _util.stringToPDFString)(js));
  854. if (jsUrl && jsUrl[2]) {
  855. url = jsUrl[2];
  856. if (jsUrl[3] === "true" && jsUrl[1] === "app.launchURL") {
  857. resultObj.newWindow = true;
  858. }
  859. break;
  860. }
  861. }
  862. default:
  863. (0, _util.warn)(`parseDestDictionary: unsupported action type "${actionName}".`);
  864. break;
  865. }
  866. } else if (destDict.has("Dest")) {
  867. dest = destDict.get("Dest");
  868. }
  869. if ((0, _util.isString)(url)) {
  870. url = tryConvertUrlEncoding(url);
  871. const absoluteUrl = (0, _util.createValidAbsoluteUrl)(url, docBaseUrl);
  872. if (absoluteUrl) {
  873. resultObj.url = absoluteUrl.href;
  874. }
  875. resultObj.unsafeUrl = url;
  876. }
  877. if (dest) {
  878. if ((0, _primitives.isName)(dest)) {
  879. dest = dest.name;
  880. }
  881. if ((0, _util.isString)(dest) || Array.isArray(dest)) {
  882. resultObj.dest = dest;
  883. }
  884. }
  885. }
  886. }
  887. exports.Catalog = Catalog;
  888. var XRef = function XRefClosure() {
  889. function XRef(stream, pdfManager) {
  890. this.stream = stream;
  891. this.pdfManager = pdfManager;
  892. this.entries = [];
  893. this.xrefstms = Object.create(null);
  894. this._cacheMap = new Map();
  895. this.stats = {
  896. streamTypes: Object.create(null),
  897. fontTypes: Object.create(null)
  898. };
  899. }
  900. XRef.prototype = {
  901. setStartXRef: function XRef_setStartXRef(startXRef) {
  902. this.startXRefQueue = [startXRef];
  903. },
  904. parse: function XRef_parse(recoveryMode) {
  905. var trailerDict;
  906. if (!recoveryMode) {
  907. trailerDict = this.readXRef();
  908. } else {
  909. (0, _util.warn)("Indexing all PDF objects");
  910. trailerDict = this.indexObjects();
  911. }
  912. trailerDict.assignXref(this);
  913. this.trailer = trailerDict;
  914. let encrypt;
  915. try {
  916. encrypt = trailerDict.get("Encrypt");
  917. } catch (ex) {
  918. if (ex instanceof _core_utils.MissingDataException) {
  919. throw ex;
  920. }
  921. (0, _util.warn)(`XRef.parse - Invalid "Encrypt" reference: "${ex}".`);
  922. }
  923. if ((0, _primitives.isDict)(encrypt)) {
  924. var ids = trailerDict.get("ID");
  925. var fileId = ids && ids.length ? ids[0] : "";
  926. encrypt.suppressEncryption = true;
  927. this.encrypt = new _crypto.CipherTransformFactory(encrypt, fileId, this.pdfManager.password);
  928. }
  929. let root;
  930. try {
  931. root = trailerDict.get("Root");
  932. } catch (ex) {
  933. if (ex instanceof _core_utils.MissingDataException) {
  934. throw ex;
  935. }
  936. (0, _util.warn)(`XRef.parse - Invalid "Root" reference: "${ex}".`);
  937. }
  938. if ((0, _primitives.isDict)(root) && root.has("Pages")) {
  939. this.root = root;
  940. } else {
  941. if (!recoveryMode) {
  942. throw new _core_utils.XRefParseException();
  943. }
  944. throw new _util.FormatError("Invalid root reference");
  945. }
  946. },
  947. processXRefTable: function XRef_processXRefTable(parser) {
  948. if (!("tableState" in this)) {
  949. this.tableState = {
  950. entryNum: 0,
  951. streamPos: parser.lexer.stream.pos,
  952. parserBuf1: parser.buf1,
  953. parserBuf2: parser.buf2
  954. };
  955. }
  956. var obj = this.readXRefTable(parser);
  957. if (!(0, _primitives.isCmd)(obj, "trailer")) {
  958. throw new _util.FormatError("Invalid XRef table: could not find trailer dictionary");
  959. }
  960. var dict = parser.getObj();
  961. if (!(0, _primitives.isDict)(dict) && dict.dict) {
  962. dict = dict.dict;
  963. }
  964. if (!(0, _primitives.isDict)(dict)) {
  965. throw new _util.FormatError("Invalid XRef table: could not parse trailer dictionary");
  966. }
  967. delete this.tableState;
  968. return dict;
  969. },
  970. readXRefTable: function XRef_readXRefTable(parser) {
  971. var stream = parser.lexer.stream;
  972. var tableState = this.tableState;
  973. stream.pos = tableState.streamPos;
  974. parser.buf1 = tableState.parserBuf1;
  975. parser.buf2 = tableState.parserBuf2;
  976. var obj;
  977. while (true) {
  978. if (!("firstEntryNum" in tableState) || !("entryCount" in tableState)) {
  979. if ((0, _primitives.isCmd)(obj = parser.getObj(), "trailer")) {
  980. break;
  981. }
  982. tableState.firstEntryNum = obj;
  983. tableState.entryCount = parser.getObj();
  984. }
  985. var first = tableState.firstEntryNum;
  986. var count = tableState.entryCount;
  987. if (!Number.isInteger(first) || !Number.isInteger(count)) {
  988. throw new _util.FormatError("Invalid XRef table: wrong types in subsection header");
  989. }
  990. for (var i = tableState.entryNum; i < count; i++) {
  991. tableState.streamPos = stream.pos;
  992. tableState.entryNum = i;
  993. tableState.parserBuf1 = parser.buf1;
  994. tableState.parserBuf2 = parser.buf2;
  995. var entry = {};
  996. entry.offset = parser.getObj();
  997. entry.gen = parser.getObj();
  998. var type = parser.getObj();
  999. if (type instanceof _primitives.Cmd) {
  1000. switch (type.cmd) {
  1001. case "f":
  1002. entry.free = true;
  1003. break;
  1004. case "n":
  1005. entry.uncompressed = true;
  1006. break;
  1007. }
  1008. }
  1009. if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.gen) || !(entry.free || entry.uncompressed)) {
  1010. throw new _util.FormatError(`Invalid entry in XRef subsection: ${first}, ${count}`);
  1011. }
  1012. if (i === 0 && entry.free && first === 1) {
  1013. first = 0;
  1014. }
  1015. if (!this.entries[i + first]) {
  1016. this.entries[i + first] = entry;
  1017. }
  1018. }
  1019. tableState.entryNum = 0;
  1020. tableState.streamPos = stream.pos;
  1021. tableState.parserBuf1 = parser.buf1;
  1022. tableState.parserBuf2 = parser.buf2;
  1023. delete tableState.firstEntryNum;
  1024. delete tableState.entryCount;
  1025. }
  1026. if (this.entries[0] && !this.entries[0].free) {
  1027. throw new _util.FormatError("Invalid XRef table: unexpected first object");
  1028. }
  1029. return obj;
  1030. },
  1031. processXRefStream: function XRef_processXRefStream(stream) {
  1032. if (!("streamState" in this)) {
  1033. var streamParameters = stream.dict;
  1034. var byteWidths = streamParameters.get("W");
  1035. var range = streamParameters.get("Index");
  1036. if (!range) {
  1037. range = [0, streamParameters.get("Size")];
  1038. }
  1039. this.streamState = {
  1040. entryRanges: range,
  1041. byteWidths,
  1042. entryNum: 0,
  1043. streamPos: stream.pos
  1044. };
  1045. }
  1046. this.readXRefStream(stream);
  1047. delete this.streamState;
  1048. return stream.dict;
  1049. },
  1050. readXRefStream: function XRef_readXRefStream(stream) {
  1051. var i, j;
  1052. var streamState = this.streamState;
  1053. stream.pos = streamState.streamPos;
  1054. var byteWidths = streamState.byteWidths;
  1055. var typeFieldWidth = byteWidths[0];
  1056. var offsetFieldWidth = byteWidths[1];
  1057. var generationFieldWidth = byteWidths[2];
  1058. var entryRanges = streamState.entryRanges;
  1059. while (entryRanges.length > 0) {
  1060. var first = entryRanges[0];
  1061. var n = entryRanges[1];
  1062. if (!Number.isInteger(first) || !Number.isInteger(n)) {
  1063. throw new _util.FormatError(`Invalid XRef range fields: ${first}, ${n}`);
  1064. }
  1065. if (!Number.isInteger(typeFieldWidth) || !Number.isInteger(offsetFieldWidth) || !Number.isInteger(generationFieldWidth)) {
  1066. throw new _util.FormatError(`Invalid XRef entry fields length: ${first}, ${n}`);
  1067. }
  1068. for (i = streamState.entryNum; i < n; ++i) {
  1069. streamState.entryNum = i;
  1070. streamState.streamPos = stream.pos;
  1071. var type = 0,
  1072. offset = 0,
  1073. generation = 0;
  1074. for (j = 0; j < typeFieldWidth; ++j) {
  1075. type = type << 8 | stream.getByte();
  1076. }
  1077. if (typeFieldWidth === 0) {
  1078. type = 1;
  1079. }
  1080. for (j = 0; j < offsetFieldWidth; ++j) {
  1081. offset = offset << 8 | stream.getByte();
  1082. }
  1083. for (j = 0; j < generationFieldWidth; ++j) {
  1084. generation = generation << 8 | stream.getByte();
  1085. }
  1086. var entry = {};
  1087. entry.offset = offset;
  1088. entry.gen = generation;
  1089. switch (type) {
  1090. case 0:
  1091. entry.free = true;
  1092. break;
  1093. case 1:
  1094. entry.uncompressed = true;
  1095. break;
  1096. case 2:
  1097. break;
  1098. default:
  1099. throw new _util.FormatError(`Invalid XRef entry type: ${type}`);
  1100. }
  1101. if (!this.entries[first + i]) {
  1102. this.entries[first + i] = entry;
  1103. }
  1104. }
  1105. streamState.entryNum = 0;
  1106. streamState.streamPos = stream.pos;
  1107. entryRanges.splice(0, 2);
  1108. }
  1109. },
  1110. indexObjects: function XRef_indexObjects() {
  1111. var TAB = 0x9,
  1112. LF = 0xa,
  1113. CR = 0xd,
  1114. SPACE = 0x20;
  1115. var PERCENT = 0x25,
  1116. LT = 0x3c;
  1117. function readToken(data, offset) {
  1118. var token = "",
  1119. ch = data[offset];
  1120. while (ch !== LF && ch !== CR && ch !== LT) {
  1121. if (++offset >= data.length) {
  1122. break;
  1123. }
  1124. token += String.fromCharCode(ch);
  1125. ch = data[offset];
  1126. }
  1127. return token;
  1128. }
  1129. function skipUntil(data, offset, what) {
  1130. var length = what.length,
  1131. dataLength = data.length;
  1132. var skipped = 0;
  1133. while (offset < dataLength) {
  1134. var i = 0;
  1135. while (i < length && data[offset + i] === what[i]) {
  1136. ++i;
  1137. }
  1138. if (i >= length) {
  1139. break;
  1140. }
  1141. offset++;
  1142. skipped++;
  1143. }
  1144. return skipped;
  1145. }
  1146. var objRegExp = /^(\d+)\s+(\d+)\s+obj\b/;
  1147. const endobjRegExp = /\bendobj[\b\s]$/;
  1148. const nestedObjRegExp = /\s+(\d+\s+\d+\s+obj[\b\s<])$/;
  1149. const CHECK_CONTENT_LENGTH = 25;
  1150. var trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
  1151. var startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]);
  1152. const objBytes = new Uint8Array([111, 98, 106]);
  1153. var xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
  1154. this.entries.length = 0;
  1155. var stream = this.stream;
  1156. stream.pos = 0;
  1157. var buffer = stream.getBytes();
  1158. var position = stream.start,
  1159. length = buffer.length;
  1160. var trailers = [],
  1161. xrefStms = [];
  1162. while (position < length) {
  1163. var ch = buffer[position];
  1164. if (ch === TAB || ch === LF || ch === CR || ch === SPACE) {
  1165. ++position;
  1166. continue;
  1167. }
  1168. if (ch === PERCENT) {
  1169. do {
  1170. ++position;
  1171. if (position >= length) {
  1172. break;
  1173. }
  1174. ch = buffer[position];
  1175. } while (ch !== LF && ch !== CR);
  1176. continue;
  1177. }
  1178. var token = readToken(buffer, position);
  1179. var m;
  1180. if (token.startsWith("xref") && (token.length === 4 || /\s/.test(token[4]))) {
  1181. position += skipUntil(buffer, position, trailerBytes);
  1182. trailers.push(position);
  1183. position += skipUntil(buffer, position, startxrefBytes);
  1184. } else if (m = objRegExp.exec(token)) {
  1185. const num = m[1] | 0,
  1186. gen = m[2] | 0;
  1187. if (!this.entries[num] || this.entries[num].gen === gen) {
  1188. this.entries[num] = {
  1189. offset: position - stream.start,
  1190. gen,
  1191. uncompressed: true
  1192. };
  1193. }
  1194. let contentLength,
  1195. startPos = position + token.length;
  1196. while (startPos < buffer.length) {
  1197. const endPos = startPos + skipUntil(buffer, startPos, objBytes) + 4;
  1198. contentLength = endPos - position;
  1199. const checkPos = Math.max(endPos - CHECK_CONTENT_LENGTH, startPos);
  1200. const tokenStr = (0, _util.bytesToString)(buffer.subarray(checkPos, endPos));
  1201. if (endobjRegExp.test(tokenStr)) {
  1202. break;
  1203. } else {
  1204. const objToken = nestedObjRegExp.exec(tokenStr);
  1205. if (objToken && objToken[1]) {
  1206. (0, _util.warn)('indexObjects: Found new "obj" inside of another "obj", ' + 'caused by missing "endobj" -- trying to recover.');
  1207. contentLength -= objToken[1].length;
  1208. break;
  1209. }
  1210. }
  1211. startPos = endPos;
  1212. }
  1213. const content = buffer.subarray(position, position + contentLength);
  1214. var xrefTagOffset = skipUntil(content, 0, xrefBytes);
  1215. if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) {
  1216. xrefStms.push(position - stream.start);
  1217. this.xrefstms[position - stream.start] = 1;
  1218. }
  1219. position += contentLength;
  1220. } else if (token.startsWith("trailer") && (token.length === 7 || /\s/.test(token[7]))) {
  1221. trailers.push(position);
  1222. position += skipUntil(buffer, position, startxrefBytes);
  1223. } else {
  1224. position += token.length + 1;
  1225. }
  1226. }
  1227. var i, ii;
  1228. for (i = 0, ii = xrefStms.length; i < ii; ++i) {
  1229. this.startXRefQueue.push(xrefStms[i]);
  1230. this.readXRef(true);
  1231. }
  1232. let trailerDict;
  1233. for (i = 0, ii = trailers.length; i < ii; ++i) {
  1234. stream.pos = trailers[i];
  1235. const parser = new _parser.Parser({
  1236. lexer: new _parser.Lexer(stream),
  1237. xref: this,
  1238. allowStreams: true,
  1239. recoveryMode: true
  1240. });
  1241. var obj = parser.getObj();
  1242. if (!(0, _primitives.isCmd)(obj, "trailer")) {
  1243. continue;
  1244. }
  1245. const dict = parser.getObj();
  1246. if (!(0, _primitives.isDict)(dict)) {
  1247. continue;
  1248. }
  1249. let rootDict;
  1250. try {
  1251. rootDict = dict.get("Root");
  1252. } catch (ex) {
  1253. if (ex instanceof _core_utils.MissingDataException) {
  1254. throw ex;
  1255. }
  1256. continue;
  1257. }
  1258. if (!(0, _primitives.isDict)(rootDict) || !rootDict.has("Pages")) {
  1259. continue;
  1260. }
  1261. if (dict.has("ID")) {
  1262. return dict;
  1263. }
  1264. trailerDict = dict;
  1265. }
  1266. if (trailerDict) {
  1267. return trailerDict;
  1268. }
  1269. throw new _util.InvalidPDFException("Invalid PDF structure.");
  1270. },
  1271. readXRef: function XRef_readXRef(recoveryMode) {
  1272. var stream = this.stream;
  1273. const startXRefParsedCache = Object.create(null);
  1274. try {
  1275. while (this.startXRefQueue.length) {
  1276. var startXRef = this.startXRefQueue[0];
  1277. if (startXRefParsedCache[startXRef]) {
  1278. (0, _util.warn)("readXRef - skipping XRef table since it was already parsed.");
  1279. this.startXRefQueue.shift();
  1280. continue;
  1281. }
  1282. startXRefParsedCache[startXRef] = true;
  1283. stream.pos = startXRef + stream.start;
  1284. const parser = new _parser.Parser({
  1285. lexer: new _parser.Lexer(stream),
  1286. xref: this,
  1287. allowStreams: true
  1288. });
  1289. var obj = parser.getObj();
  1290. var dict;
  1291. if ((0, _primitives.isCmd)(obj, "xref")) {
  1292. dict = this.processXRefTable(parser);
  1293. if (!this.topDict) {
  1294. this.topDict = dict;
  1295. }
  1296. obj = dict.get("XRefStm");
  1297. if (Number.isInteger(obj)) {
  1298. var pos = obj;
  1299. if (!(pos in this.xrefstms)) {
  1300. this.xrefstms[pos] = 1;
  1301. this.startXRefQueue.push(pos);
  1302. }
  1303. }
  1304. } else if (Number.isInteger(obj)) {
  1305. if (!Number.isInteger(parser.getObj()) || !(0, _primitives.isCmd)(parser.getObj(), "obj") || !(0, _primitives.isStream)(obj = parser.getObj())) {
  1306. throw new _util.FormatError("Invalid XRef stream");
  1307. }
  1308. dict = this.processXRefStream(obj);
  1309. if (!this.topDict) {
  1310. this.topDict = dict;
  1311. }
  1312. if (!dict) {
  1313. throw new _util.FormatError("Failed to read XRef stream");
  1314. }
  1315. } else {
  1316. throw new _util.FormatError("Invalid XRef stream header");
  1317. }
  1318. obj = dict.get("Prev");
  1319. if (Number.isInteger(obj)) {
  1320. this.startXRefQueue.push(obj);
  1321. } else if ((0, _primitives.isRef)(obj)) {
  1322. this.startXRefQueue.push(obj.num);
  1323. }
  1324. this.startXRefQueue.shift();
  1325. }
  1326. return this.topDict;
  1327. } catch (e) {
  1328. if (e instanceof _core_utils.MissingDataException) {
  1329. throw e;
  1330. }
  1331. (0, _util.info)("(while reading XRef): " + e);
  1332. }
  1333. if (recoveryMode) {
  1334. return undefined;
  1335. }
  1336. throw new _core_utils.XRefParseException();
  1337. },
  1338. getEntry: function XRef_getEntry(i) {
  1339. var xrefEntry = this.entries[i];
  1340. if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
  1341. return xrefEntry;
  1342. }
  1343. return null;
  1344. },
  1345. fetchIfRef: function XRef_fetchIfRef(obj, suppressEncryption) {
  1346. if (obj instanceof _primitives.Ref) {
  1347. return this.fetch(obj, suppressEncryption);
  1348. }
  1349. return obj;
  1350. },
  1351. fetch: function XRef_fetch(ref, suppressEncryption) {
  1352. if (!(ref instanceof _primitives.Ref)) {
  1353. throw new Error("ref object is not a reference");
  1354. }
  1355. const num = ref.num;
  1356. const cacheEntry = this._cacheMap.get(num);
  1357. if (cacheEntry !== undefined) {
  1358. if (cacheEntry instanceof _primitives.Dict && !cacheEntry.objId) {
  1359. cacheEntry.objId = ref.toString();
  1360. }
  1361. return cacheEntry;
  1362. }
  1363. let xrefEntry = this.getEntry(num);
  1364. if (xrefEntry === null) {
  1365. this._cacheMap.set(num, xrefEntry);
  1366. return xrefEntry;
  1367. }
  1368. if (xrefEntry.uncompressed) {
  1369. xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
  1370. } else {
  1371. xrefEntry = this.fetchCompressed(ref, xrefEntry, suppressEncryption);
  1372. }
  1373. if ((0, _primitives.isDict)(xrefEntry)) {
  1374. xrefEntry.objId = ref.toString();
  1375. } else if ((0, _primitives.isStream)(xrefEntry)) {
  1376. xrefEntry.dict.objId = ref.toString();
  1377. }
  1378. return xrefEntry;
  1379. },
  1380. fetchUncompressed(ref, xrefEntry, suppressEncryption = false) {
  1381. var gen = ref.gen;
  1382. var num = ref.num;
  1383. if (xrefEntry.gen !== gen) {
  1384. throw new _core_utils.XRefEntryException(`Inconsistent generation in XRef: ${ref}`);
  1385. }
  1386. var stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start);
  1387. const parser = new _parser.Parser({
  1388. lexer: new _parser.Lexer(stream),
  1389. xref: this,
  1390. allowStreams: true
  1391. });
  1392. var obj1 = parser.getObj();
  1393. var obj2 = parser.getObj();
  1394. var obj3 = parser.getObj();
  1395. if (obj1 !== num || obj2 !== gen || !(obj3 instanceof _primitives.Cmd)) {
  1396. throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
  1397. }
  1398. if (obj3.cmd !== "obj") {
  1399. if (obj3.cmd.startsWith("obj")) {
  1400. num = parseInt(obj3.cmd.substring(3), 10);
  1401. if (!Number.isNaN(num)) {
  1402. return num;
  1403. }
  1404. }
  1405. throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
  1406. }
  1407. if (this.encrypt && !suppressEncryption) {
  1408. xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
  1409. } else {
  1410. xrefEntry = parser.getObj();
  1411. }
  1412. if (!(0, _primitives.isStream)(xrefEntry)) {
  1413. this._cacheMap.set(num, xrefEntry);
  1414. }
  1415. return xrefEntry;
  1416. },
  1417. fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
  1418. const tableOffset = xrefEntry.offset;
  1419. const stream = this.fetch(_primitives.Ref.get(tableOffset, 0));
  1420. if (!(0, _primitives.isStream)(stream)) {
  1421. throw new _util.FormatError("bad ObjStm stream");
  1422. }
  1423. const first = stream.dict.get("First");
  1424. const n = stream.dict.get("N");
  1425. if (!Number.isInteger(first) || !Number.isInteger(n)) {
  1426. throw new _util.FormatError("invalid first and n parameters for ObjStm stream");
  1427. }
  1428. const parser = new _parser.Parser({
  1429. lexer: new _parser.Lexer(stream),
  1430. xref: this,
  1431. allowStreams: true
  1432. });
  1433. const nums = new Array(n);
  1434. for (let i = 0; i < n; ++i) {
  1435. const num = parser.getObj();
  1436. if (!Number.isInteger(num)) {
  1437. throw new _util.FormatError(`invalid object number in the ObjStm stream: ${num}`);
  1438. }
  1439. const offset = parser.getObj();
  1440. if (!Number.isInteger(offset)) {
  1441. throw new _util.FormatError(`invalid object offset in the ObjStm stream: ${offset}`);
  1442. }
  1443. nums[i] = num;
  1444. }
  1445. const entries = new Array(n);
  1446. for (let i = 0; i < n; ++i) {
  1447. const obj = parser.getObj();
  1448. entries[i] = obj;
  1449. if (parser.buf1 instanceof _primitives.Cmd && parser.buf1.cmd === "endobj") {
  1450. parser.shift();
  1451. }
  1452. if ((0, _primitives.isStream)(obj)) {
  1453. continue;
  1454. }
  1455. const num = nums[i],
  1456. entry = this.entries[num];
  1457. if (entry && entry.offset === tableOffset && entry.gen === i) {
  1458. this._cacheMap.set(num, obj);
  1459. }
  1460. }
  1461. xrefEntry = entries[xrefEntry.gen];
  1462. if (xrefEntry === undefined) {
  1463. throw new _core_utils.XRefEntryException(`Bad (compressed) XRef entry: ${ref}`);
  1464. }
  1465. return xrefEntry;
  1466. },
  1467. async fetchIfRefAsync(obj, suppressEncryption) {
  1468. if (obj instanceof _primitives.Ref) {
  1469. return this.fetchAsync(obj, suppressEncryption);
  1470. }
  1471. return obj;
  1472. },
  1473. async fetchAsync(ref, suppressEncryption) {
  1474. try {
  1475. return this.fetch(ref, suppressEncryption);
  1476. } catch (ex) {
  1477. if (!(ex instanceof _core_utils.MissingDataException)) {
  1478. throw ex;
  1479. }
  1480. await this.pdfManager.requestRange(ex.begin, ex.end);
  1481. return this.fetchAsync(ref, suppressEncryption);
  1482. }
  1483. },
  1484. getCatalogObj: function XRef_getCatalogObj() {
  1485. return this.root;
  1486. }
  1487. };
  1488. return XRef;
  1489. }();
  1490. exports.XRef = XRef;
  1491. class NameOrNumberTree {
  1492. constructor(root, xref, type) {
  1493. if (this.constructor === NameOrNumberTree) {
  1494. (0, _util.unreachable)("Cannot initialize NameOrNumberTree.");
  1495. }
  1496. this.root = root;
  1497. this.xref = xref;
  1498. this._type = type;
  1499. }
  1500. getAll() {
  1501. const dict = Object.create(null);
  1502. if (!this.root) {
  1503. return dict;
  1504. }
  1505. const xref = this.xref;
  1506. const processed = new _primitives.RefSet();
  1507. processed.put(this.root);
  1508. const queue = [this.root];
  1509. while (queue.length > 0) {
  1510. const obj = xref.fetchIfRef(queue.shift());
  1511. if (!(0, _primitives.isDict)(obj)) {
  1512. continue;
  1513. }
  1514. if (obj.has("Kids")) {
  1515. const kids = obj.get("Kids");
  1516. for (let i = 0, ii = kids.length; i < ii; i++) {
  1517. const kid = kids[i];
  1518. if (processed.has(kid)) {
  1519. throw new _util.FormatError(`Duplicate entry in "${this._type}" tree.`);
  1520. }
  1521. queue.push(kid);
  1522. processed.put(kid);
  1523. }
  1524. continue;
  1525. }
  1526. const entries = obj.get(this._type);
  1527. if (Array.isArray(entries)) {
  1528. for (let i = 0, ii = entries.length; i < ii; i += 2) {
  1529. dict[xref.fetchIfRef(entries[i])] = xref.fetchIfRef(entries[i + 1]);
  1530. }
  1531. }
  1532. }
  1533. return dict;
  1534. }
  1535. get(key) {
  1536. if (!this.root) {
  1537. return null;
  1538. }
  1539. const xref = this.xref;
  1540. let kidsOrEntries = xref.fetchIfRef(this.root);
  1541. let loopCount = 0;
  1542. const MAX_LEVELS = 10;
  1543. while (kidsOrEntries.has("Kids")) {
  1544. if (++loopCount > MAX_LEVELS) {
  1545. (0, _util.warn)(`Search depth limit reached for "${this._type}" tree.`);
  1546. return null;
  1547. }
  1548. const kids = kidsOrEntries.get("Kids");
  1549. if (!Array.isArray(kids)) {
  1550. return null;
  1551. }
  1552. let l = 0,
  1553. r = kids.length - 1;
  1554. while (l <= r) {
  1555. const m = l + r >> 1;
  1556. const kid = xref.fetchIfRef(kids[m]);
  1557. const limits = kid.get("Limits");
  1558. if (key < xref.fetchIfRef(limits[0])) {
  1559. r = m - 1;
  1560. } else if (key > xref.fetchIfRef(limits[1])) {
  1561. l = m + 1;
  1562. } else {
  1563. kidsOrEntries = xref.fetchIfRef(kids[m]);
  1564. break;
  1565. }
  1566. }
  1567. if (l > r) {
  1568. return null;
  1569. }
  1570. }
  1571. const entries = kidsOrEntries.get(this._type);
  1572. if (Array.isArray(entries)) {
  1573. let l = 0,
  1574. r = entries.length - 2;
  1575. while (l <= r) {
  1576. const tmp = l + r >> 1,
  1577. m = tmp + (tmp & 1);
  1578. const currentKey = xref.fetchIfRef(entries[m]);
  1579. if (key < currentKey) {
  1580. r = m - 2;
  1581. } else if (key > currentKey) {
  1582. l = m + 2;
  1583. } else {
  1584. return xref.fetchIfRef(entries[m + 1]);
  1585. }
  1586. }
  1587. (0, _util.info)(`Falling back to an exhaustive search, for key "${key}", ` + `in "${this._type}" tree.`);
  1588. for (let m = 0, mm = entries.length; m < mm; m += 2) {
  1589. const currentKey = xref.fetchIfRef(entries[m]);
  1590. if (currentKey === key) {
  1591. (0, _util.warn)(`The "${key}" key was found at an incorrect, ` + `i.e. out-of-order, position in "${this._type}" tree.`);
  1592. return xref.fetchIfRef(entries[m + 1]);
  1593. }
  1594. }
  1595. }
  1596. return null;
  1597. }
  1598. }
  1599. class NameTree extends NameOrNumberTree {
  1600. constructor(root, xref) {
  1601. super(root, xref, "Names");
  1602. }
  1603. }
  1604. class NumberTree extends NameOrNumberTree {
  1605. constructor(root, xref) {
  1606. super(root, xref, "Nums");
  1607. }
  1608. }
  1609. var FileSpec = function FileSpecClosure() {
  1610. function FileSpec(root, xref) {
  1611. if (!root || !(0, _primitives.isDict)(root)) {
  1612. return;
  1613. }
  1614. this.xref = xref;
  1615. this.root = root;
  1616. if (root.has("FS")) {
  1617. this.fs = root.get("FS");
  1618. }
  1619. this.description = root.has("Desc") ? (0, _util.stringToPDFString)(root.get("Desc")) : "";
  1620. if (root.has("RF")) {
  1621. (0, _util.warn)("Related file specifications are not supported");
  1622. }
  1623. this.contentAvailable = true;
  1624. if (!root.has("EF")) {
  1625. this.contentAvailable = false;
  1626. (0, _util.warn)("Non-embedded file specifications are not supported");
  1627. }
  1628. }
  1629. function pickPlatformItem(dict) {
  1630. if (dict.has("UF")) {
  1631. return dict.get("UF");
  1632. } else if (dict.has("F")) {
  1633. return dict.get("F");
  1634. } else if (dict.has("Unix")) {
  1635. return dict.get("Unix");
  1636. } else if (dict.has("Mac")) {
  1637. return dict.get("Mac");
  1638. } else if (dict.has("DOS")) {
  1639. return dict.get("DOS");
  1640. }
  1641. return null;
  1642. }
  1643. FileSpec.prototype = {
  1644. get filename() {
  1645. if (!this._filename && this.root) {
  1646. var filename = pickPlatformItem(this.root) || "unnamed";
  1647. this._filename = (0, _util.stringToPDFString)(filename).replace(/\\\\/g, "\\").replace(/\\\//g, "/").replace(/\\/g, "/");
  1648. }
  1649. return this._filename;
  1650. },
  1651. get content() {
  1652. if (!this.contentAvailable) {
  1653. return null;
  1654. }
  1655. if (!this.contentRef && this.root) {
  1656. this.contentRef = pickPlatformItem(this.root.get("EF"));
  1657. }
  1658. var content = null;
  1659. if (this.contentRef) {
  1660. var xref = this.xref;
  1661. var fileObj = xref.fetchIfRef(this.contentRef);
  1662. if (fileObj && (0, _primitives.isStream)(fileObj)) {
  1663. content = fileObj.getBytes();
  1664. } else {
  1665. (0, _util.warn)("Embedded file specification points to non-existing/invalid " + "content");
  1666. }
  1667. } else {
  1668. (0, _util.warn)("Embedded file specification does not have a content");
  1669. }
  1670. return content;
  1671. },
  1672. get serializable() {
  1673. return {
  1674. filename: this.filename,
  1675. content: this.content
  1676. };
  1677. }
  1678. };
  1679. return FileSpec;
  1680. }();
  1681. exports.FileSpec = FileSpec;
  1682. const ObjectLoader = function () {
  1683. function mayHaveChildren(value) {
  1684. return value instanceof _primitives.Ref || value instanceof _primitives.Dict || Array.isArray(value) || (0, _primitives.isStream)(value);
  1685. }
  1686. function addChildren(node, nodesToVisit) {
  1687. if (node instanceof _primitives.Dict || (0, _primitives.isStream)(node)) {
  1688. const dict = node instanceof _primitives.Dict ? node : node.dict;
  1689. const dictKeys = dict.getKeys();
  1690. for (let i = 0, ii = dictKeys.length; i < ii; i++) {
  1691. const rawValue = dict.getRaw(dictKeys[i]);
  1692. if (mayHaveChildren(rawValue)) {
  1693. nodesToVisit.push(rawValue);
  1694. }
  1695. }
  1696. } else if (Array.isArray(node)) {
  1697. for (let i = 0, ii = node.length; i < ii; i++) {
  1698. const value = node[i];
  1699. if (mayHaveChildren(value)) {
  1700. nodesToVisit.push(value);
  1701. }
  1702. }
  1703. }
  1704. }
  1705. function ObjectLoader(dict, keys, xref) {
  1706. this.dict = dict;
  1707. this.keys = keys;
  1708. this.xref = xref;
  1709. this.refSet = null;
  1710. }
  1711. ObjectLoader.prototype = {
  1712. async load() {
  1713. if (!this.xref.stream.allChunksLoaded || this.xref.stream.allChunksLoaded()) {
  1714. return undefined;
  1715. }
  1716. const {
  1717. keys,
  1718. dict
  1719. } = this;
  1720. this.refSet = new _primitives.RefSet();
  1721. const nodesToVisit = [];
  1722. for (let i = 0, ii = keys.length; i < ii; i++) {
  1723. const rawValue = dict.getRaw(keys[i]);
  1724. if (rawValue !== undefined) {
  1725. nodesToVisit.push(rawValue);
  1726. }
  1727. }
  1728. return this._walk(nodesToVisit);
  1729. },
  1730. async _walk(nodesToVisit) {
  1731. const nodesToRevisit = [];
  1732. const pendingRequests = [];
  1733. while (nodesToVisit.length) {
  1734. let currentNode = nodesToVisit.pop();
  1735. if (currentNode instanceof _primitives.Ref) {
  1736. if (this.refSet.has(currentNode)) {
  1737. continue;
  1738. }
  1739. try {
  1740. this.refSet.put(currentNode);
  1741. currentNode = this.xref.fetch(currentNode);
  1742. } catch (ex) {
  1743. if (!(ex instanceof _core_utils.MissingDataException)) {
  1744. throw ex;
  1745. }
  1746. nodesToRevisit.push(currentNode);
  1747. pendingRequests.push({
  1748. begin: ex.begin,
  1749. end: ex.end
  1750. });
  1751. }
  1752. }
  1753. if (currentNode && currentNode.getBaseStreams) {
  1754. const baseStreams = currentNode.getBaseStreams();
  1755. let foundMissingData = false;
  1756. for (let i = 0, ii = baseStreams.length; i < ii; i++) {
  1757. const stream = baseStreams[i];
  1758. if (stream.allChunksLoaded && !stream.allChunksLoaded()) {
  1759. foundMissingData = true;
  1760. pendingRequests.push({
  1761. begin: stream.start,
  1762. end: stream.end
  1763. });
  1764. }
  1765. }
  1766. if (foundMissingData) {
  1767. nodesToRevisit.push(currentNode);
  1768. }
  1769. }
  1770. addChildren(currentNode, nodesToVisit);
  1771. }
  1772. if (pendingRequests.length) {
  1773. await this.xref.stream.manager.requestRanges(pendingRequests);
  1774. for (let i = 0, ii = nodesToRevisit.length; i < ii; i++) {
  1775. const node = nodesToRevisit[i];
  1776. if (node instanceof _primitives.Ref) {
  1777. this.refSet.remove(node);
  1778. }
  1779. }
  1780. return this._walk(nodesToRevisit);
  1781. }
  1782. this.refSet = null;
  1783. return undefined;
  1784. }
  1785. };
  1786. return ObjectLoader;
  1787. }();
  1788. exports.ObjectLoader = ObjectLoader;