Merge pull request #13967 from calixteman/no_datasets
XFA - Overwrite AcroForm dictionary when saving if no datasets in XFA (bug 1720179)
This commit is contained in:
commit
d9d3115a7b
@ -130,6 +130,11 @@ class Catalog {
|
|||||||
return shadow(this, "acroForm", acroForm);
|
return shadow(this, "acroForm", acroForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get acroFormRef() {
|
||||||
|
const value = this._catDict.getRaw("AcroForm");
|
||||||
|
return shadow(this, "acroFormRef", isRef(value) ? value : null);
|
||||||
|
}
|
||||||
|
|
||||||
get metadata() {
|
get metadata() {
|
||||||
const streamRef = this._catDict.getRaw("Metadata");
|
const streamRef = this._catDict.getRaw("Metadata");
|
||||||
if (!isRef(streamRef)) {
|
if (!isRef(streamRef)) {
|
||||||
|
@ -573,6 +573,7 @@ class WorkerMessageHandler {
|
|||||||
const promises = [
|
const promises = [
|
||||||
pdfManager.onLoadedStream(),
|
pdfManager.onLoadedStream(),
|
||||||
pdfManager.ensureCatalog("acroForm"),
|
pdfManager.ensureCatalog("acroForm"),
|
||||||
|
pdfManager.ensureCatalog("acroFormRef"),
|
||||||
pdfManager.ensureDoc("xref"),
|
pdfManager.ensureDoc("xref"),
|
||||||
pdfManager.ensureDoc("startXRef"),
|
pdfManager.ensureDoc("startXRef"),
|
||||||
];
|
];
|
||||||
@ -597,6 +598,7 @@ class WorkerMessageHandler {
|
|||||||
return Promise.all(promises).then(function ([
|
return Promise.all(promises).then(function ([
|
||||||
stream,
|
stream,
|
||||||
acroForm,
|
acroForm,
|
||||||
|
acroFormRef,
|
||||||
xref,
|
xref,
|
||||||
startXRef,
|
startXRef,
|
||||||
...refs
|
...refs
|
||||||
@ -621,15 +623,22 @@ class WorkerMessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const xfa = (acroForm instanceof Dict && acroForm.get("XFA")) || [];
|
const xfa = (acroForm instanceof Dict && acroForm.get("XFA")) || null;
|
||||||
let xfaDatasets = null;
|
let xfaDatasets = null;
|
||||||
|
let hasDatasets = false;
|
||||||
if (Array.isArray(xfa)) {
|
if (Array.isArray(xfa)) {
|
||||||
for (let i = 0, ii = xfa.length; i < ii; i += 2) {
|
for (let i = 0, ii = xfa.length; i < ii; i += 2) {
|
||||||
if (xfa[i] === "datasets") {
|
if (xfa[i] === "datasets") {
|
||||||
xfaDatasets = xfa[i + 1];
|
xfaDatasets = xfa[i + 1];
|
||||||
|
acroFormRef = null;
|
||||||
|
hasDatasets = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (xfaDatasets === null) {
|
||||||
|
xfaDatasets = xref.getNewRef();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
acroFormRef = null;
|
||||||
// TODO: Support XFA streams.
|
// TODO: Support XFA streams.
|
||||||
warn("Unsupported XFA type.");
|
warn("Unsupported XFA type.");
|
||||||
}
|
}
|
||||||
@ -666,6 +675,9 @@ class WorkerMessageHandler {
|
|||||||
newRefs,
|
newRefs,
|
||||||
xref,
|
xref,
|
||||||
datasetsRef: xfaDatasets,
|
datasetsRef: xfaDatasets,
|
||||||
|
hasDatasets,
|
||||||
|
acroFormRef,
|
||||||
|
acroForm,
|
||||||
xfaData,
|
xfaData,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -146,10 +146,54 @@ function writeXFADataForAcroform(str, newRefs) {
|
|||||||
return buffer.join("");
|
return buffer.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateXFA(xfaData, datasetsRef, newRefs, xref) {
|
function updateXFA({
|
||||||
if (datasetsRef === null || xref === null) {
|
xfaData,
|
||||||
|
datasetsRef,
|
||||||
|
hasDatasets,
|
||||||
|
acroFormRef,
|
||||||
|
acroForm,
|
||||||
|
newRefs,
|
||||||
|
xref,
|
||||||
|
xrefInfo,
|
||||||
|
}) {
|
||||||
|
if (xref === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasDatasets) {
|
||||||
|
if (!acroFormRef) {
|
||||||
|
warn("XFA - Cannot save it");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've a XFA array which doesn't contain a datasets entry.
|
||||||
|
// So we'll update the AcroForm dictionary to have an XFA containing
|
||||||
|
// the datasets.
|
||||||
|
const oldXfa = acroForm.get("XFA");
|
||||||
|
const newXfa = oldXfa.slice();
|
||||||
|
newXfa.splice(2, 0, "datasets");
|
||||||
|
newXfa.splice(3, 0, datasetsRef);
|
||||||
|
|
||||||
|
acroForm.set("XFA", newXfa);
|
||||||
|
|
||||||
|
const encrypt = xref.encrypt;
|
||||||
|
let transform = null;
|
||||||
|
if (encrypt) {
|
||||||
|
transform = encrypt.createCipherTransform(
|
||||||
|
acroFormRef.num,
|
||||||
|
acroFormRef.gen
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = [`${acroFormRef.num} ${acroFormRef.gen} obj\n`];
|
||||||
|
writeDict(acroForm, buffer, transform);
|
||||||
|
buffer.push("\n");
|
||||||
|
|
||||||
|
acroForm.set("XFA", oldXfa);
|
||||||
|
|
||||||
|
newRefs.push({ ref: acroFormRef, data: buffer.join("") });
|
||||||
|
}
|
||||||
|
|
||||||
if (xfaData === null) {
|
if (xfaData === null) {
|
||||||
const datasets = xref.fetchIfRef(datasetsRef);
|
const datasets = xref.fetchIfRef(datasetsRef);
|
||||||
xfaData = writeXFADataForAcroform(datasets.getString(), newRefs);
|
xfaData = writeXFADataForAcroform(datasets.getString(), newRefs);
|
||||||
@ -178,9 +222,21 @@ function incrementalUpdate({
|
|||||||
newRefs,
|
newRefs,
|
||||||
xref = null,
|
xref = null,
|
||||||
datasetsRef = null,
|
datasetsRef = null,
|
||||||
|
hasDatasets = false,
|
||||||
|
acroFormRef = null,
|
||||||
|
acroForm = null,
|
||||||
xfaData = null,
|
xfaData = null,
|
||||||
}) {
|
}) {
|
||||||
updateXFA(xfaData, datasetsRef, newRefs, xref);
|
updateXFA({
|
||||||
|
xfaData,
|
||||||
|
datasetsRef,
|
||||||
|
hasDatasets,
|
||||||
|
acroFormRef,
|
||||||
|
acroForm,
|
||||||
|
newRefs,
|
||||||
|
xref,
|
||||||
|
xrefInfo,
|
||||||
|
});
|
||||||
|
|
||||||
const newXref = new Dict(null);
|
const newXref = new Dict(null);
|
||||||
const refForXrefTable = xrefInfo.newRef;
|
const refForXrefTable = xrefInfo.newRef;
|
||||||
|
@ -142,4 +142,67 @@ describe("Writer", function () {
|
|||||||
expect(buffer.join("")).toEqual(expected);
|
expect(buffer.join("")).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("XFA", function () {
|
||||||
|
it("should update AcroForm when no datasets in XFA array", function () {
|
||||||
|
const originalData = new Uint8Array();
|
||||||
|
const newRefs = [];
|
||||||
|
|
||||||
|
const acroForm = new Dict(null);
|
||||||
|
acroForm.set("XFA", [
|
||||||
|
"preamble",
|
||||||
|
Ref.get(123, 0),
|
||||||
|
"postamble",
|
||||||
|
Ref.get(456, 0),
|
||||||
|
]);
|
||||||
|
const acroFormRef = Ref.get(789, 0);
|
||||||
|
const datasetsRef = Ref.get(101112, 0);
|
||||||
|
const xfaData = "<hello>world</hello>";
|
||||||
|
|
||||||
|
const xrefInfo = {
|
||||||
|
newRef: Ref.get(131415, 0),
|
||||||
|
startXRef: 314,
|
||||||
|
fileIds: null,
|
||||||
|
rootRef: null,
|
||||||
|
infoRef: null,
|
||||||
|
encryptRef: null,
|
||||||
|
filename: "foo.pdf",
|
||||||
|
info: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = incrementalUpdate({
|
||||||
|
originalData,
|
||||||
|
xrefInfo,
|
||||||
|
newRefs,
|
||||||
|
datasetsRef,
|
||||||
|
hasDatasets: false,
|
||||||
|
acroFormRef,
|
||||||
|
acroForm,
|
||||||
|
xfaData,
|
||||||
|
xref: {},
|
||||||
|
});
|
||||||
|
data = bytesToString(data);
|
||||||
|
|
||||||
|
const expected =
|
||||||
|
"\n" +
|
||||||
|
"789 0 obj\n" +
|
||||||
|
"<< /XFA [(preamble) 123 0 R (datasets) 101112 0 R (postamble) 456 0 R]>>\n" +
|
||||||
|
"101112 0 obj\n" +
|
||||||
|
"<< /Type /EmbeddedFile /Length 20>>\n" +
|
||||||
|
"stream\n" +
|
||||||
|
"<hello>world</hello>\n" +
|
||||||
|
"endstream\n" +
|
||||||
|
"endobj\n" +
|
||||||
|
"131415 0 obj\n" +
|
||||||
|
"<< /Size 131416 /Prev 314 /Type /XRef /Index [0 1 789 1 101112 1 131415 1] /W [1 1 2] /Length 16>> stream\n" +
|
||||||
|
"\u0000\u0001ÿÿ\u0001\u0001\u0000\u0000\u0001T\u0000\u0000\u0001²\u0000\u0000\n" +
|
||||||
|
"endstream\n" +
|
||||||
|
"endobj\n" +
|
||||||
|
"startxref\n" +
|
||||||
|
"178\n" +
|
||||||
|
"%%EOF\n";
|
||||||
|
|
||||||
|
expect(data).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user