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.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest.cs b/itext.tests/itext.sign.tests/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest.cs index f4b66f7ae..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,7 +23,9 @@ 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; using iText.Test; @@ -48,8 +50,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 +62,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 +74,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 +90,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 +104,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 +120,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 +134,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 +146,203 @@ 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))); + } + } + + [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 cdc249139..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 @@ -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(); @@ -447,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 000000000..3526ca7c5 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/danglingWidgetAnnotation.pdf differ 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 000000000..d0a42fb93 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationAllowed.pdf differ 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 000000000..ab1cffc59 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockChildModificationNotAllowed.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockKidsRemovedAndAdded.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockKidsRemovedAndAdded.pdf new file mode 100644 index 000000000..90505a5e7 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockKidsRemovedAndAdded.pdf differ 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 000000000..3633ad2ae Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationAllowed.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationNotAllowed.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationNotAllowed.pdf new file mode 100644 index 000000000..a5bce0826 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockRootModificationNotAllowed.pdf differ 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 000000000..3698fb1f6 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialExcludeValues.pdf differ 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 000000000..f150cff3d Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/fieldLockSequentialIncludeValues.pdf differ 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 000000000..8ee272a5b Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedFieldRemoveAddKidsEntry.pdf differ 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 000000000..55251b3e7 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/lockedSignatureFieldModified.pdf differ 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 000000000..836750d6e Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/pageAndParentIndirectReferenceModified.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeAllAnnots.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeAllAnnots.pdf new file mode 100644 index 000000000..d16c0e046 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeAllAnnots.pdf differ 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 000000000..148168290 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeFieldAnnots.pdf differ 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 000000000..2ba3e8d3c Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removeUnnamedField.pdf differ 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 000000000..6e58e500d Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorIntegrationTest/removedLockedField.pdf differ diff --git a/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorTest/multipleRevisionsDocument3.pdf b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorTest/multipleRevisionsDocument3.pdf new file mode 100644 index 000000000..7a377c626 Binary files /dev/null and b/itext.tests/itext.sign.tests/resources/itext/signatures/validation/v1/DocumentRevisionsValidatorTest/multipleRevisionsDocument3.pdf differ 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.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.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.sign/itext/signatures/AccessPermissions.cs b/itext/itext.sign/itext/signatures/AccessPermissions.cs new file mode 100644 index 000000000..8d69f61b9 --- /dev/null +++ b/itext/itext.sign/itext/signatures/AccessPermissions.cs @@ -0,0 +1,43 @@ +/* +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 { + /// 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..9f2a9cad9 100644 --- a/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs +++ b/itext/itext.sign/itext/signatures/validation/v1/DocumentRevisionsValidator.cs @@ -38,6 +38,11 @@ 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 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."; @@ -46,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."; @@ -54,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."; @@ -80,36 +97,39 @@ 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 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 TOO_MANY_CERTIFICATION_SIGNATURES = "Document contains more than one certification signature."; - internal const String SIGNATURE_REVISION_NOT_FOUND = "Not possible to identify document revision corresponding to the first signature in the document."; + internal const String UNEXPECTED_ENTRY_IN_XREF = "New PDF document revision contains unexpected entry \"{0}\" in XREF table."; - 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 UNEXPECTED_FORM_FIELD = "New PDF document revision contains unexpected form field \"{0}\"."; 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_FORM_FIELD = "New PDF document revision contains unexpected form field \"{0}\"."; + internal const String UNRECOGNIZED_ACTION = "Signature field lock dictionary contains unrecognized " + "\"Action\" value \"{0}\". \"All\" will be used instead."; private IMetaInfo metaInfo = new ValidationMetaInfo(); - private DocumentRevisionsValidator.AccessPermissions accessPermissions = DocumentRevisionsValidator.AccessPermissions - .ANNOTATION_MODIFICATION; + private AccessPermissions accessPermissions = AccessPermissions.ANNOTATION_MODIFICATION; - private DocumentRevisionsValidator.AccessPermissions requestedAccessPermissions = DocumentRevisionsValidator.AccessPermissions - .UNSPECIFIED; + private AccessPermissions requestedAccessPermissions = AccessPermissions.UNSPECIFIED; + + private readonly ICollection lockedFields = new HashSet(); private readonly PdfDocument document; + private ICollection checkedAnnots; + + private ICollection newlyAddedFields; + internal DocumentRevisionsValidator(PdfDocument document) { this.document = document; } @@ -136,11 +156,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,17 +168,21 @@ 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; } + 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(); @@ -170,7 +194,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 +222,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,32 +243,39 @@ public virtual ValidationReport ValidateAllDocumentRevisions() { return report; } - internal virtual ValidationReport ValidateRevision(DocumentRevision previousRevision, DocumentRevision currentRevision + // + // + // Revisions validation util section: + // + // + 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); + 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()) != @@ -254,7 +287,8 @@ internal virtual ValidationReport ValidateRevision(DocumentRevision previousRevi } } 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)); } @@ -267,15 +301,10 @@ 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; } private static Stream CreateInputStreamFromRevision(PdfDocument originalDocument, DocumentRevision revision @@ -293,20 +322,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; } @@ -316,14 +345,77 @@ 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; } } + 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 +425,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; } } @@ -401,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(); @@ -414,74 +511,10 @@ 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 - ) && CompareAcroForms(previousCatalog.GetAsDictionary(PdfName.AcroForm), currentCatalog.GetAsDictionary - (PdfName.AcroForm), report); - } - - 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; + ) && 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: @@ -579,60 +612,113 @@ private bool CompareDss(PdfObject previousDss, PdfObject currentDss, ValidationR 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)); + 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; } - if (prevPages == null) { + 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; } - 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)); + if (previousKids.Size() < currentKids.Size()) { + report.AddReportItem(new ReportItem(FIELD_MDP_CHECK, MessageFormatUtil.Format(LOCKED_FIELD_KIDS_ADDED, fieldName + ), 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)); + 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 < 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; - } + 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; } - 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; - } + if (PdfFormAnnotationUtil.IsPureWidget(previousKid) && !CompareFormFieldWithFieldMDP(previousKid, currentKid + , fieldName, report)) { + return false; } } return true; @@ -640,6 +726,8 @@ private bool ComparePages(PdfDictionary prevPages, PdfDictionary currPages, Vali private bool CompareAcroForms(PdfDictionary prevAcroForm, PdfDictionary currAcroForm, ValidationReport report ) { + checkedAnnots = new HashSet(); + newlyAddedFields = new HashSet(); if (prevAcroForm == null) { if (currAcroForm == null) { return true; @@ -673,24 +761,45 @@ private bool CompareAcroForms(PdfDictionary prevAcroForm, PdfDictionary currAcro } 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); + 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)) { - report.AddReportItem(new ReportItem(DOC_MDP_CHECK, MessageFormatUtil.Format(FIELD_REMOVED, fieldEntry.Key) - , ReportItem.ReportItemStatus.INVALID)); + 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; } - currFieldsMap.JRemove(fieldEntry.Key); + if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(previousField)) { + checkedAnnots.Add(previousField); + } + if (PdfFormAnnotationUtil.IsPureWidgetOrMergedField(currentField)) { + checkedAnnots.Add(currentField); + } + currFieldsSet.Remove(currentField); } - foreach (KeyValuePair fieldEntry in currFieldsMap) { - if (!IsAllowedSignatureField(fieldEntry.Value, report)) { + foreach (PdfDictionary field in currFieldsSet) { + if (!IsAllowedSignatureField(field, report)) { return false; } } - return CompareAnnotations(prevFields, currFields, report); + return CompareWidgets(prevFields, currFields, report); + } + + private PdfDictionary RetrieveTheSameField(ICollection currFields, PdfDictionary previousField + ) { + 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 null; } /// DocMDP level >= 2 allows setting values of the fields and accordingly update the widget appearances of them. @@ -712,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))) { @@ -729,14 +830,15 @@ 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; } } else { - if (GetAccessPermissions() == DocumentRevisionsValidator.AccessPermissions.NO_CHANGES_PERMITTED && !ComparePdfObjects - (prevValue, currValue)) { + if (GetAccessPermissions() == AccessPermissions.NO_CHANGES_PERMITTED && !ComparePdfObjects(prevValue, currValue + )) { return false; } } @@ -744,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) { @@ -821,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) { @@ -832,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); @@ -850,30 +1044,38 @@ 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)); + 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) { @@ -888,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); } } @@ -936,278 +1137,27 @@ private PdfDictionary CopyFieldDictionary(PdfDictionary field) { private void RemoveAppearanceRelatedProperties(PdfDictionary annotDict) { annotDict.Remove(PdfName.P); - if (GetAccessPermissions() != DocumentRevisionsValidator.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()))); - } - } + if (GetAccessPermissions() == AccessPermissions.ANNOTATION_MODIFICATION) { + foreach (PdfName key in new PdfDictionary(annotDict).KeySet()) { + if (!PdfFormField.GetFormFieldKeys().Contains(key)) { + annotDict.Remove(key); } } } - // 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() != DocumentRevisionsValidator.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); - } - else { - // 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()); } @@ -1316,38 +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; } - internal enum AccessPermissions { - UNSPECIFIED, - NO_CHANGES_PERMITTED, - FORM_FIELDS_MODIFICATION, - ANNOTATION_MODIFICATION + 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; } - private class ReferencesPair { - private readonly PdfIndirectReference currentReference; + // 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 readonly PdfIndirectReference previousReference; + 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; + } - internal ReferencesPair(PdfIndirectReference currentReference, PdfIndirectReference previousReference) { - this.currentReference = currentReference; - this.previousReference = 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); + } + } + } + + 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/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 39b564edb..d53be0f01 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -15951163c968bb91b805b915388550f2e4296bcf +03a2c75fa888159e6b9a503e0bb7a64378c0155f