Prevent circular references in the /Pages tree
This commit is contained in:
parent
e2b30e9e9c
commit
3c7b7be100
@ -731,6 +731,7 @@ class Catalog {
|
|||||||
getPageDict(pageIndex) {
|
getPageDict(pageIndex) {
|
||||||
const capability = createPromiseCapability();
|
const capability = createPromiseCapability();
|
||||||
const nodesToVisit = [this.catDict.getRaw("Pages")];
|
const nodesToVisit = [this.catDict.getRaw("Pages")];
|
||||||
|
const visitedNodes = new RefSet();
|
||||||
const xref = this.xref,
|
const xref = this.xref,
|
||||||
pageKidsCountCache = this.pageKidsCountCache;
|
pageKidsCountCache = this.pageKidsCountCache;
|
||||||
let count,
|
let count,
|
||||||
@ -747,6 +748,14 @@ class Catalog {
|
|||||||
currentPageIndex += count;
|
currentPageIndex += count;
|
||||||
continue;
|
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) {
|
xref.fetchAsync(currentNode).then(function(obj) {
|
||||||
if (isDict(obj, "Page") || (isDict(obj) && !obj.has("Kids"))) {
|
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
|
!bug1132849.pdf
|
||||||
!issue6894.pdf
|
!issue6894.pdf
|
||||||
!issue5804.pdf
|
!issue5804.pdf
|
||||||
|
!Pages-tree-refs.pdf
|
||||||
!ShowText-ShadingPattern.pdf
|
!ShowText-ShadingPattern.pdf
|
||||||
!complex_ttf_font.pdf
|
!complex_ttf_font.pdf
|
||||||
!issue3694_reduced.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);
|
.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) {
|
it("gets page index", function(done) {
|
||||||
// reference to second page
|
// reference to second page
|
||||||
var ref = { num: 17, gen: 0 };
|
var ref = { num: 17, gen: 0 };
|
||||||
|
@ -403,16 +403,20 @@ class PDFPageView {
|
|||||||
console.error("Must be in new state before drawing");
|
console.error("Must be in new state before drawing");
|
||||||
this.reset(); // Ensure that we reset all state to prevent issues.
|
this.reset(); // Ensure that we reset all state to prevent issues.
|
||||||
}
|
}
|
||||||
|
const { div, pdfPage } = this;
|
||||||
|
|
||||||
if (!this.pdfPage) {
|
if (!pdfPage) {
|
||||||
this.renderingState = RenderingStates.FINISHED;
|
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;
|
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
|
// Wrap the canvas so that if it has a CSS transform for high DPI the
|
||||||
// overflow will be hidden in Firefox.
|
// overflow will be hidden in Firefox.
|
||||||
const canvasWrapper = document.createElement("div");
|
const canvasWrapper = document.createElement("div");
|
||||||
|
@ -164,9 +164,14 @@ class PDFRenderingQueue {
|
|||||||
break;
|
break;
|
||||||
case RenderingStates.INITIAL:
|
case RenderingStates.INITIAL:
|
||||||
this.highestPriorityPage = view.renderingId;
|
this.highestPriorityPage = view.renderingId;
|
||||||
view.draw().finally(() => {
|
view
|
||||||
this.renderHighestPriority();
|
.draw()
|
||||||
});
|
.finally(() => {
|
||||||
|
this.renderHighestPriority();
|
||||||
|
})
|
||||||
|
.catch(reason => {
|
||||||
|
console.error(`renderView: "${reason}"`);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -295,6 +295,13 @@ class PDFThumbnailView {
|
|||||||
console.error("Must be in new state before drawing");
|
console.error("Must be in new state before drawing");
|
||||||
return Promise.resolve(undefined);
|
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;
|
this.renderingState = RenderingStates.RUNNING;
|
||||||
|
|
||||||
const renderCapability = createPromiseCapability();
|
const renderCapability = createPromiseCapability();
|
||||||
@ -339,7 +346,7 @@ class PDFThumbnailView {
|
|||||||
canvasContext: ctx,
|
canvasContext: ctx,
|
||||||
viewport: drawViewport,
|
viewport: drawViewport,
|
||||||
};
|
};
|
||||||
const renderTask = (this.renderTask = this.pdfPage.render(renderContext));
|
const renderTask = (this.renderTask = pdfPage.render(renderContext));
|
||||||
renderTask.onContinue = renderContinueCallback;
|
renderTask.onContinue = renderContinueCallback;
|
||||||
|
|
||||||
renderTask.promise.then(
|
renderTask.promise.then(
|
||||||
|
Loading…
Reference in New Issue
Block a user