From fa0b8d60110e5ef38bd0b4d07791c013cb3cee34 Mon Sep 17 00:00:00 2001 From: Angelina Pavlovets Date: Thu, 23 May 2024 19:36:04 +0000 Subject: [PATCH] Support docMDP level 3 validation DEVSIX-8344 Autoported commit. Original commit hash: [03a2c75fa] --- ...cumentRevisionsValidatorIntegrationTest.cs | 57 + .../v1/DocumentRevisionsValidatorTest.cs | 21 + .../danglingWidgetAnnotation.pdf | Bin 0 -> 21405 bytes .../removeAllAnnots.pdf | Bin 0 -> 21091 bytes .../removeFieldAnnots.pdf | Bin 0 -> 21662 bytes .../removeUnnamedField.pdf | Bin 0 -> 22244 bytes .../multipleRevisionsDocument3.pdf | Bin 0 -> 23826 bytes .../v1/DocumentRevisionsValidator.cs | 1211 ++++++++--------- port-hash | 2 +- 9 files changed, 675 insertions(+), 616 deletions(-) create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/danglingWidgetAnnotation.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeAllAnnots.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeFieldAnnots.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeUnnamedField.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorTest/multipleRevisionsDocument3.pdf diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest.cs index d15d9506fe..c4be4826dd 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU Affero General Public License using System; using iText.Bouncycastleconnector; using iText.Commons.Bouncycastle; +using iText.Commons.Utils; using iText.Kernel.Pdf; using iText.Signatures; using iText.Signatures.Validation.V1.Report; @@ -288,5 +289,61 @@ public virtual void RemovedLockedFieldTest() { .INVALID))); } } + + [NUnit.Framework.Test] + public virtual void DanglingWidgetAnnotationTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "danglingWidgetAnnotation.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + // New widget annotation not included into the acroform was added to the 1st page. + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.PAGE_ANNOTATIONS_MODIFIED).WithStatus(ReportItem.ReportItemStatus.INVALID) + )); + NUnit.Framework.Assert.AreEqual(AccessPermissions.FORM_FIELDS_MODIFICATION, validator.GetAccessPermissions + ()); + } + } + + [NUnit.Framework.Test] + public virtual void RemoveAllThePageAnnotationsTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removeAllAnnots.pdf"))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + // All the annotations on the 2nd page were removed. + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); + NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( + )); + } + } + + [NUnit.Framework.Test] + public virtual void RemoveAllTheFieldAnnotationsTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removeFieldAnnots.pdf"))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + // All the annotations of the text field were removed. Note that Acrobat considers it invalid. + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); + NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( + )); + } + } + + [NUnit.Framework.Test] + public virtual void RemoveUnnamedFieldTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removeUnnamedField.pdf"))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + // Child field was removed, so parent field was modified. Both fields are unnamed. + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (3).HasNumberOfLogs(3).HasLogItems(2, 2, (l) => l.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK + ).WithMessage(MessageFormatUtil.Format(DocumentRevisionsValidator.FIELD_REMOVED, "")).WithStatus(ReportItem.ReportItemStatus + .INVALID)).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK).WithMessage(DocumentRevisionsValidator + .NOT_ALLOWED_ACROFORM_CHANGES).WithStatus(ReportItem.ReportItemStatus.INVALID))); + NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( + )); + } + } } } diff --git a/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorTest.cs index ba9b04b06d..141bb025dd 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorTest.cs @@ -448,5 +448,26 @@ public virtual void ModifyPageAnnotsTest() { .INVALID))); } } + + [NUnit.Framework.Test] + public virtual void MultipleRevisionsDocumentLevel3Test() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "multipleRevisionsDocument3.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + validator.SetAccessPermissions(AccessPermissions.ANNOTATION_MODIFICATION); + PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); + IList documentRevisions = revisionsReader.GetAllRevisions(); + ValidationReport validationReport = new ValidationReport(); + validator.ValidateRevision(documentRevisions[0], documentRevisions[1], validationReport); + // Between these two revisions annotations were added and deleted, text field was filled-in. + AssertValidationReport.AssertThat(validationReport, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID + ).HasNumberOfFailures(0).HasNumberOfLogs(0)); + validationReport = new ValidationReport(); + validator.ValidateRevision(documentRevisions[1], documentRevisions[2], validationReport); + // Between these two revisions existed annotations were modified, it is allowed. + AssertValidationReport.AssertThat(validationReport, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID + ).HasNumberOfFailures(0).HasNumberOfLogs(0)); + } + } } } diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/danglingWidgetAnnotation.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/danglingWidgetAnnotation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3526ca7c5ba2e9aa145372cbb55ba5ad430a3110 GIT binary patch literal 21405 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 XS|~0}@{`C6Q1v!Yso2`s4OIRw767U) literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeFieldAnnots.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeFieldAnnots.pdf new file mode 100644 index 0000000000000000000000000000000000000000..148168290ed594ae49b754e4c3ddded2057ea53f GIT binary patch literal 21662 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeUnnamedField.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeUnnamedField.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2ba3e8d3cfa834e96d105e08c7fdaba1e049811c GIT binary patch literal 22244 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 literal 0 HcmV?d00001 diff --git a/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs b/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs index 36e8a19040..9f2a9cad9f 100644 --- a/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs +++ b/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs @@ -40,6 +40,9 @@ internal class DocumentRevisionsValidator { internal const String FIELD_MDP_CHECK = "FieldMDP check."; + internal const String ACCESS_PERMISSIONS_ADDED = "Access permissions level specified for \"{0}\" approval signature " + + "is higher than previous one specified. These access permissions will be ignored."; + internal const String ACROFORM_REMOVED = "AcroForm dictionary was removed from catalog."; internal const String ANNOTATIONS_MODIFIED = "Field annotations were removed, added or unexpectedly modified."; @@ -48,6 +51,8 @@ internal class DocumentRevisionsValidator { internal const String DIRECT_OBJECT = "{0} must be an indirect reference."; + internal const String DOCUMENT_WITHOUT_SIGNATURES = "Document doesn't contain any signatures."; + internal const String DSS_REMOVED = "DSS dictionary was removed from catalog."; internal const String EXTENSIONS_REMOVED = "Extensions dictionary was removed from the catalog."; @@ -56,8 +61,18 @@ internal class DocumentRevisionsValidator { internal const String EXTENSION_LEVEL_DECREASED = "Extension level number in developer extension \"{0}\" dictionary was decreased."; + internal const String FIELD_NOT_DICTIONARY = "Form field \"{0}\" or one of its widgets is not a dictionary. It will not be validated."; + internal const String FIELD_REMOVED = "Form field {0} was removed or unexpectedly modified."; + internal const String LOCKED_FIELD_KIDS_ADDED = "Kids were added to locked form field \"{0}\"."; + + internal const String LOCKED_FIELD_KIDS_REMOVED = "Kids were removed from locked form field \"{0}\" ."; + + internal const String LOCKED_FIELD_MODIFIED = "Locked form field \"{0}\" or one of its widgets was modified."; + + internal const String LOCKED_FIELD_REMOVED = "Locked form field \"{0}\" was removed from the document."; + internal const String NOT_ALLOWED_ACROFORM_CHANGES = "PDF document AcroForm contains changes other than " + "document timestamp (docMDP level >= 1), form fill-in and digital signatures (docMDP level >= 2), " + "adding or editing annotations (docMDP level 3), which are not allowed."; @@ -82,40 +97,25 @@ internal class DocumentRevisionsValidator { internal const String REFERENCE_REMOVED = "Signature reference dictionary was removed or unexpectedly modified."; - internal const String SIGNATURE_MODIFIED = "Signature {0} was unexpectedly modified."; - - internal const String UNEXPECTED_ENTRY_IN_XREF = "New PDF document revision contains unexpected entry \"{0}\" in XREF table."; + internal const String REVISIONS_READING_EXCEPTION = "IOException occurred during document revisions reading."; internal const String REVISIONS_RETRIEVAL_FAILED = "Wasn't possible to retrieve document revisions."; - internal const String DOCUMENT_WITHOUT_SIGNATURES = "Document doesn't contain any signatures."; - - internal const String TOO_MANY_CERTIFICATION_SIGNATURES = "Document contains more than one certification signature."; + internal const String SIGNATURE_MODIFIED = "Signature {0} was unexpectedly modified."; internal const String SIGNATURE_REVISION_NOT_FOUND = "Not possible to identify document revision corresponding to the first signature in the document."; - internal const String ACCESS_PERMISSIONS_ADDED = "Access permissions level specified for \"{0}\" approval signature " - + "is higher than previous one specified. These access permissions will be ignored."; + internal const String TOO_MANY_CERTIFICATION_SIGNATURES = "Document contains more than one certification signature."; - internal const String UNKNOWN_ACCESS_PERMISSIONS = "Access permissions level number specified for \"{0}\" signature " - + "is undefined. Default level 2 will be used instead."; + internal const String UNEXPECTED_ENTRY_IN_XREF = "New PDF document revision contains unexpected entry \"{0}\" in XREF table."; internal const String UNEXPECTED_FORM_FIELD = "New PDF document revision contains unexpected form field \"{0}\"."; - internal const String REVISIONS_READING_EXCEPTION = "IOException occurred during document revisions reading."; + internal const String UNKNOWN_ACCESS_PERMISSIONS = "Access permissions level number specified for \"{0}\" signature " + + "is undefined. Default level 2 will be used instead."; internal const String UNRECOGNIZED_ACTION = "Signature field lock dictionary contains unrecognized " + "\"Action\" value \"{0}\". \"All\" will be used instead."; - internal const String LOCKED_FIELD_REMOVED = "Locked form field \"{0}\" was removed from the document."; - - internal const String LOCKED_FIELD_KIDS_ADDED = "Kids were added to locked form field \"{0}\"."; - - internal const String LOCKED_FIELD_KIDS_REMOVED = "Kids were removed from locked form field \"{0}\" ."; - - internal const String FIELD_NOT_DICTIONARY = "Form field \"{0}\" or one of its widgets is not a dictionary. It will not be validated."; - - internal const String LOCKED_FIELD_MODIFIED = "Locked form field \"{0}\" or one of its widgets was modified."; - private IMetaInfo metaInfo = new ValidationMetaInfo(); private AccessPermissions accessPermissions = AccessPermissions.ANNOTATION_MODIFICATION; @@ -126,6 +126,10 @@ internal class DocumentRevisionsValidator { private readonly PdfDocument document; + private ICollection checkedAnnots; + + private ICollection newlyAddedFields; + internal DocumentRevisionsValidator(PdfDocument document) { this.document = document; } @@ -170,11 +174,15 @@ public virtual iText.Signatures.Validation.V1.DocumentRevisionsValidator SetAcce return this; } + internal virtual AccessPermissions GetAccessPermissions() { + return requestedAccessPermissions == AccessPermissions.UNSPECIFIED ? accessPermissions : requestedAccessPermissions; + } + /// Validate all document revisions according to docMDP and fieldMDP transform methods. /// /// /// - /// which contains detailed validation results + /// which contains detailed validation results. /// public virtual ValidationReport ValidateAllDocumentRevisions() { ValidationReport report = new ValidationReport(); @@ -235,6 +243,11 @@ public virtual ValidationReport ValidateAllDocumentRevisions() { return report; } + // + // + // Revisions validation util section: + // + // internal virtual void ValidateRevision(DocumentRevision previousRevision, DocumentRevision currentRevision , ValidationReport validationReport) { try { @@ -252,17 +265,17 @@ internal virtual void ValidateRevision(DocumentRevision previousRevision, Docume if (!CompareCatalogs(documentWithoutRevision, documentWithRevision, validationReport)) { return; } - IList allowedReferences = CreateAllowedReferences(documentWithRevision - , documentWithoutRevision); + ICollection currentAllowedReferences = CreateAllowedReferences(documentWithRevision); + ICollection previousAllowedReferences = CreateAllowedReferences(documentWithoutRevision + ); foreach (PdfIndirectReference indirectReference in indirectReferences) { if (indirectReference.IsFree()) { // In this boolean flag we check that reference which is about to be removed is the one which // changed in the new revision. For instance DSS reference was 5 0 obj and changed to be 6 0 obj. // In this case and only in this case reference with obj number 5 can be safely removed. - bool referenceAllowedToBeRemoved = allowedReferences.Any((reference) => reference.GetPreviousReference() != - null && reference.GetPreviousReference().GetObjNumber() == indirectReference.GetObjNumber() && (reference - .GetCurrentReference() == null || reference.GetCurrentReference().GetObjNumber() != indirectReference. - GetObjNumber())); + bool referenceAllowedToBeRemoved = previousAllowedReferences.Any((reference) => reference != null && reference + .GetObjNumber() == indirectReference.GetObjNumber()) && !currentAllowedReferences.Any((reference) => reference + != null && reference.GetObjNumber() == indirectReference.GetObjNumber()); // If some reference wasn't in the previous document, it is safe to remove it, // since it is not possible to introduce new reference and remove it at the same revision. bool referenceWasInPrevDocument = documentWithoutRevision.GetPdfObject(indirectReference.GetObjNumber()) != @@ -274,7 +287,8 @@ internal virtual void ValidateRevision(DocumentRevision previousRevision, Docume } } else { - if (!CheckAllowedReferences(allowedReferences, indirectReference, documentWithoutRevision)) { + if (!CheckAllowedReferences(currentAllowedReferences, previousAllowedReferences, indirectReference, documentWithoutRevision + )) { validationReport.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(UNEXPECTED_ENTRY_IN_XREF , indirectReference.GetObjNumber()), ReportItem.ReportItemStatus.INVALID)); } @@ -293,10 +307,6 @@ internal virtual void ValidateRevision(DocumentRevision previousRevision, Docume } } - internal virtual AccessPermissions GetAccessPermissions() { - return requestedAccessPermissions == AccessPermissions.UNSPECIFIED ? accessPermissions : requestedAccessPermissions; - } - private static Stream CreateInputStreamFromRevision(PdfDocument originalDocument, DocumentRevision revision ) { RandomAccessFileOrArray raf = originalDocument.GetReader().GetSafeFile(); @@ -335,8 +345,9 @@ private void UpdateApprovalSignatureAccessPermissions(PdfDictionary signatureFie } } if (accessPermissions.CompareTo(newAccessPermissions) < 0) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(ACCESS_PERMISSIONS_ADDED, signatureField - .Get(PdfName.T)), ReportItem.ReportItemStatus.INDETERMINATE)); + PdfString fieldName = signatureField.GetAsString(PdfName.T); + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(ACCESS_PERMISSIONS_ADDED, fieldName + == null ? "" : fieldName.GetValue()), ReportItem.ReportItemStatus.INDETERMINATE)); } else { accessPermissions = newAccessPermissions; @@ -482,6 +493,11 @@ private bool RevisionContainsSignature(DocumentRevision revision, String signatu return false; } + // + // + // Compare catalogs section: + // + // private bool CompareCatalogs(PdfDocument documentWithoutRevision, PdfDocument documentWithRevision, ValidationReport report) { PdfDictionary previousCatalog = documentWithoutRevision.GetCatalog().GetPdfObject(); @@ -495,11 +511,105 @@ private bool CompareCatalogs(PdfDocument documentWithoutRevision, PdfDocument do } return CompareExtensions(previousCatalog.Get(PdfName.Extensions), currentCatalog.Get(PdfName.Extensions), report) && ComparePermissions(previousCatalog.Get(PdfName.Perms), currentCatalog.Get(PdfName.Perms), report - ) && CompareDss(previousCatalog.Get(PdfName.DSS), currentCatalog.Get(PdfName.DSS), report) && ComparePages - (previousCatalog.GetAsDictionary(PdfName.Pages), currentCatalog.GetAsDictionary(PdfName.Pages), report - ) && CompareAcroFormsWithFieldMDP(documentWithoutRevision, documentWithRevision, report) && CompareAcroForms - (previousCatalog.GetAsDictionary(PdfName.AcroForm), currentCatalog.GetAsDictionary(PdfName.AcroForm), - report); + ) && CompareDss(previousCatalog.Get(PdfName.DSS), currentCatalog.Get(PdfName.DSS), report) && CompareAcroFormsWithFieldMDP + (documentWithoutRevision, documentWithRevision, report) && CompareAcroForms(previousCatalog.GetAsDictionary + (PdfName.AcroForm), currentCatalog.GetAsDictionary(PdfName.AcroForm), report) && ComparePages(previousCatalog + .GetAsDictionary(PdfName.Pages), currentCatalog.GetAsDictionary(PdfName.Pages), report); + } + + // Compare catalogs nested methods section: + private bool CompareExtensions(PdfObject previousExtensions, PdfObject currentExtensions, ValidationReport + report) { + if (previousExtensions == null || ComparePdfObjects(previousExtensions, currentExtensions)) { + return true; + } + if (currentExtensions == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, EXTENSIONS_REMOVED, ReportItem.ReportItemStatus.INVALID + )); + return false; + } + if (!(previousExtensions is PdfDictionary) || !(currentExtensions is PdfDictionary)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, EXTENSIONS_TYPE, ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfDictionary previousExtensionsDictionary = (PdfDictionary)previousExtensions; + PdfDictionary currentExtensionsDictionary = (PdfDictionary)currentExtensions; + foreach (KeyValuePair previousExtension in previousExtensionsDictionary.EntrySet()) { + PdfDictionary currentExtension = currentExtensionsDictionary.GetAsDictionary(previousExtension.Key); + if (currentExtension == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(DEVELOPER_EXTENSION_REMOVED, previousExtension + .Key), ReportItem.ReportItemStatus.INVALID)); + return false; + } + else { + PdfDictionary currentExtensionCopy = new PdfDictionary(currentExtension); + currentExtensionCopy.Remove(PdfName.ExtensionLevel); + PdfDictionary previousExtensionCopy = new PdfDictionary((PdfDictionary)previousExtension.Value); + previousExtensionCopy.Remove(PdfName.ExtensionLevel); + // Apart from extension level dictionaries are expected to be equal. + if (!ComparePdfObjects(previousExtensionCopy, currentExtensionCopy)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(DEVELOPER_EXTENSION_REMOVED, previousExtension + .Key), ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfNumber previousExtensionLevel = ((PdfDictionary)previousExtension.Value).GetAsNumber(PdfName.ExtensionLevel + ); + PdfNumber currentExtensionLevel = currentExtension.GetAsNumber(PdfName.ExtensionLevel); + if (previousExtensionLevel != null) { + if (currentExtensionLevel == null || previousExtensionLevel.IntValue() > currentExtensionLevel.IntValue()) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(EXTENSION_LEVEL_DECREASED, previousExtension + .Key), ReportItem.ReportItemStatus.INVALID)); + return false; + } + } + } + } + return true; + } + + private bool ComparePermissions(PdfObject previousPerms, PdfObject currentPerms, ValidationReport report) { + if (previousPerms == null || ComparePdfObjects(previousPerms, currentPerms)) { + return true; + } + if (currentPerms == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PERMISSIONS_REMOVED, ReportItem.ReportItemStatus.INVALID + )); + return false; + } + if (!(previousPerms is PdfDictionary) || !(currentPerms is PdfDictionary)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PERMISSIONS_TYPE, ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfDictionary previousPermsDictionary = (PdfDictionary)previousPerms; + PdfDictionary currentPermsDictionary = (PdfDictionary)currentPerms; + foreach (KeyValuePair previousPermission in previousPermsDictionary.EntrySet()) { + PdfDictionary currentPermission = currentPermsDictionary.GetAsDictionary(previousPermission.Key); + if (currentPermission == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(PERMISSION_REMOVED, previousPermission + .Key), ReportItem.ReportItemStatus.INVALID)); + return false; + } + else { + // Perms dictionary is the signature dictionary. + if (!CompareSignatureDictionaries(previousPermission.Value, currentPermission, report)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(PERMISSION_REMOVED, previousPermission + .Key), ReportItem.ReportItemStatus.INVALID)); + return false; + } + } + } + return true; + } + + private bool CompareDss(PdfObject previousDss, PdfObject currentDss, ValidationReport report) { + if (previousDss == null) { + return true; + } + if (currentDss == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, DSS_REMOVED, ReportItem.ReportItemStatus.INVALID)); + return false; + } + return true; } private bool CompareAcroFormsWithFieldMDP(PdfDocument documentWithoutRevision, PdfDocument documentWithRevision @@ -614,277 +724,82 @@ private bool CompareFormFieldWithFieldMDP(PdfDictionary previousField, PdfDictio return true; } - private IList CreateAllowedReferences(PdfDocument documentWithRevision - , PdfDocument documentWithoutRevision) { - // First indirect reference in the pair is an allowed reference to be present in new xref table, - // and the second indirect reference in the pair is the same entry in the previous document. - // If any reference is null, we expect this object to be newly generated or direct reference. - IList allowedReferences = new List(); - if (documentWithRevision.GetTrailer().Get(PdfName.Info) != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(documentWithRevision.GetTrailer().Get( - PdfName.Info).GetIndirectReference(), GetIndirectReferenceOrNull(() => documentWithoutRevision.GetTrailer - ().Get(PdfName.Info).GetIndirectReference()))); - } - if (documentWithRevision.GetCatalog().GetPdfObject() == null) { - return allowedReferences; - } - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(documentWithRevision.GetCatalog().GetPdfObject - ().GetIndirectReference(), GetIndirectReferenceOrNull(() => documentWithoutRevision.GetCatalog().GetPdfObject - ().GetIndirectReference()))); - if (documentWithRevision.GetCatalog().GetPdfObject().Get(PdfName.Metadata) != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(documentWithRevision.GetCatalog().GetPdfObject - ().Get(PdfName.Metadata).GetIndirectReference(), GetIndirectReferenceOrNull(() => documentWithoutRevision - .GetCatalog().GetPdfObject().Get(PdfName.Metadata).GetIndirectReference()))); - } - PdfDictionary currentDssDictionary = documentWithRevision.GetCatalog().GetPdfObject().GetAsDictionary(PdfName - .DSS); - if (currentDssDictionary != null) { - PdfDictionary previousDssDictionary = documentWithoutRevision.GetCatalog().GetPdfObject().GetAsDictionary( - PdfName.DSS); - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentDssDictionary.GetIndirectReference - (), GetIndirectReferenceOrNull(() => previousDssDictionary.GetIndirectReference()))); - allowedReferences.AddAll(CreateAllowedDssEntries(documentWithRevision, documentWithoutRevision)); - } - PdfDictionary currentAcroForm = documentWithRevision.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.AcroForm - ); - if (currentAcroForm != null) { - PdfDictionary previousAcroForm = documentWithoutRevision.GetCatalog().GetPdfObject().GetAsDictionary(PdfName - .AcroForm); - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentAcroForm.GetIndirectReference() - , GetIndirectReferenceOrNull(() => previousAcroForm.GetIndirectReference()))); - allowedReferences.AddAll(CreateAllowedAcroFormEntries(documentWithRevision, documentWithoutRevision)); - } - PdfDictionary currentPagesDictionary = documentWithRevision.GetCatalog().GetPdfObject().GetAsDictionary(PdfName - .Pages); - if (currentPagesDictionary != null) { - PdfDictionary previousPagesDictionary = documentWithoutRevision.GetCatalog().GetPdfObject().GetAsDictionary - (PdfName.Pages); - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentPagesDictionary.GetIndirectReference - (), GetIndirectReferenceOrNull(() => previousPagesDictionary.GetIndirectReference()))); - allowedReferences.AddAll(CreateAllowedPagesEntries(currentPagesDictionary, previousPagesDictionary)); - } - return allowedReferences; - } - - private bool CheckAllowedReferences(IList allowedReferences, PdfIndirectReference - indirectReference, PdfDocument documentWithoutRevision) { - foreach (DocumentRevisionsValidator.ReferencesPair allowedReference in allowedReferences) { - if (IsSameReference(allowedReference.GetCurrentReference(), indirectReference)) { - return documentWithoutRevision.GetPdfObject(indirectReference.GetObjNumber()) == null || allowedReferences - .Any((reference) => IsSameReference(reference.GetPreviousReference(), indirectReference)); - } - } - return false; - } - - // Compare catalogs nested methods section: - private bool CompareExtensions(PdfObject previousExtensions, PdfObject currentExtensions, ValidationReport - report) { - if (previousExtensions == null || ComparePdfObjects(previousExtensions, currentExtensions)) { - return true; - } - if (currentExtensions == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, EXTENSIONS_REMOVED, ReportItem.ReportItemStatus.INVALID - )); - return false; - } - if (!(previousExtensions is PdfDictionary) || !(currentExtensions is PdfDictionary)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, EXTENSIONS_TYPE, ReportItem.ReportItemStatus.INVALID)); - return false; - } - PdfDictionary previousExtensionsDictionary = (PdfDictionary)previousExtensions; - PdfDictionary currentExtensionsDictionary = (PdfDictionary)currentExtensions; - foreach (KeyValuePair previousExtension in previousExtensionsDictionary.EntrySet()) { - PdfDictionary currentExtension = currentExtensionsDictionary.GetAsDictionary(previousExtension.Key); - if (currentExtension == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(DEVELOPER_EXTENSION_REMOVED, previousExtension - .Key), ReportItem.ReportItemStatus.INVALID)); - return false; + private bool CompareAcroForms(PdfDictionary prevAcroForm, PdfDictionary currAcroForm, ValidationReport report + ) { + checkedAnnots = new HashSet(); + newlyAddedFields = new HashSet(); + if (prevAcroForm == null) { + if (currAcroForm == null) { + return true; } - else { - PdfDictionary currentExtensionCopy = new PdfDictionary(currentExtension); - currentExtensionCopy.Remove(PdfName.ExtensionLevel); - PdfDictionary previousExtensionCopy = new PdfDictionary((PdfDictionary)previousExtension.Value); - previousExtensionCopy.Remove(PdfName.ExtensionLevel); - // Apart from extension level dictionaries are expected to be equal. - if (!ComparePdfObjects(previousExtensionCopy, currentExtensionCopy)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(DEVELOPER_EXTENSION_REMOVED, previousExtension - .Key), ReportItem.ReportItemStatus.INVALID)); + PdfArray fields = currAcroForm.GetAsArray(PdfName.Fields); + foreach (PdfObject field in fields) { + PdfDictionary fieldDict = (PdfDictionary)field; + if (!IsAllowedSignatureField(fieldDict, report)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, NOT_ALLOWED_ACROFORM_CHANGES, ReportItem.ReportItemStatus + .INVALID)); return false; } - PdfNumber previousExtensionLevel = ((PdfDictionary)previousExtension.Value).GetAsNumber(PdfName.ExtensionLevel - ); - PdfNumber currentExtensionLevel = currentExtension.GetAsNumber(PdfName.ExtensionLevel); - if (previousExtensionLevel != null) { - if (currentExtensionLevel == null || previousExtensionLevel.IntValue() > currentExtensionLevel.IntValue()) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(EXTENSION_LEVEL_DECREASED, previousExtension - .Key), ReportItem.ReportItemStatus.INVALID)); - return false; - } - } } - } - return true; - } - - private bool ComparePermissions(PdfObject previousPerms, PdfObject currentPerms, ValidationReport report) { - if (previousPerms == null || ComparePdfObjects(previousPerms, currentPerms)) { return true; } - if (currentPerms == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PERMISSIONS_REMOVED, ReportItem.ReportItemStatus.INVALID - )); + if (currAcroForm == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, ACROFORM_REMOVED, ReportItem.ReportItemStatus.INVALID)); return false; } - if (!(previousPerms is PdfDictionary) || !(currentPerms is PdfDictionary)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PERMISSIONS_TYPE, ReportItem.ReportItemStatus.INVALID)); + PdfDictionary previousAcroFormCopy = CopyAcroformDictionary(prevAcroForm); + PdfDictionary currentAcroFormCopy = CopyAcroformDictionary(currAcroForm); + PdfArray prevFields = prevAcroForm.GetAsArray(PdfName.Fields); + PdfArray currFields = currAcroForm.GetAsArray(PdfName.Fields); + if (!ComparePdfObjects(previousAcroFormCopy, currentAcroFormCopy) || (prevFields.Size() > currFields.Size( + )) || !CompareFormFields(prevFields, currFields, report)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, NOT_ALLOWED_ACROFORM_CHANGES, ReportItem.ReportItemStatus + .INVALID)); return false; } - PdfDictionary previousPermsDictionary = (PdfDictionary)previousPerms; - PdfDictionary currentPermsDictionary = (PdfDictionary)currentPerms; - foreach (KeyValuePair previousPermission in previousPermsDictionary.EntrySet()) { - PdfDictionary currentPermission = currentPermsDictionary.GetAsDictionary(previousPermission.Key); - if (currentPermission == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(PERMISSION_REMOVED, previousPermission - .Key), ReportItem.ReportItemStatus.INVALID)); + return true; + } + + private bool CompareFormFields(PdfArray prevFields, PdfArray currFields, ValidationReport report) { + ICollection prevFieldsSet = PopulateFormFields(prevFields); + ICollection currFieldsSet = PopulateFormFields(currFields); + foreach (PdfDictionary previousField in prevFieldsSet) { + PdfDictionary currentField = RetrieveTheSameField(currFieldsSet, previousField); + if (currentField == null || !CompareFields(previousField, currentField, report)) { + PdfString fieldName = previousField.GetAsString(PdfName.T); + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(FIELD_REMOVED, fieldName == null + ? "" : fieldName.GetValue()), ReportItem.ReportItemStatus.INVALID)); return false; } - else { - // Perms dictionary is the signature dictionary. - if (!CompareSignatureDictionaries(previousPermission.Value, currentPermission, report)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(PERMISSION_REMOVED, previousPermission - .Key), ReportItem.ReportItemStatus.INVALID)); - return false; - } + if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(previousField)) { + checkedAnnots.Add(previousField); + } + if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(currentField)) { + checkedAnnots.Add(currentField); } + currFieldsSet.Remove(currentField); } - return true; - } - - private bool CompareDss(PdfObject previousDss, PdfObject currentDss, ValidationReport report) { - if (previousDss == null) { - return true; - } - if (currentDss == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, DSS_REMOVED, ReportItem.ReportItemStatus.INVALID)); - return false; - } - return true; - } - - private bool ComparePages(PdfDictionary prevPages, PdfDictionary currPages, ValidationReport report) { - if (prevPages == null ^ currPages == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGES_MODIFIED, ReportItem.ReportItemStatus.INVALID)); - return false; - } - if (prevPages == null) { - return true; - } - PdfDictionary previousPagesCopy = new PdfDictionary(prevPages); - previousPagesCopy.Remove(PdfName.Kids); - previousPagesCopy.Remove(PdfName.Parent); - PdfDictionary currentPagesCopy = new PdfDictionary(currPages); - currentPagesCopy.Remove(PdfName.Kids); - currentPagesCopy.Remove(PdfName.Parent); - if (!ComparePdfObjects(previousPagesCopy, currentPagesCopy) || !CompareIndirectReferencesObjNums(prevPages - .Get(PdfName.Parent), currPages.Get(PdfName.Parent), report, "Page tree node parent")) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGES_MODIFIED, ReportItem.ReportItemStatus.INVALID)); - return false; - } - PdfArray prevKids = prevPages.GetAsArray(PdfName.Kids); - PdfArray currKids = currPages.GetAsArray(PdfName.Kids); - if (prevKids.Size() != currKids.Size()) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGES_MODIFIED, ReportItem.ReportItemStatus.INVALID)); - return false; - } - for (int i = 0; i < currKids.Size(); ++i) { - PdfDictionary previousKid = prevKids.GetAsDictionary(i); - PdfDictionary currentKid = currKids.GetAsDictionary(i); - if (PdfName.Pages.Equals(previousKid.GetAsName(PdfName.Type))) { - // Compare page tree nodes. - if (!ComparePages(previousKid, currentKid, report)) { - return false; - } - } - else { - // Compare page objects (leaf node in the page tree). - PdfDictionary previousPageCopy = new PdfDictionary(previousKid); - previousPageCopy.Remove(PdfName.Annots); - previousPageCopy.Remove(PdfName.Parent); - PdfDictionary currentPageCopy = new PdfDictionary(currentKid); - currentPageCopy.Remove(PdfName.Annots); - currentPageCopy.Remove(PdfName.Parent); - if (!ComparePdfObjects(previousPageCopy, currentPageCopy) || !CompareIndirectReferencesObjNums(previousKid - .Get(PdfName.Parent), currentKid.Get(PdfName.Parent), report, "Page parent")) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGE_MODIFIED, ReportItem.ReportItemStatus.INVALID)); - return false; - } - PdfArray prevAnnots = GetAnnotsNotAllowedToBeModified(previousKid); - PdfArray currAnnots = GetAnnotsNotAllowedToBeModified(currentKid); - if (!ComparePdfObjects(prevAnnots, currAnnots)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGE_ANNOTATIONS_MODIFIED, ReportItem.ReportItemStatus. - INVALID)); - return false; - } + foreach (PdfDictionary field in currFieldsSet) { + if (!IsAllowedSignatureField(field, report)) { + return false; } } - return true; + return CompareWidgets(prevFields, currFields, report); } - private bool CompareAcroForms(PdfDictionary prevAcroForm, PdfDictionary currAcroForm, ValidationReport report + private PdfDictionary RetrieveTheSameField(ICollection currFields, PdfDictionary previousField ) { - if (prevAcroForm == null) { - if (currAcroForm == null) { - return true; - } - PdfArray fields = currAcroForm.GetAsArray(PdfName.Fields); - foreach (PdfObject field in fields) { - PdfDictionary fieldDict = (PdfDictionary)field; - if (!IsAllowedSignatureField(fieldDict, report)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, NOT_ALLOWED_ACROFORM_CHANGES, ReportItem.ReportItemStatus - .INVALID)); - return false; - } - } - return true; - } - if (currAcroForm == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, ACROFORM_REMOVED, ReportItem.ReportItemStatus.INVALID)); - return false; - } - PdfDictionary previousAcroFormCopy = CopyAcroformDictionary(prevAcroForm); - PdfDictionary currentAcroFormCopy = CopyAcroformDictionary(currAcroForm); - PdfArray prevFields = prevAcroForm.GetAsArray(PdfName.Fields); - PdfArray currFields = currAcroForm.GetAsArray(PdfName.Fields); - if (!ComparePdfObjects(previousAcroFormCopy, currentAcroFormCopy) || (prevFields.Size() > currFields.Size( - )) || !CompareFormFields(prevFields, currFields, report)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, NOT_ALLOWED_ACROFORM_CHANGES, ReportItem.ReportItemStatus - .INVALID)); - return false; - } - return true; - } - - private bool CompareFormFields(PdfArray prevFields, PdfArray currFields, ValidationReport report) { - IDictionary prevFieldsMap = PopulateFormFieldsMap(prevFields); - IDictionary currFieldsMap = PopulateFormFieldsMap(currFields); - foreach (KeyValuePair fieldEntry in prevFieldsMap) { - PdfDictionary previousField = fieldEntry.Value; - PdfDictionary currentField = currFieldsMap.Get(fieldEntry.Key); - if (currentField == null || !CompareFields(previousField, currentField, report)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(FIELD_REMOVED, fieldEntry.Key) - , ReportItem.ReportItemStatus.INVALID)); - return false; - } - currFieldsMap.JRemove(fieldEntry.Key); - } - foreach (KeyValuePair fieldEntry in currFieldsMap) { - if (!IsAllowedSignatureField(fieldEntry.Value, report)) { - return false; + foreach (PdfDictionary currentField in currFields) { + PdfDictionary prevFormDict = CopyFieldDictionary(previousField); + PdfDictionary currFormDict = CopyFieldDictionary(currentField); + if (ComparePdfObjects(prevFormDict, currFormDict) && CompareIndirectReferencesObjNums(prevFormDict.Get(PdfName + .Parent), currFormDict.Get(PdfName.Parent), new ValidationReport(), "Form field parent") && CompareIndirectReferencesObjNums + (prevFormDict.Get(PdfName.P), currFormDict.Get(PdfName.P), new ValidationReport(), "Page object with which field annotation is associated" + )) { + return currentField; } } - return CompareAnnotations(prevFields, currFields, report); + return null; } /// DocMDP level >= 2 allows setting values of the fields and accordingly update the widget appearances of them. @@ -906,14 +821,6 @@ private bool CompareFormFields(PdfArray prevFields, PdfArray currFields, Validat /// private bool CompareFields(PdfDictionary previousField, PdfDictionary currentField, ValidationReport report ) { - PdfDictionary prevFormDict = CopyFieldDictionary(previousField); - PdfDictionary currFormDict = CopyFieldDictionary(currentField); - if (!ComparePdfObjects(prevFormDict, currFormDict) || !CompareIndirectReferencesObjNums(prevFormDict.Get(PdfName - .Parent), currFormDict.Get(PdfName.Parent), report, "Form field parent") || !CompareIndirectReferencesObjNums - (prevFormDict.Get(PdfName.P), currFormDict.Get(PdfName.P), report, "Page object with which field annotation is associated" - )) { - return false; - } PdfObject prevValue = previousField.Get(PdfName.V); PdfObject currValue = currentField.Get(PdfName.V); if (prevValue == null && currValue == null && PdfName.Ch.Equals(currentField.GetAsName(PdfName.FT))) { @@ -923,8 +830,9 @@ private bool CompareFields(PdfDictionary previousField, PdfDictionary currentFie } if (PdfName.Sig.Equals(currentField.GetAsName(PdfName.FT))) { if (!CompareSignatureDictionaries(prevValue, currValue, report)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(SIGNATURE_MODIFIED, currentField - .GetAsString(PdfName.T).GetValue()), ReportItem.ReportItemStatus.INVALID)); + PdfString fieldName = currentField.GetAsString(PdfName.T); + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(SIGNATURE_MODIFIED, fieldName + == null ? "" : fieldName.GetValue()), ReportItem.ReportItemStatus.INVALID)); return false; } } @@ -938,29 +846,6 @@ private bool CompareFields(PdfDictionary previousField, PdfDictionary currentFie ); } - private bool CompareAnnotations(PdfArray prevFields, PdfArray currFields, ValidationReport report) { - IList prevAnnots = PopulateAnnotations(prevFields); - IList currAnnots = PopulateAnnotations(currFields); - if (prevAnnots.Count != currAnnots.Count) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, ANNOTATIONS_MODIFIED, ReportItem.ReportItemStatus.INVALID - )); - return false; - } - for (int i = 0; i < prevAnnots.Count; i++) { - PdfDictionary prevAnnot = new PdfDictionary(prevAnnots[i]); - RemoveAppearanceRelatedProperties(prevAnnot); - PdfDictionary currAnnot = new PdfDictionary(currAnnots[i]); - RemoveAppearanceRelatedProperties(currAnnot); - if (!ComparePdfObjects(prevAnnot, currAnnot) || !CompareIndirectReferencesObjNums(prevAnnots[i].Get(PdfName - .P), currAnnots[i].Get(PdfName.P), report, "Page object with which annotation is associated")) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, ANNOTATIONS_MODIFIED, ReportItem.ReportItemStatus.INVALID - )); - return false; - } - } - return true; - } - private bool CompareSignatureDictionaries(PdfObject prevSigDict, PdfObject curSigDict, ValidationReport report ) { if (prevSigDict == null) { @@ -1015,6 +900,119 @@ private bool CompareSignatureReferenceDictionaries(PdfArray previousReferences, return true; } + private bool CompareWidgets(PdfArray prevFields, PdfArray currFields, ValidationReport report) { + if (GetAccessPermissions() == AccessPermissions.ANNOTATION_MODIFICATION) { + return true; + } + IList prevAnnots = PopulateWidgetAnnotations(prevFields); + IList currAnnots = PopulateWidgetAnnotations(currFields); + if (prevAnnots.Count != currAnnots.Count) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, ANNOTATIONS_MODIFIED, ReportItem.ReportItemStatus.INVALID + )); + return false; + } + for (int i = 0; i < prevAnnots.Count; i++) { + PdfDictionary prevAnnot = new PdfDictionary(prevAnnots[i]); + RemoveAppearanceRelatedProperties(prevAnnot); + PdfDictionary currAnnot = new PdfDictionary(currAnnots[i]); + RemoveAppearanceRelatedProperties(currAnnot); + if (!ComparePdfObjects(prevAnnot, currAnnot) || !CompareIndirectReferencesObjNums(prevAnnots[i].Get(PdfName + .P), currAnnots[i].Get(PdfName.P), report, "Page object with which annotation is associated") || !CompareIndirectReferencesObjNums + (prevAnnots[i].Get(PdfName.Parent), currAnnots[i].Get(PdfName.Parent), report, "Annotation parent")) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, ANNOTATIONS_MODIFIED, ReportItem.ReportItemStatus.INVALID + )); + return false; + } + checkedAnnots.Add(prevAnnots[i]); + checkedAnnots.Add(currAnnots[i]); + } + return true; + } + + private bool ComparePages(PdfDictionary prevPages, PdfDictionary currPages, ValidationReport report) { + if (prevPages == null ^ currPages == null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGES_MODIFIED, ReportItem.ReportItemStatus.INVALID)); + return false; + } + if (prevPages == null) { + return true; + } + PdfDictionary previousPagesCopy = new PdfDictionary(prevPages); + previousPagesCopy.Remove(PdfName.Kids); + previousPagesCopy.Remove(PdfName.Parent); + PdfDictionary currentPagesCopy = new PdfDictionary(currPages); + currentPagesCopy.Remove(PdfName.Kids); + currentPagesCopy.Remove(PdfName.Parent); + if (!ComparePdfObjects(previousPagesCopy, currentPagesCopy) || !CompareIndirectReferencesObjNums(prevPages + .Get(PdfName.Parent), currPages.Get(PdfName.Parent), report, "Page tree node parent")) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGES_MODIFIED, ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfArray prevKids = prevPages.GetAsArray(PdfName.Kids); + PdfArray currKids = currPages.GetAsArray(PdfName.Kids); + if (prevKids.Size() != currKids.Size()) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGES_MODIFIED, ReportItem.ReportItemStatus.INVALID)); + return false; + } + for (int i = 0; i < currKids.Size(); ++i) { + PdfDictionary previousKid = prevKids.GetAsDictionary(i); + PdfDictionary currentKid = currKids.GetAsDictionary(i); + if (PdfName.Pages.Equals(previousKid.GetAsName(PdfName.Type))) { + // Compare page tree nodes. + if (!ComparePages(previousKid, currentKid, report)) { + return false; + } + } + else { + // Compare page objects (leaf node in the page tree). + PdfDictionary previousPageCopy = new PdfDictionary(previousKid); + previousPageCopy.Remove(PdfName.Annots); + previousPageCopy.Remove(PdfName.Parent); + PdfDictionary currentPageCopy = new PdfDictionary(currentKid); + currentPageCopy.Remove(PdfName.Annots); + currentPageCopy.Remove(PdfName.Parent); + if (!ComparePdfObjects(previousPageCopy, currentPageCopy) || !CompareIndirectReferencesObjNums(previousKid + .Get(PdfName.Parent), currentKid.Get(PdfName.Parent), report, "Page parent")) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGE_MODIFIED, ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfArray prevAnnots = GetAnnotsNotAllowedToBeModified(previousKid); + PdfArray currAnnots = GetAnnotsNotAllowedToBeModified(currentKid); + if (!ComparePageAnnotations(prevAnnots, currAnnots, report)) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, PAGE_ANNOTATIONS_MODIFIED, ReportItem.ReportItemStatus. + INVALID)); + return false; + } + } + } + return true; + } + + private bool ComparePageAnnotations(PdfArray prevAnnots, PdfArray currAnnots, ValidationReport report) { + if (prevAnnots == null && currAnnots == null) { + return true; + } + if (prevAnnots == null || currAnnots == null || prevAnnots.Size() != currAnnots.Size()) { + return false; + } + for (int i = 0; i < prevAnnots.Size(); i++) { + PdfDictionary prevAnnot = new PdfDictionary(prevAnnots.GetAsDictionary(i)); + prevAnnot.Remove(PdfName.P); + prevAnnot.Remove(PdfName.Parent); + PdfDictionary currAnnot = new PdfDictionary(currAnnots.GetAsDictionary(i)); + currAnnot.Remove(PdfName.P); + currAnnot.Remove(PdfName.Parent); + if (!ComparePdfObjects(prevAnnot, currAnnot) || !CompareIndirectReferencesObjNums(prevAnnots.GetAsDictionary + (i).Get(PdfName.P), currAnnots.GetAsDictionary(i).Get(PdfName.P), report, "Page object with which annotation is associated" + ) || !CompareIndirectReferencesObjNums(prevAnnots.GetAsDictionary(i).Get(PdfName.Parent), currAnnots.GetAsDictionary + (i).Get(PdfName.Parent), report, "Annotation parent")) { + return false; + } + } + return true; + } + + // Compare catalogs util methods section: private bool CompareIndirectReferencesObjNums(PdfObject prevObj, PdfObject currObj, ValidationReport report , String type) { if (prevObj == null ^ currObj == null) { @@ -1026,8 +1024,10 @@ private bool CompareIndirectReferencesObjNums(PdfObject prevObj, PdfObject currO PdfIndirectReference prevObjRef = prevObj.GetIndirectReference(); PdfIndirectReference currObjRef = currObj.GetIndirectReference(); if (prevObjRef == null || currObjRef == null) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(DIRECT_OBJECT, type), ReportItem.ReportItemStatus - .INVALID)); + if (report != null) { + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(DIRECT_OBJECT, type), ReportItem.ReportItemStatus + .INVALID)); + } return false; } return IsSameReference(prevObjRef, currObjRef); @@ -1046,28 +1046,36 @@ private bool IsAllowedSignatureField(PdfDictionary field, ValidationReport repor PdfDictionary value = field.GetAsDictionary(PdfName.V); if (!PdfName.Sig.Equals(field.GetAsName(PdfName.FT)) || value == null || (GetAccessPermissions() == AccessPermissions .NO_CHANGES_PERMITTED && !PdfName.DocTimeStamp.Equals(value.GetAsName(PdfName.Type)))) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(UNEXPECTED_FORM_FIELD, field.GetAsString - (PdfName.T).GetValue()), ReportItem.ReportItemStatus.INVALID)); + PdfString fieldName = field.GetAsString(PdfName.T); + report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(UNEXPECTED_FORM_FIELD, fieldName + == null ? "" : fieldName.GetValue()), ReportItem.ReportItemStatus.INVALID)); return false; } + if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(field)) { + checkedAnnots.Add(field); + } + else { + PdfArray kids = field.GetAsArray(PdfName.Kids); + checkedAnnots.AddAll(PopulateWidgetAnnotations(kids)); + } + newlyAddedFields.Add(field); return true; } - private IDictionary PopulateFormFieldsMap(PdfArray fieldsArray) { - IDictionary fields = new Dictionary(); + private ICollection PopulateFormFields(PdfArray fieldsArray) { + ICollection fields = new HashSet(); if (fieldsArray != null) { for (int i = 0; i < fieldsArray.Size(); ++i) { PdfDictionary fieldDict = (PdfDictionary)fieldsArray.Get(i); if (PdfFormField.IsFormField(fieldDict)) { - String fieldName = fieldDict.GetAsString(PdfName.T).GetValue(); - fields.Put(fieldName, fieldDict); + fields.Add(fieldDict); } } } return fields; } - private IList PopulateAnnotations(PdfArray fieldsArray) { + private IList PopulateWidgetAnnotations(PdfArray fieldsArray) { IList annotations = new List(); if (fieldsArray != null) { for (int i = 0; i < fieldsArray.Size(); ++i) { @@ -1082,15 +1090,14 @@ private IList PopulateAnnotations(PdfArray fieldsArray) { private PdfArray GetAnnotsNotAllowedToBeModified(PdfDictionary page) { PdfArray annots = page.GetAsArray(PdfName.Annots); - if (annots == null) { + if (annots == null || GetAccessPermissions() == AccessPermissions.ANNOTATION_MODIFICATION) { return null; } PdfArray annotsCopy = new PdfArray(annots); foreach (PdfObject annot in annots) { - PdfDictionary annotDict = (PdfDictionary)annot; - if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(annotDict)) { - // Ideally we should also distinguish between docMDP level 1 (DTS) or 2 allowed annotations - // (we check them only on the acroform level, but they could be added to the page) + // checkedAnnots contains all the fields' widget annotations from the Acroform which were already validated + // during the compareAcroForms call, so we shouldn't check them once again + if (checkedAnnots.Contains(annot)) { annotsCopy.Remove(annot); } } @@ -1130,280 +1137,27 @@ private PdfDictionary CopyFieldDictionary(PdfDictionary field) { private void RemoveAppearanceRelatedProperties(PdfDictionary annotDict) { annotDict.Remove(PdfName.P); - if (GetAccessPermissions() != AccessPermissions.NO_CHANGES_PERMITTED) { + annotDict.Remove(PdfName.Parent); + if (GetAccessPermissions() == AccessPermissions.FORM_FIELDS_MODIFICATION) { annotDict.Remove(PdfName.AP); annotDict.Remove(PdfName.AS); annotDict.Remove(PdfName.M); annotDict.Remove(PdfName.F); } - } - - // Allowed references creation nested methods section: - private IList CreateAllowedDssEntries(PdfDocument documentWithRevision - , PdfDocument documentWithoutRevision) { - IList allowedReferences = new List(); - PdfDictionary currentDssDictionary = documentWithRevision.GetCatalog().GetPdfObject().GetAsDictionary(PdfName - .DSS); - PdfDictionary previousDssDictionary = documentWithoutRevision.GetCatalog().GetPdfObject().GetAsDictionary( - PdfName.DSS); - PdfArray certs = currentDssDictionary.GetAsArray(PdfName.Certs); - if (certs != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(certs.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.Get(PdfName.Certs).GetIndirectReference()))); - for (int i = 0; i < certs.Size(); ++i) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(certs.Get(i).GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsArray(PdfName.Certs).Get(finalI).GetIndirectReference()))); - } - } - PdfArray ocsps = currentDssDictionary.GetAsArray(PdfName.OCSPs); - if (ocsps != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(ocsps.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.Get(PdfName.OCSPs).GetIndirectReference()))); - for (int i = 0; i < ocsps.Size(); ++i) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(ocsps.Get(i).GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsArray(PdfName.OCSPs).Get(finalI).GetIndirectReference()))); - } - } - PdfArray crls = currentDssDictionary.GetAsArray(PdfName.CRLs); - if (crls != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(crls.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.Get(PdfName.CRLs).GetIndirectReference()))); - for (int i = 0; i < crls.Size(); ++i) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(crls.Get(i).GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsArray(PdfName.CRLs).Get(finalI).GetIndirectReference()))); - } - } - PdfDictionary vris = currentDssDictionary.GetAsDictionary(PdfName.VRI); - if (vris != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vris.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.Get(PdfName.VRI).GetIndirectReference()))); - foreach (KeyValuePair vri in vris.EntrySet()) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vri.Value.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsDictionary(PdfName.VRI).Get(vri.Key).GetIndirectReference()))); - if (vri.Value is PdfDictionary) { - PdfDictionary vriDictionary = (PdfDictionary)vri.Value; - PdfArray vriCerts = vriDictionary.GetAsArray(PdfName.Cert); - if (vriCerts != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriCerts.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary(vri.Key).Get(PdfName.Cert).GetIndirectReference - ()))); - for (int i = 0; i < vriCerts.Size(); ++i) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriCerts.Get(i).GetIndirectReference() - , GetIndirectReferenceOrNull(() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary( - vri.Key).GetAsArray(PdfName.Cert).Get(finalI).GetIndirectReference()))); - } - } - PdfArray vriOcsps = vriDictionary.GetAsArray(PdfName.OCSP); - if (vriOcsps != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriOcsps.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary(vri.Key).Get(PdfName.OCSP).GetIndirectReference - ()))); - for (int i = 0; i < vriOcsps.Size(); ++i) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriOcsps.Get(i).GetIndirectReference() - , GetIndirectReferenceOrNull(() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary( - vri.Key).GetAsArray(PdfName.OCSP).Get(finalI).GetIndirectReference()))); - } - } - PdfArray vriCrls = vriDictionary.GetAsArray(PdfName.CRL); - if (vriCrls != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriCrls.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary(vri.Key).Get(PdfName.CRL).GetIndirectReference - ()))); - for (int i = 0; i < vriCrls.Size(); ++i) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriCrls.Get(i).GetIndirectReference(), - GetIndirectReferenceOrNull(() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary(vri - .Key).GetAsArray(PdfName.CRL).Get(finalI).GetIndirectReference()))); - } - } - if (vriDictionary.Get(new PdfName("TS")) != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(vriDictionary.Get(new PdfName("TS")).GetIndirectReference - (), GetIndirectReferenceOrNull(() => previousDssDictionary.GetAsDictionary(PdfName.VRI).GetAsDictionary - (vri.Key).Get(new PdfName("TS")).GetIndirectReference()))); - } - } - } - } - return allowedReferences; - } - - private ICollection CreateAllowedPagesEntries(PdfDictionary currentPagesDictionary - , PdfDictionary previousPagesDictionary) { - IList allowedReferences = new List(); - PdfArray currentKids = currentPagesDictionary.GetAsArray(PdfName.Kids); - if (currentKids != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentKids.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousPagesDictionary.Get(PdfName.Kids).GetIndirectReference()))); - for (int i = 0; i < currentKids.Size(); ++i) { - int finalI = i; - PdfDictionary currentPageNode = currentKids.GetAsDictionary(i); - PdfDictionary previousPageNode = null; - try { - previousPageNode = previousPagesDictionary.GetAsArray(PdfName.Kids).GetAsDictionary(i); - } - catch (NullReferenceException) { - } - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentKids.Get(i).GetIndirectReference - (), GetIndirectReferenceOrNull(() => previousPagesDictionary.GetAsArray(PdfName.Kids).Get(finalI).GetIndirectReference - ()))); - if (currentPageNode != null) { - if (PdfName.Pages.Equals(currentPageNode.GetAsName(PdfName.Type))) { - allowedReferences.AddAll(CreateAllowedPagesEntries(currentPageNode, previousPageNode)); - } - else { - PdfObject currentAnnots = currentPageNode.Get(PdfName.Annots); - if (currentAnnots != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentAnnots.GetIndirectReference(), - GetIndirectReferenceOrNull(() => previousPagesDictionary.GetAsArray(PdfName.Kids).GetAsDictionary(finalI - ).Get(PdfName.Annots).GetIndirectReference()))); - } - } - } - } - } - // We don't need to add annotations because all the allowed ones are already added during acroform processing. - return allowedReferences; - } - - private ICollection CreateAllowedAcroFormEntries(PdfDocument documentWithRevision - , PdfDocument documentWithoutRevision) { - IList allowedReferences = new List(); - PdfAcroForm prevAcroForm = PdfFormCreator.GetAcroForm(documentWithoutRevision, false); - PdfAcroForm currAcroForm = PdfFormCreator.GetAcroForm(documentWithRevision, false); - IDictionary prevFields = prevAcroForm == null ? new Dictionary - () : prevAcroForm.GetAllFormFields(); - foreach (KeyValuePair fieldEntry in currAcroForm.GetAllFormFields()) { - PdfFormField previousField = prevFields.Get(fieldEntry.Key); - PdfFormField currentField = fieldEntry.Value; - PdfObject value = currentField.GetValue(); - if (GetAccessPermissions() != AccessPermissions.NO_CHANGES_PERMITTED || (value is PdfDictionary && PdfName - .DocTimeStamp.Equals(((PdfDictionary)value).GetAsName(PdfName.Type)))) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentField.GetPdfObject().GetIndirectReference - (), GetIndirectReferenceOrNull(() => previousField.GetPdfObject().GetIndirectReference()))); - if (previousField == null) { - // For newly generated form field all references are allowed to be added. - AddAllNestedDictionaryEntries(allowedReferences, currentField.GetPdfObject(), null); + if (GetAccessPermissions() == AccessPermissions.ANNOTATION_MODIFICATION) { + foreach (PdfName key in new PdfDictionary(annotDict).KeySet()) { + if (!PdfFormField.GetFormFieldKeys().Contains(key)) { + annotDict.Remove(key); } - else { - if (!lockedFields.Contains(fieldEntry.Key)) { - // For already existing form field only several entries are allowed to be updated. - allowedReferences.AddAll(CreateAllowedExistingFormFieldEntries(currentField, previousField)); - } - } - } - } - PdfDictionary currentResources = currAcroForm.GetDefaultResources(); - if (currentResources != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentResources.GetIndirectReference( - ), GetIndirectReferenceOrNull(() => prevAcroForm.GetDefaultResources().GetIndirectReference()))); - AddAllNestedDictionaryEntries(allowedReferences, currentResources, prevAcroForm == null ? null : prevAcroForm - .GetDefaultResources()); - } - return allowedReferences; - } - - private ICollection CreateAllowedExistingFormFieldEntries(PdfFormField - currentField, PdfFormField previousField) { - IList allowedReferences = new List(); - PdfObject currentValue = currentField.GetValue(); - if (currentValue != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentValue.GetIndirectReference(), GetIndirectReferenceOrNull - (() => previousField.GetValue().GetIndirectReference()))); - } - IList currAnnots = currentField.GetChildFormAnnotations(); - if (!currAnnots.IsEmpty()) { - IList prevAnnots = previousField == null ? null : previousField.GetChildFormAnnotations - (); - for (int i = 0; i < currAnnots.Count; i++) { - int finalI = i; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currAnnots[i].GetPdfObject().GetIndirectReference - (), GetIndirectReferenceOrNull(() => prevAnnots[finalI].GetPdfObject().GetIndirectReference()))); - PdfObject currentAppearance = currAnnots[i].GetPdfObject().Get(PdfName.AP); - if (currentAppearance != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentAppearance.GetIndirectReference - (), GetIndirectReferenceOrNull(() => prevAnnots[finalI].GetPdfObject().Get(PdfName.AP).GetIndirectReference - ()))); - if (currentAppearance is PdfDictionary) { - PdfObject previousAppearance; - try { - previousAppearance = prevAnnots[finalI].GetPdfObject().Get(PdfName.AP); - } - catch (NullReferenceException) { - previousAppearance = null; - } - AddAllNestedDictionaryEntries(allowedReferences, (PdfDictionary)currentAppearance, previousAppearance); - } - } - PdfObject currentAppearanceState = currAnnots[i].GetPdfObject().Get(PdfName.AS); - if (currentAppearanceState != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentAppearanceState.GetIndirectReference - (), GetIndirectReferenceOrNull(() => prevAnnots[finalI].GetPdfObject().Get(PdfName.AS).GetIndirectReference - ()))); - } - PdfObject currentTimeStamp = currAnnots[i].GetPdfObject().Get(PdfName.M); - if (currentTimeStamp != null) { - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentTimeStamp.GetIndirectReference( - ), GetIndirectReferenceOrNull(() => prevAnnots[finalI].GetPdfObject().Get(PdfName.M).GetIndirectReference - ()))); - } - } - } - return allowedReferences; - } - - private void AddAllNestedDictionaryEntries(IList allowedReferences - , PdfDictionary currentDictionary, PdfObject previousDictionary) { - foreach (KeyValuePair entry in currentDictionary.EntrySet()) { - PdfObject currValue = entry.Value; - if (currValue.GetIndirectReference() != null && allowedReferences.Any((pair) => IsSameReference(pair.GetCurrentReference - (), currValue.GetIndirectReference()))) { - // Required to not end up in an infinite loop. - continue; - } - PdfObject prevValue = previousDictionary is PdfDictionary ? ((PdfDictionary)previousDictionary).Get(entry. - Key) : null; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currValue.GetIndirectReference(), GetIndirectReferenceOrNull - (() => prevValue.GetIndirectReference()))); - if (currValue is PdfDictionary) { - AddAllNestedDictionaryEntries(allowedReferences, (PdfDictionary)currValue, prevValue); - } - if (currValue is PdfArray) { - AddAllNestedArrayEntries(allowedReferences, (PdfArray)currValue, prevValue); - } - } - } - - private void AddAllNestedArrayEntries(IList allowedReferences, - PdfArray currentArray, PdfObject previousArray) { - for (int i = 0; i < currentArray.Size(); ++i) { - PdfObject currentArrayEntry = currentArray.Get(i); - if (currentArrayEntry.GetIndirectReference() != null && allowedReferences.Any((pair) => IsSameReference(pair - .GetCurrentReference(), currentArrayEntry.GetIndirectReference()))) { - // Required to not end up in an infinite loop. - continue; - } - PdfObject previousArrayEntry = previousArray is PdfArray ? ((PdfArray)previousArray).Get(i) : null; - allowedReferences.Add(new DocumentRevisionsValidator.ReferencesPair(currentArrayEntry.GetIndirectReference - (), GetIndirectReferenceOrNull(() => previousArrayEntry.GetIndirectReference()))); - if (currentArrayEntry is PdfDictionary) { - AddAllNestedDictionaryEntries(allowedReferences, currentArray.GetAsDictionary(i), previousArrayEntry); - } - if (currentArrayEntry is PdfArray) { - AddAllNestedArrayEntries(allowedReferences, currentArray.GetAsArray(i), previousArrayEntry); } } } + // + // // Compare PDF objects util section: + // + // private static bool ComparePdfObjects(PdfObject pdfObject1, PdfObject pdfObject2) { return ComparePdfObjects(pdfObject1, pdfObject2, new HashSet()); } @@ -1512,31 +1266,258 @@ private static bool IsMaxGenerationObject(PdfIndirectReference indirectReference return indirectReference.GetObjNumber() == 0 && indirectReference.GetGenNumber() == 65535; } - private static PdfIndirectReference GetIndirectReferenceOrNull(Func referenceGetter) { - try { - return referenceGetter(); + // + // + // Allowed references section: + // + // + private ICollection CreateAllowedReferences(PdfDocument document) { + // Each indirect reference in the set is an allowed reference to be present in the new xref table + // or the same entry in the previous document. + // If any reference is null, we expect this object to be newly generated or direct reference. + ICollection allowedReferences = new HashSet(); + if (document.GetTrailer().Get(PdfName.Info) != null) { + allowedReferences.Add(document.GetTrailer().Get(PdfName.Info).GetIndirectReference()); } - catch (Exception) { - return null; + if (document.GetCatalog().GetPdfObject() == null) { + return allowedReferences; + } + allowedReferences.Add(document.GetCatalog().GetPdfObject().GetIndirectReference()); + if (document.GetCatalog().GetPdfObject().Get(PdfName.Metadata) != null) { + allowedReferences.Add(document.GetCatalog().GetPdfObject().Get(PdfName.Metadata).GetIndirectReference()); + } + PdfDictionary dssDictionary = document.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.DSS); + if (dssDictionary != null) { + allowedReferences.Add(dssDictionary.GetIndirectReference()); + allowedReferences.AddAll(CreateAllowedDssEntries(document)); + } + PdfDictionary acroForm = document.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.AcroForm); + if (acroForm != null) { + allowedReferences.Add(acroForm.GetIndirectReference()); + PdfArray fields = acroForm.GetAsArray(PdfName.Fields); + CreateAllowedFormFieldEntries(fields, allowedReferences); + PdfDictionary resources = acroForm.GetAsDictionary(PdfName.DR); + if (resources != null) { + allowedReferences.Add(resources.GetIndirectReference()); + AddAllNestedDictionaryEntries(allowedReferences, resources); + } + } + PdfDictionary pagesDictionary = document.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.Pages); + if (pagesDictionary != null) { + allowedReferences.Add(pagesDictionary.GetIndirectReference()); + allowedReferences.AddAll(CreateAllowedPagesEntries(pagesDictionary)); + } + return allowedReferences; + } + + private bool CheckAllowedReferences(ICollection currentAllowedReferences, ICollection + previousAllowedReferences, PdfIndirectReference indirectReference, PdfDocument + documentWithoutRevision) { + foreach (PdfIndirectReference currentAllowedReference in currentAllowedReferences) { + if (IsSameReference(currentAllowedReference, indirectReference)) { + return documentWithoutRevision.GetPdfObject(indirectReference.GetObjNumber()) == null || previousAllowedReferences + .Any((reference) => IsSameReference(reference, indirectReference)); + } + } + return false; + } + + // Allowed references creation nested methods section: + private ICollection CreateAllowedDssEntries(PdfDocument document) { + ICollection allowedReferences = new HashSet(); + PdfDictionary dssDictionary = document.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.DSS); + PdfArray certs = dssDictionary.GetAsArray(PdfName.Certs); + if (certs != null) { + allowedReferences.Add(certs.GetIndirectReference()); + for (int i = 0; i < certs.Size(); ++i) { + allowedReferences.Add(certs.Get(i).GetIndirectReference()); + } + } + PdfArray ocsps = dssDictionary.GetAsArray(PdfName.OCSPs); + if (ocsps != null) { + allowedReferences.Add(ocsps.GetIndirectReference()); + for (int i = 0; i < ocsps.Size(); ++i) { + allowedReferences.Add(ocsps.Get(i).GetIndirectReference()); + } + } + PdfArray crls = dssDictionary.GetAsArray(PdfName.CRLs); + if (crls != null) { + allowedReferences.Add(crls.GetIndirectReference()); + for (int i = 0; i < crls.Size(); ++i) { + allowedReferences.Add(crls.Get(i).GetIndirectReference()); + } + } + PdfDictionary vris = dssDictionary.GetAsDictionary(PdfName.VRI); + if (vris != null) { + allowedReferences.Add(vris.GetIndirectReference()); + foreach (KeyValuePair vri in vris.EntrySet()) { + allowedReferences.Add(vri.Value.GetIndirectReference()); + if (vri.Value is PdfDictionary) { + PdfDictionary vriDictionary = (PdfDictionary)vri.Value; + PdfArray vriCerts = vriDictionary.GetAsArray(PdfName.Cert); + if (vriCerts != null) { + allowedReferences.Add(vriCerts.GetIndirectReference()); + for (int i = 0; i < vriCerts.Size(); ++i) { + allowedReferences.Add(vriCerts.Get(i).GetIndirectReference()); + } + } + PdfArray vriOcsps = vriDictionary.GetAsArray(PdfName.OCSP); + if (vriOcsps != null) { + allowedReferences.Add(vriOcsps.GetIndirectReference()); + for (int i = 0; i < vriOcsps.Size(); ++i) { + allowedReferences.Add(vriOcsps.Get(i).GetIndirectReference()); + } + } + PdfArray vriCrls = vriDictionary.GetAsArray(PdfName.CRL); + if (vriCrls != null) { + allowedReferences.Add(vriCrls.GetIndirectReference()); + for (int i = 0; i < vriCrls.Size(); ++i) { + allowedReferences.Add(vriCrls.Get(i).GetIndirectReference()); + } + } + if (vriDictionary.Get(new PdfName("TS")) != null) { + allowedReferences.Add(vriDictionary.Get(new PdfName("TS")).GetIndirectReference()); + } + } + } } + return allowedReferences; } - private class ReferencesPair { - private readonly PdfIndirectReference currentReference; + private ICollection CreateAllowedPagesEntries(PdfDictionary pagesDictionary) { + ICollection allowedReferences = new HashSet(); + PdfArray kids = pagesDictionary.GetAsArray(PdfName.Kids); + if (kids != null) { + allowedReferences.Add(kids.GetIndirectReference()); + for (int i = 0; i < kids.Size(); ++i) { + PdfDictionary pageNode = kids.GetAsDictionary(i); + allowedReferences.Add(kids.Get(i).GetIndirectReference()); + if (pageNode != null) { + if (PdfName.Pages.Equals(pageNode.GetAsName(PdfName.Type))) { + allowedReferences.AddAll(CreateAllowedPagesEntries(pageNode)); + } + else { + PdfObject annots = pageNode.Get(PdfName.Annots); + if (annots != null) { + allowedReferences.Add(annots.GetIndirectReference()); + if (GetAccessPermissions() == AccessPermissions.ANNOTATION_MODIFICATION) { + AddAllNestedArrayEntries(allowedReferences, (PdfArray)annots); + } + } + } + } + } + } + return allowedReferences; + } - private readonly PdfIndirectReference previousReference; + private void CreateAllowedFormFieldEntries(PdfArray fields, ICollection allowedReferences + ) { + if (fields == null) { + return; + } + foreach (PdfObject field in fields) { + PdfDictionary fieldDict = (PdfDictionary)field; + if (PdfFormField.IsFormField(fieldDict)) { + PdfObject value = fieldDict.Get(PdfName.V); + if (GetAccessPermissions() != AccessPermissions.NO_CHANGES_PERMITTED || (value is PdfDictionary && PdfName + .DocTimeStamp.Equals(((PdfDictionary)value).GetAsName(PdfName.Type)))) { + allowedReferences.Add(fieldDict.GetIndirectReference()); + PdfString fieldName = PdfFormCreator.CreateFormField(fieldDict).GetFieldName(); + if (newlyAddedFields.Contains(fieldDict)) { + // For newly generated form field all references are allowed to be added. + AddAllNestedDictionaryEntries(allowedReferences, fieldDict); + } + else { + if (fieldName == null || !lockedFields.Contains(fieldName.GetValue())) { + // For already existing form field only several entries are allowed to be updated. + if (value != null) { + allowedReferences.Add(value.GetIndirectReference()); + } + if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(fieldDict)) { + AddWidgetAnnotation(allowedReferences, fieldDict); + } + else { + PdfArray kids = fieldDict.GetAsArray(PdfName.Kids); + CreateAllowedFormFieldEntries(kids, allowedReferences); + } + } + } + } + } + else { + // Add annotation. + AddWidgetAnnotation(allowedReferences, fieldDict); + } + } + } - internal ReferencesPair(PdfIndirectReference currentReference, PdfIndirectReference previousReference) { - this.currentReference = currentReference; - this.previousReference = previousReference; + private void AddWidgetAnnotation(ICollection allowedReferences, PdfDictionary annotDict + ) { + allowedReferences.Add(annotDict.GetIndirectReference()); + if (GetAccessPermissions() == AccessPermissions.ANNOTATION_MODIFICATION) { + PdfDictionary pureAnnotDict = new PdfDictionary(annotDict); + foreach (PdfName key in annotDict.KeySet()) { + if (PdfFormField.GetFormFieldKeys().Contains(key)) { + pureAnnotDict.Remove(key); + } + } + AddAllNestedDictionaryEntries(allowedReferences, pureAnnotDict); } + else { + PdfObject appearance = annotDict.Get(PdfName.AP); + if (appearance != null) { + allowedReferences.Add(appearance.GetIndirectReference()); + if (appearance is PdfDictionary) { + AddAllNestedDictionaryEntries(allowedReferences, (PdfDictionary)appearance); + } + } + PdfObject appearanceState = annotDict.Get(PdfName.AS); + if (appearanceState != null) { + allowedReferences.Add(appearanceState.GetIndirectReference()); + } + PdfObject timeStamp = annotDict.Get(PdfName.M); + if (timeStamp != null) { + allowedReferences.Add(timeStamp.GetIndirectReference()); + } + } + } - public virtual PdfIndirectReference GetCurrentReference() { - return currentReference; + private void AddAllNestedDictionaryEntries(ICollection allowedReferences, PdfDictionary + dictionary) { + foreach (KeyValuePair entry in dictionary.EntrySet()) { + PdfObject value = entry.Value; + if (value.GetIndirectReference() != null && allowedReferences.Any((reference) => IsSameReference(reference + , value.GetIndirectReference()))) { + // Required to not end up in an infinite loop. + continue; + } + allowedReferences.Add(value.GetIndirectReference()); + if (value is PdfDictionary) { + AddAllNestedDictionaryEntries(allowedReferences, (PdfDictionary)value); + } + if (value is PdfArray) { + AddAllNestedArrayEntries(allowedReferences, (PdfArray)value); + } } + } - public virtual PdfIndirectReference GetPreviousReference() { - return previousReference; + private void AddAllNestedArrayEntries(ICollection allowedReferences, PdfArray pdfArray + ) { + for (int i = 0; i < pdfArray.Size(); ++i) { + PdfObject arrayEntry = pdfArray.Get(i); + if (arrayEntry.GetIndirectReference() != null && allowedReferences.Any((reference) => IsSameReference(reference + , arrayEntry.GetIndirectReference()))) { + // Required to not end up in an infinite loop. + continue; + } + allowedReferences.Add(arrayEntry.GetIndirectReference()); + if (arrayEntry is PdfDictionary) { + AddAllNestedDictionaryEntries(allowedReferences, pdfArray.GetAsDictionary(i)); + } + if (arrayEntry is PdfArray) { + AddAllNestedArrayEntries(allowedReferences, pdfArray.GetAsArray(i)); + } } } } diff --git a/port-hash b/port-hash index b2e72dfad6..d53be0f01d 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -75916d2ca4991a01c47cc8304ab61c0e1143b385 +03a2c75fa888159e6b9a503e0bb7a64378c0155f