From b7c6d33a9c7ee8d3a1d6d296c2361568dd601b73 Mon Sep 17 00:00:00 2001 From: Dmitry Chubrick Date: Thu, 5 Sep 2024 09:16:38 +0000 Subject: [PATCH 1/3] Provide a lazy initialization for PdfDocument#xmpMetadata and info DEVSIX-5292 Autoported commit. Original commit hash: [e952e0abf] --- .../crypto/pdfencryption/PdfEncryptionTest.cs | 2 +- .../itext/kernel/pdf/PdfDocumentUnitTest.cs | 64 +------ .../itext/kernel/pdf/PdfReaderTest.cs | 43 +++-- .../itext/kernel/pdf/PdfStampingTest.cs | 7 +- .../itext/kernel/pdf/PdfXrefTableTest.cs | 6 +- .../itext/kernel/pdf/XMPMetadataTest.cs | 50 ++--- .../itext/kernel/utils/PdfSplitterTest.cs | 11 +- .../itext/layout/PdfUA2Test.cs | 2 +- .../pdfa/PdfAAgnosticPdfDocumentUnitTest.cs | 4 +- .../itext/pdfa/PdfAXmpTest.cs | 6 +- .../itext/pdfa/checker/PdfA4MetaDataTest.cs | 2 +- .../itext/pdfua/PdfUAMetadataUnitTest.cs | 54 +++--- .../itext/kernel/pdf/PdfDocument.cs | 181 +++++++++++++----- .../itext/kernel/pdf/PdfDocumentInfo.cs | 10 +- .../itext/kernel/pdf/PdfReader.cs | 10 +- .../itext/kernel/pdf/XmpMetaInfoConverter.cs | 5 +- .../itext/kernel/utils/CompareTool.cs | 4 +- .../itext/pdfua/checkers/PdfUA1Checker.cs | 12 +- port-hash | 2 +- 19 files changed, 255 insertions(+), 220 deletions(-) diff --git a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs index 58af785e65..cbb7db5bc3 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/crypto/pdfencryption/PdfEncryptionTest.cs @@ -223,7 +223,7 @@ public virtual void MetadataReadingInEncryptedDoc() { PdfReader reader = new PdfReader(sourceFolder + "encryptedWithPlainMetadata.pdf", new ReaderProperties().SetPassword (PdfEncryptionTestUtils.OWNER)); PdfDocument doc = new PdfDocument(reader); - XMPMeta xmpMeta = XMPMetaFactory.ParseFromBuffer(doc.GetXmpMetadata()); + XMPMeta xmpMeta = doc.GetXmpMetadata(); XMPProperty creatorToolXmp = xmpMeta.GetProperty(XMPConst.NS_XMP, "CreatorTool"); doc.Close(); NUnit.Framework.Assert.IsNotNull(creatorToolXmp); diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentUnitTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentUnitTest.cs index 81d13294ee..7b9d17029d 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentUnitTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfDocumentUnitTest.cs @@ -187,64 +187,6 @@ public virtual void CopyPagesFlushedResources() { } } - [NUnit.Framework.Test] - public virtual void PdfDocumentInstanceNoWriterInfoAndConformanceLevelInitialization() { - PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf")); - NUnit.Framework.Assert.IsNull(pdfDocument.info); - NUnit.Framework.Assert.IsNull(pdfDocument.reader.pdfAConformanceLevel); - pdfDocument.Close(); - NUnit.Framework.Assert.IsNull(pdfDocument.info); - NUnit.Framework.Assert.IsNull(pdfDocument.reader.pdfAConformanceLevel); - } - - [NUnit.Framework.Test] - public virtual void PdfDocumentInstanceWriterInfoAndConformanceLevelInitialization() { - PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf"), new PdfWriter - (new ByteArrayOutputStream())); - NUnit.Framework.Assert.IsNotNull(pdfDocument.info); - NUnit.Framework.Assert.IsNull(pdfDocument.reader.pdfAConformanceLevel); - pdfDocument.Close(); - NUnit.Framework.Assert.IsNotNull(pdfDocument.info); - NUnit.Framework.Assert.IsNull(pdfDocument.reader.pdfAConformanceLevel); - } - - [NUnit.Framework.Test] - public virtual void ExtendedPdfDocumentNoWriterInfoAndConformanceLevelInitialization() { - PdfDocument pdfDocument = new _PdfDocument_252(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf")); - // This class instance extends pdfDocument - // TODO DEVSIX-5292 These fields shouldn't be initialized during the document's opening - NUnit.Framework.Assert.IsNotNull(pdfDocument.info); - NUnit.Framework.Assert.IsNotNull(pdfDocument.reader.pdfAConformanceLevel); - pdfDocument.Close(); - NUnit.Framework.Assert.IsNotNull(pdfDocument.info); - NUnit.Framework.Assert.IsNotNull(pdfDocument.reader.pdfAConformanceLevel); - } - - private sealed class _PdfDocument_252 : PdfDocument { - public _PdfDocument_252(PdfReader baseArg1) - : base(baseArg1) { - } - } - - [NUnit.Framework.Test] - public virtual void ExtendedPdfDocumentWriterInfoAndConformanceLevelInitialization() { - PdfDocument pdfDocument = new _PdfDocument_269(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf"), new PdfWriter - (new ByteArrayOutputStream())); - // This class instance extends pdfDocument - NUnit.Framework.Assert.IsNotNull(pdfDocument.info); - // TODO DEVSIX-5292 pdfAConformanceLevel shouldn't be initialized during the document's opening - NUnit.Framework.Assert.IsNotNull(pdfDocument.reader.pdfAConformanceLevel); - pdfDocument.Close(); - NUnit.Framework.Assert.IsNotNull(pdfDocument.info); - NUnit.Framework.Assert.IsNotNull(pdfDocument.reader.pdfAConformanceLevel); - } - - private sealed class _PdfDocument_269 : PdfDocument { - public _PdfDocument_269(PdfReader baseArg1, PdfWriter baseArg2) - : base(baseArg1, baseArg2) { - } - } - [NUnit.Framework.Test] public virtual void GetDocumentInfoAlreadyClosedTest() { PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf")); @@ -253,17 +195,15 @@ public virtual void GetDocumentInfoAlreadyClosedTest() { } [NUnit.Framework.Test] - public virtual void GetDocumentInfoNotInitializedTest() { + public virtual void GetDocumentInfoInitializationTest() { PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf")); - NUnit.Framework.Assert.IsNull(pdfDocument.info); NUnit.Framework.Assert.IsNotNull(pdfDocument.GetDocumentInfo()); pdfDocument.Close(); } [NUnit.Framework.Test] - public virtual void GetPdfAConformanceLevelNotInitializedTest() { + public virtual void GetPdfAConformanceLevelInitializationTest() { PdfDocument pdfDocument = new PdfDocument(new PdfReader(SOURCE_FOLDER + "pdfWithMetadata.pdf")); - NUnit.Framework.Assert.IsNull(pdfDocument.reader.pdfAConformanceLevel); NUnit.Framework.Assert.IsNotNull(pdfDocument.reader.GetPdfAConformanceLevel()); pdfDocument.Close(); } diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfReaderTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfReaderTest.cs index ddf7ae7063..9e93faebaa 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfReaderTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfReaderTest.cs @@ -2357,14 +2357,14 @@ public virtual void StreamWithoutEndstreamKeywordTest() { using (PdfReader reader = new PdfReader(fileName)) { reader.SetStrictnessLevel(PdfReader.StrictnessLevel.LENIENT); using (PdfDocument document = new PdfDocument(reader)) { + // Initialize xmp metadata, because we in reader mode in which xmp will be initialized only during closing + byte[] metadataBytes = document.GetXmpMetadataBytes(); PdfCatalog catalog = new PdfCatalog((PdfDictionary)reader.trailer.Get(PdfName.Root, true)); PdfStream xmpMetadataStream = catalog.GetPdfObject().GetAsStream(PdfName.Metadata); int xmpMetadataStreamLength = ((PdfNumber)xmpMetadataStream.Get(PdfName.Length)).IntValue(); - // 27600 is actual invalid length of stream. In reader StrictnessLevel#LENIENT we expect, that this - // length will be fixed. - NUnit.Framework.Assert.AreNotEqual(27600, xmpMetadataStreamLength); - // 3090 is expected length of the stream after fix. + // Initial length was 27600. 3090 is expected length of the stream after the fix NUnit.Framework.Assert.AreEqual(3090, xmpMetadataStreamLength); + NUnit.Framework.Assert.AreEqual(3090, metadataBytes.Length); } } } @@ -2374,7 +2374,10 @@ public virtual void StreamWithoutEndstreamKeywordConservativeModeTest() { String fileName = SOURCE_FOLDER + "NoEndstreamKeyword.pdf"; using (PdfReader reader = new PdfReader(fileName)) { reader.SetStrictnessLevel(PdfReader.StrictnessLevel.CONSERVATIVE); - Exception exception = NUnit.Framework.Assert.Catch(typeof(PdfException), () => new PdfDocument(reader)); + PdfDocument pdfDocument = new PdfDocument(reader); + // Initialize xmp metadata, because we in reader mode in which xmp will be initialized only during closing + Exception exception = NUnit.Framework.Assert.Catch(typeof(PdfException), () => pdfDocument.GetXmpMetadata( + )); NUnit.Framework.Assert.AreEqual(KernelExceptionMessageConstant.STREAM_SHALL_END_WITH_ENDSTREAM, exception. Message); PdfCatalog catalog = new PdfCatalog((PdfDictionary)reader.trailer.Get(PdfName.Root, true)); @@ -2385,6 +2388,18 @@ public virtual void StreamWithoutEndstreamKeywordConservativeModeTest() { } } + [NUnit.Framework.Test] + public virtual void StreamWithoutEndKeyConservativeModeWithWriterTest() { + String fileName = SOURCE_FOLDER + "NoEndstreamKeyword.pdf"; + using (PdfReader reader = new PdfReader(fileName)) { + reader.SetStrictnessLevel(PdfReader.StrictnessLevel.CONSERVATIVE); + Exception exception = NUnit.Framework.Assert.Catch(typeof(PdfException), () => new PdfDocument(reader, new + PdfWriter(new ByteArrayOutputStream()))); + NUnit.Framework.Assert.AreEqual(KernelExceptionMessageConstant.STREAM_SHALL_END_WITH_ENDSTREAM, exception. + Message); + } + } + [NUnit.Framework.Test] public virtual void TokensPositionIsNotUpdatedWhileReadingLengthTest() { String filename = SOURCE_FOLDER + "simpleDocWithIndirectLength.pdf"; @@ -2418,7 +2433,7 @@ public virtual void ConformanceLevelCacheTest() { for (int i = 0; i < 1000; ++i) { pdfTestDoc.GetReader().GetPdfAConformanceLevel(); } - NUnit.Framework.Assert.AreEqual(2, pdfTestDoc.GetCounter()); + NUnit.Framework.Assert.AreEqual(1, pdfTestDoc.GetCounter()); } [NUnit.Framework.Test] @@ -2520,14 +2535,14 @@ public virtual void StreamObjIsNullTest() { int objNumber = pdfDictionary.GetIndirectReference().objNr; pdfDocument.catalog.GetPdfObject().Put(PdfName.StructTreeRoot, pdfDictionary); pdfDocument.Close(); - PdfReader pdfReader = new _PdfReader_2841(objNumber, new MemoryStream(bsaos.ToArray())); + PdfReader pdfReader = new _PdfReader_2853(objNumber, new MemoryStream(bsaos.ToArray())); Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => new PdfDocument(pdfReader)); NUnit.Framework.Assert.AreEqual(MessageFormatUtil.Format(KernelExceptionMessageConstant.INVALID_OBJECT_STREAM_NUMBER , 5, 4, 492), e.Message); } - private sealed class _PdfReader_2841 : PdfReader { - public _PdfReader_2841(int objNumber, Stream baseArg1) + private sealed class _PdfReader_2853 : PdfReader { + public _PdfReader_2853(int objNumber, Stream baseArg1) : base(baseArg1) { this.objNumber = objNumber; } @@ -2546,7 +2561,7 @@ protected internal override PdfObject ReadObject(PdfIndirectReference reference) [NUnit.Framework.Test] public virtual void InitTagTreeStructureThrowsOOMIsCatched() { FileInfo file = new FileInfo(SOURCE_FOLDER + "big_table_lot_of_mcrs.pdf"); - MemoryLimitsAwareHandler memoryLimitsAwareHandler = new _MemoryLimitsAwareHandler_2860(); + MemoryLimitsAwareHandler memoryLimitsAwareHandler = new _MemoryLimitsAwareHandler_2872(); memoryLimitsAwareHandler.SetMaxSizeOfDecompressedPdfStreamsSum(100000); NUnit.Framework.Assert.Catch(typeof(MemoryLimitsAwareException), () => { using (PdfReader reader = new PdfReader(file, new ReaderProperties().SetMemoryLimitsAwareHandler(memoryLimitsAwareHandler @@ -2558,8 +2573,8 @@ public virtual void InitTagTreeStructureThrowsOOMIsCatched() { ); } - private sealed class _MemoryLimitsAwareHandler_2860 : MemoryLimitsAwareHandler { - public _MemoryLimitsAwareHandler_2860() { + private sealed class _MemoryLimitsAwareHandler_2872 : MemoryLimitsAwareHandler { + public _MemoryLimitsAwareHandler_2872() { } public override bool IsMemoryLimitsAwarenessRequiredOnDecompression(PdfArray filters) { @@ -2626,9 +2641,9 @@ public TestPdfDocumentCache(PdfReaderTest _enclosing, PdfReader pdfReader) this._enclosing = _enclosing; } - public override byte[] GetXmpMetadata(bool createNew) { + public override byte[] GetXmpMetadataBytes(bool createdNew) { ++this.getXmpMetadataCounter; - return base.GetXmpMetadata(createNew); + return base.GetXmpMetadataBytes(createdNew); } public virtual int GetCounter() { diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStampingTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStampingTest.cs index 2f6ce8364c..4f5a911683 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStampingTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStampingTest.cs @@ -31,7 +31,6 @@ You should have received a copy of the GNU Affero General Public License using iText.Kernel.Pdf.Canvas.Parser; using iText.Kernel.Pdf.Canvas.Parser.Listener; using iText.Kernel.Utils; -using iText.Kernel.XMP; using iText.Test; using iText.Test.Attributes; @@ -689,8 +688,7 @@ public virtual void StampingXmp1() { for (int i = 0; i < pdfDoc3.GetNumberOfPages(); i++) { pdfDoc3.GetPage(i + 1); } - NUnit.Framework.Assert.IsNotNull(XMPMetaFactory.ParseFromBuffer(pdfDoc3.GetXmpMetadata()), "XmpMetadata not found" - ); + NUnit.Framework.Assert.IsNotNull(pdfDoc3.GetXmpMetadata(), "XmpMetadata not found"); NUnit.Framework.Assert.AreEqual(pageCount, pdfDoc3.GetNumberOfPages(), "Number of pages"); NUnit.Framework.Assert.IsFalse(reader3.HasRebuiltXref(), "Rebuilt"); NUnit.Framework.Assert.IsFalse(reader3.HasFixedXref(), "Fixed"); @@ -732,8 +730,7 @@ public virtual void StampingXmp2() { for (int i = 0; i < pdfDoc3.GetNumberOfPages(); i++) { pdfDoc3.GetPage(i + 1); } - NUnit.Framework.Assert.IsNotNull(XMPMetaFactory.ParseFromBuffer(pdfDoc3.GetXmpMetadata()), "XmpMetadata not found" - ); + NUnit.Framework.Assert.IsNotNull(pdfDoc3.GetXmpMetadata(), "XmpMetadata not found"); NUnit.Framework.Assert.AreEqual(pageCount, pdfDoc3.GetNumberOfPages(), "Number of pages"); NUnit.Framework.Assert.IsFalse(reader3.HasRebuiltXref(), "Rebuilt"); NUnit.Framework.Assert.IsFalse(reader3.HasFixedXref(), "Fixed"); diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfXrefTableTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfXrefTableTest.cs index bc50acda39..f3b6bb7619 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfXrefTableTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfXrefTableTest.cs @@ -52,13 +52,13 @@ public static void AfterClass() { LogLevel = LogLevelConstants.ERROR)] public virtual void OpenInvalidDocWithHugeRefTest() { String inputFile = SOURCE_FOLDER + "invalidDocWithHugeRef.pdf"; - MemoryLimitsAwareHandler memoryLimitsAwareHandler = new _MemoryLimitsAwareHandler_67(); + MemoryLimitsAwareHandler memoryLimitsAwareHandler = new _MemoryLimitsAwareHandler_68(); NUnit.Framework.Assert.DoesNotThrow(() => new PdfDocument(new PdfReader(inputFile, new ReaderProperties(). SetMemoryLimitsAwareHandler(memoryLimitsAwareHandler)))); } - private sealed class _MemoryLimitsAwareHandler_67 : MemoryLimitsAwareHandler { - public _MemoryLimitsAwareHandler_67() { + private sealed class _MemoryLimitsAwareHandler_68 : MemoryLimitsAwareHandler { + public _MemoryLimitsAwareHandler_68() { } public override void CheckIfXrefStructureExceedsTheLimit(int requestedCapacity) { diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/XMPMetadataTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/XMPMetadataTest.cs index 6789b0a23c..61b85a8634 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/XMPMetadataTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/XMPMetadataTest.cs @@ -31,26 +31,26 @@ You should have received a copy of the GNU Affero General Public License namespace iText.Kernel.Pdf { [NUnit.Framework.Category("IntegrationTest")] public class XMPMetadataTest : ExtendedITextTest { - public static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext + public static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext .CurrentContext.TestDirectory) + "/resources/itext/kernel/pdf/XmpWriterTest/"; - public static readonly String destinationFolder = NUnit.Framework.TestContext.CurrentContext.TestDirectory + public static readonly String DESTINATION_FOLDER = NUnit.Framework.TestContext.CurrentContext.TestDirectory + "/test/itext/kernel/pdf/XmpWriterTest/"; [NUnit.Framework.OneTimeSetUp] public static void BeforeClass() { - CreateOrClearDestinationFolder(destinationFolder); + CreateOrClearDestinationFolder(DESTINATION_FOLDER); } [NUnit.Framework.OneTimeTearDown] public static void AfterClass() { - CompareTool.Cleanup(destinationFolder); + CompareTool.Cleanup(DESTINATION_FOLDER); } [NUnit.Framework.Test] public virtual void CreateEmptyDocumentWithXmp() { String filename = "emptyDocumentWithXmp.pdf"; - PdfWriter writer = CompareTool.CreateTestPdfWriter(destinationFolder + filename, new WriterProperties().AddXmpMetadata + PdfWriter writer = CompareTool.CreateTestPdfWriter(DESTINATION_FOLDER + filename, new WriterProperties().AddXmpMetadata ()); PdfDocument pdfDoc = new PdfDocument(writer); pdfDoc.GetDocumentInfo().SetAuthor("Alexander Chingarev").SetCreator("iText").SetTitle("Empty iText Document" @@ -60,12 +60,12 @@ public virtual void CreateEmptyDocumentWithXmp() { PdfPage page = pdfDoc.AddNewPage(); page.Flush(); pdfDoc.Close(); - PdfReader reader = CompareTool.CreateOutputReader(destinationFolder + filename); + PdfReader reader = CompareTool.CreateOutputReader(DESTINATION_FOLDER + filename); PdfDocument pdfDocument = new PdfDocument(reader); NUnit.Framework.Assert.AreEqual(false, reader.HasRebuiltXref(), "Rebuilt"); - byte[] outBytes = pdfDocument.GetXmpMetadata(); + byte[] outBytes = pdfDocument.GetXmpMetadataBytes(); pdfDocument.Close(); - byte[] cmpBytes = ReadFile(sourceFolder + "emptyDocumentWithXmp.xml"); + byte[] cmpBytes = ReadFile(SOURCE_FOLDER + "emptyDocumentWithXmp.xml"); cmpBytes = RemoveAlwaysDifferentEntries(cmpBytes); outBytes = RemoveAlwaysDifferentEntries(outBytes); NUnit.Framework.Assert.IsTrue(new CompareTool().CompareXmls(outBytes, cmpBytes)); @@ -73,9 +73,9 @@ public virtual void CreateEmptyDocumentWithXmp() { [NUnit.Framework.Test] public virtual void EmptyDocumentWithXmpAppendMode01() { - String created = destinationFolder + "emptyDocumentWithXmpAppendMode01.pdf"; - String updated = destinationFolder + "emptyDocumentWithXmpAppendMode01_updated.pdf"; - String updatedAgain = destinationFolder + "emptyDocumentWithXmpAppendMode01_updatedAgain.pdf"; + String created = DESTINATION_FOLDER + "emptyDocumentWithXmpAppendMode01.pdf"; + String updated = DESTINATION_FOLDER + "emptyDocumentWithXmpAppendMode01_updated.pdf"; + String updatedAgain = DESTINATION_FOLDER + "emptyDocumentWithXmpAppendMode01_updatedAgain.pdf"; PdfDocument pdfDocument = new PdfDocument(CompareTool.CreateTestPdfWriter(created)); pdfDocument.AddNewPage(); // create XMP metadata @@ -95,9 +95,9 @@ public virtual void EmptyDocumentWithXmpAppendMode01() { (); NUnit.Framework.Assert.AreEqual(6, metadataRef.GetObjNumber()); NUnit.Framework.Assert.AreEqual(0, metadataRef.GetGenNumber()); - byte[] outBytes = pdfDocument.GetXmpMetadata(); + byte[] outBytes = pdfDocument.GetXmpMetadataBytes(); pdfDocument.Close(); - byte[] cmpBytes = ReadFile(sourceFolder + "emptyDocumentWithXmpAppendMode01.xml"); + byte[] cmpBytes = ReadFile(SOURCE_FOLDER + "emptyDocumentWithXmpAppendMode01.xml"); cmpBytes = RemoveAlwaysDifferentEntries(cmpBytes); outBytes = RemoveAlwaysDifferentEntries(outBytes); NUnit.Framework.Assert.IsTrue(new CompareTool().CompareXmls(outBytes, cmpBytes)); @@ -105,9 +105,9 @@ public virtual void EmptyDocumentWithXmpAppendMode01() { [NUnit.Framework.Test] public virtual void EmptyDocumentWithXmpAppendMode02() { - String created = destinationFolder + "emptyDocumentWithXmpAppendMode02.pdf"; - String updated = destinationFolder + "emptyDocumentWithXmpAppendMode02_updated.pdf"; - String updatedAgain = destinationFolder + "emptyDocumentWithXmpAppendMode02_updatedAgain.pdf"; + String created = DESTINATION_FOLDER + "emptyDocumentWithXmpAppendMode02.pdf"; + String updated = DESTINATION_FOLDER + "emptyDocumentWithXmpAppendMode02_updated.pdf"; + String updatedAgain = DESTINATION_FOLDER + "emptyDocumentWithXmpAppendMode02_updatedAgain.pdf"; PdfDocument pdfDocument = new PdfDocument(CompareTool.CreateTestPdfWriter(created)); pdfDocument.AddNewPage(); pdfDocument.Close(); @@ -127,16 +127,16 @@ public virtual void EmptyDocumentWithXmpAppendMode02() { (); NUnit.Framework.Assert.AreEqual(6, metadataRef.GetObjNumber()); NUnit.Framework.Assert.AreEqual(0, metadataRef.GetGenNumber()); - byte[] outBytes = pdfDocument.GetXmpMetadata(); + byte[] outBytes = pdfDocument.GetXmpMetadataBytes(); pdfDocument.Close(); - byte[] cmpBytes = ReadFile(sourceFolder + "emptyDocumentWithXmpAppendMode02.xml"); + byte[] cmpBytes = ReadFile(SOURCE_FOLDER + "emptyDocumentWithXmpAppendMode02.xml"); cmpBytes = RemoveAlwaysDifferentEntries(cmpBytes); outBytes = RemoveAlwaysDifferentEntries(outBytes); NUnit.Framework.Assert.IsTrue(new CompareTool().CompareXmls(outBytes, cmpBytes)); } [NUnit.Framework.Test] - [LogMessage(iText.IO.Logs.IoLogMessageConstant.EXCEPTION_WHILE_UPDATING_XMPMETADATA)] + [LogMessage(iText.IO.Logs.IoLogMessageConstant.EXCEPTION_WHILE_UPDATING_XMPMETADATA, Count = 2)] public virtual void CreateEmptyDocumentWithAbcXmp() { MemoryStream fos = new MemoryStream(); PdfWriter writer = new PdfWriter(fos); @@ -151,8 +151,8 @@ public virtual void CreateEmptyDocumentWithAbcXmp() { pdfDoc.Close(); PdfReader reader = new PdfReader(new MemoryStream(fos.ToArray())); PdfDocument pdfDocument = new PdfDocument(reader); - NUnit.Framework.Assert.AreEqual(false, reader.HasRebuiltXref(), "Rebuilt"); - NUnit.Framework.Assert.AreEqual("abc".GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1), pdfDocument.GetXmpMetadata + NUnit.Framework.Assert.IsFalse(reader.HasRebuiltXref(), "Rebuilt"); + NUnit.Framework.Assert.AreEqual("abc".GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1), pdfDocument.GetXmpMetadataBytes ()); NUnit.Framework.Assert.IsNotNull(pdfDocument.GetPage(1)); reader.Close(); @@ -181,16 +181,16 @@ public virtual void CustomXmpTest02() { } private void RunCustomXmpTest(String name, String xmp) { - String outPath = destinationFolder + name + ".pdf"; - String cmpPath = sourceFolder + "cmp_" + name + ".pdf"; + String outPath = DESTINATION_FOLDER + name + ".pdf"; + String cmpPath = SOURCE_FOLDER + "cmp_" + name + ".pdf"; PdfDocument pdfDoc = new PdfDocument(CompareTool.CreateTestPdfWriter(outPath)); PdfPage page = pdfDoc.AddNewPage(); page.Flush(); pdfDoc.SetXmpMetadata(xmp.GetBytes(iText.Commons.Utils.EncodingUtil.ISO_8859_1)); pdfDoc.Close(); CompareTool compareTool = new CompareTool(); - NUnit.Framework.Assert.IsNull(compareTool.CompareByContent(outPath, cmpPath, destinationFolder, "diff_" + - name + "_")); + NUnit.Framework.Assert.IsNull(compareTool.CompareByContent(outPath, cmpPath, DESTINATION_FOLDER, "diff_" + + name + "_")); NUnit.Framework.Assert.IsNull(compareTool.CompareDocumentInfo(outPath, cmpPath)); } diff --git a/itext.tests/itext.kernel.tests/itext/kernel/utils/PdfSplitterTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/utils/PdfSplitterTest.cs index 70baf97b25..903fd8bd20 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/utils/PdfSplitterTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/utils/PdfSplitterTest.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.IO; using iText.Commons.Utils; using iText.Kernel.Pdf; using iText.Test; @@ -79,7 +78,7 @@ protected internal override PdfWriter GetNextPdfWriter(PageRange documentPageRan return CompareTool.CreateTestPdfWriter(PdfSplitterTest.destinationFolder + "splitDocument1_" + (this.partNumber ++).ToString() + ".pdf"); } - catch (FileNotFoundException) { + catch (System.IO.IOException) { throw new Exception(); } } @@ -115,7 +114,7 @@ protected internal override PdfWriter GetNextPdfWriter(PageRange documentPageRan (this.partNumber++).ToString() + ".pdf"); return writer; } - catch (FileNotFoundException) { + catch (System.IO.IOException) { throw new Exception(); } } @@ -167,7 +166,7 @@ protected internal override PdfWriter GetNextPdfWriter(PageRange documentPageRan return CompareTool.CreateTestPdfWriter(PdfSplitterTest.destinationFolder + "splitDocument3_" + (this.partNumber ++).ToString() + ".pdf"); } - catch (FileNotFoundException) { + catch (System.IO.IOException) { throw new Exception(); } } @@ -208,7 +207,7 @@ protected internal override PdfWriter GetNextPdfWriter(PageRange documentPageRan return CompareTool.CreateTestPdfWriter(PdfSplitterTest.destinationFolder + "splitDocument4_" + (this.partNumber ++).ToString() + ".pdf"); } - catch (FileNotFoundException) { + catch (System.IO.IOException) { throw new Exception(); } } @@ -260,7 +259,7 @@ protected internal override PdfWriter GetNextPdfWriter(PageRange documentPageRan return CompareTool.CreateTestPdfWriter(PdfSplitterTest.destinationFolder + "splitBySize_part" + (this.partNumber ++).ToString() + ".pdf"); } - catch (FileNotFoundException) { + catch (System.IO.IOException) { throw new Exception(); } } diff --git a/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs b/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs index 88489d939f..236ef7354f 100644 --- a/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs +++ b/itext.tests/itext.layout.tests/itext/layout/PdfUA2Test.cs @@ -72,7 +72,7 @@ public virtual void CheckXmpMetadataTest() { PdfFont font = PdfFontFactory.CreateFont(FONT_FOLDER + "FreeSans.ttf", "WinAnsi", PdfFontFactory.EmbeddingStrategy .FORCE_EMBEDDED); Paragraph paragraph = new Paragraph("Hello PdfUA2").SetFont(font); - byte[] byteMetaData = pdfDocument.GetXmpMetadata(); + byte[] byteMetaData = pdfDocument.GetXmpMetadataBytes(); documentMetaData = iText.Commons.Utils.JavaUtil.GetStringForBytes(byteMetaData); document.Add(paragraph); } diff --git a/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAAgnosticPdfDocumentUnitTest.cs b/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAAgnosticPdfDocumentUnitTest.cs index 410f7e5355..343ba0b80c 100644 --- a/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAAgnosticPdfDocumentUnitTest.cs +++ b/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAAgnosticPdfDocumentUnitTest.cs @@ -58,7 +58,7 @@ public virtual void LoadPdfDocumentTest() { NUnit.Framework.Assert.IsFalse(pdfDoc.GetPageFactoryPublic() is PdfAPageFactory); NUnit.Framework.Assert.IsNull(pdfDoc.GetConformanceLevel()); pdfDoc.UpdateXmpMetadataPublic(); - XMPMeta xmpMeta = XMPMetaFactory.ParseFromBuffer(pdfDoc.GetXmpMetadata(true)); + XMPMeta xmpMeta = pdfDoc.GetXmpMetadata(true); NUnit.Framework.Assert.IsNull(xmpMeta.GetProperty(XMPConst.NS_PDFA_ID, XMPConst.PART)); NUnit.Framework.Assert.IsNull(xmpMeta.GetProperty(XMPConst.NS_PDFA_ID, XMPConst.CONFORMANCE)); pdfDoc.Close(); @@ -84,7 +84,7 @@ public virtual void LoadPdfADocumentTest() { NUnit.Framework.Assert.AreEqual(PdfAConformanceLevel.PDF_A_2B, pdfADoc.GetConformanceLevel()); NUnit.Framework.Assert.IsTrue(pdfADoc.GetPageFactoryPublic() is PdfAPageFactory); pdfADoc.UpdateXmpMetadataPublic(); - XMPMeta xmpMeta = XMPMetaFactory.ParseFromBuffer(pdfADoc.GetXmpMetadata(true)); + XMPMeta xmpMeta = pdfADoc.GetXmpMetadata(); NUnit.Framework.Assert.IsNotNull(xmpMeta.GetProperty(XMPConst.NS_PDFA_ID, XMPConst.PART)); NUnit.Framework.Assert.IsNotNull(xmpMeta.GetProperty(XMPConst.NS_PDFA_ID, XMPConst.CONFORMANCE)); // Extra PdfA error message check diff --git a/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAXmpTest.cs b/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAXmpTest.cs index 906e23c0c8..c810ad4dd7 100644 --- a/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAXmpTest.cs +++ b/itext.tests/itext.pdfa.tests/itext/pdfa/PdfAXmpTest.cs @@ -104,8 +104,8 @@ public virtual void SaveAndReadDocumentWithCanonicalXmpMetadata() { // Closing document and reopening it to flush it XMP metadata ModifyDate using (PdfDocument doc_1 = new PdfDocument(new PdfReader(outFile))) { using (PdfDocument cmpDoc = new PdfDocument(new PdfReader(cmpFile))) { - byte[] rdf = doc_1.GetXmpMetadata(); - byte[] expectedRdf = cmpDoc.GetXmpMetadata(); + byte[] rdf = doc_1.GetXmpMetadataBytes(); + byte[] expectedRdf = cmpDoc.GetXmpMetadataBytes(); // Comparing angle brackets, since it's the main difference between canonical and compact format. NUnit.Framework.Assert.AreEqual(Count(expectedRdf, (byte)'<'), Count(rdf, (byte)'<')); NUnit.Framework.Assert.IsNull(new CompareTool().CompareXmp(cmpFile, outFile, true)); @@ -130,7 +130,7 @@ public virtual void TestPdfUAIdSchemaNameSpaceUriIsNotText() { GeneratePdfAWithUA(baos); // check whether the pdfuaid NS URI was properly encoded as a URI with rdf:resource PdfDocument readDoc = new PdfDocument(new PdfReader(new MemoryStream(baos.ToArray()))); - String xmpString = iText.Commons.Utils.JavaUtil.GetStringForBytes(readDoc.GetXmpMetadata(), System.Text.Encoding + String xmpString = iText.Commons.Utils.JavaUtil.GetStringForBytes(readDoc.GetXmpMetadataBytes(), System.Text.Encoding .UTF8); NUnit.Framework.Assert.IsTrue(xmpString.Contains("" ), "Did not find expected namespaceURI definition"); diff --git a/itext.tests/itext.pdfa.tests/itext/pdfa/checker/PdfA4MetaDataTest.cs b/itext.tests/itext.pdfa.tests/itext/pdfa/checker/PdfA4MetaDataTest.cs index 71d01c24fc..d4bac83c7a 100644 --- a/itext.tests/itext.pdfa.tests/itext/pdfa/checker/PdfA4MetaDataTest.cs +++ b/itext.tests/itext.pdfa.tests/itext/pdfa/checker/PdfA4MetaDataTest.cs @@ -564,7 +564,7 @@ private void GeneratePdfADocument(PdfAConformanceLevel conformanceLevel, String } private static PdfDictionary GenerateCustomXmpCatalog(PdfADocument pdfADocument, Action action) { - XMPMeta xmpMeta = XMPMetaFactory.Parse(new MemoryStream(pdfADocument.GetXmpMetadata())); + XMPMeta xmpMeta = pdfADocument.GetXmpMetadata(); PdfDictionary catalog = pdfADocument.GetCatalog().GetPdfObject(); MemoryStream baos = new MemoryStream(); action(xmpMeta); diff --git a/itext.tests/itext.pdfua.tests/itext/pdfua/PdfUAMetadataUnitTest.cs b/itext.tests/itext.pdfua.tests/itext/pdfua/PdfUAMetadataUnitTest.cs index 463a23630b..85f2ed3608 100644 --- a/itext.tests/itext.pdfua.tests/itext/pdfua/PdfUAMetadataUnitTest.cs +++ b/itext.tests/itext.pdfua.tests/itext/pdfua/PdfUAMetadataUnitTest.cs @@ -26,6 +26,7 @@ You should have received a copy of the GNU Affero General Public License using iText.Pdfua.Checkers; using iText.Pdfua.Exceptions; using iText.Test; +using iText.Test.Attributes; namespace iText.Pdfua { [NUnit.Framework.Category("UnitTest")] @@ -51,18 +52,20 @@ public virtual void DocumentWithNoTitleInMetadataTest() { [NUnit.Framework.Test] public virtual void DocumentWithInvalidMetadataVersionTest() { - using (PdfDocument pdfDocument = new PdfUATestPdfDocument(new PdfWriter(new MemoryStream()))) { - pdfDocument.AddNewPage(); - PdfCatalog catalog = pdfDocument.GetCatalog(); - byte[] bytes = File.ReadAllBytes(System.IO.Path.Combine(SOURCE_FOLDER + "invalid_version_metadata.xmp")); - catalog.Put(PdfName.Metadata, new PdfStream(bytes)); - PdfUAMetadataUnitTest.PdfUA1MetadataChecker checker = new PdfUAMetadataUnitTest.PdfUA1MetadataChecker(pdfDocument - ); - Exception e = NUnit.Framework.Assert.Catch(typeof(PdfUAConformanceException), () => checker.CheckMetadata( - catalog)); - NUnit.Framework.Assert.AreEqual(PdfUAExceptionMessageConstants.METADATA_SHALL_CONTAIN_UA_VERSION_IDENTIFIER - , e.Message); - } + PdfDocument pdfDocument = new PdfUATestPdfDocument(new PdfWriter(new MemoryStream())); + pdfDocument.AddNewPage(); + PdfCatalog catalog = pdfDocument.GetCatalog(); + byte[] bytes = File.ReadAllBytes(System.IO.Path.Combine(SOURCE_FOLDER + "invalid_version_metadata.xmp")); + catalog.Put(PdfName.Metadata, new PdfStream(bytes)); + PdfUAMetadataUnitTest.PdfUA1MetadataChecker checker = new PdfUAMetadataUnitTest.PdfUA1MetadataChecker(pdfDocument + ); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfUAConformanceException), () => checker.CheckMetadata( + catalog)); + NUnit.Framework.Assert.AreEqual(PdfUAExceptionMessageConstants.METADATA_SHALL_CONTAIN_UA_VERSION_IDENTIFIER + , e.Message); + e = NUnit.Framework.Assert.Catch(typeof(PdfUAConformanceException), () => pdfDocument.Close()); + NUnit.Framework.Assert.AreEqual(PdfUAExceptionMessageConstants.METADATA_SHALL_CONTAIN_UA_VERSION_IDENTIFIER + , e.Message); } [NUnit.Framework.Test] @@ -106,19 +109,22 @@ public virtual void DocumentWithInvalidPdfVersionTest() { } [NUnit.Framework.Test] + [LogMessage(iText.IO.Logs.IoLogMessageConstant.EXCEPTION_WHILE_UPDATING_XMPMETADATA)] public virtual void DocumentWithBrokenMetadataTest() { - using (PdfDocument pdfDocument = new PdfUATestPdfDocument(new PdfWriter(new MemoryStream()))) { - pdfDocument.AddNewPage(); - PdfCatalog catalog = pdfDocument.GetCatalog(); - byte[] bytes = File.ReadAllBytes(System.IO.Path.Combine(SOURCE_FOLDER + "invalid_metadata.xmp")); - catalog.Put(PdfName.Metadata, new PdfStream(bytes)); - PdfUAMetadataUnitTest.PdfUA1MetadataChecker checker = new PdfUAMetadataUnitTest.PdfUA1MetadataChecker(pdfDocument - ); - Exception e = NUnit.Framework.Assert.Catch(typeof(PdfUAConformanceException), () => checker.CheckMetadata( - catalog)); - NUnit.Framework.Assert.AreEqual(PdfUAExceptionMessageConstants.DOCUMENT_SHALL_CONTAIN_XMP_METADATA_STREAM, - e.Message); - } + PdfDocument pdfDocument = new PdfUATestPdfDocument(new PdfWriter(new MemoryStream())); + pdfDocument.AddNewPage(); + PdfCatalog catalog = pdfDocument.GetCatalog(); + byte[] bytes = File.ReadAllBytes(System.IO.Path.Combine(SOURCE_FOLDER + "invalid_metadata.xmp")); + catalog.Put(PdfName.Metadata, new PdfStream(bytes)); + PdfUAMetadataUnitTest.PdfUA1MetadataChecker checker = new PdfUAMetadataUnitTest.PdfUA1MetadataChecker(pdfDocument + ); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfUAConformanceException), () => checker.CheckMetadata( + catalog)); + NUnit.Framework.Assert.AreEqual(PdfUAExceptionMessageConstants.DOCUMENT_SHALL_CONTAIN_XMP_METADATA_STREAM, + e.Message); + e = NUnit.Framework.Assert.Catch(typeof(PdfUAConformanceException), () => pdfDocument.Close()); + NUnit.Framework.Assert.AreEqual(PdfUAExceptionMessageConstants.DOCUMENT_SHALL_CONTAIN_XMP_METADATA_STREAM, + e.Message); } private class PdfUA1MetadataChecker : PdfUA1Checker { diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs b/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs index 8c7b7a44c4..5f47d1eb97 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfDocument.cs @@ -54,7 +54,6 @@ You should have received a copy of the GNU Affero General Public License namespace iText.Kernel.Pdf { /// Main enter point to work with PDF document. public class PdfDocument : IEventDispatcher, IDisposable { - // private static readonly PdfName[] PDF_NAMES_TO_REMOVE_FROM_ORIGINAL_TRAILER = new PdfName[] { PdfName.Encrypt , PdfName.Size, PdfName.Prev, PdfName.Root, PdfName.Info, PdfName.ID, PdfName.XRefStm }; @@ -97,18 +96,12 @@ public class PdfDocument : IEventDispatcher, IDisposable { /// protected internal PdfReader reader = null; - /// XMP Metadata for the document. - protected internal byte[] xmpMetadata = null; - /// Document catalog. protected internal PdfCatalog catalog = null; /// Document trailed. protected internal PdfDictionary trailer = null; - /// Document info. - protected internal PdfDocumentInfo info = null; - /// Document version. protected internal PdfVersion pdfVersion = PdfVersion.PDF_1_7; @@ -161,6 +154,15 @@ public class PdfDocument : IEventDispatcher, IDisposable { private EncryptedEmbeddedStreamsHandler encryptedEmbeddedStreamsHandler; + /// Document info. + private PdfDocumentInfo info = null; + + /// XMP Metadata bytes for the document. + private byte[] xmpMetadataBytes = null; + + /// XMP Metadata which is used to prevent bytes deserialization for a few times on the same bytes. + private XMPMeta xmpMetadata = null; + private readonly DIContainer diContainer = new DIContainer(); /// Open PDF document in reading mode. @@ -248,37 +250,125 @@ public PdfDocument(PdfReader reader, PdfWriter writer, StampingProperties proper } /// Sets the XMP Metadata. + /// + /// Sets the XMP Metadata. + /// + /// The XMP Metadata values are synchronized with information dictionary. + /// /// the xmpMetadata to set /// serialization options public virtual void SetXmpMetadata(XMPMeta xmpMeta, SerializeOptions serializeOptions) { this.serializeOptions = serializeOptions; - SetXmpMetadata(XMPMetaFactory.SerializeToBuffer(xmpMeta, serializeOptions)); - } - - /// Use this method to set the XMP Metadata. - /// The xmpMetadata to set. - protected internal virtual void SetXmpMetadata(byte[] xmpMetadata) { - this.xmpMetadata = xmpMetadata; + this.xmpMetadataBytes = XMPMetaFactory.SerializeToBuffer(xmpMeta, serializeOptions); + this.xmpMetadata = xmpMeta; } /// Sets the XMP Metadata. + /// + /// Sets the XMP Metadata. + /// + /// The XMP Metadata values are synchronized with information dictionary. + /// + /// + /// will be used for serialization, they + /// can be changed by + /// . + /// /// the xmpMetadata to set public virtual void SetXmpMetadata(XMPMeta xmpMeta) { - serializeOptions.SetPadding(2000); SetXmpMetadata(xmpMeta, serializeOptions); } - /// Gets XMPMetadata. - /// the XMPMetadata - public virtual byte[] GetXmpMetadata() { + /// Sets the XMP Metadata. + /// + /// Sets the XMP Metadata. + /// + /// The XMP Metadata values are synchronized with information dictionary. + /// + /// the xmpMetadata bytes to set + protected internal virtual void SetXmpMetadata(byte[] xmpMetadata) { + this.xmpMetadataBytes = xmpMetadata; + this.xmpMetadata = null; + try { + GetXmpMetadata(); + } + catch (XMPException e) { + ILogger logger = ITextLogManager.GetLogger(typeof(iText.Kernel.Pdf.PdfDocument)); + logger.LogError(e, iText.IO.Logs.IoLogMessageConstant.EXCEPTION_WHILE_UPDATING_XMPMETADATA); + } + } + + /// Gets XMP Metadata. + /// + /// Gets XMP Metadata. + /// + /// XMP Metadata is lazy initialized. It will be initialized during the first call of this method. + /// + /// To update XMP Metadata of the document, use + /// + /// method. + /// + /// existed XMP Metadata + public virtual XMPMeta GetXmpMetadata() { return GetXmpMetadata(false); } - /// Gets XMPMetadata or create a new one. - /// if true, create a new empty XMPMetadata if it did not present. - /// existed or newly created XMPMetadata byte array. - public virtual byte[] GetXmpMetadata(bool createNew) { - if (xmpMetadata == null && createNew) { + /// Gets XMP Metadata or create a new one. + /// + /// Gets XMP Metadata or create a new one. + /// + /// XMP Metadata is lazy initialized. It will be initialized during the first call of this method. + /// + /// To update XMP Metadata of the document, use + /// + /// method. + /// + /// if true, create a new empty XMP Metadata if it did not present + /// existed or newly created XMP Metadata + public virtual XMPMeta GetXmpMetadata(bool createNew) { + if (xmpMetadata == null) { + byte[] bytes = GetXmpMetadataBytes(createNew); + xmpMetadata = bytes == null ? null : XMPMetaFactory.ParseFromBuffer(bytes); + } + return xmpMetadata; + } + + /// Gets XMP Metadata. + /// + /// Gets XMP Metadata. + /// + /// XMP Metadata is lazy initialized. It will be initialized during the first call of this method. + /// + /// To update XMP Metadata of the document, use + /// + /// method. + /// + /// existed XMP Metadata bytes + public virtual byte[] GetXmpMetadataBytes() { + return GetXmpMetadataBytes(false); + } + + /// Gets XMP Metadata or create a new one. + /// + /// Gets XMP Metadata or create a new one. + /// + /// XMP Metadata is lazy initialized. It will be initialized during the first call of this method. + /// + /// To update XMP Metadata of the document, use + /// + /// method. + /// + /// if true, create a new empty XMP Metadata if it did not present + /// existed or newly created XMP Metadata byte array + public virtual byte[] GetXmpMetadataBytes(bool createNew) { + CheckClosingStatus(); + if (xmpMetadataBytes == null) { + PdfStream xmpMetadataStream = catalog.GetPdfObject().GetAsStream(PdfName.Metadata); + if (xmpMetadataStream != null) { + xmpMetadataBytes = xmpMetadataStream.GetBytes(); + } + } + if (createNew && xmpMetadataBytes == null) { XMPMeta xmpMeta = XMPMetaFactory.Create(); xmpMeta.SetObjectName(XMPConst.TAG_XMPMETA); xmpMeta.SetObjectName(""); @@ -290,7 +380,10 @@ public virtual byte[] GetXmpMetadata(bool createNew) { catch (XMPException) { } } - return xmpMetadata; + if (xmpMetadataBytes == null) { + return null; + } + return JavaUtil.ArraysCopyOf(xmpMetadataBytes, xmpMetadataBytes.Length); } /// Gets PdfObject by object number. @@ -571,18 +664,23 @@ public virtual DIContainer GetDiContainer() { /// Gets document information dictionary. /// /// Gets document information dictionary. + /// /// /// is lazy initialized. It will be initialized during the first call of this method. + /// /// The information dictionary values are synchronized with document XMP Metadata. /// /// document information dictionary. public virtual PdfDocumentInfo GetDocumentInfo() { CheckClosingStatus(); if (info == null) { - PdfObject infoDict = trailer.Get(PdfName.Info); - info = new PdfDocumentInfo(infoDict is PdfDictionary ? (PdfDictionary)infoDict : new PdfDictionary(), this - ); - XmpMetaInfoConverter.AppendMetadataToInfo(xmpMetadata, info); + PdfDictionary infoDict = trailer == null ? null : trailer.GetAsDictionary(PdfName.Info); + info = new PdfDocumentInfo(infoDict == null ? new PdfDictionary() : infoDict, this); + try { + XmpMetaInfoConverter.AppendMetadataToInfo(GetXmpMetadata(), info); + } + catch (XMPException) { + } } return info; } @@ -595,7 +693,7 @@ public virtual PdfDocumentInfo GetDocumentInfo() { /// /// should be used /// - /// original dccument id + /// original document id public virtual PdfString GetOriginalDocumentId() { return originalDocumentId; } @@ -749,17 +847,17 @@ public virtual void Close() { GetDocumentInfo().GetPdfObject().Remove(deprecatedKey); } } - if (GetXmpMetadata() != null) { + if (GetXmpMetadataBytes() != null) { PdfStream xmp = catalog.GetPdfObject().GetAsStream(PdfName.Metadata); if (IsAppendMode() && xmp != null && !xmp.IsFlushed() && xmp.GetIndirectReference() != null) { // Use existing object for append mode - xmp.SetData(xmpMetadata); + xmp.SetData(GetXmpMetadataBytes()); xmp.SetModified(); } else { // Create new object xmp = (PdfStream)new PdfStream().MakeIndirect(this); - xmp.GetOutputStream().Write(xmpMetadata); + xmp.GetOutputStream().Write(GetXmpMetadataBytes()); catalog.GetPdfObject().Put(PdfName.Metadata, xmp); catalog.SetModified(); } @@ -2031,16 +2129,6 @@ protected internal virtual void Open(PdfVersion newPdfVersion) { } catalog = new PdfCatalog(catalogDictionary); UpdatePdfVersionFromCatalog(); - PdfStream xmpMetadataStream = catalog.GetPdfObject().GetAsStream(PdfName.Metadata); - if (xmpMetadataStream != null) { - xmpMetadata = xmpMetadataStream.GetBytes(); - if (!this.GetType().Equals(typeof(iText.Kernel.Pdf.PdfDocument))) { - // TODO DEVSIX-5292 If somebody extends PdfDocument we have to initialize document info - // and conformance level to provide compatibility. This code block shall be removed - reader.GetPdfAConformanceLevel(); - GetDocumentInfo(); - } - } PdfDictionary str = catalog.GetPdfObject().GetAsDictionary(PdfName.StructTreeRoot); if (str != null) { TryInitTagStructure(str); @@ -2064,7 +2152,8 @@ protected internal virtual void Open(PdfVersion newPdfVersion) { writer.document = this; if (reader == null) { catalog = new PdfCatalog(this); - info = new PdfDocumentInfo(this).AddCreationDate(); + // initialize document info + GetDocumentInfo().AddCreationDate(); } GetDocumentInfo().AddModDate(); if (trailer == null) { @@ -2201,8 +2290,8 @@ protected internal virtual void UpdateXmpMetadata() { try { // We add PDF producer info in any case, and the valid way to do it for PDF 2.0 in only in metadata, not // in the info dictionary. - if (xmpMetadata != null || writer.properties.addXmpMetadata || pdfVersion.CompareTo(PdfVersion.PDF_2_0) >= - 0) { + if (GetXmpMetadataBytes() != null || writer.properties.addXmpMetadata || pdfVersion.CompareTo(PdfVersion.PDF_2_0 + ) >= 0) { SetXmpMetadata(UpdateDefaultXmpMetadata()); } } @@ -2218,7 +2307,7 @@ protected internal virtual void UpdateXmpMetadata() { /// /// the XMPMetadata protected internal virtual XMPMeta UpdateDefaultXmpMetadata() { - XMPMeta xmpMeta = XMPMetaFactory.ParseFromBuffer(GetXmpMetadata(true)); + XMPMeta xmpMeta = GetXmpMetadata(true); XmpMetaInfoConverter.AppendDocumentInfoToMetadata(GetDocumentInfo(), xmpMeta); if (IsTagged() && writer.properties.addUAXmpMetadata && !IsXmpMetaHasProperty(xmpMeta, XMPConst.NS_PDFUA_ID , XMPConst.PART)) { diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfDocumentInfo.cs b/itext/itext.kernel/itext/kernel/pdf/PdfDocumentInfo.cs index 99bf3cadf9..98020a9dfe 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfDocumentInfo.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfDocumentInfo.cs @@ -31,7 +31,7 @@ public class PdfDocumentInfo { PdfName.Subject, PdfName.Keywords, PdfName.Creator, PdfName.Producer, PdfName.Trapped }; //\endcond - private PdfDictionary infoDictionary; + private readonly PdfDictionary infoDictionary; //\cond DO_NOT_DOCUMENT /// Create a PdfDocumentInfo based on the passed PdfDictionary. @@ -44,14 +44,6 @@ internal PdfDocumentInfo(PdfDictionary pdfObject, PdfDocument pdfDocument) { } //\endcond -//\cond DO_NOT_DOCUMENT - /// Create a default, empty PdfDocumentInfo and link it to the passed PdfDocument - /// document the info will belong to - internal PdfDocumentInfo(PdfDocument pdfDocument) - : this(new PdfDictionary(), pdfDocument) { - } -//\endcond - public virtual iText.Kernel.Pdf.PdfDocumentInfo SetTitle(String title) { return Put(PdfName.Title, new PdfString(title, PdfEncodings.UNICODE_BIG)); } diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfReader.cs b/itext/itext.kernel/itext/kernel/pdf/PdfReader.cs index 7e2098550b..2fb963602b 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfReader.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfReader.cs @@ -65,8 +65,6 @@ public class PdfReader : IDisposable { //indicate nearest first Indirect reference object which includes current reading the object, using for PdfString decrypt private PdfIndirectReference currentIndirectReference; - private XMPMeta xmpMeta; - private PdfReader.XrefProcessor xrefProcessor = new PdfReader.XrefProcessor(); protected internal PdfTokenizer tokens; @@ -85,8 +83,6 @@ public class PdfReader : IDisposable { protected internal PdfDocument pdfDocument; - protected internal PdfAConformanceLevel pdfAConformanceLevel; - protected internal ReaderProperties properties; protected internal bool encrypted = false; @@ -99,6 +95,10 @@ public class PdfReader : IDisposable { protected internal bool xrefStm = false; + private XMPMeta xmpMeta; + + private PdfAConformanceLevel pdfAConformanceLevel; + /// Constructs a new PdfReader. /// source of bytes for the reader /// properties of the created reader @@ -672,7 +672,7 @@ public virtual PdfAConformanceLevel GetPdfAConformanceLevel() { } try { if (xmpMeta == null && pdfDocument.GetXmpMetadata() != null) { - xmpMeta = XMPMetaFactory.ParseFromBuffer(pdfDocument.GetXmpMetadata()); + xmpMeta = pdfDocument.GetXmpMetadata(); } if (xmpMeta != null) { pdfAConformanceLevel = PdfAConformanceLevel.GetConformanceLevel(xmpMeta); diff --git a/itext/itext.kernel/itext/kernel/pdf/XmpMetaInfoConverter.cs b/itext/itext.kernel/itext/kernel/pdf/XmpMetaInfoConverter.cs index eef1c76e82..d5e1c5452f 100644 --- a/itext/itext.kernel/itext/kernel/pdf/XmpMetaInfoConverter.cs +++ b/itext/itext.kernel/itext/kernel/pdf/XmpMetaInfoConverter.cs @@ -34,10 +34,9 @@ private XmpMetaInfoConverter() { } //\cond DO_NOT_DOCUMENT - internal static void AppendMetadataToInfo(byte[] xmpMetadata, PdfDocumentInfo info) { - if (xmpMetadata != null) { + internal static void AppendMetadataToInfo(XMPMeta meta, PdfDocumentInfo info) { + if (meta != null) { try { - XMPMeta meta = XMPMetaFactory.ParseFromBuffer(xmpMetadata); XMPProperty title = meta.GetLocalizedText(XMPConst.NS_DC, PdfConst.Title, XMPConst.X_DEFAULT, XMPConst.X_DEFAULT ); if (title != null) { diff --git a/itext/itext.kernel/itext/kernel/utils/CompareTool.cs b/itext/itext.kernel/itext/kernel/utils/CompareTool.cs index a4bea38ae2..bea60a43f0 100644 --- a/itext/itext.kernel/itext/kernel/utils/CompareTool.cs +++ b/itext/itext.kernel/itext/kernel/utils/CompareTool.cs @@ -918,8 +918,8 @@ public virtual String CompareXmp(String outPdf, String cmpPdf, bool ignoreDateAn using (PdfReader readerOut = iText.Kernel.Utils.CompareTool.CreateOutputReader(this.outPdf)) { using (PdfDocument outDocument = new PdfDocument(readerOut, new DocumentProperties().SetEventCountingMetaInfo (metaInfo))) { - byte[] cmpBytes = cmpDocument.GetXmpMetadata(); - byte[] outBytes = outDocument.GetXmpMetadata(); + byte[] cmpBytes = cmpDocument.GetXmpMetadataBytes(); + byte[] outBytes = outDocument.GetXmpMetadataBytes(); if (ignoreDateAndProducerProperties) { XMPMeta xmpMeta = XMPMetaFactory.ParseFromBuffer(cmpBytes, new ParseOptions().SetOmitNormalization(true)); XMPUtils.RemoveProperties(xmpMeta, XMPConst.NS_XMP, PdfConst.CreateDate, true, true); diff --git a/itext/itext.pdfua/itext/pdfua/checkers/PdfUA1Checker.cs b/itext/itext.pdfua/itext/pdfua/checkers/PdfUA1Checker.cs index 0b9aeec0df..fc1d33ec95 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/PdfUA1Checker.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/PdfUA1Checker.cs @@ -147,14 +147,12 @@ protected internal virtual void CheckMetadata(PdfCatalog catalog) { if (catalog.GetDocument().GetPdfVersion().CompareTo(PdfVersion.PDF_1_7) > 0) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.INVALID_PDF_VERSION); } - PdfObject pdfMetadata = catalog.GetPdfObject().Get(PdfName.Metadata); - if (pdfMetadata == null || !pdfMetadata.IsStream()) { - throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.DOCUMENT_SHALL_CONTAIN_XMP_METADATA_STREAM - ); - } - byte[] metaBytes = ((PdfStream)pdfMetadata).GetBytes(); try { - XMPMeta metadata = XMPMetaFactory.ParseFromBuffer(metaBytes); + XMPMeta metadata = catalog.GetDocument().GetXmpMetadata(); + if (metadata == null) { + throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.DOCUMENT_SHALL_CONTAIN_XMP_METADATA_STREAM + ); + } int? part = metadata.GetPropertyInteger(XMPConst.NS_PDFUA_ID, XMPConst.PART); if (!Convert.ToInt32(1).Equals(part)) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.METADATA_SHALL_CONTAIN_UA_VERSION_IDENTIFIER diff --git a/port-hash b/port-hash index 8dd4a705d3..ad404a65e8 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -258d4b5833e7559914ee4084520aa564f8566b23 +e952e0abf98bab660a3cb892b6642e444a161f11 From 64cdc07ec4c507ee11869ac91ee8e6831a97efda Mon Sep 17 00:00:00 2001 From: Andrei Stryhelski Date: Thu, 5 Sep 2024 18:54:12 +0000 Subject: [PATCH 2/3] Fix Unsupported type of transformation exception, add a test DEVSIX-8590 Autoported commit. Original commit hash: [e009ccc4c] --- .../itext.svg.tests/itext/svg/utils/TransformUtilsTest.cs | 7 +++++++ itext/itext.svg/itext/svg/utils/TransformUtils.cs | 3 +++ port-hash | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/itext.tests/itext.svg.tests/itext/svg/utils/TransformUtilsTest.cs b/itext.tests/itext.svg.tests/itext/svg/utils/TransformUtilsTest.cs index 0cb7527916..f355307397 100644 --- a/itext.tests/itext.svg.tests/itext/svg/utils/TransformUtilsTest.cs +++ b/itext.tests/itext.svg.tests/itext/svg/utils/TransformUtilsTest.cs @@ -118,6 +118,13 @@ public virtual void CombinedReverseTransformTest() { NUnit.Framework.Assert.AreEqual(actual, expected); } + [NUnit.Framework.Test] + public virtual void CombinedReverseTransformWithCommaTest() { + AffineTransform actual = TransformUtils.ParseTransform("scale(3),translate(40,20)"); + AffineTransform expected = new AffineTransform(3d, 0d, 0d, 3d, 90d, 45d); + NUnit.Framework.Assert.AreEqual(actual, expected); + } + [NUnit.Framework.Test] public virtual void DoubleTransformationTest() { AffineTransform expected = new AffineTransform(9d, 0d, 0d, 9d, 0d, 0d); diff --git a/itext/itext.svg/itext/svg/utils/TransformUtils.cs b/itext/itext.svg/itext/svg/utils/TransformUtils.cs index c5fba3eb02..db57f76f43 100644 --- a/itext/itext.svg/itext/svg/utils/TransformUtils.cs +++ b/itext/itext.svg/itext/svg/utils/TransformUtils.cs @@ -148,6 +148,9 @@ private static IList SplitString(String transform) { while (tokenizer.HasMoreTokens()) { String trim = tokenizer.NextToken().Trim(); if (trim != null && !String.IsNullOrEmpty(trim)) { + if (trim.StartsWith(",")) { + trim = trim.Substring(1).Trim(); + } list.Add(trim + ")"); } } diff --git a/port-hash b/port-hash index ad404a65e8..6711724da3 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -e952e0abf98bab660a3cb892b6642e444a161f11 +e009ccc4cbe8c68a54496d09fcb56bcbcb8c5587 From 300f172a71cf3450a35939004feeb5cd3a5ff80c Mon Sep 17 00:00:00 2001 From: Angelina Pavlovets Date: Fri, 6 Sep 2024 14:36:35 +0000 Subject: [PATCH 3/3] Rework TagTreeIteratorApprover related logic DEVSIX-8569 Autoported commit. Original commit hash: [0af84b16d] --- .../pdf/tagutils/TagTreeIteratorTest.cs | 41 ++++++++------ .../itext/kernel/pdf/tagging/McrCheckUtil.cs | 8 ++- .../kernel/pdf/tagging/PdfStructTreeRoot.cs | 3 +- ...tAvoidDuplicatesTagTreeIteratorHandler.cs} | 47 ++++++++-------- .../pdf/tagutils/ITagTreeIteratorHandler.cs | 15 ++--- .../kernel/pdf/tagutils/TagTreeIterator.cs | 35 ++++-------- .../TagTreeIteratorElementApprover.cs | 56 ------------------- .../pdf/tagutils/TagTreeIteratorFlusher.cs | 38 +++++++++++-- .../kernel/pdf/tagutils/TagTreePointer.cs | 23 ++++---- .../kernel/pdf/tagutils/WaitingTagsManager.cs | 23 ++------ .../checkers/utils/AnnotationCheckUtil.cs | 14 +++-- .../ContextAwareTagTreeIteratorHandler.cs | 4 +- .../pdfua/checkers/utils/FormCheckUtil.cs | 14 +++-- .../pdfua/checkers/utils/FormulaCheckUtil.cs | 10 ++-- .../pdfua/checkers/utils/GraphicsCheckUtil.cs | 10 ++-- .../pdfua/checkers/utils/NoteCheckUtil.cs | 10 ++-- .../utils/headings/HeadingsChecker.cs | 8 ++- .../checkers/utils/tables/TableCheckUtil.cs | 10 ++-- port-hash | 2 +- 19 files changed, 168 insertions(+), 203 deletions(-) rename itext/itext.kernel/itext/kernel/pdf/tagutils/{TagTreeIteratorAvoidDuplicatesApprover.cs => AbstractAvoidDuplicatesTagTreeIteratorHandler.cs} (60%) delete mode 100644 itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorElementApprover.cs diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/tagutils/TagTreeIteratorTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/tagutils/TagTreeIteratorTest.cs index b4eea8fb34..ff5daed1b9 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/tagutils/TagTreeIteratorTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/tagutils/TagTreeIteratorTest.cs @@ -40,17 +40,6 @@ public virtual void TagTreeIteratorTagPointerNull() { NUnit.Framework.Assert.AreEqual(e.Message, errorMessage); } - [NUnit.Framework.Test] - public virtual void TagTreeIteratorApproverNull() { - String errorMessage = MessageFormatUtil.Format(KernelExceptionMessageConstant.ARG_SHOULD_NOT_BE_NULL, "approver" - ); - PdfDocument doc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream(), new WriterProperties())); - doc.SetTagged(); - Exception e = NUnit.Framework.Assert.Catch(typeof(ArgumentException), () => new TagTreeIterator(doc.GetStructTreeRoot - (), null, TagTreeIterator.TreeTraversalOrder.PRE_ORDER)); - NUnit.Framework.Assert.AreEqual(e.Message, errorMessage); - } - [NUnit.Framework.Test] public virtual void TagTreeIteratorHandlerNull() { String errorMessage = MessageFormatUtil.Format(KernelExceptionMessageConstant.ARG_SHOULD_NOT_BE_NULL, "handler" @@ -109,8 +98,8 @@ public virtual void PostOrderTraversal() { tp.MoveToParent(); tp.AddTag(StandardRoles.DIV); tp.AddTag(StandardRoles.CODE); - TagTreeIterator iterator = new TagTreeIterator(doc.GetStructTreeRoot(), new TagTreeIteratorElementApprover - (), TagTreeIterator.TreeTraversalOrder.POST_ORDER); + TagTreeIterator iterator = new TagTreeIterator(doc.GetStructTreeRoot(), TagTreeIterator.TreeTraversalOrder + .POST_ORDER); TagTreeIteratorTest.TestHandler handler = new TagTreeIteratorTest.TestHandler(); iterator.AddHandler(handler); iterator.Traverse(); @@ -134,9 +123,10 @@ public virtual void CyclicReferencesTraversal() { doc.GetStructTreeRoot().AddKid(kid2); kid1.AddKid(kid2); kid2.AddKid(kid1); - TagTreeIterator iterator = new TagTreeIterator(doc.GetStructTreeRoot(), new TagTreeIteratorAvoidDuplicatesApprover - (), TagTreeIterator.TreeTraversalOrder.POST_ORDER); - TagTreeIteratorTest.TestHandler handler = new TagTreeIteratorTest.TestHandler(); + TagTreeIterator iterator = new TagTreeIterator(doc.GetStructTreeRoot(), TagTreeIterator.TreeTraversalOrder + .POST_ORDER); + TagTreeIteratorTest.TestHandlerAvoidDuplicates handler = new TagTreeIteratorTest.TestHandlerAvoidDuplicates + (); iterator.AddHandler(handler); iterator.Traverse(); NUnit.Framework.Assert.AreEqual(3, handler.nodes.Count); @@ -151,9 +141,24 @@ internal class TestHandler : ITagTreeIteratorHandler { internal readonly IList nodes = new List(); //\endcond - public virtual bool NextElement(IStructureNode elem) { + public virtual bool Accept(IStructureNode node) { + return node != null; + } + + public virtual void ProcessElement(IStructureNode elem) { + nodes.Add(elem); + } + } +//\endcond + +//\cond DO_NOT_DOCUMENT + internal class TestHandlerAvoidDuplicates : AbstractAvoidDuplicatesTagTreeIteratorHandler { +//\cond DO_NOT_DOCUMENT + internal readonly IList nodes = new List(); +//\endcond + + public override void ProcessElement(IStructureNode elem) { nodes.Add(elem); - return true; } } //\endcond diff --git a/itext/itext.kernel/itext/kernel/pdf/tagging/McrCheckUtil.cs b/itext/itext.kernel/itext/kernel/pdf/tagging/McrCheckUtil.cs index 48a830f135..324c66b7a3 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagging/McrCheckUtil.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagging/McrCheckUtil.cs @@ -64,12 +64,14 @@ public McrTagHandler() { } //empty constructor - /// - public virtual bool NextElement(IStructureNode elem) { + public virtual bool Accept(IStructureNode node) { + return node != null; + } + + public virtual void ProcessElement(IStructureNode elem) { if ((elem is PdfMcr)) { haveMcr = true; } - return true; } } } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagging/PdfStructTreeRoot.cs b/itext/itext.kernel/itext/kernel/pdf/tagging/PdfStructTreeRoot.cs index 7e95ffa915..1c99ee9f07 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagging/PdfStructTreeRoot.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagging/PdfStructTreeRoot.cs @@ -587,8 +587,7 @@ protected internal override bool IsWrappedObjectMustBeIndirect() { } private static void FlushAllKids(iText.Kernel.Pdf.Tagging.PdfStructTreeRoot elem) { - TagTreeIterator iterator = new TagTreeIterator(elem, new TagTreeIteratorAvoidDuplicatesApprover(), TagTreeIterator.TreeTraversalOrder - .POST_ORDER); + TagTreeIterator iterator = new TagTreeIterator(elem, TagTreeIterator.TreeTraversalOrder.POST_ORDER); iterator.AddHandler(new TagTreeIteratorFlusher()); iterator.Traverse(); } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorAvoidDuplicatesApprover.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/AbstractAvoidDuplicatesTagTreeIteratorHandler.cs similarity index 60% rename from itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorAvoidDuplicatesApprover.cs rename to itext/itext.kernel/itext/kernel/pdf/tagutils/AbstractAvoidDuplicatesTagTreeIteratorHandler.cs index b3688c6bd5..151df950a7 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorAvoidDuplicatesApprover.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagutils/AbstractAvoidDuplicatesTagTreeIteratorHandler.cs @@ -26,43 +26,40 @@ You should have received a copy of the GNU Affero General Public License namespace iText.Kernel.Pdf.Tagutils { /// - /// Element checker for + /// Handler for /// . /// /// - /// Element checker for + /// Handler for /// . /// It is used to check whether specific element should be traversed. - /// It doesn't approve elements which have been traversed before. + /// It doesn't accept elements which have been traversed before. /// - public class TagTreeIteratorAvoidDuplicatesApprover : TagTreeIteratorElementApprover { + public abstract class AbstractAvoidDuplicatesTagTreeIteratorHandler : ITagTreeIteratorHandler { private readonly ICollection processedObjects = new HashSet(); - /// - /// Creates a new instance of - /// - /// - public TagTreeIteratorAvoidDuplicatesApprover() - : base() { - } - - /// - public override bool Approve(IStructureNode elem) { - if (elem is PdfStructTreeRoot) { + public virtual bool Accept(IStructureNode node) { + if (node is PdfStructTreeRoot) { return true; } - if (!base.Approve(elem) || !(elem is PdfStructElem)) { - return false; - } - PdfObject obj = ((PdfStructElem)elem).GetPdfObject(); - bool isProcessed = processedObjects.Contains(obj); - if (isProcessed) { - return false; - } else { - processedObjects.Add(obj); - return true; + if (!(node is PdfStructElem)) { + return false; + } + else { + PdfObject obj = ((PdfStructElem)node).GetPdfObject(); + bool isProcessed = processedObjects.Contains(obj); + if (isProcessed) { + return false; + } + else { + processedObjects.Add(obj); + return true; + } + } } } + + public abstract void ProcessElement(IStructureNode arg1); } } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/ITagTreeIteratorHandler.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/ITagTreeIteratorHandler.cs index 22c6222381..2c4c5b62ec 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/ITagTreeIteratorHandler.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagutils/ITagTreeIteratorHandler.cs @@ -33,18 +33,19 @@ namespace iText.Kernel.Pdf.Tagutils { /// Is used to handle specific events during the traversal. /// public interface ITagTreeIteratorHandler { - /// Called when the next element is reached during the traversal. - /// the next element + /// Checks whether the element should be traversed. + /// the element to check /// /// /// /// if the iteration should be continued, /// - /// otherwise. Note that this value - /// is relevant only in case - /// - /// is used for the traversal + /// otherwise /// - bool NextElement(IStructureNode elem); + bool Accept(IStructureNode node); + + /// Called when the next element is reached during the traversal to process it. + /// the element to process + void ProcessElement(IStructureNode elem); } } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIterator.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIterator.cs index ed7c889063..709c56df2c 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIterator.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIterator.cs @@ -38,8 +38,6 @@ public class TagTreeIterator { private readonly ICollection handlerList; - private readonly TagTreeIteratorElementApprover approver; - private readonly TagTreeIterator.TreeTraversalOrder traversalOrder; /// @@ -49,36 +47,24 @@ public class TagTreeIterator { /// /// Creates a new instance of /// - /// . It will use - /// - /// to filter - /// elements and TreeTraversalOrder.PRE_ORDER for tree traversal. + /// . It will use TreeTraversalOrder.PRE_ORDER for tree traversal. /// /// the tag tree pointer. public TagTreeIterator(IStructureNode tagTreePointer) - : this(tagTreePointer, new TagTreeIteratorElementApprover(), TagTreeIterator.TreeTraversalOrder.PRE_ORDER) { + : this(tagTreePointer, TagTreeIterator.TreeTraversalOrder.PRE_ORDER) { } /// /// Creates a new instance of /// . /// - /// the tag tree pointer. - /// - /// a filter that will be called to let iterator know whether some particular element - /// should be traversed or not. - /// + /// the tag tree pointer /// an order in which the tree will be traversed. - public TagTreeIterator(IStructureNode tagTreePointer, TagTreeIteratorElementApprover approver, TagTreeIterator.TreeTraversalOrder - traversalOrder) { + public TagTreeIterator(IStructureNode tagTreePointer, TagTreeIterator.TreeTraversalOrder traversalOrder) { if (tagTreePointer == null) { throw new ArgumentException(MessageFormatUtil.Format(KernelExceptionMessageConstant.ARG_SHOULD_NOT_BE_NULL , "tagTreepointer")); } - if (approver == null) { - throw new ArgumentException(MessageFormatUtil.Format(KernelExceptionMessageConstant.ARG_SHOULD_NOT_BE_NULL - , "approver")); - } if (traversalOrder == null) { throw new ArgumentException(MessageFormatUtil.Format(KernelExceptionMessageConstant.ARG_SHOULD_NOT_BE_NULL , "traversalOrder")); @@ -86,7 +72,6 @@ public TagTreeIterator(IStructureNode tagTreePointer, TagTreeIteratorElementAppr this.pointer = tagTreePointer; this.traversalOrder = traversalOrder; handlerList = new HashSet(); - this.approver = approver; } /// Adds a handler that will be called for the elements during the traversal. @@ -116,14 +101,14 @@ public virtual void Traverse() { } private void Traverse(IStructureNode elem) { - if (!approver.Approve(elem)) { - return; + foreach (ITagTreeIteratorHandler handler in handlerList) { + if (!handler.Accept(elem)) { + return; + } } if (traversalOrder == TagTreeIterator.TreeTraversalOrder.PRE_ORDER) { foreach (ITagTreeIteratorHandler handler in handlerList) { - if (!handler.NextElement(elem)) { - return; - } + handler.ProcessElement(elem); } } IList kids = elem.GetKids(); @@ -134,7 +119,7 @@ private void Traverse(IStructureNode elem) { } if (traversalOrder == TagTreeIterator.TreeTraversalOrder.POST_ORDER) { foreach (ITagTreeIteratorHandler handler in handlerList) { - handler.NextElement(elem); + handler.ProcessElement(elem); } } } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorElementApprover.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorElementApprover.cs deleted file mode 100644 index 5ff992fd1e..0000000000 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorElementApprover.cs +++ /dev/null @@ -1,56 +0,0 @@ -/* -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.Kernel.Pdf.Tagging; - -namespace iText.Kernel.Pdf.Tagutils { - /// - /// Element checker for - /// . - /// - /// - /// Element checker for - /// . - /// It is used to check whether specific element should be traversed. - /// - public class TagTreeIteratorElementApprover { - /// - /// Creates a new instance of - /// - /// - public TagTreeIteratorElementApprover() { - } - - // Empty constructor - /// Checks whether the element should be traversed. - /// the element to check - /// - /// - /// - /// if the element should be traversed, - /// false otherwise - /// - public virtual bool Approve(IStructureNode elem) { - return elem != null; - } - } -} diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorFlusher.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorFlusher.cs index 3ec7400e65..0ea6ed10cb 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorFlusher.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreeIteratorFlusher.cs @@ -20,6 +20,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ +using System.Collections.Generic; +using iText.Kernel.Pdf; using iText.Kernel.Pdf.Tagging; namespace iText.Kernel.Pdf.Tagutils { @@ -27,21 +29,47 @@ namespace iText.Kernel.Pdf.Tagutils { /// Class that flushes struct elements while iterating over struct tree root with /// . /// - public class TagTreeIteratorFlusher : ITagTreeIteratorHandler { + public class TagTreeIteratorFlusher : AbstractAvoidDuplicatesTagTreeIteratorHandler { + private ICollection waitingTags; + + private bool waitingTagsUsed = false; + /// /// Creates a new instance of - /// + /// . /// public TagTreeIteratorFlusher() { } // Empty constructor - /// - public virtual bool NextElement(IStructureNode elem) { + /// + /// Sets waiting tags for + /// . + /// + /// waiting tags to set + /// + /// this same + /// + /// instance + /// + public virtual ITagTreeIteratorHandler SetWaitingTags(ICollection waitingTags) { + this.waitingTags = waitingTags; + this.waitingTagsUsed = true; + return this; + } + + public override bool Accept(IStructureNode node) { + if (waitingTagsUsed) { + return base.Accept(node) && node is PdfStructElem && (waitingTags == null || !waitingTags.Contains(((PdfStructElem + )node).GetPdfObject())); + } + return base.Accept(node); + } + + public override void ProcessElement(IStructureNode elem) { if (elem is PdfStructElem && !((PdfStructElem)elem).IsFlushed()) { ((PdfStructElem)elem).Flush(); } - return true; } } } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreePointer.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreePointer.cs index 73f8c6d459..f326a1d721 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreePointer.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagutils/TagTreePointer.cs @@ -762,8 +762,8 @@ public virtual iText.Kernel.Pdf.Tagutils.TagTreePointer MoveToKid(int n, String throw new PdfException(KernelExceptionMessageConstant.CANNOT_MOVE_TO_MARKED_CONTENT_REFERENCE); } TagTreePointer.RoleFinderHandler handler = new TagTreePointer.RoleFinderHandler(n, role); - TagTreeIterator iterator = new TagTreeIterator(GetCurrentStructElem(), new TagTreeIteratorAvoidDuplicatesApprover - (), TagTreeIterator.TreeTraversalOrder.PRE_ORDER); + TagTreeIterator iterator = new TagTreeIterator(GetCurrentStructElem(), TagTreeIterator.TreeTraversalOrder. + PRE_ORDER); iterator.AddHandler(handler); iterator.Traverse(); PdfStructElem elem = handler.GetFoundElement(); @@ -1127,7 +1127,7 @@ private void ThrowExceptionIfCurrentPageIsNotInited() { } } - private class RoleFinderHandler : ITagTreeIteratorHandler { + private class RoleFinderHandler : AbstractAvoidDuplicatesTagTreeIteratorHandler { private readonly int n; private readonly String role; @@ -1143,19 +1143,22 @@ internal RoleFinderHandler(int n, String role) { } //\endcond - public virtual bool NextElement(IStructureNode elem) { + public virtual PdfStructElem GetFoundElement() { + return foundElem; + } + + public override bool Accept(IStructureNode node) { + return GetFoundElement() == null && base.Accept(node); + } + + public override void ProcessElement(IStructureNode elem) { if (foundElem != null) { - return false; + return; } String descendantRole = elem.GetRole().GetValue(); if (descendantRole.Equals(role) && foundIdx++ == n) { foundElem = (PdfStructElem)elem; } - return true; - } - - public virtual PdfStructElem GetFoundElement() { - return foundElem; } } } diff --git a/itext/itext.kernel/itext/kernel/pdf/tagutils/WaitingTagsManager.cs b/itext/itext.kernel/itext/kernel/pdf/tagutils/WaitingTagsManager.cs index 18afe508f4..b931a83b3e 100644 --- a/itext/itext.kernel/itext/kernel/pdf/tagutils/WaitingTagsManager.cs +++ b/itext/itext.kernel/itext/kernel/pdf/tagutils/WaitingTagsManager.cs @@ -38,9 +38,9 @@ namespace iText.Kernel.Pdf.Tagutils { /// Waiting state could also be perceived as a temporal association of the object to some particular tag. /// public class WaitingTagsManager { - private IDictionary associatedObjToWaitingTag; + private readonly IDictionary associatedObjToWaitingTag; - private IDictionary waitingTagToAssociatedObj; + private readonly IDictionary waitingTagToAssociatedObj; //\cond DO_NOT_DOCUMENT internal WaitingTagsManager() { @@ -222,9 +222,8 @@ private void FlushStructElementAndItKids(PdfStructElem elem) { if (waitingTagToAssociatedObj.ContainsKey(elem.GetPdfObject())) { return; } - TagTreeIterator iterator = new TagTreeIterator(elem, new WaitingTagsManager.WaitingTagsApprover(waitingTagToAssociatedObj - .Keys), TagTreeIterator.TreeTraversalOrder.POST_ORDER); - iterator.AddHandler(new TagTreeIteratorFlusher()); + TagTreeIterator iterator = new TagTreeIterator(elem, TagTreeIterator.TreeTraversalOrder.POST_ORDER); + iterator.AddHandler(new TagTreeIteratorFlusher().SetWaitingTags(waitingTagToAssociatedObj.Keys)); iterator.Traverse(); } @@ -237,19 +236,5 @@ private void RemoveWaitingStateAndFlushIfParentFlushed(PdfStructElem structElem) } } } - - private class WaitingTagsApprover : TagTreeIteratorAvoidDuplicatesApprover { - private readonly ICollection waitingTags; - - public WaitingTagsApprover(ICollection waitingTags) - : base() { - this.waitingTags = waitingTags; - } - - public override bool Approve(IStructureNode elem) { - return base.Approve(elem) && elem is PdfStructElem && (waitingTags == null || !waitingTags.Contains(((PdfStructElem - )elem).GetPdfObject())); - } - } } } diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/AnnotationCheckUtil.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/AnnotationCheckUtil.cs index d34433fa1e..e08f5f3084 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/AnnotationCheckUtil.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/AnnotationCheckUtil.cs @@ -84,15 +84,18 @@ public AnnotationHandler(PdfUAValidationContext context) : base(context) { } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { if (!(elem is PdfObjRef)) { - return true; + return; } PdfObjRef objRef = (PdfObjRef)elem; PdfDictionary annotObj = objRef.GetReferencedObject(); if (annotObj == null) { - return true; + return; } if (annotObj.GetAsDictionary(PdfName.P) != null) { PdfDictionary pageDict = annotObj.GetAsDictionary(PdfName.P); @@ -103,7 +106,7 @@ public override bool NextElement(IStructureNode elem) { } PdfName subtype = annotObj.GetAsName(PdfName.Subtype); if (!IsAnnotationVisible(annotObj) || PdfName.Popup.Equals(subtype)) { - return true; + return; } if (PdfName.PrinterMark.Equals(subtype)) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.PRINTER_MARK_IS_NOT_PERMITTED); @@ -132,7 +135,6 @@ public override bool NextElement(IStructureNode elem) { ActionCheckUtil.CheckAction(action); CheckAAEntry(additionalActions); } - return true; } private static void CheckAAEntry(PdfDictionary additionalActions) { diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/ContextAwareTagTreeIteratorHandler.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/ContextAwareTagTreeIteratorHandler.cs index a026d11866..314b2d9b63 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/ContextAwareTagTreeIteratorHandler.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/ContextAwareTagTreeIteratorHandler.cs @@ -37,6 +37,8 @@ protected internal ContextAwareTagTreeIteratorHandler(PdfUAValidationContext con this.context = context; } - public abstract bool NextElement(IStructureNode arg1); + public abstract bool Accept(IStructureNode arg1); + + public abstract void ProcessElement(IStructureNode arg1); } } diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/FormCheckUtil.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/FormCheckUtil.cs index 093a674cc0..59bb7b552d 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/FormCheckUtil.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/FormCheckUtil.cs @@ -48,19 +48,22 @@ public FormTagHandler(PdfUAValidationContext context) : base(context) { } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { PdfStructElem form = context.GetElementIfRoleMatches(PdfName.Form, elem); if (form == null) { - return true; + return; } PdfDictionary formField = GetInteractiveKidForm(form); if (formField == null) { - return true; + return; } // Check is not applicable for hidden annotations if (!AnnotationCheckUtil.IsAnnotationVisible(formField)) { - return true; + return; } // Parent check is required for the case when form field and widget annotation are split up. // It is still not 100% correct because TU is not inheritable thus shouldn't be taken into account @@ -72,7 +75,6 @@ public override bool NextElement(IStructureNode elem) { if (formField.Get(PdfName.TU) == null && !parentContainsTU && form.GetAlt() == null) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.MISSING_FORM_FIELD_DESCRIPTION); } - return true; } /// Gets a widget annotation kid if it exists. diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/FormulaCheckUtil.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/FormulaCheckUtil.cs index 327bfba210..e8f563d27c 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/FormulaCheckUtil.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/FormulaCheckUtil.cs @@ -61,17 +61,19 @@ public FormulaTagHandler(PdfUAValidationContext context) : base(context) { } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { PdfStructElem structElem = context.GetElementIfRoleMatches(PdfName.Formula, elem); if (structElem == null) { - return true; + return; } PdfDictionary pdfObject = structElem.GetPdfObject(); if (HasInvalidValues(pdfObject.GetAsString(PdfName.Alt), pdfObject.GetAsString(PdfName.ActualText))) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.FORMULA_SHALL_HAVE_ALT); } - return true; } } } diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/GraphicsCheckUtil.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/GraphicsCheckUtil.cs index 81c17f9b59..49d4cd853a 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/GraphicsCheckUtil.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/GraphicsCheckUtil.cs @@ -91,18 +91,20 @@ public GraphicsHandler(PdfUAValidationContext context) : base(context) { } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { PdfStructElem structElem = context.GetElementIfRoleMatches(PdfName.Figure, elem); if (structElem == null) { - return true; + return; } PdfDictionary pdfObject = structElem.GetPdfObject(); if (!HasAtleastOneValidValue(pdfObject.GetAsString(PdfName.Alt), pdfObject.GetAsString(PdfName.ActualText) )) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.IMAGE_SHALL_HAVE_ALT); } - return true; } } } diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/NoteCheckUtil.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/NoteCheckUtil.cs index dc3fc1d7f2..6c99a25843 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/NoteCheckUtil.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/NoteCheckUtil.cs @@ -39,17 +39,19 @@ public NoteTagHandler(PdfUAValidationContext context) : base(context) { } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { PdfStructElem structElem = context.GetElementIfRoleMatches(PdfName.Note, elem); if (structElem == null) { - return true; + return; } PdfDictionary pdfObject = structElem.GetPdfObject(); if (pdfObject.Get(PdfName.ID) == null) { throw new PdfUAConformanceException(PdfUAExceptionMessageConstants.NOTE_TAG_SHALL_HAVE_ID_ENTRY); } - return true; } } } diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/headings/HeadingsChecker.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/headings/HeadingsChecker.cs index 17abba6dab..17931fb119 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/headings/HeadingsChecker.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/headings/HeadingsChecker.cs @@ -170,10 +170,12 @@ public HeadingHandler(PdfUAValidationContext context) checker = new HeadingsChecker(context); } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { checker.CheckStructElement(elem); - return true; } } } diff --git a/itext/itext.pdfua/itext/pdfua/checkers/utils/tables/TableCheckUtil.cs b/itext/itext.pdfua/itext/pdfua/checkers/utils/tables/TableCheckUtil.cs index eff70d5941..5987abde9f 100644 --- a/itext/itext.pdfua/itext/pdfua/checkers/utils/tables/TableCheckUtil.cs +++ b/itext/itext.pdfua/itext/pdfua/checkers/utils/tables/TableCheckUtil.cs @@ -57,14 +57,16 @@ public TableHandler(PdfUAValidationContext context) : base(context) { } - /// - public override bool NextElement(IStructureNode elem) { + public override bool Accept(IStructureNode node) { + return node != null; + } + + public override void ProcessElement(IStructureNode elem) { PdfStructElem table = context.GetElementIfRoleMatches(PdfName.Table, elem); if (table == null) { - return true; + return; } new StructTreeResultMatrix((PdfStructElem)elem, context).CheckValidTableTagging(); - return true; } } } diff --git a/port-hash b/port-hash index 6711724da3..07b074bd51 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -e009ccc4cbe8c68a54496d09fcb56bcbcb8c5587 +0af84b16dc49ad7731dcd72fba6644e6079af932