From 4b0538d07ac4e79b7cdbb21b373a5f5315459829 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Thu, 23 Sep 2021 18:18:55 +0200 Subject: [PATCH] Don't save anything in XFA entry if no XFA! (bug 1732344) - it aims to fix https://bugzilla.mozilla.org/show_bug.cgi?id=1732344 - rename some variables to have a more clear code; - and last but no least, add a unit test to test saving. --- src/core/worker.js | 17 ++++++++------- src/core/writer.js | 45 +++++++++++++++++++++------------------- test/unit/api_spec.js | 22 ++++++++++++++++++++ test/unit/writer_spec.js | 7 ++++--- web/app.js | 1 + 5 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/core/worker.js b/src/core/worker.js index 14ac279bf..96443a8f5 100644 --- a/src/core/worker.js +++ b/src/core/worker.js @@ -624,18 +624,18 @@ class WorkerMessageHandler { } const xfa = (acroForm instanceof Dict && acroForm.get("XFA")) || null; - let xfaDatasets = null; - let hasDatasets = false; + let xfaDatasetsRef = null; + let hasXfaDatasetsEntry = false; if (Array.isArray(xfa)) { for (let i = 0, ii = xfa.length; i < ii; i += 2) { if (xfa[i] === "datasets") { - xfaDatasets = xfa[i + 1]; + xfaDatasetsRef = xfa[i + 1]; acroFormRef = null; - hasDatasets = true; + hasXfaDatasetsEntry = true; } } - if (xfaDatasets === null) { - xfaDatasets = xref.getNewRef(); + if (xfaDatasetsRef === null) { + xfaDatasetsRef = xref.getNewRef(); } } else if (xfa) { acroFormRef = null; @@ -674,8 +674,9 @@ class WorkerMessageHandler { xrefInfo: newXrefInfo, newRefs, xref, - datasetsRef: xfaDatasets, - hasDatasets, + hasXfa: !!xfa, + xfaDatasetsRef, + hasXfaDatasetsEntry, acroFormRef, acroForm, xfaData, diff --git a/src/core/writer.js b/src/core/writer.js index 54a476d6f..96b16beeb 100644 --- a/src/core/writer.js +++ b/src/core/writer.js @@ -154,8 +154,8 @@ function writeXFADataForAcroform(str, newRefs) { function updateXFA({ xfaData, - datasetsRef, - hasDatasets, + xfaDatasetsRef, + hasXfaDatasetsEntry, acroFormRef, acroForm, newRefs, @@ -166,7 +166,7 @@ function updateXFA({ return; } - if (!hasDatasets) { + if (!hasXfaDatasetsEntry) { if (!acroFormRef) { warn("XFA - Cannot save it"); return; @@ -178,7 +178,7 @@ function updateXFA({ const oldXfa = acroForm.get("XFA"); const newXfa = oldXfa.slice(); newXfa.splice(2, 0, "datasets"); - newXfa.splice(3, 0, datasetsRef); + newXfa.splice(3, 0, xfaDatasetsRef); acroForm.set("XFA", newXfa); @@ -201,25 +201,25 @@ function updateXFA({ } if (xfaData === null) { - const datasets = xref.fetchIfRef(datasetsRef); + const datasets = xref.fetchIfRef(xfaDatasetsRef); xfaData = writeXFADataForAcroform(datasets.getString(), newRefs); } const encrypt = xref.encrypt; if (encrypt) { const transform = encrypt.createCipherTransform( - datasetsRef.num, - datasetsRef.gen + xfaDatasetsRef.num, + xfaDatasetsRef.gen ); xfaData = transform.encryptString(xfaData); } const data = - `${datasetsRef.num} ${datasetsRef.gen} obj\n` + + `${xfaDatasetsRef.num} ${xfaDatasetsRef.gen} obj\n` + `<< /Type /EmbeddedFile /Length ${xfaData.length}>>\nstream\n` + xfaData + "\nendstream\nendobj\n"; - newRefs.push({ ref: datasetsRef, data }); + newRefs.push({ ref: xfaDatasetsRef, data }); } function incrementalUpdate({ @@ -227,22 +227,25 @@ function incrementalUpdate({ xrefInfo, newRefs, xref = null, - datasetsRef = null, - hasDatasets = false, + hasXfa = false, + xfaDatasetsRef = null, + hasXfaDatasetsEntry = false, acroFormRef = null, acroForm = null, xfaData = null, }) { - updateXFA({ - xfaData, - datasetsRef, - hasDatasets, - acroFormRef, - acroForm, - newRefs, - xref, - xrefInfo, - }); + if (hasXfa) { + updateXFA({ + xfaData, + xfaDatasetsRef, + hasXfaDatasetsEntry, + acroFormRef, + acroForm, + newRefs, + xref, + xrefInfo, + }); + } const newXref = new Dict(null); const refForXrefTable = xrefInfo.newRef; diff --git a/test/unit/api_spec.js b/test/unit/api_spec.js index 8dfb7eb85..f5a81f243 100644 --- a/test/unit/api_spec.js +++ b/test/unit/api_spec.js @@ -1283,6 +1283,28 @@ describe("api", function () { await Promise.all([loadingTask1.destroy(), loadingTask2.destroy()]); }); + it("write a value in an annotation, save the pdf and load it", async function () { + let loadingTask = getDocument(buildGetDocumentParams("evaljs.pdf")); + let pdfDoc = await loadingTask.promise; + const value = "Hello World"; + + pdfDoc.annotationStorage.setValue("55R", { value }); + + const data = await pdfDoc.saveDocument(); + await loadingTask.destroy(); + + loadingTask = getDocument(data); + pdfDoc = await loadingTask.promise; + const pdfPage = await pdfDoc.getPage(1); + const annotations = await pdfPage.getAnnotations(); + + const field = annotations.find(annotation => annotation.id === "55R"); + expect(!!field).toEqual(true); + expect(field.fieldValue).toEqual(value); + + await loadingTask.destroy(); + }); + describe("Cross-origin", function () { let loadingTask; function _checkCanLoad(expectSuccess, filename, options) { diff --git a/test/unit/writer_spec.js b/test/unit/writer_spec.js index 1cfb5a8d0..39504b2e1 100644 --- a/test/unit/writer_spec.js +++ b/test/unit/writer_spec.js @@ -162,7 +162,7 @@ describe("Writer", function () { Ref.get(456, 0), ]); const acroFormRef = Ref.get(789, 0); - const datasetsRef = Ref.get(101112, 0); + const xfaDatasetsRef = Ref.get(101112, 0); const xfaData = "world"; const xrefInfo = { @@ -180,8 +180,9 @@ describe("Writer", function () { originalData, xrefInfo, newRefs, - datasetsRef, - hasDatasets: false, + hasXfa: true, + xfaDatasetsRef, + hasXfaDatasetsEntry: false, acroFormRef, acroForm, xfaData, diff --git a/web/app.js b/web/app.js index 125383681..66c1c7b8b 100644 --- a/web/app.js +++ b/web/app.js @@ -1015,6 +1015,7 @@ const PDFViewerApplication = { } catch (reason) { // When the PDF document isn't ready, or the PDF file is still // downloading, simply fallback to a "regular" download. + console.error(`Error when saving the document: ${reason.message}`); await this.download({ sourceEventType }); } finally { await this.pdfScriptingManager.dispatchDidSave();