xref.js 22 KB

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