diff --git a/src/core/worker.js b/src/core/worker.js index 13661b528..471895c32 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -660,6 +660,7 @@ class WorkerMessageHandler { }); } + const lastXRefStreamPos = xref.lastXRefStreamPos; newXrefInfo = { rootRef: xref.trailer.getRaw("Root") || null, encryptRef: xref.trailer.getRaw("Encrypt") || null, @@ -667,7 +668,8 @@ class WorkerMessageHandler { infoRef: xref.trailer.getRaw("Info") || null, info: infoObj, fileIds: xref.trailer.get("ID") || null, - startXRef, + startXRef: + lastXRefStreamPos === null ? startXRef : lastXRefStreamPos, filename, }; } @@ -836,6 +838,11 @@ class WorkerMessageHandler { handler.on("GetXFADatasets", function (data) { return pdfManager.ensureDoc("xfaDatasets"); }); + handler.on("GetXRefPrevValue", function (data) { + return pdfManager + .ensureXRef("trailer") + .then(trailer => trailer.get("Prev")); + }); } return workerHandlerName; diff --git a/src/core/xref.js b/src/core/xref.js index b378e9476..e32e1ab48 100644 --- a/src/core/xref.js +++ b/src/core/xref.js @@ -756,6 +756,11 @@ class XRef { throw new XRefParseException(); } + get lastXRefStreamPos() { + const pos = Object.keys(this.xrefstms); + return pos.length === 0 ? null : Math.max(...pos); + } + getEntry(i) { const xrefEntry = this.entries[i]; if (xrefEntry && !xrefEntry.free && xrefEntry.offset) { diff --git a/src/display/api.js b/src/display/api.js index 96b7243cf..b3177a761 100644 --- a/src/display/api.js +++ b/src/display/api.js @@ -777,6 +777,11 @@ class PDFDocumentProxy { return this._transport.getXFADatasets(); }, }); + Object.defineProperty(this, "getXRefPrevValue", { + value: () => { + return this._transport.getXRefPrevValue(); + }, + }); } } @@ -2397,6 +2402,11 @@ class WorkerTransport { return this.messageHandler.sendWithPromise("GetXFADatasets", null); }, }); + Object.defineProperty(this, "getXRefPrevValue", { + value: () => { + return this.messageHandler.sendWithPromise("GetXRefPrevValue", null); + }, + }); } } diff --git a/test/pdfs/bug1823296.pdf.link b/test/pdfs/bug1823296.pdf.link new file mode 100644 index 000000000..e96e48ef1 --- /dev/null +++ b/test/pdfs/bug1823296.pdf.link @@ -0,0 +1,2 @@ +https://bugzilla.mozilla.org/attachment.cgi?id=9324226 + diff --git a/test/test_manifest.json b/test/test_manifest.json index eb14cf6e9..a7521f7eb 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -7496,5 +7496,12 @@ "md5": "d95a83a868671a03cbf322f16b2e2b9d", "link": true, "type": "other" + }, + { + "id": "bug1823296", + "file": "pdfs/bug1823296.pdf", + "md5": "f71e89ebe3d6e75e0c83ce41cd72df1f", + "link": true, + "type": "other" } ] diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 2203eb7f9..e90c03db4 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -14,6 +14,7 @@ */ import { + AnnotationEditorType, AnnotationMode, AnnotationType, createPromiseCapability, @@ -1980,6 +1981,35 @@ describe("api", function () { await loadingTask.destroy(); }); + it("write a a new annotation, save the pdf and check that the prev entry in xref stream is correct", async function () { + if (isNodeJS) { + pending("Linked test-cases are not supported in Node.js."); + } + + let loadingTask = getDocument(buildGetDocumentParams("bug1823296.pdf")); + let pdfDoc = await loadingTask.promise; + pdfDoc.annotationStorage.setValue("pdfjs_internal_editor_0", { + annotationType: AnnotationEditorType.FREETEXT, + rect: [12, 34, 56, 78], + rotation: 0, + fontSize: 10, + color: [0, 0, 0], + value: "Hello PDF.js World!", + pageIndex: 0, + }); + + const data = await pdfDoc.saveDocument(); + await loadingTask.destroy(); + + loadingTask = getDocument(data); + pdfDoc = await loadingTask.promise; + const xrefPrev = await pdfDoc.getXRefPrevValue(); + + expect(xrefPrev).toEqual(143954); + + await loadingTask.destroy(); + }); + describe("Cross-origin", function () { let loadingTask; function _checkCanLoad(expectSuccess, filename, options) {