Prevent circular references in the /Pages tree
This commit is contained in:
parent
e2b30e9e9c
commit
3c7b7be100
@ -731,6 +731,7 @@ class Catalog {
|
||||
getPageDict(pageIndex) {
|
||||
const capability = createPromiseCapability();
|
||||
const nodesToVisit = [this.catDict.getRaw("Pages")];
|
||||
const visitedNodes = new RefSet();
|
||||
const xref = this.xref,
|
||||
pageKidsCountCache = this.pageKidsCountCache;
|
||||
let count,
|
||||
@ -747,6 +748,14 @@ class Catalog {
|
||||
currentPageIndex += count;
|
||||
continue;
|
||||
}
|
||||
// Prevent circular references in the /Pages tree.
|
||||
if (visitedNodes.has(currentNode)) {
|
||||
capability.reject(
|
||||
new FormatError("Pages tree contains circular reference.")
|
||||
);
|
||||
return;
|
||||
}
|
||||
visitedNodes.put(currentNode);
|
||||
|
||||
xref.fetchAsync(currentNode).then(function(obj) {
|
||||
if (isDict(obj, "Page") || (isDict(obj) && !obj.has("Kids"))) {
|
||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -117,6 +117,7 @@
|
||||
!bug1132849.pdf
|
||||
!issue6894.pdf
|
||||
!issue5804.pdf
|
||||
!Pages-tree-refs.pdf
|
||||
!ShowText-ShadingPattern.pdf
|
||||
!complex_ttf_font.pdf
|
||||
!issue3694_reduced.pdf
|
||||
|
84
test/pdfs/Pages-tree-refs.pdf
Normal file
84
test/pdfs/Pages-tree-refs.pdf
Normal file
@ -0,0 +1,84 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< /Type /Catalog
|
||||
/Pages 2 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [6 0 R 3 0 R]
|
||||
/Count 2
|
||||
/MediaBox [0 0 595 842]
|
||||
>>
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [4 0 R]
|
||||
/Count 1
|
||||
/MediaBox [0 0 595 842]
|
||||
>>
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [5 0 R]
|
||||
/Count 1
|
||||
/MediaBox [0 0 595 842]
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Type /Pages
|
||||
/Kids [3 0 R]
|
||||
/Count 1
|
||||
/MediaBox [0 0 595 842]
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Type /Page
|
||||
/Parent 2 0 R
|
||||
/Resources
|
||||
<< /Font
|
||||
<< /F1
|
||||
<< /Type /Font
|
||||
/Subtype /Type1
|
||||
/BaseFont /Courier
|
||||
>>
|
||||
>>
|
||||
>>
|
||||
/Contents [7 0 R]
|
||||
>>
|
||||
endobj
|
||||
|
||||
7 0 obj
|
||||
<< /Length 69 >>
|
||||
stream
|
||||
BT
|
||||
/F1 22 Tf
|
||||
30 800 Td
|
||||
(Testcase: 'Pages loop') Tj
|
||||
ET
|
||||
endstream
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 8
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000069 00000 n
|
||||
0000000176 00000 n
|
||||
0000000277 00000 n
|
||||
0000000378 00000 n
|
||||
0000000479 00000 n
|
||||
0000000744 00000 n
|
||||
trailer
|
||||
<< /Root 1 0 R
|
||||
/Size 8
|
||||
>>
|
||||
startxref
|
||||
866
|
||||
%%EOF
|
@ -546,6 +546,43 @@ describe("api", function() {
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
|
||||
it("gets page, from /Pages tree with circular reference", function(done) {
|
||||
const loadingTask = getDocument(
|
||||
buildGetDocumentParams("Pages-tree-refs.pdf")
|
||||
);
|
||||
|
||||
const page1 = loadingTask.promise.then(function(pdfDoc) {
|
||||
return pdfDoc.getPage(1).then(
|
||||
function(pdfPage) {
|
||||
expect(pdfPage instanceof PDFPageProxy).toEqual(true);
|
||||
expect(pdfPage.ref).toEqual({ num: 6, gen: 0 });
|
||||
},
|
||||
function(reason) {
|
||||
throw new Error("shall not fail for valid page");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const page2 = loadingTask.promise.then(function(pdfDoc) {
|
||||
return pdfDoc.getPage(2).then(
|
||||
function(pdfPage) {
|
||||
throw new Error("shall fail for invalid page");
|
||||
},
|
||||
function(reason) {
|
||||
expect(reason instanceof Error).toEqual(true);
|
||||
expect(reason.message).toEqual(
|
||||
"Pages tree contains circular reference."
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
Promise.all([page1, page2]).then(function() {
|
||||
loadingTask.destroy().then(done);
|
||||
}, done.fail);
|
||||
});
|
||||
|
||||
it("gets page index", function(done) {
|
||||
// reference to second page
|
||||
var ref = { num: 17, gen: 0 };
|
||||
|
@ -403,16 +403,20 @@ class PDFPageView {
|
||||
console.error("Must be in new state before drawing");
|
||||
this.reset(); // Ensure that we reset all state to prevent issues.
|
||||
}
|
||||
const { div, pdfPage } = this;
|
||||
|
||||
if (!this.pdfPage) {
|
||||
if (!pdfPage) {
|
||||
this.renderingState = RenderingStates.FINISHED;
|
||||
return Promise.reject(new Error("Page is not loaded"));
|
||||
|
||||
if (this.loadingIconDiv) {
|
||||
div.removeChild(this.loadingIconDiv);
|
||||
delete this.loadingIconDiv;
|
||||
}
|
||||
return Promise.reject(new Error("pdfPage is not loaded"));
|
||||
}
|
||||
|
||||
this.renderingState = RenderingStates.RUNNING;
|
||||
|
||||
const pdfPage = this.pdfPage;
|
||||
const div = this.div;
|
||||
// Wrap the canvas so that if it has a CSS transform for high DPI the
|
||||
// overflow will be hidden in Firefox.
|
||||
const canvasWrapper = document.createElement("div");
|
||||
|
@ -164,8 +164,13 @@ class PDFRenderingQueue {
|
||||
break;
|
||||
case RenderingStates.INITIAL:
|
||||
this.highestPriorityPage = view.renderingId;
|
||||
view.draw().finally(() => {
|
||||
view
|
||||
.draw()
|
||||
.finally(() => {
|
||||
this.renderHighestPriority();
|
||||
})
|
||||
.catch(reason => {
|
||||
console.error(`renderView: "${reason}"`);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
@ -295,6 +295,13 @@ class PDFThumbnailView {
|
||||
console.error("Must be in new state before drawing");
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
const { pdfPage } = this;
|
||||
|
||||
if (!pdfPage) {
|
||||
this.renderingState = RenderingStates.FINISHED;
|
||||
return Promise.reject(new Error("pdfPage is not loaded"));
|
||||
}
|
||||
|
||||
this.renderingState = RenderingStates.RUNNING;
|
||||
|
||||
const renderCapability = createPromiseCapability();
|
||||
@ -339,7 +346,7 @@ class PDFThumbnailView {
|
||||
canvasContext: ctx,
|
||||
viewport: drawViewport,
|
||||
};
|
||||
const renderTask = (this.renderTask = this.pdfPage.render(renderContext));
|
||||
const renderTask = (this.renderTask = pdfPage.render(renderContext));
|
||||
renderTask.onContinue = renderContinueCallback;
|
||||
|
||||
renderTask.promise.then(
|
||||
|
Loading…
Reference in New Issue
Block a user