Follow-up of pr #12344

This commit is contained in:
Calixte Denizet 2020-09-09 11:46:02 +02:00
parent e51e9d1f33
commit 64a6efd95e
9 changed files with 69 additions and 56 deletions

View File

@ -165,6 +165,26 @@ function isWhiteSpace(ch) {
return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a; return ch === 0x20 || ch === 0x09 || ch === 0x0d || ch === 0x0a;
} }
/**
* AcroForm field names use an array like notation to refer to
* repeated XFA elements e.g. foo.bar[nnn].
* see: XFA Spec Chapter 3 - Repeated Elements
*
* @param {string} path - XFA path name.
* @returns {Array} - Array of Objects with the name and pos of
* each part of the path.
*/
function parseXFAPath(path) {
const positionPattern = /(.+)\[([0-9]+)\]$/;
return path.split(".").map(component => {
const m = component.match(positionPattern);
if (m) {
return { name: m[1], pos: parseInt(m[2], 10) };
}
return { name: component, pos: 0 };
});
}
export { export {
getLookupTableFactory, getLookupTableFactory,
MissingDataException, MissingDataException,
@ -173,6 +193,7 @@ export {
getInheritableProperty, getInheritableProperty,
toRomanNumerals, toRomanNumerals,
log2, log2,
parseXFAPath,
readInt8, readInt8,
readUint16, readUint16,
readUint32, readUint32,

View File

@ -589,13 +589,13 @@ class WorkerMessageHandler {
} }
xref.resetNewRef(); xref.resetNewRef();
return incrementalUpdate( return incrementalUpdate({
stream.bytes, originalData: stream.bytes,
newXrefInfo, xrefInfo: newXrefInfo,
newRefs, newRefs,
xref, xref,
xfaDatasets datasetsRef: xfaDatasets,
); });
}); });
}); });

View File

@ -14,15 +14,11 @@
*/ */
/* eslint no-var: error */ /* eslint no-var: error */
import { import { bytesToString, escapeString, warn } from "../shared/util.js";
bytesToString,
escapeString,
parseXFAPath,
warn,
} from "../shared/util.js";
import { Dict, isDict, isName, isRef, isStream, Name } from "./primitives.js"; import { Dict, isDict, isName, isRef, isStream, Name } from "./primitives.js";
import { SimpleDOMNode, SimpleXMLParser } from "../shared/xml_parser.js"; import { SimpleDOMNode, SimpleXMLParser } from "../shared/xml_parser.js";
import { calculateMD5 } from "./crypto.js"; import { calculateMD5 } from "./crypto.js";
import { parseXFAPath } from "./core_utils.js";
function writeDict(dict, buffer, transform) { function writeDict(dict, buffer, transform) {
buffer.push("<<"); buffer.push("<<");
@ -175,7 +171,13 @@ function updateXFA(datasetsRef, newRefs, xref) {
newRefs.push({ ref: datasetsRef, data }); newRefs.push({ ref: datasetsRef, data });
} }
function incrementalUpdate(originalData, xrefInfo, newRefs, xref, datasetsRef) { function incrementalUpdate({
originalData,
xrefInfo,
newRefs,
xref = null,
datasetsRef = null,
}) {
updateXFA(datasetsRef, newRefs, xref); updateXFA(datasetsRef, newRefs, xref);
const newXref = new Dict(null); const newXref = new Dict(null);

View File

@ -910,26 +910,6 @@ const createObjectURL = (function createObjectURLClosure() {
}; };
})(); })();
/**
* AcroForm field names use an array like notation to refer to
* repeated XFA elements e.g. foo.bar[nnn].
* see: XFA Spec Chapter 3 - Repeated Elements
*
* @param {string} path - XFA path name.
* @returns {Array} - Array of Objects with the name and pos of
* each part of the path.
*/
function parseXFAPath(path) {
const positionPattern = /(.+)\[([0-9]+)\]$/;
return path.split(".").map(component => {
const m = component.match(positionPattern);
if (m) {
return { name: m[1], pos: parseInt(m[2], 10) };
}
return { name: component, pos: 0 };
});
}
const XMLEntities = { const XMLEntities = {
/* < */ 0x3c: "&lt;", /* < */ 0x3c: "&lt;",
/* > */ 0x3e: "&gt;", /* > */ 0x3e: "&gt;",
@ -1027,7 +1007,6 @@ export {
createValidAbsoluteUrl, createValidAbsoluteUrl,
IsLittleEndianCached, IsLittleEndianCached,
IsEvalSupportedCached, IsEvalSupportedCached,
parseXFAPath,
removeNullCharacters, removeNullCharacters,
setVerbosityLevel, setVerbosityLevel,
shadow, shadow,

View File

@ -329,6 +329,18 @@ class SimpleDOMNode {
return this.childNodes && this.childNodes.length > 0; return this.childNodes && this.childNodes.length > 0;
} }
/**
* Search a node in the tree with the given path
* foo.bar[nnn], i.e. find the nnn-th node named
* bar under a node named foo.
*
* @param {Array} paths - an array of objects as
* returned by {parseXFAPath}.
* @param {number} pos - the current position in
* the paths array.
* @returns {SimpleDOMNode} The node corresponding
* to the path or null if not found.
*/
searchNode(paths, pos) { searchNode(paths, pos) {
if (pos >= paths.length) { if (pos >= paths.length) {
return this; return this;

View File

@ -18,6 +18,7 @@ import {
getInheritableProperty, getInheritableProperty,
isWhiteSpace, isWhiteSpace,
log2, log2,
parseXFAPath,
toRomanNumerals, toRomanNumerals,
} from "../../src/core/core_utils.js"; } from "../../src/core/core_utils.js";
import { XRefMock } from "./test_utils.js"; import { XRefMock } from "./test_utils.js";
@ -211,4 +212,18 @@ describe("core_utils", function () {
expect(isWhiteSpace(undefined)).toEqual(false); expect(isWhiteSpace(undefined)).toEqual(false);
}); });
}); });
describe("parseXFAPath", function () {
it("should get a correctly parsed path", function () {
const path = "foo.bar[12].oof[3].rab.FOO[123].BAR[456]";
expect(parseXFAPath(path)).toEqual([
{ name: "foo", pos: 0 },
{ name: "bar", pos: 12 },
{ name: "oof", pos: 3 },
{ name: "rab", pos: 0 },
{ name: "FOO", pos: 123 },
{ name: "BAR", pos: 456 },
]);
});
});
}); });

