From b943576d424508758708a2adeec5fef66c0d58c5 Mon Sep 17 00:00:00 2001 From: Artyom Barmazel Date: Sun, 12 Jan 2025 22:27:53 +0000 Subject: [PATCH 1/3] =?UTF-8?q?Bug:=20Empty=20PdfString=20decodes=20into?= =?UTF-8?q?=20a=20string=20of=2064=20=C3=AF=20characters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More info: https://stackoverflow.com/q/76690294/1722457 DEVSIX-8732 Autoported commit. Original commit hash: [caeec7501] --- .../itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs | 8 ++++++++ itext/itext.kernel/itext/kernel/pdf/PdfString.cs | 3 +++ port-hash | 2 +- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs index 89c96d371..af2c920ce 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs @@ -262,5 +262,13 @@ public virtual void WriteUtf8ActualText() { NUnit.Framework.Assert.IsNull(new CompareTool().CompareByContent(destinationFolder + "writeUtf8ActualText.pdf" , sourceFolder + "cmp_writeUtf8ActualText.pdf", destinationFolder, "diffActualText_")); } + + [NUnit.Framework.Test] + public virtual void EmptyHexWriting() { + PdfString @string = new PdfString(""); + NUnit.Framework.Assert.AreEqual("", @string.ToUnicodeString()); + @string.SetHexWriting(true); + NUnit.Framework.Assert.AreEqual("", @string.ToUnicodeString()); + } } } diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfString.cs b/itext/itext.kernel/itext/kernel/pdf/PdfString.cs index 60a9c75b5..698e7c7d6 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfString.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfString.cs @@ -326,6 +326,9 @@ protected internal virtual byte[] DecodeContent() { /// byte array to manipulate with. /// Hexadecimal string or string with escaped symbols in byte array view. protected internal virtual byte[] EncodeBytes(byte[] bytes) { + if (bytes.Length == 0) { + return bytes; + } if (hexWriting) { ByteBuffer buf = new ByteBuffer(bytes.Length * 2); foreach (byte b in bytes) { diff --git a/port-hash b/port-hash index 21f7d0595..820975649 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -86e2d518cf3bf4ca60842b4e1084a7f57db35fba +caeec750161bc5e252833820d7db85e2cd878283 From 82ef90ffdaeee180c1f3d3b0ff2f2f7081f576f4 Mon Sep 17 00:00:00 2001 From: Guust Ysebie Date: Sun, 12 Jan 2025 22:30:17 +0000 Subject: [PATCH 2/3] Add null check DEVSIX-8732 Autoported commit. Original commit hash: [b0f983bc1] --- .../itext/kernel/pdf/PdfStringTest.cs | 11 ++++++ .../itext/signatures/sign/SignDeferredTest.cs | 38 +++++++++++-------- .../itext/kernel/pdf/PdfString.cs | 6 +++ port-hash | 2 +- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs index af2c920ce..01418e33b 100644 --- a/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs +++ b/itext.tests/itext.kernel.tests/itext/kernel/pdf/PdfStringTest.cs @@ -26,6 +26,7 @@ You should have received a copy of the GNU Affero General Public License using iText.IO.Font.Constants; using iText.IO.Image; using iText.Kernel.Colors; +using iText.Kernel.Exceptions; using iText.Kernel.Font; using iText.Kernel.Geom; using iText.Kernel.Pdf.Canvas; @@ -270,5 +271,15 @@ public virtual void EmptyHexWriting() { @string.SetHexWriting(true); NUnit.Framework.Assert.AreEqual("", @string.ToUnicodeString()); } + + [NUnit.Framework.Test] + public virtual void NullHexWriting() { + PdfString @string = new PdfString("hello"); + Exception e = NUnit.Framework.Assert.Catch(typeof(PdfException), () => { + @string.EncodeBytes(null); + } + ); + NUnit.Framework.Assert.AreEqual("byte[] should not be null.", e.Message); + } } } diff --git a/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs b/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs index 21d1e1a20..97464fb37 100644 --- a/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs +++ b/itext.tests/itext.sign.tests/itext/signatures/sign/SignDeferredTest.cs @@ -21,6 +21,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ using System; +using System.Collections.Generic; using System.IO; using iText.Commons.Bouncycastle.Cert; using iText.Commons.Bouncycastle.Crypto; @@ -105,23 +106,13 @@ public virtual void PrepareDocForSignDeferredNotEnoughSizeTest() { [NUnit.Framework.Test] public virtual void PrepareDocForSignDeferredLittleSpaceTest() { String input = sourceFolder + "helloWorldDoc.pdf"; - String sigFieldName = "DeferredSignature1"; - PdfName filter = PdfName.Adobe_PPKLite; - PdfName subFilter = PdfName.Adbe_pkcs7_detached; PdfReader reader = new PdfReader(input); - PdfSigner signer = new PdfSigner(reader, new MemoryStream(), new StampingProperties()); - SignerProperties signerProperties = new SignerProperties().SetFieldName(sigFieldName); - signer.SetSignerProperties(signerProperties); - SignatureFieldAppearance appearance = new SignatureFieldAppearance(SignerProperties.IGNORED_ID).SetContent - ("Signature field which signing is deferred."); - signerProperties.SetPageRect(new Rectangle(36, 600, 200, 100)).SetPageNumber(1).SetSignatureAppearance(appearance - ); - IExternalSignatureContainer external = new ExternalBlankSignatureContainer(filter, subFilter); - // This size is definitely not enough, however, the size check will pass. - // The test will fail lately on an invalid key - int estimatedSize = 0; - Exception e = NUnit.Framework.Assert.Catch(typeof(ArgumentException), () => signer.SignExternalContainer(external - , estimatedSize)); + SignDeferredTest.DummySigner dummySigner = new SignDeferredTest.DummySigner(reader, new MemoryStream(), new + StampingProperties()); + PdfDictionary content = new PdfDictionary(); + content.Put(PdfName.Contents, new PdfString("test")); + Exception e = NUnit.Framework.Assert.Catch(typeof(ArgumentException), () => dummySigner.DummyClose(content + )); NUnit.Framework.Assert.AreEqual(SignExceptionMessageConstant.TOO_BIG_KEY, e.Message); } @@ -343,5 +334,20 @@ public virtual void ModifySigningDictionary(PdfDictionary signDic) { } } //\endcond + +//\cond DO_NOT_DOCUMENT + internal class DummySigner : PdfSigner { + public DummySigner(PdfReader reader, Stream outputStream, StampingProperties properties) + : base(reader, outputStream, properties) { + } + + public virtual void DummyClose(PdfDictionary content) { + preClosed = true; + exclusionLocations = new Dictionary(); + exclusionLocations.Put(PdfName.Contents, new PdfLiteral(1)); + Close(content); + } + } +//\endcond } } diff --git a/itext/itext.kernel/itext/kernel/pdf/PdfString.cs b/itext/itext.kernel/itext/kernel/pdf/PdfString.cs index 698e7c7d6..413990219 100644 --- a/itext/itext.kernel/itext/kernel/pdf/PdfString.cs +++ b/itext/itext.kernel/itext/kernel/pdf/PdfString.cs @@ -22,9 +22,11 @@ You should have received a copy of the GNU Affero General Public License */ using System; using System.Text; +using iText.Commons.Utils; using iText.IO.Font; using iText.IO.Source; using iText.IO.Util; +using iText.Kernel.Exceptions; using iText.Kernel.Utils; namespace iText.Kernel.Pdf { @@ -326,6 +328,10 @@ protected internal virtual byte[] DecodeContent() { /// byte array to manipulate with. /// Hexadecimal string or string with escaped symbols in byte array view. protected internal virtual byte[] EncodeBytes(byte[] bytes) { + if (bytes == null) { + throw new PdfException(MessageFormatUtil.Format(KernelExceptionMessageConstant.ARG_SHOULD_NOT_BE_NULL, "byte[]" + )); + } if (bytes.Length == 0) { return bytes; } diff --git a/port-hash b/port-hash index 820975649..e3d912b19 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -caeec750161bc5e252833820d7db85e2cd878283 +b0f983bc1149da54d374193a5d64dd78e5c47015 From 66744c0c398f2dcb338acd7b2ae344b0eca322ba Mon Sep 17 00:00:00 2001 From: Guust Ysebie Date: Mon, 13 Jan 2025 04:25:20 +0000 Subject: [PATCH 3/3] Rename rendering mode to display option DEVSIX-8745 Autoported commit. Original commit hash: [e78a4b7fe] --- .../renderer/SignatureAppearanceRenderer.cs | 56 +++++++++---------- port-hash | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/itext/itext.forms/itext/forms/form/renderer/SignatureAppearanceRenderer.cs b/itext/itext.forms/itext/forms/form/renderer/SignatureAppearanceRenderer.cs index dc97f9982..ee16e8aa3 100644 --- a/itext/itext.forms/itext/forms/form/renderer/SignatureAppearanceRenderer.cs +++ b/itext/itext.forms/itext/forms/form/renderer/SignatureAppearanceRenderer.cs @@ -50,7 +50,7 @@ public class SignatureAppearanceRenderer : AbstractTextFieldRenderer { private const float EPS = 1e-5f; - private readonly SignatureAppearanceRenderer.RenderingMode renderingMode; + private readonly SignatureAppearanceRenderer.DisplayOption displayOption; private bool isFontSizeApproximated = false; @@ -62,7 +62,7 @@ public class SignatureAppearanceRenderer : AbstractTextFieldRenderer { /// the model element public SignatureAppearanceRenderer(SignatureFieldAppearance modelElement) : base(modelElement) { - renderingMode = RetrieveRenderingMode(); + displayOption = RetrieveRenderingMode(); } /// @@ -114,9 +114,9 @@ protected internal override void AdjustFieldLayout(LayoutContext layoutContext) } Rectangle descriptionRect = null; Rectangle signatureRect = null; - switch (renderingMode) { - case SignatureAppearanceRenderer.RenderingMode.NAME_AND_DESCRIPTION: - case SignatureAppearanceRenderer.RenderingMode.GRAPHIC_AND_DESCRIPTION: { + switch (displayOption) { + case SignatureAppearanceRenderer.DisplayOption.NAME_AND_DESCRIPTION: + case SignatureAppearanceRenderer.DisplayOption.GRAPHIC_AND_DESCRIPTION: { // Split the signature field into two and add the name of the signer or an image to the one side, // the description to the other side. UnitValue[] paddings = GetPaddings(); @@ -140,13 +140,13 @@ protected internal override void AdjustFieldLayout(LayoutContext layoutContext) break; } - case SignatureAppearanceRenderer.RenderingMode.GRAPHIC: { + case SignatureAppearanceRenderer.DisplayOption.GRAPHIC: { // The signature field will consist of an image only; no description will be shown. signatureRect = bBox; break; } - case SignatureAppearanceRenderer.RenderingMode.DESCRIPTION: { + case SignatureAppearanceRenderer.DisplayOption.DESCRIPTION: { // Default one, it just shows whatever description was defined for the signature. float additionalHeight = CalculateAdditionalHeight(); if (RetrieveHeight() == null) { @@ -167,7 +167,7 @@ protected internal override void AdjustFieldLayout(LayoutContext layoutContext) return; } } - AdjustChildrenLayout(renderingMode, signatureRect, descriptionRect, layoutContext.GetArea().GetPageNumber( + AdjustChildrenLayout(displayOption, signatureRect, descriptionRect, layoutContext.GetArea().GetPageNumber( )); } @@ -232,10 +232,10 @@ protected internal override void ApplyAcroField(DrawContext drawContext) { FormFieldRendererUtil.ReapplyProperties(modelElement, properties); } - private void AdjustChildrenLayout(SignatureAppearanceRenderer.RenderingMode renderingMode, Rectangle signatureRect + private void AdjustChildrenLayout(SignatureAppearanceRenderer.DisplayOption displayOption, Rectangle signatureRect , Rectangle descriptionRect, int pageNum) { - switch (renderingMode) { - case SignatureAppearanceRenderer.RenderingMode.NAME_AND_DESCRIPTION: { + switch (displayOption) { + case SignatureAppearanceRenderer.DisplayOption.NAME_AND_DESCRIPTION: { ParagraphRenderer name = (ParagraphRenderer)flatRenderer.GetChildRenderers()[0]; RelayoutParagraph(name, signatureRect, pageNum); ParagraphRenderer description = (ParagraphRenderer)flatRenderer.GetChildRenderers()[1]; @@ -243,14 +243,14 @@ private void AdjustChildrenLayout(SignatureAppearanceRenderer.RenderingMode rend break; } - case SignatureAppearanceRenderer.RenderingMode.GRAPHIC_AND_DESCRIPTION: { + case SignatureAppearanceRenderer.DisplayOption.GRAPHIC_AND_DESCRIPTION: { RelayoutImage(signatureRect, pageNum); ParagraphRenderer description = (ParagraphRenderer)flatRenderer.GetChildRenderers()[1]; RelayoutParagraph(description, descriptionRect, pageNum); break; } - case SignatureAppearanceRenderer.RenderingMode.GRAPHIC: { + case SignatureAppearanceRenderer.DisplayOption.GRAPHIC: { RelayoutImage(signatureRect, pageNum); break; } @@ -338,8 +338,8 @@ private void ApproximateFontSizeToFitLayoutArea(LayoutContext layoutContext) { if (this.HasOwnProperty(Property.FONT_SIZE) || modelElement.HasOwnProperty(Property.FONT_SIZE)) { return; } - if (SignatureAppearanceRenderer.RenderingMode.GRAPHIC == renderingMode || SignatureAppearanceRenderer.RenderingMode - .GRAPHIC_AND_DESCRIPTION == renderingMode || SignatureAppearanceRenderer.RenderingMode.CUSTOM == renderingMode + if (SignatureAppearanceRenderer.DisplayOption.GRAPHIC == displayOption || SignatureAppearanceRenderer.DisplayOption + .GRAPHIC_AND_DESCRIPTION == displayOption || SignatureAppearanceRenderer.DisplayOption.CUSTOM == displayOption ) { // We can expect CLIP_ELEMENT log messages since the initial image size may be larger than the field height. // But image size will be adjusted during its relayout in #adjustFieldLayout. @@ -352,38 +352,38 @@ private void ApproximateFontSizeToFitLayoutArea(LayoutContext layoutContext) { } } - private SignatureAppearanceRenderer.RenderingMode RetrieveRenderingMode() { + private SignatureAppearanceRenderer.DisplayOption RetrieveRenderingMode() { IList contentElements = ((SignatureFieldAppearance)modelElement).GetContentElements(); if (contentElements.Count == 2 && contentElements[1] is Paragraph) { if (contentElements[0] is Paragraph) { - return SignatureAppearanceRenderer.RenderingMode.NAME_AND_DESCRIPTION; + return SignatureAppearanceRenderer.DisplayOption.NAME_AND_DESCRIPTION; } if (contentElements[0] is Image) { - return SignatureAppearanceRenderer.RenderingMode.GRAPHIC_AND_DESCRIPTION; + return SignatureAppearanceRenderer.DisplayOption.GRAPHIC_AND_DESCRIPTION; } } if (contentElements.Count == 1) { if (contentElements[0] is Paragraph) { - return SignatureAppearanceRenderer.RenderingMode.DESCRIPTION; + return SignatureAppearanceRenderer.DisplayOption.DESCRIPTION; } if (contentElements[0] is Image) { - return SignatureAppearanceRenderer.RenderingMode.GRAPHIC; + return SignatureAppearanceRenderer.DisplayOption.GRAPHIC; } } - return SignatureAppearanceRenderer.RenderingMode.CUSTOM; + return SignatureAppearanceRenderer.DisplayOption.CUSTOM; } - /// Signature rendering modes. - private enum RenderingMode { - /// The rendering mode is just the description. + /// Signature display options. + private enum DisplayOption { + /// The display option is just the description. DESCRIPTION, - /// The rendering mode is the name of the signer and the description. + /// The display option is the name of the signer and the description. NAME_AND_DESCRIPTION, - /// The rendering mode is an image and the description. + /// The display option is an image and the description. GRAPHIC_AND_DESCRIPTION, - /// The rendering mode is just an image. + /// The display option is just an image. GRAPHIC, - /// The rendering mode is div. + /// The display option is div. CUSTOM } } diff --git a/port-hash b/port-hash index e3d912b19..1829f2252 100644 --- a/port-hash +++ b/port-hash @@ -1 +1 @@ -b0f983bc1149da54d374193a5d64dd78e5c47015 +e78a4b7fe88d0ac47d4083cb01603adb40483bfc