From 5a1a35eff3dd270bbd41de6ff02280571bc8c623 Mon Sep 17 00:00:00 2001 From: Eugene Bochilo Date: Wed, 22 May 2024 23:08:32 +0000 Subject: [PATCH 1/4] Support FieldMDP DEVSIX-8350 Autoported commit. Original commit hash: [3e7c187e7] --- ...cumentRevisionsValidatorIntegrationTest.cs | 171 ++++++++++- .../v1/DocumentRevisionsValidatorTest.cs | 41 +-- .../fieldLockChildModificationAllowed.pdf | Bin 0 -> 21950 bytes .../fieldLockChildModificationNotAllowed.pdf | Bin 0 -> 21970 bytes .../fieldLockKidsRemovedAndAdded.pdf | Bin 0 -> 22950 bytes .../fieldLockRootModificationAllowed.pdf | Bin 0 -> 21953 bytes .../fieldLockRootModificationNotAllowed.pdf | Bin 0 -> 21933 bytes .../fieldLockSequentialExcludeValues.pdf | Bin 0 -> 42664 bytes .../fieldLockSequentialIncludeValues.pdf | Bin 0 -> 42674 bytes .../lockedFieldRemoveAddKidsEntry.pdf | Bin 0 -> 22469 bytes .../lockedSignatureFieldModified.pdf | Bin 0 -> 56669 bytes ...pageAndParentIndirectReferenceModified.pdf | Bin 0 -> 23323 bytes .../removedLockedField.pdf | Bin 0 -> 21118 bytes itext/itext.forms/itext/forms/PdfAcroForm.cs | 2 +- .../itext/signatures/AccessPermissions.cs | 21 ++ .../itext/signatures/PdfPadesSigner.cs | 37 +++ .../itext.sign/itext/signatures/PdfSigner.cs | 20 ++ .../v1/DocumentRevisionsValidator.cs | 277 +++++++++++++++--- port-hash | 2 +- 19 files changed, 489 insertions(+), 82 deletions(-) create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationAllowed.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationNotAllowed.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockKidsRemovedAndAdded.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationAllowed.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationNotAllowed.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialExcludeValues.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialIncludeValues.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedFieldRemoveAddKidsEntry.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedSignatureFieldModified.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/pageAndParentIndirectReferenceModified.pdf create mode 100644 itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removedLockedField.pdf create mode 100644 itext/itext.sign/itext/signatures/AccessPermissions.cs 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 f4b66f7ae..d15d9506f 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 @@ -24,6 +24,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Bouncycastleconnector; using iText.Commons.Bouncycastle; using iText.Kernel.Pdf; +using iText.Signatures; using iText.Signatures.Validation.V1.Report; using iText.Test; @@ -48,8 +49,8 @@ public virtual void NoSignaturesDocTest() { (0).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK).WithMessage (DocumentRevisionsValidator.DOCUMENT_WITHOUT_SIGNATURES).WithStatus(ReportItem.ReportItemStatus.INFO)) ); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.ANNOTATION_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( + )); } } @@ -60,8 +61,8 @@ public virtual void MultipleRevisionsDocumentWithoutPermissionsTest() { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); ValidationReport report = validator.ValidateAllDocumentRevisions(); AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.ANNOTATION_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( + )); } } @@ -72,8 +73,8 @@ public virtual void MultipleRevisionsDocumentWithPermissionsTest() { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); ValidationReport report = validator.ValidateAllDocumentRevisions(); AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.FORM_FIELDS_MODIFICATION, validator.GetAccessPermissions + ()); } } @@ -88,8 +89,8 @@ public virtual void TwoCertificationSignaturesTest() { (DocumentRevisionsValidator.PERMISSION_REMOVED, (i) => PdfName.DocMDP).WithStatus(ReportItem.ReportItemStatus .INVALID)).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK).WithMessage(DocumentRevisionsValidator .TOO_MANY_CERTIFICATION_SIGNATURES).WithStatus(ReportItem.ReportItemStatus.INDETERMINATE))); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.FORM_FIELDS_MODIFICATION, validator.GetAccessPermissions + ()); } } @@ -102,8 +103,8 @@ public virtual void SignatureNotFoundTest() { (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.DOC_MDP_CHECK).WithMessage (DocumentRevisionsValidator.SIGNATURE_REVISION_NOT_FOUND).WithStatus(ReportItem.ReportItemStatus.INVALID ))); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.ANNOTATION_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.ANNOTATION_MODIFICATION, validator.GetAccessPermissions( + )); } } @@ -118,8 +119,7 @@ public virtual void DifferentFieldLockLevelsTest() { (DocumentRevisionsValidator.UNEXPECTED_FORM_FIELD, (i) => "Signature4").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(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.NO_CHANGES_PERMITTED, validator.GetAccessPermissions()); } } @@ -133,8 +133,8 @@ public virtual void FieldLockLevelIncreaseTest() { ).HasNumberOfFailures(1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator .DOC_MDP_CHECK).WithMessage(DocumentRevisionsValidator.ACCESS_PERMISSIONS_ADDED, (i) => "Signature3"). WithStatus(ReportItem.ReportItemStatus.INDETERMINATE))); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.FORM_FIELDS_MODIFICATION, validator.GetAccessPermissions + ()); } } @@ -145,8 +145,147 @@ public virtual void CertificationSignatureAfterApprovalTest() { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); ValidationReport report = validator.ValidateAllDocumentRevisions(); AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); - NUnit.Framework.Assert.AreEqual(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION, validator - .GetAccessPermissions()); + NUnit.Framework.Assert.AreEqual(AccessPermissions.FORM_FIELDS_MODIFICATION, validator.GetAccessPermissions + ()); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockChildModificationAllowedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockChildModificationAllowed.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockChildModificationNotAllowedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockChildModificationNotAllowed.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_MODIFIED, (i) => "rootField.childTextField").WithStatus(ReportItem.ReportItemStatus + .INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockRootModificationAllowedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockRootModificationAllowed.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.VALID)); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockRootModificationNotAllowedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockRootModificationNotAllowed.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_MODIFIED, (i) => "childTextField").WithStatus(ReportItem.ReportItemStatus + .INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockSequentialExcludeValuesTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockSequentialExcludeValues.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_MODIFIED, (i) => "rootField.childTextField").WithStatus(ReportItem.ReportItemStatus + .INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockSequentialIncludeValuesTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockSequentialIncludeValues.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (2).HasNumberOfLogs(2).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_MODIFIED, (i) => "rootField.childTextField").WithStatus(ReportItem.ReportItemStatus + .INVALID)).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage(DocumentRevisionsValidator + .LOCKED_FIELD_MODIFIED, (i) => "childTextField").WithStatus(ReportItem.ReportItemStatus.INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void FieldLockKidsRemovedAndAddedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fieldLockKidsRemovedAndAdded.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (2).HasNumberOfLogs(2).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_KIDS_REMOVED, (i) => "rootField").WithStatus(ReportItem.ReportItemStatus + .INVALID)).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage(DocumentRevisionsValidator + .LOCKED_FIELD_KIDS_ADDED, (i) => "rootField").WithStatus(ReportItem.ReportItemStatus.INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void PageAndParentIndirectReferenceModifiedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "pageAndParentIndirectReferenceModified.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_MODIFIED, (i) => "rootField.childTextField2").WithStatus(ReportItem.ReportItemStatus + .INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void LockedSignatureFieldModifiedTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "lockedSignatureFieldModified.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_MODIFIED, (i) => "Signature2").WithStatus(ReportItem.ReportItemStatus + .INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void LockedFieldRemoveAddKidsEntryTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "lockedFieldRemoveAddKidsEntry.pdf" + ))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (2).HasNumberOfLogs(2).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_KIDS_REMOVED, (i) => "rootField").WithStatus(ReportItem.ReportItemStatus + .INVALID)).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage(DocumentRevisionsValidator + .LOCKED_FIELD_KIDS_ADDED, (i) => "rootField").WithStatus(ReportItem.ReportItemStatus.INVALID))); + } + } + + [NUnit.Framework.Test] + public virtual void RemovedLockedFieldTest() { + using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removedLockedField.pdf"))) { + DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); + ValidationReport report = validator.ValidateAllDocumentRevisions(); + AssertValidationReport.AssertThat(report, (a) => a.HasStatus(ValidationReport.ValidationResult.INVALID).HasNumberOfFailures + (1).HasNumberOfLogs(1).HasLogItem((l) => l.WithCheckName(DocumentRevisionsValidator.FIELD_MDP_CHECK).WithMessage + (DocumentRevisionsValidator.LOCKED_FIELD_REMOVED, (i) => "textField").WithStatus(ReportItem.ReportItemStatus + .INVALID))); } } } 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 cdc249139..ba9b04b06 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 @@ -25,6 +25,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Bouncycastleconnector; using iText.Commons.Bouncycastle; using iText.Kernel.Pdf; +using iText.Signatures; using iText.Signatures.Validation.V1.Report; using iText.Test; @@ -45,7 +46,7 @@ public virtual void MultipleRevisionsDocumentLevel1Test() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "multipleRevisionsDocument.pdf" ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -68,7 +69,7 @@ public virtual void MultipleRevisionsDocumentLevel1Test() { public virtual void HugeDocumentTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "hugeDocument.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -83,7 +84,7 @@ public virtual void ExtensionsModificationsTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "extensionsModifications.pdf") )) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -122,7 +123,7 @@ public virtual void CompletelyInvalidDocumentTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "completelyInvalidDocument.pdf" ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -140,7 +141,7 @@ public virtual void MakeFontDirectAndIndirectTest() { ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); validator.ValidateRevision(documentRevisions[0], documentRevisions[1], validationReport); @@ -167,7 +168,7 @@ public virtual void MakeFontDirectAndIndirectTest() { public virtual void RandomEntryAddedTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "randomEntryAdded.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -185,7 +186,7 @@ public virtual void RandomEntryWithoutUsageTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "randomEntryWithoutUsage.pdf") )) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -202,7 +203,7 @@ public virtual void RandomEntryWithoutUsageTest() { public virtual void ChangeExistingFontTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "changeExistingFont.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -219,7 +220,7 @@ public virtual void ChangeExistingFontAndAddAsDssTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "changeExistingFontAndAddAsDss.pdf" ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -236,7 +237,7 @@ public virtual void ChangeExistingFontAndAddAsDssTest() { public virtual void FillInFieldAtLevel1Test() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "fillInField.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED); + validator.SetAccessPermissions(AccessPermissions.NO_CHANGES_PERMITTED); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -255,7 +256,7 @@ public virtual void MultipleRevisionsDocumentLevel2Test() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "multipleRevisionsDocument2.pdf" ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -280,7 +281,7 @@ public virtual void MultipleRevisionsDocumentLevel2Test() { public virtual void RemovePermissionsTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removePermissions.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -298,7 +299,7 @@ public virtual void RemovePermissionsTest() { public virtual void RemoveDSSTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removeDSS.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -316,7 +317,7 @@ public virtual void RemoveDSSTest() { public virtual void RemoveAcroformTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removeAcroform.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -334,7 +335,7 @@ public virtual void RemoveAcroformTest() { public virtual void RemoveFieldTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "removeField.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -352,7 +353,7 @@ public virtual void RemoveFieldTest() { public virtual void RenameFieldTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "renameField.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -371,7 +372,7 @@ public virtual void RenameFieldTest() { public virtual void AddTextFieldTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "addTextField.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -392,7 +393,7 @@ public virtual void AddUnsignedSignatureFieldTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "addUnsignedSignatureField.pdf" ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -413,7 +414,7 @@ public virtual void BrokenSignatureFieldDictionaryTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "brokenSignatureFieldDictionary.pdf" ))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); @@ -434,7 +435,7 @@ public virtual void BrokenSignatureFieldDictionaryTest() { public virtual void ModifyPageAnnotsTest() { using (PdfDocument document = new PdfDocument(new PdfReader(SOURCE_FOLDER + "modifyPageAnnots.pdf"))) { DocumentRevisionsValidator validator = new DocumentRevisionsValidator(document); - validator.SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION); + validator.SetAccessPermissions(AccessPermissions.FORM_FIELDS_MODIFICATION); PdfRevisionsReader revisionsReader = new PdfRevisionsReader(document.GetReader()); IList documentRevisions = revisionsReader.GetAllRevisions(); ValidationReport validationReport = new ValidationReport(); diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationAllowed.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationAllowed.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d0a42fb93e03c9ec38170b8a4b62bae636e46103 GIT binary patch literal 21950 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 Ot{3sZR_oUg?|%VEt-#3u literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationNotAllowed.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationNotAllowed.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ab1cffc59af4ae1f1b920afbf5edbd9238124042 GIT binary patch literal 21970 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 SbnZmAzvbvhO%*>y_x}RMWac3N literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationAllowed.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationAllowed.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3633ad2aee780c645d6561f7e1ed87777d7a9553 GIT binary patch literal 21953 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 AZ2$lO literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialExcludeValues.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialExcludeValues.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3698fb1f66a9d7dd3335ec1eddada3514a262a8e GIT binary patch literal 42664 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 S-OJBcEPcqn_Fir9^Zx@9Un6}0 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialIncludeValues.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialIncludeValues.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f150cff3d757907a37efdfa295de255639a09d6a GIT binary patch literal 42674 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedFieldRemoveAddKidsEntry.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedFieldRemoveAddKidsEntry.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8ee272a5b17f02c50b930fc37ea87be3d9c37b8b GIT binary patch literal 22469 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedSignatureFieldModified.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedSignatureFieldModified.pdf new file mode 100644 index 0000000000000000000000000000000000000000..55251b3e751a93116ee96e15a24d9ac98cf817cb GIT binary patch literal 56669 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/pageAndParentIndirectReferenceModified.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/pageAndParentIndirectReferenceModified.pdf new file mode 100644 index 0000000000000000000000000000000000000000..836750d6e7cef76b9b360dfa5c1edc9b20cbfde6 GIT binary patch literal 23323 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 literal 0 HcmV?d00001 diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removedLockedField.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removedLockedField.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6e58e500d07be656930ba424cb656c3ac28dd6c3 GIT binary patch literal 21118 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 C+t0HA literal 0 HcmV?d00001 diff --git a/itext/itext.forms/itext/forms/PdfAcroForm.cs b/itext/itext.forms/itext/forms/PdfAcroForm.cs index 5b844a16a..f854280e8 100644 --- a/itext/itext.forms/itext/forms/PdfAcroForm.cs +++ b/itext/itext.forms/itext/forms/PdfAcroForm.cs @@ -373,7 +373,7 @@ public virtual IDictionary GetRootFormFields() { /// objects /// public virtual IDictionary GetAllFormFields() { - if (fields.Count == 0) { + if (fields.IsEmpty()) { fields = PopulateFormFieldsMap(); } IDictionary allFields = new LinkedDictionary(fields); diff --git a/itext/itext.sign/itext/signatures/AccessPermissions.cs b/itext/itext.sign/itext/signatures/AccessPermissions.cs new file mode 100644 index 000000000..6425e5bbc --- /dev/null +++ b/itext/itext.sign/itext/signatures/AccessPermissions.cs @@ -0,0 +1,21 @@ +namespace iText.Signatures { + /// Access permissions value to be set to certification signature as a part of DocMDP configuration. + public enum AccessPermissions { + /// Unspecified access permissions value which makes signature "approval" rather than "certification". + /// + UNSPECIFIED, + /// Access permissions level 1 which indicates that no changes are permitted except for DSS and DTS creation. + /// + NO_CHANGES_PERMITTED, + /// + /// Access permissions level 2 which indicates that permitted changes, with addition to level 1, are: + /// filling in forms, instantiating page templates, and signing. + /// + FORM_FIELDS_MODIFICATION, + /// + /// Access permissions level 3 which indicates that permitted changes, with addition to level 2, are: + /// annotation creation, deletion and modification. + /// + ANNOTATION_MODIFICATION + } +} diff --git a/itext/itext.sign/itext/signatures/PdfPadesSigner.cs b/itext/itext.sign/itext/signatures/PdfPadesSigner.cs index 01d5198b1..f06a103b0 100644 --- a/itext/itext.sign/itext/signatures/PdfPadesSigner.cs +++ b/itext/itext.sign/itext/signatures/PdfPadesSigner.cs @@ -28,6 +28,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Commons.Bouncycastle.Cert; using iText.Commons.Bouncycastle.Crypto; using iText.Commons.Utils; +using iText.Forms; using iText.Kernel.Exceptions; using iText.Kernel.Pdf; using iText.Signatures.Exceptions; @@ -57,6 +58,10 @@ public class PdfPadesSigner { private String temporaryDirectoryPath = null; + private AccessPermissions accessPermissions = AccessPermissions.UNSPECIFIED; + + private PdfSigFieldLock fieldLock = null; + private IExternalDigest externalDigest = new BouncyCastleDigest(); private StampingProperties stampingProperties = new StampingProperties().UseAppendMode(); @@ -373,6 +378,36 @@ public virtual iText.Signatures.PdfPadesSigner SetTemporaryDirectoryPath(String return this; } + /// Set certification level which specifies DocMDP level which is expected to be set. + /// + /// + /// + /// certification level + /// + /// + /// same instance of + /// + /// + public virtual iText.Signatures.PdfPadesSigner SetCertificationLevel(AccessPermissions accessPermissions) { + this.accessPermissions = accessPermissions; + return this; + } + + /// Set FieldMDP rules to be applied for this signature. + /// + /// + /// + /// field lock dictionary. + /// + /// + /// same instance of + /// + /// + public virtual iText.Signatures.PdfPadesSigner SetSignatureFieldLock(PdfSigFieldLock fieldLock) { + this.fieldLock = fieldLock; + return this; + } + /// Set the name to be used for timestamp signature creation. /// /// Set the name to be used for timestamp signature creation. @@ -641,6 +676,8 @@ private void PerformSignDetached(SignerProperties signerProperties, bool isFinal , IX509Certificate[] chain, ITSAClient tsaClient) { IX509Certificate[] fullChain = issuingCertificateRetriever.RetrieveMissingCertificates(chain); PdfSigner signer = CreatePdfSigner(signerProperties, isFinal); + signer.SetCertificationLevel(accessPermissions); + signer.SetFieldLockDict(fieldLock); try { signer.SignDetached(externalDigest, externalSignature, fullChain, null, null, tsaClient, estimatedSize, PdfSigner.CryptoStandard .CADES); diff --git a/itext/itext.sign/itext/signatures/PdfSigner.cs b/itext/itext.sign/itext/signatures/PdfSigner.cs index 724d7b3dc..0ad314a79 100644 --- a/itext/itext.sign/itext/signatures/PdfSigner.cs +++ b/itext/itext.sign/itext/signatures/PdfSigner.cs @@ -327,6 +327,11 @@ public virtual int GetCertificationLevel() { } /// Sets the document's certification level. + /// + /// Sets the document's certification level. + /// This method overrides the value set by + /// . + /// /// /// a new certification level for a document. /// Possible values are: @@ -348,6 +353,21 @@ public virtual void SetCertificationLevel(int certificationLevel) { this.certificationLevel = certificationLevel; } + /// Sets the document's certification level. + /// + /// Sets the document's certification level. + /// This method overrides the value set by + /// . + /// + /// + /// + /// + /// enum which specifies which certification level shall be used + /// + public virtual void SetCertificationLevel(AccessPermissions accessPermissions) { + this.certificationLevel = (int)(accessPermissions); + } + /// Gets the field name. /// the field name public virtual String GetFieldName() { diff --git a/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs b/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs index 52f0a5971..36e8a1904 100644 --- a/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs +++ b/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs @@ -38,6 +38,8 @@ namespace iText.Signatures.Validation.V1 { internal class DocumentRevisionsValidator { internal const String DOC_MDP_CHECK = "DocMDP check."; + internal const String FIELD_MDP_CHECK = "FieldMDP check."; + internal const String ACROFORM_REMOVED = "AcroForm dictionary was removed from catalog."; internal const String ANNOTATIONS_MODIFIED = "Field annotations were removed, added or unexpectedly modified."; @@ -100,13 +102,27 @@ internal class DocumentRevisionsValidator { 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 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 DocumentRevisionsValidator.AccessPermissions accessPermissions = DocumentRevisionsValidator.AccessPermissions - .ANNOTATION_MODIFICATION; + private AccessPermissions accessPermissions = AccessPermissions.ANNOTATION_MODIFICATION; + + private AccessPermissions requestedAccessPermissions = AccessPermissions.UNSPECIFIED; - private DocumentRevisionsValidator.AccessPermissions requestedAccessPermissions = DocumentRevisionsValidator.AccessPermissions - .UNSPECIFIED; + private readonly ICollection lockedFields = new HashSet(); private readonly PdfDocument document; @@ -136,11 +152,11 @@ public virtual iText.Signatures.Validation.V1.DocumentRevisionsValidator SetEven /// Set access permissions to be used during docMDP validation. /// /// Set access permissions to be used during docMDP validation. - /// If value is provided, related signature fields will be ignored during the validation. + /// If value is provided, access permission related signature parameters will be ignored during the validation. /// /// /// - /// + /// /// docMDP validation level /// /// @@ -148,7 +164,7 @@ public virtual iText.Signatures.Validation.V1.DocumentRevisionsValidator SetEven /// /// instance /// - public virtual iText.Signatures.Validation.V1.DocumentRevisionsValidator SetAccessPermissions(DocumentRevisionsValidator.AccessPermissions + public virtual iText.Signatures.Validation.V1.DocumentRevisionsValidator SetAccessPermissions(AccessPermissions accessPermissions) { this.requestedAccessPermissions = accessPermissions; return this; @@ -170,7 +186,7 @@ public virtual ValidationReport ValidateAllDocumentRevisions() { } catch (System.IO.IOException) { report.AddReportItem(new ReportItem(DOC_MDP_CHECK, REVISIONS_RETRIEVAL_FAILED, ReportItem.ReportItemStatus - .INVALID)); + .INDETERMINATE)); return report; } SignatureUtil signatureUtil = new SignatureUtil(document); @@ -198,6 +214,8 @@ public virtual ValidationReport ValidateAllDocumentRevisions() { } UpdateApprovalSignatureAccessPermissions(signatureUtil.GetSignatureFormFieldDictionary(signatures[0]), report ); + UpdateApprovalSignatureFieldLock(documentRevisions[i], signatureUtil.GetSignatureFormFieldDictionary(signatures + [0]), report); signatures.JRemoveAt(0); if (signatures.IsEmpty()) { currentSignature = null; @@ -217,20 +235,22 @@ public virtual ValidationReport ValidateAllDocumentRevisions() { return report; } - internal virtual ValidationReport ValidateRevision(DocumentRevision previousRevision, DocumentRevision currentRevision + internal virtual void ValidateRevision(DocumentRevision previousRevision, DocumentRevision currentRevision , ValidationReport validationReport) { try { using (Stream previousInputStream = CreateInputStreamFromRevision(document, previousRevision)) { - using (PdfReader previousReader = new PdfReader(previousInputStream)) { + using (PdfReader previousReader = new PdfReader(previousInputStream).SetStrictnessLevel(PdfReader.StrictnessLevel + .CONSERVATIVE)) { using (PdfDocument documentWithoutRevision = new PdfDocument(previousReader, new DocumentProperties().SetEventCountingMetaInfo (metaInfo))) { using (Stream currentInputStream = CreateInputStreamFromRevision(document, currentRevision)) { - using (PdfReader currentReader = new PdfReader(currentInputStream)) { + using (PdfReader currentReader = new PdfReader(currentInputStream).SetStrictnessLevel(PdfReader.StrictnessLevel + .CONSERVATIVE)) { using (PdfDocument documentWithRevision = new PdfDocument(currentReader, new DocumentProperties().SetEventCountingMetaInfo (metaInfo))) { ICollection indirectReferences = currentRevision.GetModifiedObjects(); if (!CompareCatalogs(documentWithoutRevision, documentWithRevision, validationReport)) { - return validationReport; + return; } IList allowedReferences = CreateAllowedReferences(documentWithRevision , documentWithoutRevision); @@ -267,15 +287,14 @@ internal virtual ValidationReport ValidateRevision(DocumentRevision previousRevi } } } - catch (System.IO.IOException) { + catch (System.IO.IOException exception) { + validationReport.AddReportItem(new ReportItem(DOC_MDP_CHECK, REVISIONS_READING_EXCEPTION, exception, ReportItem.ReportItemStatus + .INDETERMINATE)); } - // error - return validationReport; } - internal virtual DocumentRevisionsValidator.AccessPermissions GetAccessPermissions() { - return requestedAccessPermissions == DocumentRevisionsValidator.AccessPermissions.UNSPECIFIED ? accessPermissions - : requestedAccessPermissions; + internal virtual AccessPermissions GetAccessPermissions() { + return requestedAccessPermissions == AccessPermissions.UNSPECIFIED ? accessPermissions : requestedAccessPermissions; } private static Stream CreateInputStreamFromRevision(PdfDocument originalDocument, DocumentRevision revision @@ -293,20 +312,20 @@ private void UpdateApprovalSignatureAccessPermissions(PdfDictionary signatureFie return; } PdfNumber p = fieldLock.GetAsNumber(PdfName.P); - DocumentRevisionsValidator.AccessPermissions newAccessPermissions; + AccessPermissions newAccessPermissions; switch (p.IntValue()) { case 1: { - newAccessPermissions = DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED; + newAccessPermissions = AccessPermissions.NO_CHANGES_PERMITTED; break; } case 2: { - newAccessPermissions = DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION; + newAccessPermissions = AccessPermissions.FORM_FIELDS_MODIFICATION; break; } case 3: { - newAccessPermissions = DocumentRevisionsValidator.AccessPermissions.ANNOTATION_MODIFICATION; + newAccessPermissions = AccessPermissions.ANNOTATION_MODIFICATION; break; } @@ -324,6 +343,68 @@ private void UpdateApprovalSignatureAccessPermissions(PdfDictionary signatureFie } } + private void UpdateApprovalSignatureFieldLock(DocumentRevision revision, PdfDictionary signatureField, ValidationReport + report) { + PdfDictionary fieldLock = signatureField.GetAsDictionary(PdfName.Lock); + if (fieldLock == null || fieldLock.GetAsName(PdfName.Action) == null) { + return; + } + PdfName action = fieldLock.GetAsName(PdfName.Action); + if (PdfName.Include.Equals(action)) { + PdfArray fields = fieldLock.GetAsArray(PdfName.Fields); + if (fields != null) { + foreach (PdfObject fieldName in fields) { + if (fieldName is PdfString) { + lockedFields.Add(((PdfString)fieldName).ToUnicodeString()); + } + } + } + } + else { + if (PdfName.Exclude.Equals(action)) { + PdfArray fields = fieldLock.GetAsArray(PdfName.Fields); + IList excludedFields = JavaCollectionsUtil.EmptyList(); + if (fields != null) { + excludedFields = fields.SubList(0, fields.Size()).Select((field) => field is PdfString ? ((PdfString)field + ).ToUnicodeString() : "").ToList(); + } + LockAllFormFields(revision, excludedFields, report); + } + else { + if (!PdfName.All.Equals(action)) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(UNRECOGNIZED_ACTION, action. + GetValue()), ReportItem.ReportItemStatus.INVALID)); + } + LockAllFormFields(revision, JavaCollectionsUtil.EmptyList(), report); + } + } + } + + private void LockAllFormFields(DocumentRevision revision, IList excludedFields, ValidationReport report + ) { + try { + using (Stream inputStream = CreateInputStreamFromRevision(document, revision)) { + using (PdfReader reader = new PdfReader(inputStream)) { + using (PdfDocument documentWithRevision = new PdfDocument(reader, new DocumentProperties().SetEventCountingMetaInfo + (metaInfo))) { + PdfAcroForm acroForm = PdfFormCreator.GetAcroForm(documentWithRevision, false); + if (acroForm != null) { + foreach (String fieldName in acroForm.GetAllFormFields().Keys) { + if (!excludedFields.Contains(fieldName)) { + lockedFields.Add(fieldName); + } + } + } + } + } + } + } + catch (System.IO.IOException exception) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, REVISIONS_READING_EXCEPTION, exception, ReportItem.ReportItemStatus + .INDETERMINATE)); + } + } + private void UpdateCertificationSignatureAccessPermissions(PdfSignature signature, ValidationReport report ) { PdfArray references = signature.GetPdfObject().GetAsArray(PdfName.Reference); @@ -333,30 +414,30 @@ private void UpdateCertificationSignatureAccessPermissions(PdfSignature signatur if (PdfName.DocMDP.Equals(transformMethod)) { PdfDictionary transformParameters = referenceDict.GetAsDictionary(PdfName.TransformParams); if (transformParameters == null || transformParameters.GetAsNumber(PdfName.P) == null) { - accessPermissions = DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION; + accessPermissions = AccessPermissions.FORM_FIELDS_MODIFICATION; return; } PdfNumber p = transformParameters.GetAsNumber(PdfName.P); switch (p.IntValue()) { case 1: { - accessPermissions = DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED; + accessPermissions = AccessPermissions.NO_CHANGES_PERMITTED; break; } case 2: { - accessPermissions = DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION; + accessPermissions = AccessPermissions.FORM_FIELDS_MODIFICATION; break; } case 3: { - accessPermissions = DocumentRevisionsValidator.AccessPermissions.ANNOTATION_MODIFICATION; + accessPermissions = AccessPermissions.ANNOTATION_MODIFICATION; break; } default: { report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(UNKNOWN_ACCESS_PERMISSIONS, signature .GetName()), ReportItem.ReportItemStatus.INDETERMINATE)); - accessPermissions = DocumentRevisionsValidator.AccessPermissions.FORM_FIELDS_MODIFICATION; + accessPermissions = AccessPermissions.FORM_FIELDS_MODIFICATION; break; } } @@ -416,8 +497,121 @@ private bool CompareCatalogs(PdfDocument documentWithoutRevision, PdfDocument do 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 - ) && CompareAcroForms(previousCatalog.GetAsDictionary(PdfName.AcroForm), currentCatalog.GetAsDictionary - (PdfName.AcroForm), report); + ) && CompareAcroFormsWithFieldMDP(documentWithoutRevision, documentWithRevision, report) && CompareAcroForms + (previousCatalog.GetAsDictionary(PdfName.AcroForm), currentCatalog.GetAsDictionary(PdfName.AcroForm), + report); + } + + private bool CompareAcroFormsWithFieldMDP(PdfDocument documentWithoutRevision, PdfDocument documentWithRevision + , ValidationReport report) { + PdfAcroForm currentAcroForm = PdfFormCreator.GetAcroForm(documentWithRevision, false); + PdfAcroForm previousAcroForm = PdfFormCreator.GetAcroForm(documentWithoutRevision, false); + if (currentAcroForm == null || previousAcroForm == null) { + // This is not a part of FieldMDP validation. + return true; + } + if (accessPermissions == AccessPermissions.NO_CHANGES_PERMITTED) { + // In this case FieldMDP makes no sense, because related changes are forbidden anyway. + return true; + } + foreach (KeyValuePair previousField in previousAcroForm.GetAllFormFields()) { + if (lockedFields.Contains(previousField.Key)) { + // For locked form fields nothing can change, + // however annotations can contain page link which should be excluded from direct comparison. + PdfFormField currentFormField = currentAcroForm.GetField(previousField.Key); + if (currentFormField == null) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_REMOVED, previousField + .Key), ReportItem.ReportItemStatus.INVALID)); + return false; + } + if (!CompareFormFieldWithFieldMDP(previousField.Value.GetPdfObject(), currentFormField.GetPdfObject(), previousField + .Key, report)) { + return false; + } + } + } + return true; + } + + private bool CompareFormFieldWithFieldMDP(PdfDictionary previousField, PdfDictionary currentField, String + fieldName, ValidationReport report) { + PdfDictionary previousFieldCopy = new PdfDictionary(previousField); + previousFieldCopy.Remove(PdfName.Kids); + previousFieldCopy.Remove(PdfName.P); + previousFieldCopy.Remove(PdfName.Parent); + previousFieldCopy.Remove(PdfName.V); + PdfDictionary currentFieldCopy = new PdfDictionary(currentField); + currentFieldCopy.Remove(PdfName.Kids); + currentFieldCopy.Remove(PdfName.P); + currentFieldCopy.Remove(PdfName.Parent); + currentFieldCopy.Remove(PdfName.V); + if (!ComparePdfObjects(previousFieldCopy, currentFieldCopy)) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_MODIFIED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfObject prevValue = previousField.Get(PdfName.V); + PdfObject currValue = currentField.Get(PdfName.V); + if (PdfName.Sig.Equals(currentField.GetAsName(PdfName.FT))) { + if (!CompareSignatureDictionaries(prevValue, currValue, report)) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_MODIFIED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + } + else { + if (!ComparePdfObjects(prevValue, currValue)) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_MODIFIED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + } + if (!CompareIndirectReferencesObjNums(previousField.Get(PdfName.P), currentField.Get(PdfName.P), report, "Page object with which field annotation is associated" + ) || !CompareIndirectReferencesObjNums(previousField.Get(PdfName.Parent), currentField.Get(PdfName.Parent + ), report, "Form field parent")) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_MODIFIED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + PdfArray previousKids = previousField.GetAsArray(PdfName.Kids); + PdfArray currentKids = currentField.GetAsArray(PdfName.Kids); + if (previousKids == null && currentKids != null) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_KIDS_ADDED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + if (previousKids != null && currentKids == null) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_KIDS_REMOVED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + if (previousKids == currentKids) { + return true; + } + if (previousKids.Size() < currentKids.Size()) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_KIDS_ADDED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + if (previousKids.Size() > currentKids.Size()) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_KIDS_REMOVED, fieldName + ), ReportItem.ReportItemStatus.INVALID)); + return false; + } + for (int i = 0; i < previousKids.Size(); ++i) { + PdfDictionary previousKid = previousKids.GetAsDictionary(i); + PdfDictionary currentKid = currentKids.GetAsDictionary(i); + if (previousKid == null || currentKid == null) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(FIELD_NOT_DICTIONARY, fieldName + ), ReportItem.ReportItemStatus.INDETERMINATE)); + continue; + } + if (PdfFormAnnotationUtil.IsPureWidget(previousKid) && !CompareFormFieldWithFieldMDP(previousKid, currentKid + , fieldName, report)) { + return false; + } + } + return true; } private IList CreateAllowedReferences(PdfDocument documentWithRevision @@ -735,8 +929,8 @@ private bool CompareFields(PdfDictionary previousField, PdfDictionary currentFie } } else { - if (GetAccessPermissions() == DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED && !ComparePdfObjects - (prevValue, currValue)) { + if (GetAccessPermissions() == AccessPermissions.NO_CHANGES_PERMITTED && !ComparePdfObjects(prevValue, currValue + )) { return false; } } @@ -850,7 +1044,7 @@ private bool CompareIndirectReferencesObjNums(PdfObject prevObj, PdfObject currO /// true if newly added field is allowed to be added, false otherwise. private bool IsAllowedSignatureField(PdfDictionary field, ValidationReport report) { PdfDictionary value = field.GetAsDictionary(PdfName.V); - if (!PdfName.Sig.Equals(field.GetAsName(PdfName.FT)) || value == null || (GetAccessPermissions() == DocumentRevisionsValidator.AccessPermissions + 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)); @@ -936,7 +1130,7 @@ private PdfDictionary CopyFieldDictionary(PdfDictionary field) { private void RemoveAppearanceRelatedProperties(PdfDictionary annotDict) { annotDict.Remove(PdfName.P); - if (GetAccessPermissions() != DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED) { + if (GetAccessPermissions() != AccessPermissions.NO_CHANGES_PERMITTED) { annotDict.Remove(PdfName.AP); annotDict.Remove(PdfName.AS); annotDict.Remove(PdfName.M); @@ -1090,8 +1284,8 @@ private void RemoveAppearanceRelatedProperties(PdfDictionary annotDict) { PdfFormField previousField = prevFields.Get(fieldEntry.Key); PdfFormField currentField = fieldEntry.Value; PdfObject value = currentField.GetValue(); - if (GetAccessPermissions() != DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED || (value - is PdfDictionary && PdfName.DocTimeStamp.Equals(((PdfDictionary)value).GetAsName(PdfName.Type)))) { + 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) { @@ -1099,8 +1293,10 @@ private void RemoveAppearanceRelatedProperties(PdfDictionary annotDict) { AddAllNestedDictionaryEntries(allowedReferences, currentField.GetPdfObject(), null); } else { - // For already existing form field only several entries are allowed to be updated. - allowedReferences.AddAll(CreateAllowedExistingFormFieldEntries(currentField, previousField)); + if (!lockedFields.Contains(fieldEntry.Key)) { + // For already existing form field only several entries are allowed to be updated. + allowedReferences.AddAll(CreateAllowedExistingFormFieldEntries(currentField, previousField)); + } } } } @@ -1325,13 +1521,6 @@ private static PdfIndirectReference GetIndirectReferenceOrNull(Func Date: Wed, 22 May 2024 23:11:19 +0000 Subject: [PATCH 2/4] Add missing copyright headers Autoported commit. Original commit hash: [393503353] --- .../itext/signatures/AccessPermissions.cs | 22 +++++++++++++++++++ port-hash | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/itext/itext.sign/itext/signatures/AccessPermissions.cs b/itext/itext.sign/itext/signatures/AccessPermissions.cs index 6425e5bbc..8d69f61b9 100644 --- a/itext/itext.sign/itext/signatures/AccessPermissions.cs +++ b/itext/itext.sign/itext/signatures/AccessPermissions.cs @@ -1,3 +1,25 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ namespace iText.Signatures { /// Access permissions value to be set to certification signature as a part of DocMDP configuration. public enum AccessPermissions { diff --git a/port-hash b/port-hash index acfd6a2d3..0dc777194 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -3e7c187e78067eeee09878a3ec2cb8eb7d74e2ef +39350335380cdac65faa272806156560209869e1 From 0a42acdb04fd3763ed634373292ce27d396e653c Mon Sep 17 00:00:00 2001 From: Dmitry Chubrick Date: Thu, 23 May 2024 13:46:13 +0000 Subject: [PATCH 3/4] Support GridValue as values for grid-template-columns\row and grid-auto-columns\row DEVSIX-8324 Autoported commit. Original commit hash: [75916d2ca] --- .../itext/layout/element/GridContainerTest.cs | 139 +++++++-------- .../itext/layout/properties/GridValueTest.cs | 58 +++++++ .../layout/properties/SizingValueTest.cs | 57 +++++++ .../css/util/CssDimensionParsingUtilsTest.cs | 11 ++ .../itext/layout/properties/GridValue.cs | 160 ++++++++++++++++++ .../itext/layout/properties/SizingValue.cs | 159 +++++++++++++++++ .../layout/renderer/GridContainerRenderer.cs | 45 ++--- .../itext/layout/renderer/GridSizer.cs | 32 ++-- .../styledxmlparser/css/CommonCssConstants.cs | 3 + .../css/util/CssDimensionParsingUtils.cs | 17 ++ port-hash | 2 +- 11 files changed, 571 insertions(+), 112 deletions(-) create mode 100644 itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs create mode 100644 itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs create mode 100644 itext/itext.layout/itext/layout/properties/GridValue.cs create mode 100644 itext/itext.layout/itext/layout/properties/SizingValue.cs diff --git a/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs index 124c7f3ff..e7d82010c 100644 --- a/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs +++ b/itext.tests/itext.layout.tests/itext/layout/element/GridContainerTest.cs @@ -49,10 +49,10 @@ public static void BeforeClass() { public virtual void BasicThreeColumnsTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 150.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 150.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 150.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f))); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -73,7 +73,8 @@ public virtual void BasicAutoColumnsTest() { SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); - grid.SetProperty(Property.GRID_AUTO_COLUMNS, new UnitValue(UnitValue.POINT, 150.0f)); + grid.SetProperty(Property.GRID_AUTO_COLUMNS, GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 150.0f + ))); for (int i = 0; i < 5; ++i) { grid.Add(new Paragraph("Test" + i).SetBorder(border)); } @@ -90,7 +91,8 @@ public virtual void BasicAutoRowsTest() { SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); - grid.SetProperty(Property.GRID_AUTO_ROWS, new UnitValue(UnitValue.POINT, 100.0f)); + grid.SetProperty(Property.GRID_AUTO_ROWS, GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f) + )); grid.Add(new Paragraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, " + "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, " + "quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute " + "irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim " + @@ -106,10 +108,10 @@ public virtual void BasicAutoRowsTest() { public virtual void BasicThreeColumnsWithCustomColumnIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomColumnIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomColumnIndexesTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -134,11 +136,11 @@ public virtual void BasicThreeColumnsWithCustomColumnIndexesTest() { public virtual void ThreeColumnsWithAdjacentWideCellsTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithAdjacentWideCellsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithAdjacentWideCellsTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); GridContainer grid = new GridContainer(); @@ -170,10 +172,10 @@ public virtual void ThreeColumnsWithAdjacentWideCellsTest() { public virtual void BasicThreeColumnsWithCustomRowIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomRowIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomRowIndexesTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -198,10 +200,10 @@ public virtual void BasicThreeColumnsWithCustomRowIndexesTest() { public virtual void BasicThreeColumnsWithCustomColumnAndRowIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithCustomColumnAndRowIndexesTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -227,10 +229,10 @@ public virtual void BasicThreeColumnsWithCustomColumnAndRowIndexesTest() { public virtual void BasicThreeColumnsWithReversedIndexesTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithReversedIndexesTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithReversedIndexesTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -264,10 +266,10 @@ public virtual void BasicThreeColumnsWithReversedIndexesTest() { public virtual void BasicThreeColumnsWithoutColumnEndTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithoutColumnEndTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithoutColumnEndTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -299,10 +301,10 @@ public virtual void BasicThreeColumnsWithoutColumnEndTest() { public virtual void FixedColumnRowGoesFirstTest() { String filename = DESTINATION_FOLDER + "fixedColumnRowGoesFirstTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_fixedColumnRowGoesFirstTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -344,10 +346,10 @@ public virtual void FixedColumnRowGoesFirstTest() { [NUnit.Framework.Test] public virtual void OverlapWithExistingColumnTest() { String filename = DESTINATION_FOLDER + "overlapWithExistingColumnTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -374,15 +376,15 @@ public virtual void OverlapWithExistingColumnTest() { } } - //TODO DEVSIX-8324 [NUnit.Framework.Test] + [NUnit.Framework.Ignore("TODO DEVSIX-8324")] public virtual void BasicThreeColumnsWithPtAndPercentTest() { String filename = DESTINATION_FOLDER + "basicThreeColumnsWithPtAndPercentTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_basicThreeColumnsWithPtAndPercentTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.PERCENT, 15.0f)); - templateColumns.Add(new UnitValue(UnitValue.PERCENT, 50.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.PERCENT, 15.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.PERCENT, 50.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -400,10 +402,10 @@ public virtual void BasicThreeColumnsWithPtAndPercentTest() { public virtual void ThirdColumnNotLayoutedTest() { String filename = DESTINATION_FOLDER + "thirdColumnNotLayoutedTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_thirdColumnNotLayoutedTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 200.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 200.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 200.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 200.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 200.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 200.0f))); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); @@ -421,10 +423,10 @@ public virtual void ThirdColumnNotLayoutedTest() { public virtual void ThreeColumnsWithSquareAndVerticalCellsTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithSquareAndVerticalCellsTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithSquareAndVerticalCellsTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -455,10 +457,10 @@ public virtual void ThreeColumnsWithSquareAndVerticalCellsTest() { public virtual void ThreeColumnsWithSquareCellAndCellWithExplicitHeightTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithSquareCellAndCellWithExplicitHeightTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -485,10 +487,10 @@ public virtual void ThreeColumnsWithSquareCellAndCellWithExplicitHeightTest() { public virtual void ThreeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest() { String filename = DESTINATION_FOLDER + "threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_threeColumnsWithVerticalCellWithSeveralNeighboursToTheLeftTest.pdf"; - IList templateColumns = new List(); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); - templateColumns.Add(new UnitValue(UnitValue.POINT, 100.0f)); + IList templateColumns = new List(); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); + templateColumns.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 100.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); SolidBorder border = new SolidBorder(ColorConstants.BLUE, 1); @@ -534,14 +536,15 @@ public virtual void BigCellMinContentTest() { public virtual void ColumnRowGapTest() { String filename = DESTINATION_FOLDER + "columnRowGapTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_columnRowGapTest.pdf"; - IList template = new List(); - template.Add(new UnitValue(UnitValue.POINT, 50.0f)); - template.Add(new UnitValue(UnitValue.POINT, 50.0f)); + IList template = new List(); + template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); + template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, template); grid.SetProperty(Property.GRID_TEMPLATE_ROWS, template); - grid.SetProperty(Property.GRID_AUTO_ROWS, new UnitValue(UnitValue.POINT, 70.0f)); + grid.SetProperty(Property.GRID_AUTO_ROWS, GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 70.0f)) + ); grid.SetProperty(Property.COLUMN_GAP, 20.0f); grid.SetProperty(Property.ROW_GAP, 20.0f); grid.Add(new Paragraph("One").SetBackgroundColor(ColorConstants.CYAN)); @@ -561,10 +564,10 @@ public virtual void ColumnRowGapTest() { public virtual void FewBigCellsWithGapTest() { String filename = DESTINATION_FOLDER + "fewBigCellsWithGapTest.pdf"; String cmpName = SOURCE_FOLDER + "cmp_fewBigCellsWithGapTest.pdf"; - IList template = new List(); - template.Add(new UnitValue(UnitValue.POINT, 50.0f)); - template.Add(new UnitValue(UnitValue.POINT, 50.0f)); - template.Add(new UnitValue(UnitValue.POINT, 50.0f)); + IList template = new List(); + template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); + template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); + template.Add(GridValue.CreateUnitValue(new UnitValue(UnitValue.POINT, 50.0f))); using (Document document = new Document(new PdfDocument(new PdfWriter(filename)))) { GridContainer grid = new GridContainer(); grid.SetProperty(Property.GRID_TEMPLATE_COLUMNS, template); diff --git a/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs b/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs new file mode 100644 index 000000000..dadd65f32 --- /dev/null +++ b/itext.tests/itext.layout.tests/itext/layout/properties/GridValueTest.cs @@ -0,0 +1,58 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +using iText.Test; + +namespace iText.Layout.Properties { + [NUnit.Framework.Category("UnitTest")] + public class GridValueTest : ExtendedITextTest { + [NUnit.Framework.Test] + public virtual void SizingValueTest() { + GridValue value = GridValue.CreateSizeValue(SizingValue.CreateUnitValue(UnitValue.CreatePointValue(1.3f))); + NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); + NUnit.Framework.Assert.AreEqual(1.3f, (float)value.GetAbsoluteValue(), 0.00001); + value = GridValue.CreateSizeValue(SizingValue.CreateUnitValue(UnitValue.CreatePercentValue(30))); + NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + NUnit.Framework.Assert.AreEqual(30, value.GetSizingValue().GetUnitValue().GetValue(), 0.00001); + } + + [NUnit.Framework.Test] + public virtual void UnitValueTest() { + GridValue value = GridValue.CreateUnitValue(UnitValue.CreatePointValue(1.3f)); + NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); + NUnit.Framework.Assert.AreEqual(1.3f, (float)value.GetAbsoluteValue(), 0.00001); + value = GridValue.CreateUnitValue(UnitValue.CreatePercentValue(30)); + NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.SIZING, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + NUnit.Framework.Assert.AreEqual(30, value.GetSizingValue().GetUnitValue().GetValue(), 0.00001); + } + + [NUnit.Framework.Test] + public virtual void FlexValueTest() { + GridValue value = GridValue.CreateFlexValue(1.5f); + NUnit.Framework.Assert.AreEqual(GridValue.GridValueType.FLEX, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + NUnit.Framework.Assert.AreEqual(1.5f, (float)value.GetFlexValue(), 0.00001); + } + } +} diff --git a/itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs b/itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs new file mode 100644 index 000000000..d1bbf1a13 --- /dev/null +++ b/itext.tests/itext.layout.tests/itext/layout/properties/SizingValueTest.cs @@ -0,0 +1,57 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +using iText.Test; + +namespace iText.Layout.Properties { + [NUnit.Framework.Category("UnitTest")] + public class SizingValueTest : ExtendedITextTest { + [NUnit.Framework.Test] + public virtual void UnitValueTest() { + SizingValue value = SizingValue.CreateUnitValue(UnitValue.CreatePointValue(3.2f)); + NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.UNIT, value.GetType()); + NUnit.Framework.Assert.AreEqual(3.2f, value.GetUnitValue().GetValue(), 0.00001); + NUnit.Framework.Assert.AreEqual(3.2f, (float)value.GetAbsoluteValue(), 0.00001); + value = SizingValue.CreateUnitValue(UnitValue.CreatePercentValue(30)); + NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.UNIT, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + NUnit.Framework.Assert.AreEqual(30, value.GetUnitValue().GetValue(), 0.00001); + } + + [NUnit.Framework.Test] + public virtual void MinMaxContentTest() { + SizingValue value = SizingValue.CreateMinContentValue(); + NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.MIN_CONTENT, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + value = SizingValue.CreateMaxContentValue(); + NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.MAX_CONTENT, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + } + + [NUnit.Framework.Test] + public virtual void AutoTest() { + SizingValue value = SizingValue.CreateAutoValue(); + NUnit.Framework.Assert.AreEqual(SizingValue.SizingValueType.AUTO, value.GetType()); + NUnit.Framework.Assert.IsNull(value.GetAbsoluteValue()); + } + } +} diff --git a/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/util/CssDimensionParsingUtilsTest.cs b/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/util/CssDimensionParsingUtilsTest.cs index bf771a9e3..fe3ca6fb0 100644 --- a/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/util/CssDimensionParsingUtilsTest.cs +++ b/itext.tests/itext.styledxmlparser.tests/itext/styledxmlparser/css/util/CssDimensionParsingUtilsTest.cs @@ -304,5 +304,16 @@ public virtual void ParseLengthInvalidTest() { float result = CssDimensionParsingUtils.ParseLength("10cmm", 10, 2, 8, 9); NUnit.Framework.Assert.AreEqual(2, result, 0.0001f); } + + [NUnit.Framework.Test] + public virtual void ParseFlexTest() { + NUnit.Framework.Assert.AreEqual(13.3f, CssDimensionParsingUtils.ParseFlex("13.3fr"), 0.0001); + NUnit.Framework.Assert.AreEqual(13.3f, CssDimensionParsingUtils.ParseFlex("13.3fr "), 0.0001); + NUnit.Framework.Assert.AreEqual(13.3f, CssDimensionParsingUtils.ParseFlex(" 13.3fr "), 0.0001); + NUnit.Framework.Assert.IsNull(CssDimensionParsingUtils.ParseFlex("13.3 fr")); + NUnit.Framework.Assert.IsNull(CssDimensionParsingUtils.ParseFlex("13.3f")); + NUnit.Framework.Assert.IsNull(CssDimensionParsingUtils.ParseFlex("13.3")); + NUnit.Framework.Assert.IsNull(CssDimensionParsingUtils.ParseFlex(null)); + } } } diff --git a/itext/itext.layout/itext/layout/properties/GridValue.cs b/itext/itext.layout/itext/layout/properties/GridValue.cs new file mode 100644 index 000000000..290ae75eb --- /dev/null +++ b/itext/itext.layout/itext/layout/properties/GridValue.cs @@ -0,0 +1,160 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +namespace iText.Layout.Properties { + /// + /// A specialized class that holds a value for grid-template-columns/rows and + /// grid-auto-columns/rows properties and the type it is measured in. + /// + public class GridValue { + /// The type of the value. + private GridValue.GridValueType type; + + /// The flexible value. + private float? flex; + + /// The sizing value. + private SizingValue sizingValue; + + /// + /// Creates a new empty instance of + /// + /// class. + /// + private GridValue() { + } + + // do nothing + /// + /// Creates an instance of + /// + /// with + /// + /// value. + /// + /// the sizing value + /// the grid value instance + public static iText.Layout.Properties.GridValue CreateSizeValue(SizingValue sizingValue) { + iText.Layout.Properties.GridValue result = new iText.Layout.Properties.GridValue(); + result.sizingValue = sizingValue; + result.type = GridValue.GridValueType.SIZING; + return result; + } + + /// + /// Creates an instance of + /// + /// with + /// + /// inside of + /// + /// value. + /// + /// the unit value + /// the grid value instance + public static iText.Layout.Properties.GridValue CreateUnitValue(UnitValue unitValue) { + iText.Layout.Properties.GridValue result = new iText.Layout.Properties.GridValue(); + result.sizingValue = SizingValue.CreateUnitValue(unitValue); + result.type = GridValue.GridValueType.SIZING; + return result; + } + + /// + /// Creates an instance of + /// + /// with flex value. + /// + /// the flex value + /// the grid value instance + public static iText.Layout.Properties.GridValue CreateFlexValue(float flex) { + iText.Layout.Properties.GridValue result = new iText.Layout.Properties.GridValue(); + result.flex = flex; + result.type = GridValue.GridValueType.FLEX; + return result; + } + + /// Checks whether the value is absolute. + /// + /// + /// + /// if absolute, + /// + /// otherwise + /// + public virtual bool IsAbsoluteValue() { + return type == GridValue.GridValueType.SIZING && sizingValue.IsAbsoluteValue(); + } + + /// Gets absolute value, if exists. + /// + /// absolute value, or + /// + /// if value is relative + /// + public virtual float? GetAbsoluteValue() { + if (IsAbsoluteValue()) { + return sizingValue.GetAbsoluteValue(); + } + return null; + } + + /// Gets type of value. + /// the type of the value + public virtual GridValue.GridValueType GetType() { + return type; + } + + /// Gets the flex value. + /// + /// the flex value of + /// + /// if another value type is stored + /// + public virtual float? GetFlexValue() { + return flex; + } + + /// Gets the sizing value. + /// + /// the instance of + /// + /// or + /// + /// if another value type is stored + /// + public virtual SizingValue GetSizingValue() { + return sizingValue; + } + + /// Enum of grid value types. + public enum GridValueType { + /// + /// Type which presents + /// + /// value. + /// + SIZING, + /// Type which presents relative flexible value. + FLEX + } + } +} diff --git a/itext/itext.layout/itext/layout/properties/SizingValue.cs b/itext/itext.layout/itext/layout/properties/SizingValue.cs new file mode 100644 index 000000000..9bdc0a661 --- /dev/null +++ b/itext/itext.layout/itext/layout/properties/SizingValue.cs @@ -0,0 +1,159 @@ +/* +This file is part of the iText (R) project. +Copyright (c) 1998-2024 Apryse Group NV +Authors: Apryse Software. + +This program is offered under a commercial and under the AGPL license. +For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below. + +AGPL licensing: +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ +namespace iText.Layout.Properties { + /// A specialized class that holds a sizing value and the type it is measured in. + /// + /// A specialized class that holds a sizing value and the type it is measured in. + /// + /// For more information see https://www.w3.org/TR/css-sizing-3/#sizing-values. + /// + public class SizingValue { + /// The type of the value. + private SizingValue.SizingValueType type; + + /// The unit value. + private UnitValue unitValue; + + /// + /// Creates a new empty instance of + /// + /// class. + /// + private SizingValue() { + } + + // do nothing + /// + /// Creates an instance of + /// + /// with + /// + /// value. + /// + /// the unit value + /// the sizing value instance + public static iText.Layout.Properties.SizingValue CreateUnitValue(UnitValue unitValue) { + iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); + result.type = SizingValue.SizingValueType.UNIT; + result.unitValue = unitValue; + return result; + } + + /// + /// Creates an instance of + /// + /// with min-content value. + /// + /// the sizing value instance + public static iText.Layout.Properties.SizingValue CreateMinContentValue() { + iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); + result.type = SizingValue.SizingValueType.MIN_CONTENT; + return result; + } + + /// + /// Creates an instance of + /// + /// with max-content value. + /// + /// the sizing value instance + public static iText.Layout.Properties.SizingValue CreateMaxContentValue() { + iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); + result.type = SizingValue.SizingValueType.MAX_CONTENT; + return result; + } + + /// + /// Creates an instance of + /// + /// with auto value. + /// + /// the sizing value instance + public static iText.Layout.Properties.SizingValue CreateAutoValue() { + iText.Layout.Properties.SizingValue result = new iText.Layout.Properties.SizingValue(); + result.type = SizingValue.SizingValueType.AUTO; + return result; + } + + /// Checks whether the value is absolute. + /// + /// + /// + /// if absolute, + /// + /// otherwise + /// + public virtual bool IsAbsoluteValue() { + return type == SizingValue.SizingValueType.UNIT && unitValue.IsPointValue(); + } + + /// Gets absolute value, if exists. + /// + /// absolute value, or + /// + /// if value is relative + /// + public virtual float? GetAbsoluteValue() { + if (IsAbsoluteValue()) { + return unitValue.GetValue(); + } + return null; + } + + /// Gets the type of the value. + /// the type of the value + public virtual SizingValue.SizingValueType GetType() { + return type; + } + + /// Gets unit value. + /// + /// the + /// + /// or + /// + /// if another value type is stored + /// + public virtual UnitValue GetUnitValue() { + return unitValue; + } + + /// Enum of sizing value types. + public enum SizingValueType { + /// + /// Type which presents + /// + /// value, can be both relative (percentage) and absolute (points). + /// + UNIT, + /// Type which presents relative auto value. + AUTO, + /// Type which presents relative min content value. + MIN_CONTENT, + /// Type which presents relative max content value. + MAX_CONTENT, + /// Type which presents relative fit content function value. + FIT_CONTENT + } + } +} diff --git a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs index 36b1121bb..496b23302 100644 --- a/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs +++ b/itext/itext.layout/itext/layout/renderer/GridContainerRenderer.cs @@ -22,7 +22,6 @@ You should have received a copy of the GNU Affero General Public License */ using System; using System.Collections.Generic; -using System.Linq; using iText.Commons.Utils; using iText.Kernel.Geom; using iText.Layout.Borders; @@ -262,17 +261,14 @@ private float SafelyRetrieveFloatProperty(int property) { // if it is inline-grid, than it won't be needed. private static Grid ConstructGrid(iText.Layout.Renderer.GridContainerRenderer renderer, Rectangle actualBBox ) { - //TODO DEVSIX-8324 create a new class GridTemplateValue, which will store fr, pt, %, minmax, etc. values - //TODO DEVSIX-8324 Use this new class instead of Float and use it inside Grid Sizing Algorithm - //TODO DEVSIX-8324 Right now we're assuming that all template values are points, and there is no % and fr in this list - IList templateColumns = ProcessTemplateValues(renderer.GetProperty>(Property.GRID_TEMPLATE_COLUMNS - )); - IList templateRows = ProcessTemplateValues(renderer.GetProperty>(Property.GRID_TEMPLATE_ROWS - )); - float? columnAutoWidth = renderer.GetProperty(Property.GRID_AUTO_COLUMNS) == null ? null : (float? - )((UnitValue)renderer.GetProperty(Property.GRID_AUTO_COLUMNS)).GetValue(); - float? rowAutoHeight = renderer.GetProperty(Property.GRID_AUTO_ROWS) == null ? null : (float?)( - (UnitValue)renderer.GetProperty(Property.GRID_AUTO_ROWS)).GetValue(); + IList templateColumns = renderer.GetProperty>(Property.GRID_TEMPLATE_COLUMNS) + == null ? null : renderer.GetProperty>(Property.GRID_TEMPLATE_COLUMNS); + IList templateRows = renderer.GetProperty>(Property.GRID_TEMPLATE_ROWS) == null + ? null : renderer.GetProperty>(Property.GRID_TEMPLATE_ROWS); + GridValue columnAutoWidth = renderer.GetProperty(Property.GRID_AUTO_COLUMNS) == null ? null : renderer + .GetProperty(Property.GRID_AUTO_COLUMNS); + GridValue rowAutoHeight = renderer.GetProperty(Property.GRID_AUTO_ROWS) == null ? null : renderer + .GetProperty(Property.GRID_AUTO_ROWS); float? columnGap = renderer.GetProperty(Property.COLUMN_GAP); float? rowGap = renderer.GetProperty(Property.ROW_GAP); //Grid Item Placement Algorithm @@ -309,32 +305,27 @@ private static Grid ConstructGrid(iText.Layout.Renderer.GridContainerRenderer re return grid; } - //TODO DEVSIX-8324 This is temporary method, we should remove it and instead of having Property.GRID_TEMPLATE_... - // as a UnitValue and returning list of Float, we need a new class which will be passed to Grid Sizing Algorithm. - private static IList ProcessTemplateValues(IList template) { - if (template == null) { - return null; - } - return template.Select((value) => value.GetValue()).ToList(); - } - //This method calculates container minimal height, because if number of cells is not enough to fill all specified //rows by template than we need to set the height of the container higher than it's actual occupied height. - private static void SetGridContainerMinimalHeight(Grid grid, IList templateRows) { + private static void SetGridContainerMinimalHeight(Grid grid, IList templateRows) { float explicitContainerHeight = 0.0f; if (templateRows != null) { - foreach (float? template in templateRows) { - explicitContainerHeight += (float)template; + foreach (GridValue template in templateRows) { + if (template.IsAbsoluteValue()) { + explicitContainerHeight += (float)template.GetAbsoluteValue(); + } } } grid.SetMinHeight(explicitContainerHeight); } - private static void SetGridContainerMinimalWidth(Grid grid, IList templateColumns) { + private static void SetGridContainerMinimalWidth(Grid grid, IList templateColumns) { float explicitContainerWidth = 0.0f; if (templateColumns != null) { - foreach (float? template in templateColumns) { - explicitContainerWidth += (float)template; + foreach (GridValue template in templateColumns) { + if (template.IsAbsoluteValue()) { + explicitContainerWidth += (float)template.GetAbsoluteValue(); + } } } grid.SetMinWidth(explicitContainerWidth); diff --git a/itext/itext.layout/itext/layout/renderer/GridSizer.cs b/itext/itext.layout/itext/layout/renderer/GridSizer.cs index 62b8cd33c..879c130f6 100644 --- a/itext/itext.layout/itext/layout/renderer/GridSizer.cs +++ b/itext/itext.layout/itext/layout/renderer/GridSizer.cs @@ -35,13 +35,13 @@ internal class GridSizer { //TODO DEVSIX-8326 since templates will have not only absoulute values, we're probably need to create // separate fields, something like rowsHeights, columnsWidths which will store absolute/calculated values. // replace all absolute value logic using this new fields - private readonly IList templateRows; + private readonly IList templateRows; - private readonly IList templateColumns; + private readonly IList templateColumns; - private readonly float? rowAutoHeight; + private readonly GridValue rowAutoHeight; - private readonly float? columnAutoWidth; + private readonly GridValue columnAutoWidth; //TODO DEVSIX-8326 here should be a list/map of different resolvers private readonly GridSizer.SizeResolver sizeResolver; @@ -50,8 +50,8 @@ internal class GridSizer { private readonly float rowGap; - internal GridSizer(Grid grid, IList templateRows, IList templateColumns, float? rowAutoHeight - , float? columnAutoWidth, float? columnGap, float? rowGap) { + internal GridSizer(Grid grid, IList templateRows, IList templateColumns, GridValue rowAutoHeight + , GridValue columnAutoWidth, float? columnGap, float? rowGap) { this.grid = grid; this.templateRows = templateRows; this.templateColumns = templateColumns; @@ -105,7 +105,7 @@ private float CalculateCellX(GridCell cell) { int currentColumn = 0; if (templateColumns != null) { for (; currentColumn < Math.Min(templateColumns.Count, cell.GetColumnStart()); ++currentColumn) { - x += (float)templateColumns[currentColumn]; + x += (float)templateColumns[currentColumn].GetAbsoluteValue(); x += columnGap; } if (currentColumn == cell.GetColumnStart()) { @@ -114,7 +114,7 @@ private float CalculateCellX(GridCell cell) { } if (columnAutoWidth != null) { for (; currentColumn < cell.GetColumnStart(); ++currentColumn) { - x += (float)columnAutoWidth; + x += (float)columnAutoWidth.GetAbsoluteValue(); x += columnGap; } return x; @@ -148,12 +148,12 @@ private float CalculateCellHeight(GridCell cell) { for (int i = cell.GetRowStart(); i < cell.GetRowEnd(); ++i) { if (templateRows != null && i < templateRows.Count) { ++counter; - cellHeight += (float)templateRows[i]; + cellHeight += (float)templateRows[i].GetAbsoluteValue(); } else { if (rowAutoHeight != null) { ++counter; - cellHeight += (float)rowAutoHeight; + cellHeight += (float)rowAutoHeight.GetAbsoluteValue(); } } } @@ -167,12 +167,12 @@ private float CalculateCellHeight(GridCell cell) { if (templateRows == null || cell.GetRowStart() >= templateRows.Count) { //TODO DEVSIX-8324 if row auto height value is fr or min-content do not return here if (rowAutoHeight != null) { - return (float)rowAutoHeight; + return (float)rowAutoHeight.GetAbsoluteValue(); } cellHeight = sizeResolver.ResolveHeight(cell, cellHeight); } else { - cellHeight = templateRows[cell.GetRowStart()]; + cellHeight = (float)templateRows[cell.GetRowStart()].GetAbsoluteValue(); } return cellHeight; } @@ -187,12 +187,12 @@ private float CalculateCellWidth(GridCell cell) { for (int i = cell.GetColumnStart(); i < cell.GetColumnEnd(); ++i) { if (templateColumns != null && i < templateColumns.Count) { ++counter; - cellWidth += templateColumns[i]; + cellWidth += (float)templateColumns[i].GetAbsoluteValue(); } else { if (columnAutoWidth != null) { ++counter; - cellWidth += (float)columnAutoWidth; + cellWidth += (float)columnAutoWidth.GetAbsoluteValue(); } } } @@ -206,13 +206,13 @@ private float CalculateCellWidth(GridCell cell) { if (templateColumns == null || cell.GetColumnEnd() > templateColumns.Count) { //TODO DEVSIX-8324 if row auto width value is fr or min-content do not return here if (columnAutoWidth != null) { - return (float)columnAutoWidth; + return (float)columnAutoWidth.GetAbsoluteValue(); } cellWidth = sizeResolver.ResolveWidth(cell, cellWidth); } else { //process absolute template values - cellWidth = templateColumns[cell.GetColumnStart()]; + cellWidth = (float)templateColumns[cell.GetColumnStart()].GetAbsoluteValue(); } return cellWidth; } diff --git a/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs b/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs index 2169fec11..bbe19e34f 100644 --- a/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs +++ b/itext/itext.styledxmlparser/itext/styledxmlparser/css/CommonCssConstants.cs @@ -307,6 +307,9 @@ static CommonCssConstants() { /// The Constant FONT_WEIGHT. public const String FONT_WEIGHT = "font-weight"; + /// The Constant FR. + public const String FR = "fr"; + /// The Constant GAP. public const String GAP = "gap"; diff --git a/itext/itext.styledxmlparser/itext/styledxmlparser/css/util/CssDimensionParsingUtils.cs b/itext/itext.styledxmlparser/itext/styledxmlparser/css/util/CssDimensionParsingUtils.cs index 8b45d6d44..428234fe3 100644 --- a/itext/itext.styledxmlparser/itext/styledxmlparser/css/util/CssDimensionParsingUtils.cs +++ b/itext/itext.styledxmlparser/itext/styledxmlparser/css/util/CssDimensionParsingUtils.cs @@ -315,6 +315,23 @@ public static UnitValue ParseLengthValueToPt(String value, float emValue, float return null; } + /// Parses a flex value "xfr" to x. + /// String containing the flex value to parse + /// the flex value as a float + public static float? ParseFlex(String value) { + if (value == null) { + return null; + } + value = value.Trim(); + if (value.EndsWith(CommonCssConstants.FR)) { + value = value.JSubstring(0, value.Length - CommonCssConstants.FR.Length); + if (CssTypesValidationUtils.IsNumber(value)) { + return float.Parse(value, System.Globalization.CultureInfo.InvariantCulture); + } + } + return null; + } + /// Parse length attributes. /// /// diff --git a/port-hash b/port-hash index 0dc777194..b2e72dfad 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -39350335380cdac65faa272806156560209869e1 +75916d2ca4991a01c47cc8304ab61c0e1143b385 From fa0b8d60110e5ef38bd0b4d07791c013cb3cee34 Mon Sep 17 00:00:00 2001 From: Angelina Pavlovets Date: Thu, 23 May 2024 19:36:04 +0000 Subject: [PATCH 4/4] 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 d15d9506f..c4be4826d 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 ba9b04b06..141bb025d 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 zcmeHPYm8mjS+$+2H51#s5>V719Fe%5iDTdWeh|lE{EFS!&U9vMhd37Or!&Ex>)g3^ z9MT^|2n0k?Tk1cM(9odJ1fe>Dh)O_EQV_&xQd>@tLJ5>Kp@2$h39VcdK&*Z4otf(y zJGco}6>+X*pL@^Q&$YjAeQO_if2+r~Y+Fay>!HF!LmffK`sW0ELhnKMcl zqp~KEP@)NQ^;4>Pr6?l|_bI0&bAmFcqe!VkFi^sYsGm!Muf$)lMOwG0qpw@!$<|jE zaUYdR>!lANP12sEFx$(5kx{f>_aX(xg0_f7Z(K@@KvA?Kn6!A3@FdJV(fBS!R8}R; zm0$GSmFLPzp`f~M=(X(eT@1iA8s?6$pHDB~g=W)h-DZ9{ofh`prD6ukY%%<27W$dDB zNy}OiUP_T%%%J|}2&=CYi<@0mJZYsJmeeONtT9|@s=UC(Y2^*e#F;>7Lgz%Mz-VMx zd=V2?LTM^VB9ceVtjs|(;h3XTa#Ox~?Je=%n*gixsFJJ+qBLxRG?M!qROFFor98_j zaL0{;DI~@u3o*FB(Jv3tqY_U^shDyygfRm<)kad9U2u_L3NU~W4dsbN6O@dY3R*=u zbm6R))@mOd*EvYXd@@484J?N0ohDi-m!kC&Eo9C^Fdzxcj(bK4=P5=(lT+|TtuSy; zosuFGrZHpS;2j1|VRq;yi|D*!j=O-#(wqSS6VincC>)<~l%?n?c^Im4!b_UCrb#*? zyfJ{2daQ|a4iILP$teLNADJ=9$p~yU!L(^0UIia8M`c0%j9kA|i{Nf)OM# z2fwFQBpsrLMPwhja3)iQfx#$X2ZWaK`@$X6n|ZIN5k>~?!5tLTx#yEG0Nm9mrxgfF zNOYkwbs!j{@kv^bE7_<;4wcIoR=~v zt#y>%7N<}`phMWT!kEDu5frAAHr~4^5rv&(v`|5DdgHT%?=qG#TTYyaQYB2xg7;X| z8jKR7mas-nybd6TEVE|JCgH8NRO0HWr2q=HXMNOB=$wH_PyuGEG*AeX;+w;`gTY;} zh6G)3CNqY^;OuZy1NutJS*uVoCn3>-%shpJ`7xd?Xv`qKDDVoVZi51IS~#$F7=R-x z#}sG)LBk;0$ef(?ZyZrz^B{+rwrOBx{wikC6R#1g8^YaU|Sk>@lKRX zSS4H;oNiHM?^)^FS<`#T_bw9IIbu1Mp3{p)_JI=bt@)O?{BGiT$XUZc6N7;U&I=L2 z35e1NqD&#?5NmQB<|v56WCB;PT!cdU2pbt@i1322={(FGE@qAAQNSOWhxccfLPpqP zh<6&w(l7-ZhHgs~gh5fR0FO^)_SX@o15E7g`8Y>GoP>OJKroe&B3YHwyM$C$3fq(+_0SyjCQltt*6Q=?TRRjqfV=kVD zq7W(QnjkXtBM)wY(sPMF68HPRn%I8f*nX+X<|473LR?>BY=^O^%!(>?#wn;knHe0} zAYLI77@2a2F+(HM5R}R}1aDCe2IMk_>?%XWQQ3;78oHtWFZD`;YOe##6?b$gGh$& z5C)G6!k|LN&JQX^Lv%v9BWS{J0fSD|U<(5A!y?zt1&NuI&9W_RD~|mL^l)&{&|YDR z(7F*$=7&ImXRX1rmRJX!t07!s#+E8W!UWJTffhDUDBglAU8WKrE+JUJ6X5Bx zKZmc@SM1S>pCWpJE#Et88KYkGhT+2RG4QqmIvHMPz)TC@k63KE%A1JAPq6cWDkyBW zxDMVNF!Ya?E-qtzh*O9I7Hb+9HboMYiPtXyK}%~W_M+La7lg|M?eR(`L5gxLaV)Hf z9hM?~fgZOYR)|vc0xi$r*$m_F^_XDG(4*OzWD!j;N<;(hBVuN>CQ%4G_yp8pgk~v{ zH%J%@ET1&k~~O0+2N#It$ojF_^rg#j(K%9-T?}ALgxH34khK?+9&A(7L7> zF%0!+fKN#HtEEmVVI?+Zh`|BjMJ9`gV-et>s$r%=)LL9Si&qT}vKg-f0$@tmR6x_? zVR_3#S;!!d$W!qy?aMZRTeO%ET%gjiGj@1wq!F?ZgYfpnfgCiT3jw|YhA}}~L||-t z4O)R8qCbRgY{5MU0i41(d?aBv0yoA^Awzn=?-9*4qAa%X9=i*nrEo4XytZIO8*G^o zvCGECfFdz|3^icmQn0|=BI+>bvI~&lAg)8%vw=<+$jt`^2mu7e6gW#DOe~BCvtUb& z@gwRYYDbKL3cSxKQv+QwTaWDa@zy=>Ag`Hc95N4c}2mrYPeu1iIFjtRFc=KrxXb@-+Xb@-+Xb@-+ zXb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+Xb@-+ zXb@-+Xb@-+Xb@-+Xb@-+Xb`w82yAR^n>y4@oz`e<`?P*+?3SHV-PGFI4z4@Zo*th4 zGSb>LyyYkGpZ{?p2ZxQzMXV)!4IyhrT4SB|k)Pglbm~w<5`)nrNAT}%cQ~~+;?o*W zZUznYE+hDvQzuP_v>&CmxUQ=x5+IDXCOd9=Cbv6>cct!~?bzDV4!gFD&EFn#9d~#J zb;c^*n!NW&TKK57w?)@8bXY%}m^z4_Hf}u7nmFqFQ`|Z^v19$_(YSSDeN4!PaA%5h zg*R>-O4ESgt|3b16EcjBm8n!zmLa0)O%wRNuafw>>lS?7w7Dc|sOW*#rkm?;u;_L9DtqeW?>ht$zfERcHN_$L`PbCt2+M#<~BS1GSz-Miau=H4!LgH zl0rMeF4FYD?wyr18#m5$JINg$I{xt5H#$SFoxO)o5;4Af$LmZ@kk38&GFN+-?|AL( zH@Cld>eRmFr(4hO_{hsEPJN}b^0lEimMvNRM=P!?J@y;vLtkL)_dPm2-R{l+urle2 z7C6Qa%;&AB7o@c-#VNO`eH_q}3TGKABiMmfANCq9nA=SIXeXp%Iopr}qg-gEN^`Y! zPIjgaFKVH-pfPta&BH=Ds`SS;R+XF`~ItixFoUDXAun>+2JN2=X>t2>5AZywvZ?pW%~ zU=(+Z+*loM$EiG(Vs&(8YWiTW{Aa7p?M|u;T9xyy_Ucx1b?3Taq8dHYxpyYb^>dk; z9T~8;d1D(5o%S}+Vnurfz4drEO_%8vi{3i1V{@S)HZg$=j}142ln=EJ&X0x-Fk^`r-Ey3odz`kU69!H zD26uo8_ZjiTX84aYr9mPZp81X~Sif{dPCEkAj0)>z1iFv%lu$p7$Q;4X8$C zenf>BF2{fhNA%m>GCEu+2+KK{M+%Kk9&c^S6{$yvj6W!eXgJ)3>4Tr^YgOW61v@?z z2aRN4mRrWpHxZwPyC$BsIsQ2mxUAgEJMMpL!kSX6HUji6xRq#Hovu6iz~4 zgk%Q>F>49MkbAh_cB{V&5pf`l9RAo%t3FRw{Ng>2eE!-S#QI-(<$*6f`04TM)}MLb z{kM<(_NtpUe(}eaPL6!yk^lU=gKPNm>#q8z=^Jjl{{D|Xy!6VOUU>Gp_Vp)*)>PO0 z`SKC7>G~)B>*mLfzrjBAr~h{PnU!aM;Rn}_W%cnD+xL9x>id7_-Kw*!`u^Kk70R+f2uSH+;imAKbGM8!~2#!w|E|PlkZ@hTwG+F(-0v&Z8yy-u;^^ay|e+d zNwQ?q@?U@W3y(c=@VEZ{*G^yk+@4<^3Ge&F(j`CeS3~z*VE6;#Vbh@b{x2}&MC*Cu zpBD)=?e(1KQilBCi#HbgU2^7cKl9Dy58QqBcOJXuKh{07WQ$)VCPyECTwL+$r}i%W z&@Zj}@8{n9gAe{pyy|za%pWyo)5?`Etk}8t(T6^={>&Xe`RMh-r_P)pw}0pP58U_1 zPe1wXJzxLuhNu7Ht3%iR%fFv}=3h_V`k513zwzLG?|=PEPqx4Q>P^cYSi0fV6W{rh z&pkVJ;)V&ob-cReH-CTcKmYt%w&t3Xhra)7OW*qOYp*_c?u&nT?)LC|S3Lgc)QN}Q z`s??9`ET0iW^O!w#j|(szkmd*SL_{F0X>fe5N<97vWY!MzVF!cJ6`z0SC=hWwQt$! z#jAR}lk!jzvqQ7HA8IRPG2pVwRqr0vR)RFkr<$Iw?`dHcw})g23(G;2!VS)E4;hINRL{SMqsCBk3+~~F{la@13BwlL>(wg% z(s^8rGz-g7gCm`b>lW%SpLzTg(nBn`R~qlNH`oVKbu1`{v&_B{klTE!F-F$Y+EsR!Ba9v$Y)Qe<;qu8=SVsDOP0p31;Jlkc2}-Larg4 zEymeeoJ>W&9Avv78u@K((8w=kk*fx$do{&De|+N{XYz4AnBefRib7JHWK}q2i^I|$ z**a`O203IDK<)~h!ACAI#gMlP8QgF%7w3SHG5~3YaKaepu8~d$`^}PKud3;}HQsJ_ z``g=zsh>+QV}#q)wP;;eH0ZkXHR#Yx*LAwJ$y1~PLx#ZBTW{SqG*lYvyX3o4*m7{g z{{K;7Uw+{}5QJv8WA*myd%1NT*dmrJkagb2%e*JN6uEmT61VmRUa=n2V;9L6vL?>V z%K_HZ744TrcAo)Ov-9_na$ufyzI%p2ZVn`F!0CO9#0mkqO_2En=i>1JIU$iB5-cFO z97h@<&UAE0D1zKKB{P6DS>ObI$VeFxB+{D^CLL01MV64y0|`}-K@jb6l3DObT_AAY mzNFvK7HI?=&i1p6)DQZ6h8gRmV^vKS?}BU?WtR2H=6?XTY;@ZI 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 36e8a1904..9f2a9cad9 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 b2e72dfad..d53be0f01 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -75916d2ca4991a01c47cc8304ab61c0e1143b385 +03a2c75fa888159e6b9a503e0bb7a64378c0155f