View File

@ -25,7 +25,6 @@ import {
isNum, isNum,
isSameOrigin, isSameOrigin,
isString, isString,
parseXFAPath,
removeNullCharacters, removeNullCharacters,
string32, string32,
stringToBytes, stringToBytes,
@ -334,20 +333,6 @@ describe("util", function () {
}); });
}); });
describe("parseXFAPath", function () {
it("should get a correctly parsed path", function () {
const path = "foo.bar[12].oof[3].rab.FOO[123].BAR[456]";
expect(parseXFAPath(path)).toEqual([
{ name: "foo", pos: 0 },
{ name: "bar", pos: 12 },
{ name: "oof", pos: 3 },
{ name: "rab", pos: 0 },
{ name: "FOO", pos: 123 },
{ name: "BAR", pos: 456 },
]);
});
});
describe("encodeToXmlString", function () { describe("encodeToXmlString", function () {
it("should get a correctly encoded string with some entities", function () { it("should get a correctly encoded string with some entities", function () {
const str = "\"\u0397ell😂' & <W😂rld>"; const str = "\"\u0397ell😂' & <W😂rld>";

View File

@ -37,7 +37,7 @@ describe("Writer", function () {
info: {}, info: {},
}; };
let data = incrementalUpdate(originalData, xrefInfo, newRefs, null, null); let data = incrementalUpdate({ originalData, xrefInfo, newRefs });
data = bytesToString(data); data = bytesToString(data);
const expected = const expected =

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { parseXFAPath } from "../../src/shared/util.js"; import { parseXFAPath } from "../../src/core/core_utils.js";
import { SimpleXMLParser } from "../../src/shared/xml_parser.js"; import { SimpleXMLParser } from "../../src/shared/xml_parser.js";
describe("XML", function () { describe("XML", function () {
@ -69,7 +69,7 @@ describe("XML", function () {
}); });
it("should dump a xml tree", function () { it("should dump a xml tree", function () {
let xml = ` const xml = `
<a> <a>
<b> <b>
<c a="123"/> <c a="123"/>
@ -87,9 +87,7 @@ describe("XML", function () {
<h> <h>
<i/> <i/>
<j/> <j/>
<k> <k>&#xA;W&#x1F602;rld&#xA;<g a="654"/>
W&#x1F602;rld
<g a="654"/>
</k> </k>
</h> </h>
<b> <b>
@ -98,13 +96,14 @@ describe("XML", function () {
<g a="121110"/> <g a="121110"/>
</b> </b>
</a>`; </a>`;
xml = xml.replace(/\s+/g, "");
const root = new SimpleXMLParser(true).parseFromString(xml) const root = new SimpleXMLParser(true).parseFromString(xml)
.documentElement; .documentElement;
const buffer = []; const buffer = [];
root.dump(buffer); root.dump(buffer);
expect(buffer.join("").replace(/\s+/g, "")).toEqual(xml); expect(buffer.join("").replace(/\s+/g, "")).toEqual(
xml.replace(/\s+/g, "")
);
}); });
}); });
}); });