: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
entry.uncompressed = true;
throw new FormatError(`Invalid XRef entry type: ${type}`);
if (!this.entries[first + i]) {
this.entries[first + i] = entry;
streamState.entryNum = 0;
streamState.streamPos = stream.pos;
entryRanges.splice(0, 2);
function readToken(data, offset) {
while (ch !== LF && ch !== CR && ch !== LT) {
if (++offset >= data.length) {
token += String.fromCharCode(ch);
function skipUntil(data, offset, what) {
const length = what.length,
dataLength = data.length;
while (offset < dataLength) {
while (i < length && data[offset + i] === what[i]) {
const gEndobjRegExp = /\b(endobj|\d+\s+\d+\s+obj|xref|trailer\s*<<)\b/g;
const gStartxrefRegExp = /\b(startxref|\d+\s+\d+\s+obj)\b/g;
const objRegExp = /^(\d+)\s+(\d+)\s+obj\b/;
const trailerBytes = new Uint8Array([116, 114, 97, 105, 108, 101, 114]);
const startxrefBytes = new Uint8Array([115, 116, 97, 114, 116, 120, 114, 101, 102]);
const xrefBytes = new Uint8Array([47, 88, 82, 101, 102]);
const stream = this.stream;
const buffer = stream.getBytes(),
bufferStr = bytesToString(buffer),
let position = stream.start;
while (position < length) {
let ch = buffer[position];
if (ch === TAB || ch === LF || ch === CR || ch === SPACE) {
if (position >= length) {
} while (ch !== LF && ch !== CR);
const token = readToken(buffer, position);
if (token.startsWith("xref") && (token.length === 4 || /\s/.test(token[4]))) {
position += skipUntil(buffer, position, trailerBytes);
position += skipUntil(buffer, position, startxrefBytes);
} else if (m = objRegExp.exec(token)) {
const startPos = position + token.length;
if (!this.entries[num]) {
} else if (this.entries[num].gen === gen) {
const parser = new Parser({
lexer: new Lexer(stream.makeSubStream(startPos))
if (ex instanceof ParserEOFException) {
warn(`indexObjects -- checking object (${token}): "${ex}".`);
offset: position - stream.start,
gEndobjRegExp.lastIndex = startPos;
const match = gEndobjRegExp.exec(bufferStr);
const endPos = gEndobjRegExp.lastIndex + 1;
contentLength = endPos - position;
if (match[1] !== "endobj") {
warn(`indexObjects: Found "${match[1]}" inside of another "obj", ` + 'caused by missing "endobj" -- trying to recover.');
contentLength -= match[1].length + 1;
contentLength = length - position;
const content = buffer.subarray(position, position + contentLength);
const xrefTagOffset = skipUntil(content, 0, xrefBytes);
if (xrefTagOffset < contentLength && content[xrefTagOffset + 5] < 64) {
xrefStms.push(position - stream.start);
this._xrefStms.add(position - stream.start);
position += contentLength;
} else if (token.startsWith("trailer") && (token.length === 7 || /\s/.test(token[7]))) {
const startPos = position + token.length;
gStartxrefRegExp.lastIndex = startPos;
const match = gStartxrefRegExp.exec(bufferStr);
const endPos = gStartxrefRegExp.lastIndex + 1;
contentLength = endPos - position;
if (match[1] !== "startxref") {
warn(`indexObjects: Found "${match[1]}" after "trailer", ` + 'caused by missing "startxref" -- trying to recover.');
contentLength -= match[1].length + 1;
contentLength = length - position;
position += contentLength;
position += token.length + 1;
for (const xrefStm of xrefStms) {
this.startXRefQueue.push(xrefStm);
for (const trailer of trailers) {
const parser = new Parser({
lexer: new Lexer(stream),
const obj = parser.getObj();
if (!isCmd(obj, "trailer")) {
const dict = parser.getObj();
if (!(dict instanceof Dict)) {
if (dict.has("Encrypt")) {
let trailerDict, trailerError;
for (const dict of [...trailerDicts, "genFallback", ...trailerDicts]) {
if (dict === "genFallback") {
this._generationFallback = true;
let validPagesDict = false;
const rootDict = dict.get("Root");
if (!(rootDict instanceof Dict)) {
const pagesDict = rootDict.get("Pages");
if (!(pagesDict instanceof Dict)) {
const pagesCount = pagesDict.get("Count");
if (Number.isInteger(pagesCount)) {
if (validPagesDict && (!isEncrypted || dict.has("Encrypt")) && dict.has("ID")) {
throw new InvalidPDFException("Invalid PDF structure.");
readXRef(recoveryMode = false) {
const stream = this.stream;
const startXRefParsedCache = new Set();
while (this.startXRefQueue.length) {
const startXRef = this.startXRefQueue[0];
if (startXRefParsedCache.has(startXRef)) {
warn("readXRef - skipping XRef table since it was already parsed.");
this.startXRefQueue.shift();
startXRefParsedCache.add(startXRef);
stream.pos = startXRef + stream.start;
const parser = new Parser({
lexer: new Lexer(stream),
let obj = parser.getObj();
if (isCmd(obj, "xref")) {
dict = this.processXRefTable(parser);
obj = dict.get("XRefStm");
if (Number.isInteger(obj) && !this._xrefStms.has(obj)) {
this.startXRefQueue.push(obj);
this.#firstXRefStmPos ??= obj;
} else if (Number.isInteger(obj)) {
if (!Number.isInteger(parser.getObj()) || !isCmd(parser.getObj(), "obj") || !((obj = parser.getObj()) instanceof BaseStream)) {
throw new FormatError("Invalid XRef stream");
dict = this.processXRefStream(obj);
throw new FormatError("Failed to read XRef stream");
throw new FormatError("Invalid XRef stream header");
if (Number.isInteger(obj)) {
this.startXRefQueue.push(obj);
} else if (obj instanceof Ref) {
this.startXRefQueue.push(obj.num);
if (e instanceof MissingDataException) {
info("(while reading XRef): " + e);
this.startXRefQueue.shift();
throw new XRefParseException();
get lastXRefStreamPos() {
return this.#firstXRefStmPos ?? (this._xrefStms.size > 0 ? Math.max(...this._xrefStms) : null);
const xrefEntry = this.entries[i];
if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
fetchIfRef(obj, suppressEncryption = false) {
if (obj instanceof Ref) {
return this.fetch(obj, suppressEncryption);
fetch(ref, suppressEncryption = false) {
if (!(ref instanceof Ref)) {
throw new Error("ref object is not a reference");
const cacheEntry = this._cacheMap.get(num);
if (cacheEntry !== undefined) {
if (cacheEntry instanceof Dict && !cacheEntry.objId) {
cacheEntry.objId = ref.toString();
let xrefEntry = this.getEntry(num);
if (xrefEntry === null) {
this._cacheMap.set(num, xrefEntry);
if (this._pendingRefs.has(ref)) {
this._pendingRefs.remove(ref);
warn(`Ignoring circular reference: ${ref}.`);
this._pendingRefs.put(ref);
xrefEntry = xrefEntry.uncompressed ? this.fetchUncompressed(ref, xrefEntry, suppressEncryption) : this.fetchCompressed(ref, xrefEntry, suppressEncryption);
this._pendingRefs.remove(ref);
this._pendingRefs.remove(ref);
if (xrefEntry instanceof Dict) {
xrefEntry.objId = ref.toString();
} else if (xrefEntry instanceof BaseStream) {
xrefEntry.dict.objId = ref.toString();
fetchUncompressed(ref, xrefEntry, suppressEncryption = false) {
if (xrefEntry.gen !== gen) {
const msg = `Inconsistent generation in XRef: ${ref}`;
if (this._generationFallback && xrefEntry.gen < gen) {
return this.fetchUncompressed(Ref.get(num, xrefEntry.gen), xrefEntry, suppressEncryption);
throw new XRefEntryException(msg);
const stream = this.stream.makeSubStream(xrefEntry.offset + this.stream.start);
const parser = new Parser({
lexer: new Lexer(stream),
const obj1 = parser.getObj();
const obj2 = parser.getObj();
const obj3 = parser.getObj();
if (obj1 !== num || obj2 !== gen || !(obj3 instanceof Cmd)) {
throw new XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
if (obj3.cmd !== "obj") {
if (obj3.cmd.startsWith("obj")) {
num = parseInt(obj3.cmd.substring(3), 10);
if (!Number.isNaN(num)) {
throw new XRefEntryException(`Bad (uncompressed) XRef entry: ${ref}`);
xrefEntry = this.encrypt && !suppressEncryption ? parser.getObj(this.encrypt.createCipherTransform(num, gen)) : parser.getObj();
if (!(xrefEntry instanceof BaseStream)) {
this._cacheMap.set(num, xrefEntry);
fetchCompressed(ref, xrefEntry, suppressEncryption = false) {
const tableOffset = xrefEntry.offset;
const stream = this.fetch(Ref.get(tableOffset, 0));
if (!(stream instanceof BaseStream)) {
throw new FormatError("bad ObjStm stream");
const first = stream.dict.get("First");
const n = stream.dict.get("N");
if (!Number.isInteger(first) || !Number.isInteger(n)) {
throw new FormatError("invalid first and n parameters for ObjStm stream");
let parser = new Parser({
lexer: new Lexer(stream),
const nums = new Array(n);
const offsets = new Array(n);
for (let i = 0; i < n; ++i) {
const num = parser.getObj();
if (!Number.isInteger(num)) {
throw new FormatError(`invalid object number in the ObjStm stream: ${num}`);
const offset = parser.getObj();
if (!Number.isInteger(offset)) {
throw new FormatError(`invalid object offset in the ObjStm stream: ${offset}`);
const start = (stream.start || 0) + first;
const entries = new Array(n);
for (let i = 0; i < n; ++i) {
const length = i < n - 1 ? offsets[i + 1] - offsets[i] : undefined;
throw new FormatError("Invalid offset in the ObjStm stream.");
lexer: new Lexer(stream.makeSubStream(start + offsets[i], length, stream.dict)),
const obj = parser.getObj();
if (obj instanceof BaseStream) {
entry = this.entries[num];
if (entry && entry.offset === tableOffset && entry.gen === i) {
this._cacheMap.set(num, obj);
xrefEntry = entries[xrefEntry.gen];
if (xrefEntry === undefined) {
throw new XRefEntryException(`Bad (compressed) XRef entry: ${ref}`);
async fetchIfRefAsync(obj, suppressEncryption) {
if (obj instanceof Ref) {
return this.fetchAsync(obj, suppressEncryption);
async fetchAsync(ref, suppressEncryption) {
return this.fetch(ref, suppressEncryption);
if (!(ex instanceof MissingDataException)) {
await this.pdfManager.requestRange(ex.begin, ex.end);
return this.fetchAsync(ref, suppressEncryption);
;// CONCATENATED MODULE: ./src/core/document.js