Merge pull request #12483 from Snuffleupagus/formInfo-hasFields
Don't store complex data in `PDFDocument.formInfo`, and replace the `fields` object with a `hasFields` boolean instead
This commit is contained in:
commit
32bceae732
@ -687,8 +687,15 @@ class PDFDocument {
|
|||||||
*/
|
*/
|
||||||
_hasOnlyDocumentSignatures(fields, recursionDepth = 0) {
|
_hasOnlyDocumentSignatures(fields, recursionDepth = 0) {
|
||||||
const RECURSION_LIMIT = 10;
|
const RECURSION_LIMIT = 10;
|
||||||
|
|
||||||
|
if (!Array.isArray(fields)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return fields.every(field => {
|
return fields.every(field => {
|
||||||
field = this.xref.fetchIfRef(field);
|
field = this.xref.fetchIfRef(field);
|
||||||
|
if (!(field instanceof Dict)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (field.has("Kids")) {
|
if (field.has("Kids")) {
|
||||||
if (++recursionDepth > RECURSION_LIMIT) {
|
if (++recursionDepth > RECURSION_LIMIT) {
|
||||||
warn("_hasOnlyDocumentSignatures: maximum recursion depth reached");
|
warn("_hasOnlyDocumentSignatures: maximum recursion depth reached");
|
||||||
@ -708,20 +715,23 @@ class PDFDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get formInfo() {
|
get formInfo() {
|
||||||
const formInfo = { hasAcroForm: false, hasXfa: false, fields: null };
|
const formInfo = { hasFields: false, hasAcroForm: false, hasXfa: false };
|
||||||
const acroForm = this.catalog.acroForm;
|
const acroForm = this.catalog.acroForm;
|
||||||
if (!acroForm) {
|
if (!acroForm) {
|
||||||
return shadow(this, "formInfo", formInfo);
|
return shadow(this, "formInfo", formInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const fields = acroForm.get("Fields");
|
||||||
|
const hasFields = Array.isArray(fields) && fields.length > 0;
|
||||||
|
formInfo.hasFields = hasFields; // Used by the `fieldObjects` getter.
|
||||||
|
|
||||||
// The document contains XFA data if the `XFA` entry is a non-empty
|
// The document contains XFA data if the `XFA` entry is a non-empty
|
||||||
// array or stream.
|
// array or stream.
|
||||||
const xfa = acroForm.get("XFA");
|
const xfa = acroForm.get("XFA");
|
||||||
const hasXfa =
|
formInfo.hasXfa =
|
||||||
(Array.isArray(xfa) && xfa.length > 0) ||
|
(Array.isArray(xfa) && xfa.length > 0) ||
|
||||||
(isStream(xfa) && !xfa.isEmpty);
|
(isStream(xfa) && !xfa.isEmpty);
|
||||||
formInfo.hasXfa = hasXfa;
|
|
||||||
|
|
||||||
// The document contains AcroForm data if the `Fields` entry is a
|
// The document contains AcroForm data if the `Fields` entry is a
|
||||||
// non-empty array and it doesn't consist of only document signatures.
|
// non-empty array and it doesn't consist of only document signatures.
|
||||||
@ -730,20 +740,15 @@ class PDFDocument {
|
|||||||
// store (invisible) document signatures. This can be detected using
|
// store (invisible) document signatures. This can be detected using
|
||||||
// the first bit of the `SigFlags` integer (see Table 219 in the
|
// the first bit of the `SigFlags` integer (see Table 219 in the
|
||||||
// specification).
|
// specification).
|
||||||
const fields = acroForm.get("Fields");
|
|
||||||
const hasFields = Array.isArray(fields) && fields.length > 0;
|
|
||||||
const sigFlags = acroForm.get("SigFlags");
|
const sigFlags = acroForm.get("SigFlags");
|
||||||
const hasOnlyDocumentSignatures =
|
const hasOnlyDocumentSignatures =
|
||||||
!!(sigFlags & 0x1) && this._hasOnlyDocumentSignatures(fields);
|
!!(sigFlags & 0x1) && this._hasOnlyDocumentSignatures(fields);
|
||||||
formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures;
|
formInfo.hasAcroForm = hasFields && !hasOnlyDocumentSignatures;
|
||||||
if (hasFields) {
|
|
||||||
formInfo.fields = fields;
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
if (ex instanceof MissingDataException) {
|
if (ex instanceof MissingDataException) {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
info("Cannot fetch form information.");
|
warn(`Cannot fetch form information: "${ex}".`);
|
||||||
}
|
}
|
||||||
return shadow(this, "formInfo", formInfo);
|
return shadow(this, "formInfo", formInfo);
|
||||||
}
|
}
|
||||||
@ -939,6 +944,9 @@ class PDFDocument {
|
|||||||
: clearPrimitiveCaches();
|
: clearPrimitiveCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
_collectFieldObjects(name, fieldRef, promises) {
|
_collectFieldObjects(name, fieldRef, promises) {
|
||||||
const field = this.xref.fetchIfRef(fieldRef);
|
const field = this.xref.fetchIfRef(fieldRef);
|
||||||
if (field.has("T")) {
|
if (field.has("T")) {
|
||||||
@ -976,19 +984,18 @@ class PDFDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get fieldObjects() {
|
get fieldObjects() {
|
||||||
const formInfo = this.formInfo;
|
if (!this.formInfo.hasFields) {
|
||||||
if (!formInfo.fields) {
|
|
||||||
return shadow(this, "fieldObjects", Promise.resolve(null));
|
return shadow(this, "fieldObjects", Promise.resolve(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
const allFields = Object.create(null);
|
const allFields = Object.create(null);
|
||||||
const fieldPromises = new Map();
|
const fieldPromises = new Map();
|
||||||
for (const fieldRef of formInfo.fields) {
|
for (const fieldRef of this.catalog.acroForm.get("Fields")) {
|
||||||
this._collectFieldObjects("", fieldRef, fieldPromises);
|
this._collectFieldObjects("", fieldRef, fieldPromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
const allPromises = [];
|
const allPromises = [];
|
||||||
for (const [name, promises] of fieldPromises.entries()) {
|
for (const [name, promises] of fieldPromises) {
|
||||||
allPromises.push(
|
allPromises.push(
|
||||||
Promise.all(promises).then(fields => {
|
Promise.all(promises).then(fields => {
|
||||||
fields = fields.filter(field => field !== null);
|
fields = fields.filter(field => field !== null);
|
||||||
|
@ -878,8 +878,9 @@ class PDFDocumentProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<Array<Object>>} A promise that is resolved with an
|
* @returns {Promise<Array<Object> | null>} A promise that is resolved with an
|
||||||
* {Array<Object>} containing field data for the JS sandbox.
|
* {Array<Object>} containing /AcroForm field data for the JS sandbox,
|
||||||
|
* or `null` when no field data is present in the PDF file.
|
||||||
*/
|
*/
|
||||||
getFieldObjects() {
|
getFieldObjects() {
|
||||||
return this._transport.getFieldObjects();
|
return this._transport.getFieldObjects();
|
||||||
|
@ -64,7 +64,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: null,
|
hasFields: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: null,
|
hasFields: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
acroForm.set("XFA", ["foo", "bar"]);
|
acroForm.set("XFA", ["foo", "bar"]);
|
||||||
@ -85,7 +85,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: true,
|
hasXfa: true,
|
||||||
fields: null,
|
hasFields: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
acroForm.set("XFA", new StringStream(""));
|
acroForm.set("XFA", new StringStream(""));
|
||||||
@ -93,7 +93,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: null,
|
hasFields: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
acroForm.set("XFA", new StringStream("non-empty"));
|
acroForm.set("XFA", new StringStream("non-empty"));
|
||||||
@ -101,7 +101,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: true,
|
hasXfa: true,
|
||||||
fields: null,
|
hasFields: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: null,
|
hasFields: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
acroForm.set("Fields", ["foo", "bar"]);
|
acroForm.set("Fields", ["foo", "bar"]);
|
||||||
@ -122,7 +122,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: true,
|
hasAcroForm: true,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: ["foo", "bar"],
|
hasFields: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the first bit of the `SigFlags` entry is set and the `Fields` array
|
// If the first bit of the `SigFlags` entry is set and the `Fields` array
|
||||||
@ -133,7 +133,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: true,
|
hasAcroForm: true,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: ["foo", "bar"],
|
hasFields: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const annotationDict = new Dict();
|
const annotationDict = new Dict();
|
||||||
@ -156,7 +156,7 @@ describe("document", function () {
|
|||||||
expect(pdfDocument.formInfo).toEqual({
|
expect(pdfDocument.formInfo).toEqual({
|
||||||
hasAcroForm: false,
|
hasAcroForm: false,
|
||||||
hasXfa: false,
|
hasXfa: false,
|
||||||
fields: [kidsRef],
|
hasFields: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user