2
0

xref.js 24 KB

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