xref.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * JavaScript code in this page
  4. *
  5. * Copyright 2022 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.XRef = void 0;
  27. var _util = require("../shared/util.js");
  28. var _primitives = require("./primitives.js");
  29. var _core_utils = require("./core_utils.js");
  30. var _parser = require("./parser.js");
  31. var _base_stream = require("./base_stream.js");
  32. var _crypto = require("./crypto.js");
  33. class XRef {
  34. constructor(stream, pdfManager) {
  35. this.stream = stream;
  36. this.pdfManager = pdfManager;
  37. this.entries = [];
  38. this.xrefstms = Object.create(null);
  39. this._cacheMap = new Map();
  40. this._pendingRefs = new _primitives.RefSet();
  41. this.stats = new _core_utils.DocStats(pdfManager.msgHandler);
  42. this._newRefNum = null;
  43. }
  44. getNewRef() {
  45. if (this._newRefNum === null) {
  46. this._newRefNum = this.entries.length || 1;
  47. }
  48. return _primitives.Ref.get(this._newRefNum++, 0);
  49. }
  50. resetNewRef() {
  51. this._newRefNum = null;
  52. }
  53. setStartXRef(startXRef) {
  54. this.startXRefQueue = [startXRef];
  55. }
  56. parse(recoveryMode = false) {
  57. let trailerDict;
  58. if (!recoveryMode) {
  59. trailerDict = this.readXRef();
  60. } else {
  61. (0, _util.warn)("Indexing all PDF objects");
  62. trailerDict = this.indexObjects();
  63. }
  64. trailerDict.assignXref(this);
  65. this.trailer = trailerDict;
  66. let encrypt;
  67. try {
  68. encrypt = trailerDict.get("Encrypt");
  69. } catch (ex) {
  70. if (ex instanceof _core_utils.MissingDataException) {
  71. throw ex;
  72. }
  73. (0, _util.warn)(`XRef.parse - Invalid "Encrypt" reference: "${ex}".`);
  74. }
  75. if (encrypt instanceof _primitives.Dict) {
  76. const ids = trailerDict.get("ID");
  77. const fileId = ids && ids.length ? ids[0] : "";
  78. encrypt.suppressEncryption = true;
  79. this.encrypt = new _crypto.CipherTransformFactory(encrypt, fileId, this.pdfManager.password);
  80. }
  81. let root;
  82. try {
  83. root = trailerDict.get("Root");
  84. } catch (ex) {
  85. if (ex instanceof _core_utils.MissingDataException) {
  86. throw ex;
  87. }
  88. (0, _util.warn)(`XRef.parse - Invalid "Root" reference: "${ex}".`);
  89. }
  90. if (root instanceof _primitives.Dict) {
  91. try {
  92. const pages = root.get("Pages");
  93. if (pages instanceof _primitives.Dict) {
  94. this.root = root;
  95. return;
  96. }
  97. } catch (ex) {
  98. if (ex instanceof _core_utils.MissingDataException) {
  99. throw ex;
  100. }
  101. (0, _util.warn)(`XRef.parse - Invalid "Pages" reference: "${ex}".`);
  102. }
  103. }
  104. if (!recoveryMode) {
  105. throw new _core_utils.XRefParseException();
  106. }
  107. throw new _util.InvalidPDFException("Invalid Root reference.");
  108. }
  109. processXRefTable(parser) {
  110. if (!("tableState" in this)) {
  111. this.tableState = {
  112. entryNum: 0,
  113. streamPos: parser.lexer.stream.pos,
  114. parserBuf1: parser.buf1,
  115. parserBuf2: parser.buf2
  116. };
  117. }
  118. const obj = this.readXRefTable(parser);
  119. if (!(0, _primitives.isCmd)(obj, "trailer")) {
  120. throw new _util.FormatError("Invalid XRef table: could not find trailer dictionary");
  121. }
  122. let dict = parser.getObj();
  123. if (!(dict instanceof _primitives.Dict) && dict.dict) {
  124. dict = dict.dict;
  125. }
  126. if (!(dict instanceof _primitives.Dict)) {
  127. throw new _util.FormatError("Invalid XRef table: could not parse trailer dictionary");
  128. }
  129. delete this.tableState;
  130. return dict;
  131. }
  132. readXRefTable(parser) {
  133. const stream = parser.lexer.stream;
  134. const tableState = this.tableState;
  135. stream.pos = tableState.streamPos;
  136. parser.buf1 = tableState.parserBuf1;
  137. parser.buf2 = tableState.parserBuf2;
  138. let obj;
  139. while (true) {
  140. if (!("firstEntryNum" in tableState) || !("entryCount" in tableState)) {
  141. if ((0, _primitives.isCmd)(obj = parser.getObj(), "trailer")) {
  142. break;
  143. }
  144. tableState.firstEntryNum = obj;
  145. tableState.entryCount = parser.getObj();
  146. }
  147. let first = tableState.firstEntryNum;
  148. const count = tableState.entryCount;
  149. if (!Number.isInteger(first) || !Number.isInteger(count)) {
  150. throw new _util.FormatError("Invalid XRef table: wrong types in subsection header");
  151. }
  152. for (let i = tableState.entryNum; i < count; i++) {
  153. tableState.streamPos = stream.pos;
  154. tableState.entryNum = i;
  155. tableState.parserBuf1 = parser.buf1;
  156. tableState.parserBuf2 = parser.buf2;
  157. const entry = {};
  158. entry.offset = parser.getObj();
  159. entry.gen = parser.getObj();
  160. const type = parser.getObj();
  161. if (type instanceof _primitives.Cmd) {
  162. switch (type.cmd) {
  163. case "f":
  164. entry.free = true;
  165. break;
  166. case "n":
  167. entry.uncompressed = true;
  168. break;
  169. }
  170. }
  171. if (!Number.isInteger(entry.offset) || !Number.isInteger(entry.gen) || !(entry.free || entry.uncompressed)) {
  172. throw new _util.FormatError(`Invalid entry in XRef subsection: ${first}, ${count}`);
  173. }
  174. if (i === 0 && entry.free && first === 1) {
  175. first = 0;
  176. }
  177. if (!this.entries[i + first]) {
  178. this.entries[i + first] = entry;
  179. }
  180. }
  181. tableState.entryNum = 0;
  182. tableState.streamPos = stream.pos;
  183. tableState.parserBuf1 = parser.buf1;
  184. tableState.parserBuf2 = parser.buf2;
  185. delete tableState.firstEntryNum;
  186. delete tableState.entryCount;
  187. }
  188. if (this.entries[0] && !this.entries[0].free) {
  189. throw new _util.FormatError("Invalid XRef table: unexpected first object");
  190. }
  191. return obj;
  192. }
  193. processXRefStream(stream) {
  194. if (!("streamState" in this)) {
  195. const streamParameters = stream.dict;
  196. const byteWidths = streamParameters.get("W");
  197. let range = streamParameters.get("Index");
  198. if (!range) {
  199. range = [0, streamParameters.get("Size")];
  200. }
  201. this.streamState = {
  202. entryRanges: range,
  203. byteWidths,
  204. entryNum: 0,
  205. streamPos: stream.pos
  206. };
  207. }
  208. this.readXRefStream(stream);
  209. delete this.streamState;
  210. return stream.dict;
  211. }
  212. readXRefStream(stream) {
  213. const streamState = this.streamState;
  214. stream.pos = streamState.streamPos;
  215. const [typeFieldWidth, offsetFieldWidth, generationFieldWidth] = streamState.byteWidths;
  216. const entryRanges = streamState.entryRanges;
  217. while (entryRanges.length > 0) {
  218. const [first, n] = entryRanges;
  219. if (!Number.isInteger(first) || !Number.isInteger(n)) {
  220. throw new _util.FormatError(`Invalid XRef range fields: ${first}, ${n}`);
  221. }
  222. if (!Number.isInteger(typeFieldWidth) || !Number.isInteger(offsetFieldWidth) || !Number.isInteger(generationFieldWidth)) {
  223. throw new _util.FormatError(`Invalid XRef entry fields length: ${first}, ${n}`);
  224. }
  225. for (let i = streamState.entryNum; i < n; ++i) {
  226. streamState.entryNum = i;
  227. streamState.streamPos = stream.pos;
  228. let type = 0,
  229. offset = 0,
  230. generation = 0;
  231. for (let j = 0; j < typeFieldWidth; ++j) {
  232. const typeByte = stream.getByte();
  233. if (typeByte === -1) {
  234. throw new _util.FormatError("Invalid XRef byteWidths 'type'.");
  235. }
  236. type = type << 8 | typeByte;
  237. }
  238. if (typeFieldWidth === 0) {
  239. type = 1;
  240. }
  241. for (let j = 0; j < offsetFieldWidth; ++j) {
  242. const offsetByte = stream.getByte();
  243. if (offsetByte === -1) {
  244. throw new _util.FormatError("Invalid XRef byteWidths 'offset'.");
  245. }
  246. offset = offset << 8 | offsetByte;
  247. }
  248. for (let j = 0; j < generationFieldWidth; ++j) {
  249. const generationByte = stream.getByte();
  250. if (generationByte === -1) {
  251. throw new _util.FormatError("Invalid XRef byteWidths 'generation'.");
  252. }
  253. generation = generation << 8 | generationByte;
  254. }
  255. const entry = {};
  256. entry.offset = offset;
  257. entry.gen = generation;
  258. switch (type) {
  259. case 0:
  260. entry.free = true;
  261. break;
  262. case 1:
  263. entry.uncompressed = true;
  264. break;
  265. case 2:
  266. break;
  267. default:
  268. throw new _util.FormatError(`Invalid XRef entry type: ${type}`);
  269. }
  270. if (!this.entries[first + i]) {
  271. this.entries[first + i] = entry;
  272. }
  273. }
  274. streamState.entryNum = 0;
  275. streamState.streamPos = stream.pos;
  276. entryRanges.splice(0, 2);
  277. }
  278. }
  279. indexObjects() {
  280. const TAB = 0x9,
  281. LF = 0xa,
  282. CR = 0xd,
  283. SPACE = 0x20;
  284. const PERCENT = 0x25,
  285. LT = 0x3c;
  286. function readToken(data, offset) {
  287. let token = "",
  288. ch = data[offset];
  289. while (ch !== LF && ch !== CR && ch !== LT) {
  290. if (++offset >= data.length) {
  291. break;
  292. }
  293. token += String.fromCharCode(ch);
  294. ch = data[offset];
  295. }
  296. return token;
  297. }
  298. function skipUntil(data, offset, what) {
  299. const length = what.length,
  300. dataLength = data.length;
  301. let skipped = 0;
  302. while (offset < dataLength) {
  303. let i = 0;
  304. while (i < length && data[offset + i] === what[i]) {
  305. ++i;
  306. }
  307. if (i >= length) {
  308. break;
  309. }
  310. offset++;
  311. skipped++;
  312. }
  313. return skipped;
  314. }
  315. const objRegExp = /^(\d+)\s+(\d+)\s+obj\b/;
  316. const endobjRegExp = /\bendobj[\b\s]$/;
  317. const nestedObjRegExp = /\s+(\d+\s+\d+\s+obj[\b\s<])$/;
  318. const CHECK_CONTENT_LENGTH = 25;
  319. const trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
  320. const startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]);
  321. const objBytes = new Uint8Array([111, 98, 106]);
  322. const xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
  323. this.entries.length = 0;
  324. this._cacheMap.clear();
  325. const stream = this.stream;
  326. stream.pos = 0;
  327. const buffer = stream.getBytes(),
  328. length = buffer.length;
  329. let position = stream.start;
  330. const trailers = [],
  331. xrefStms = [];
  332. while (position < length) {
  333. let ch = buffer[position];
  334. if (ch === TAB || ch === LF || ch === CR || ch === SPACE) {
  335. ++position;
  336. continue;
  337. }
  338. if (ch === PERCENT) {
  339. do {
  340. ++position;
  341. if (position >= length) {
  342. break;
  343. }
  344. ch = buffer[position];
  345. } while (ch !== LF && ch !== CR);
  346. continue;
  347. }
  348. const token = readToken(buffer, position);
  349. let m;
  350. if (token.startsWith("xref") && (token.length === 4 || /\s/.test(token[4]))) {
  351. position += skipUntil(buffer, position, trailerBytes);
  352. trailers.push(position);
  353. position += skipUntil(buffer, position, startxrefBytes);
  354. } else if (m = objRegExp.exec(token)) {
  355. const num = m[1] | 0,
  356. gen = m[2] | 0;
  357. let contentLength,
  358. startPos = position + token.length,
  359. updateEntries = false;
  360. if (!this.entries[num]) {
  361. updateEntries = true;
  362. } else if (this.entries[num].gen === gen) {
  363. try {
  364. const parser = new _parser.Parser({
  365. lexer: new _parser.Lexer(stream.makeSubStream(startPos))
  366. });
  367. parser.getObj();
  368. updateEntries = true;
  369. } catch (ex) {
  370. if (ex instanceof _core_utils.ParserEOFException) {
  371. (0, _util.warn)(`indexObjects -- checking object (${token}): "${ex}".`);
  372. } else {
  373. updateEntries = true;
  374. }
  375. }
  376. }
  377. if (updateEntries) {
  378. this.entries[num] = {
  379. offset: position - stream.start,
  380. gen,
  381. uncompressed: true
  382. };
  383. }
  384. while (startPos < buffer.length) {
  385. const endPos = startPos + skipUntil(buffer, startPos, objBytes) + 4;
  386. contentLength = endPos - position;
  387. const checkPos = Math.max(endPos - CHECK_CONTENT_LENGTH, startPos);
  388. const tokenStr = (0, _util.bytesToString)(buffer.subarray(checkPos, endPos));
  389. if (endobjRegExp.test(tokenStr)) {
  390. break;
  391. } else {
  392. const objToken = nestedObjRegExp.exec(tokenStr);
  393. if (objToken && objToken[1]) {
  394. (0, _util.warn)('indexObjects: Found new "obj" inside of another "obj", ' + 'caused by missing "endobj" -- trying to recover.');
  395. contentLength -= objToken[1].length;
  396. break;
  397. }
  398. }
  399. startPos = endPos;
  400. }
  401. const content = buffer.subarray(position, position + contentLength);
  402. const xrefTagOffset = skipUntil(content, 0, xrefBytes);
  403. if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) {
  404. xrefStms.push(position - stream.start);
  405. this.xrefstms[position - stream.start] = 1;
  406. }
  407. position += contentLength;
  408. } else if (token.startsWith("trailer") && (token.length === 7 || /\s/.test(token[7]))) {
  409. trailers.push(position);
  410. position += skipUntil(buffer, position, startxrefBytes);
  411. } else {
  412. position += token.length + 1;
  413. }
  414. }
  415. for (const xrefStm of xrefStms) {
  416. this.startXRefQueue.push(xrefStm);
  417. this.readXRef(true);
  418. }
  419. let trailerDict, trailerError;
  420. for (const trailer of [...trailers, "generationFallback", ...trailers]) {
  421. if (trailer === "generationFallback") {
  422. if (!trailerError) {
  423. break;
  424. }
  425. this._generationFallback = true;
  426. continue;
  427. }
  428. stream.pos = trailer;
  429. const parser = new _parser.Parser({
  430. lexer: new _parser.Lexer(stream),
  431. xref: this,
  432. allowStreams: true,
  433. recoveryMode: true
  434. });
  435. const obj = parser.getObj();
  436. if (!(0, _primitives.isCmd)(obj, "trailer")) {
  437. continue;
  438. }
  439. const dict = parser.getObj();
  440. if (!(dict instanceof _primitives.Dict)) {
  441. continue;
  442. }
  443. let validPagesDict = false;
  444. try {
  445. const rootDict = dict.get("Root");
  446. if (!(rootDict instanceof _primitives.Dict)) {
  447. continue;
  448. }
  449. const pagesDict = rootDict.get("Pages");
  450. if (!(pagesDict instanceof _primitives.Dict)) {
  451. continue;
  452. }
  453. const pagesCount = pagesDict.get("Count");
  454. if (Number.isInteger(pagesCount)) {
  455. validPagesDict = true;
  456. }
  457. } catch (ex) {
  458. trailerError = ex;
  459. continue;
  460. }
  461. if (validPagesDict && dict.has("ID")) {
  462. return dict;
  463. }
  464. trailerDict = dict;
  465. }
  466. if (trailerDict) {
  467. return trailerDict;
  468. }
  469. if (this.topDict) {
  470. return this.topDict;
  471. }
  472. throw new _util.InvalidPDFException("Invalid PDF structure.");
  473. }
  474. readXRef(recoveryMode = false) {
  475. const stream = this.stream;
  476. const startXRefParsedCache = new Set();
  477. try {
  478. while (this.startXRefQueue.length) {
  479. const startXRef = this.startXRefQueue[0];
  480. if (startXRefParsedCache.has(startXRef)) {
  481. (0, _util.warn)("readXRef - skipping XRef table since it was already parsed.");
  482. this.startXRefQueue.shift();
  483. continue;
  484. }
  485. startXRefParsedCache.add(startXRef);
  486. stream.pos = startXRef + stream.start;
  487. const parser = new _parser.Parser({
  488. lexer: new _parser.Lexer(stream),
  489. xref: this,
  490. allowStreams: true
  491. });
  492. let obj = parser.getObj();
  493. let dict;
  494. if ((0, _primitives.isCmd)(obj, "xref")) {
  495. dict = this.processXRefTable(parser);
  496. if (!this.topDict) {
  497. this.topDict = dict;
  498. }
  499. obj = dict.get("XRefStm");
  500. if (Number.isInteger(obj)) {
  501. const pos = obj;
  502. if (!(pos in this.xrefstms)) {
  503. this.xrefstms[pos] = 1;
  504. this.startXRefQueue.push(pos);
  505. }
  506. }
  507. } else if (Number.isInteger(obj)) {
  508. if (!Number.isInteger(parser.getObj()) || !(0, _primitives.isCmd)(parser.getObj(), "obj") || !((obj = parser.getObj()) instanceof _base_stream.BaseStream)) {
  509. throw new _util.FormatError("Invalid XRef stream");
  510. }
  511. dict = this.processXRefStream(obj);
  512. if (!this.topDict) {
  513. this.topDict = dict;
  514. }
  515. if (!dict) {
  516. throw new _util.FormatError("Failed to read XRef stream");
  517. }
  518. } else {
  519. throw new _util.FormatError("Invalid XRef stream header");
  520. }
  521. obj = dict.get("Prev");
  522. if (Number.isInteger(obj)) {
  523. this.startXRefQueue.push(obj);
  524. } else if (obj instanceof _primitives.Ref) {
  525. this.startXRefQueue.push(obj.num);
  526. }
  527. this.startXRefQueue.shift();
  528. }
  529. return this.topDict;
  530. } catch (e) {
  531. if (e instanceof _core_utils.MissingDataException) {
  532. throw e;
  533. }
  534. (0, _util.info)("(while reading XRef): " + e);
  535. this.startXRefQueue.shift();
  536. }
  537. if (recoveryMode) {
  538. return undefined;
  539. }
  540. throw new _core_utils.XRefParseException();
  541. }
  542. getEntry(i) {
  543. const xrefEntry = this.entries[i];
  544. if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
  545. return xrefEntry;
  546. }
  547. return null;
  548. }
  549. fetchIfRef(obj, suppressEncryption = false) {
  550. if (obj instanceof _primitives.Ref) {
  551. return this.fetch(obj, suppressEncryption);
  552. }
  553. return obj;
  554. }
  555. fetch(ref, suppressEncryption = false) {
  556. if (!(ref instanceof _primitives.Ref)) {
  557. throw new Error("ref object is not a reference");
  558. }
  559. const num = ref.num;
  560. const cacheEntry = this._cacheMap.get(num);
  561. if (cacheEntry !== undefined) {
  562. if (cacheEntry instanceof _primitives.Dict && !cacheEntry.objId) {
  563. cacheEntry.objId = ref.toString();
  564. }
  565. return cacheEntry;
  566. }
  567. let xrefEntry = this.getEntry(num);
  568. if (xrefEntry === null) {
  569. this._cacheMap.set(num, xrefEntry);
  570. return xrefEntry;
  571. }
  572. if (this._pendingRefs.has(ref)) {
  573. this._pendingRefs.remove(ref);
  574. (0, _util.warn)(`Ignoring circular reference: ${ref}.`);
  575. return _primitives.CIRCULAR_REF;
  576. }
  577. this._pendingRefs.put(ref);
  578. try {
  579. if (xrefEntry.uncompressed) {
  580. xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
  581. } else {
  582. xrefEntry = this.fetchCompressed(ref, xrefEntry, suppressEncryption);
  583. }
  584. this._pendingRefs.remove(ref);
  585. } catch (ex) {
  586. this._pendingRefs.remove(ref);
  587. throw ex;
  588. }
  589. if (xrefEntry instanceof _primitives.Dict) {
  590. xrefEntry.objId = ref.toString();
  591. } else if (xrefEntry instanceof _base_stream.BaseStream) {
  592. xrefEntry.dict.objId = ref.toString();
  593. }
  594. return xrefEntry;
  595. }
  596. fetchUncompressed(ref, xrefEntry, suppressEncryption = false) {
  597. const gen = ref.gen;
  598. let num = ref.num;
  599. if (xrefEntry.gen !== gen) {
  600. const msg = `Inconsistent generation in XRef: ${ref}`;
  601. if (this._generationFallback && xrefEntry.gen < gen) {
  602. (0, _util.warn)(msg);
  603. return this.fetchUncompressed(_primitives.Ref.get(num, xrefEntry.gen), xrefEntry, suppressEncryption);
  604. }
  605. throw new _core_utils.XRefEntryException(msg);
  606. }
  607. const stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start);
  608. const parser = new _parser.Parser({
  609. lexer: new _parser.Lexer(stream),
  610. xref: this,
  611. allowStreams: true
  612. });
  613. const obj1 = parser.getObj();
  614. const obj2 = parser.getObj();
  615. const obj3 = parser.getObj();
  616. if (obj1 !== num || obj2 !== gen || !(obj3 instanceof _primitives.Cmd)) {
  617. throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
  618. }
  619. if (obj3.cmd !== "obj") {
  620. if (obj3.cmd.startsWith("obj")) {
  621. num = parseInt(obj3.cmd.substring(3), 10);
  622. if (!Number.isNaN(num)) {
  623. return num;
  624. }
  625. }
  626. throw new _core_utils.XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
  627. }
  628. if (this.encrypt && !suppressEncryption) {
  629. xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
  630. } else {
  631. xrefEntry = parser.getObj();
  632. }
  633. if (!(xrefEntry instanceof _base_stream.BaseStream)) {
  634. this._cacheMap.set(num, xrefEntry);
  635. }
  636. return xrefEntry;
  637. }
  638. fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
  639. const tableOffset = xrefEntry.offset;
  640. const stream = this.fetch(_primitives.Ref.get(tableOffset, 0));
  641. if (!(stream instanceof _base_stream.BaseStream)) {
  642. throw new _util.FormatError("bad ObjStm stream");
  643. }
  644. const first = stream.dict.get("First");
  645. const n = stream.dict.get("N");
  646. if (!Number.isInteger(first) || !Number.isInteger(n)) {
  647. throw new _util.FormatError("invalid first and n parameters for ObjStm stream");
  648. }
  649. let parser = new _parser.Parser({
  650. lexer: new _parser.Lexer(stream),
  651. xref: this,
  652. allowStreams: true
  653. });
  654. const nums = new Array(n);
  655. const offsets = new Array(n);
  656. for (let i = 0; i < n; ++i) {
  657. const num = parser.getObj();
  658. if (!Number.isInteger(num)) {
  659. throw new _util.FormatError(`invalid object number in the ObjStm stream: ${num}`);
  660. }
  661. const offset = parser.getObj();
  662. if (!Number.isInteger(offset)) {
  663. throw new _util.FormatError(`invalid object offset in the ObjStm stream: ${offset}`);
  664. }
  665. nums[i] = num;
  666. offsets[i] = offset;
  667. }
  668. const start = (stream.start || 0) + first;
  669. const entries = new Array(n);
  670. for (let i = 0; i < n; ++i) {
  671. const length = i < n - 1 ? offsets[i + 1] - offsets[i] : undefined;
  672. if (length < 0) {
  673. throw new _util.FormatError("Invalid offset in the ObjStm stream.");
  674. }
  675. parser = new _parser.Parser({
  676. lexer: new _parser.Lexer(stream.makeSubStream(start + offsets[i], length, stream.dict)),
  677. xref: this,
  678. allowStreams: true
  679. });
  680. const obj = parser.getObj();
  681. entries[i] = obj;
  682. if (obj instanceof _base_stream.BaseStream) {
  683. continue;
  684. }
  685. const num = nums[i],
  686. entry = this.entries[num];
  687. if (entry && entry.offset === tableOffset && entry.gen === i) {
  688. this._cacheMap.set(num, obj);
  689. }
  690. }
  691. xrefEntry = entries[xrefEntry.gen];
  692. if (xrefEntry === undefined) {
  693. throw new _core_utils.XRefEntryException(`Bad (compressed) XRef entry: ${ref}`);
  694. }
  695. return xrefEntry;
  696. }
  697. async fetchIfRefAsync(obj, suppressEncryption) {
  698. if (obj instanceof _primitives.Ref) {
  699. return this.fetchAsync(obj, suppressEncryption);
  700. }
  701. return obj;
  702. }
  703. async fetchAsync(ref, suppressEncryption) {
  704. try {
  705. return this.fetch(ref, suppressEncryption);
  706. } catch (ex) {
  707. if (!(ex instanceof _core_utils.MissingDataException)) {
  708. throw ex;
  709. }
  710. await this.pdfManager.requestRange(ex.begin, ex.end);
  711. return this.fetchAsync(ref, suppressEncryption);
  712. }
  713. }
  714. getCatalogObj() {
  715. return this.root;
  716. }
  717. }
  718. exports.XRef = XRef;