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