From 6f4634e622b7f165048004d933f59a8a593f1a22 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 30 Dec 2024 20:55:58 +0100 Subject: [PATCH] port SHA-1: 3b189fc700c9c7c210f4b78fc66b01f4c13ae5d2 * PDF417: Check that input is made of 0...127 chars when using Compaction.TEXT, throw an explicit exception if not the case (#1878) * throw a more explicit exception when trying to PDF417/TEXT encode something outside of 0...255 * refactor PDF417HighLevelEncoder to avoid code duplication extend UT to new method PDF417HighLevelEncoder#checkCharset * fix javadoc typo make UT more stringent on PDF417HighLevelEncoder#checkCharset * restrict TEXT to 0...127 test with CP437 and Greek chars * reinstate testEncodeAuto UT * refactor testEncodeAuto UT * address codacy findings * formatting --- Source/lib/Properties/AssemblyInfo.cs | 2 +- .../pdf417/encoder/PDF417HighLevelEncoder.cs | 36 ++++-- .../pdf417/encoder/PDF417EncoderTestCase.cs | 107 +++++++++++++++++- 3 files changed, 129 insertions(+), 16 deletions(-) diff --git a/Source/lib/Properties/AssemblyInfo.cs b/Source/lib/Properties/AssemblyInfo.cs index 1defa47d..dfbc50c3 100644 --- a/Source/lib/Properties/AssemblyInfo.cs +++ b/Source/lib/Properties/AssemblyInfo.cs @@ -52,7 +52,7 @@ #if NETFX_CORE && !WINDOWS_UWP [assembly: AssemblyTitle("zxing.net for windows rt")] #endif -[assembly: AssemblyDescription("port of the java based barcode scanning library for .net (java zxing 19.10.2024 03:38:56)")] +[assembly: AssemblyDescription("port of the java based barcode scanning library for .net (java zxing 22.10.2024 15:24:36)")] [assembly: AssemblyCompany("ZXing.Net Development")] [assembly: AssemblyProduct("ZXing.Net")] [assembly: AssemblyCopyright("Copyright © 2012")] diff --git a/Source/lib/pdf417/encoder/PDF417HighLevelEncoder.cs b/Source/lib/pdf417/encoder/PDF417HighLevelEncoder.cs index c83c36d7..6cf243c7 100644 --- a/Source/lib/pdf417/encoder/PDF417HighLevelEncoder.cs +++ b/Source/lib/pdf417/encoder/PDF417HighLevelEncoder.cs @@ -21,6 +21,7 @@ using System; #if (NET40 || NET45 || NET46 || NET47 || NET48 || NETFX_CORE || NETSTANDARD) && !NETSTANDARD1_0 using System.Numerics; + #else using BigIntegerLibrary; #endif @@ -184,18 +185,16 @@ internal static String encodeHighLevel(String msg, Compaction compaction, Encodi throw new ArgumentException("Empty message not allowed"); } + if (Compaction.TEXT == compaction) + { + checkCharset(msg, 127, "Consider specifying Compaction.AUTO instead of Compaction.TEXT"); + } + if (encoding == null && !autoECI) { - for (int i = 0; i < msg.Length; i++) - { - if (msg[i] > 255) - { - throw new WriterException("Non-encodable character detected: " + msg[i] + " (Unicode: " + - (int)msg[i] + - "). Consider specifying EncodeHintType.PDF417_AUTO_ECI and/or EncodeTypeHint.CHARACTER_SET."); - } - } + checkCharset(msg, 255, "Consider specifying EncodeHintType.PDF417_AUTO_ECI and/or EncodeTypeHint.CHARACTER_SET"); } + encoding = ECIEncoderSet.Clone(encoding); // needed because of ECIEncoderSet.canEncode //the codewords 0..928 are encoded as Unicode characters @@ -367,6 +366,25 @@ private static byte[] toBytes(char msg, Encoding encoding) return getEncoder(encoding).GetBytes(new[] { msg }); } + /// + /// Check if input is only made of characters between 0 and the upper limit + /// + /// the input + /// the upper limit for charset + /// the message to explain the error + /// exception highlighting the offending character and a suggestion to avoid the error + internal static void checkCharset(String input, int max, String errorMessage) + { + for (int i = 0; i < input.Length; i++) + { + if (input[i] > max) + { + throw new WriterException("Non-encodable character detected: " + input[i] + " (Unicode: " + + (int)input[i] + ") at position #" + i + " - " + errorMessage); + } + } + } + /// /// Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E), /// chapter 4.4.2. diff --git a/Source/test/src/pdf417/encoder/PDF417EncoderTestCase.cs b/Source/test/src/pdf417/encoder/PDF417EncoderTestCase.cs index 21038847..8e999061 100644 --- a/Source/test/src/pdf417/encoder/PDF417EncoderTestCase.cs +++ b/Source/test/src/pdf417/encoder/PDF417EncoderTestCase.cs @@ -18,25 +18,120 @@ using System.Text; using NUnit.Framework; +using ZXing.Common; namespace ZXing.PDF417.Internal.Test { public sealed class PDF417EncoderTestCase { + private static String PDF417PFX = "\u039f\u001A\u0385"; + [Test] public void testEncodeAuto() { - var encoded = PDF417HighLevelEncoder.encodeHighLevel( - "ABCD", Compaction.AUTO, Encoding.UTF8, false, false); - Assert.AreEqual("\u039f\u001A\u0385ABCD", encoded); + var input = "ABCD"; + Assert.That(checkEncodeAutoWithSpecialChars(input, Compaction.AUTO), Is.EqualTo(PDF417PFX + input)); } [Test] public void testEncodeAutoWithSpecialChars() { - //Just check if this does not throw an exception - PDF417HighLevelEncoder.encodeHighLevel( - "1%§s ?aG$", Compaction.AUTO, Encoding.UTF8, false, false); + // Just check if this does not throw an exception + checkEncodeAutoWithSpecialChars("1%§s ?aG$", Compaction.AUTO); + checkEncodeAutoWithSpecialChars("日本語", Compaction.AUTO); + checkEncodeAutoWithSpecialChars("₸ 5555", Compaction.AUTO); + checkEncodeAutoWithSpecialChars("€ 123,45", Compaction.AUTO); + checkEncodeAutoWithSpecialChars("€ 123,45", Compaction.BYTE); + checkEncodeAutoWithSpecialChars("123,45", Compaction.TEXT); + + // Greek alphabet + var cp437 = CharacterSetECI.getEncoding("IBM437"); + Assert.That(cp437, Is.Not.Null); + byte[] cp437Array = { (byte)224, (byte)225, (byte)226, (byte)227, (byte)228 }; //αßΓπΣ + var greek = cp437.GetString(cp437Array); + Assert.That("αßΓπΣ", Is.EqualTo(greek)); + checkEncodeAutoWithSpecialChars(greek, Compaction.AUTO); + checkEncodeAutoWithSpecialChars(greek, Compaction.BYTE); + PDF417HighLevelEncoder.encodeHighLevel(greek, Compaction.AUTO, cp437, false, true); + PDF417HighLevelEncoder.encodeHighLevel(greek, Compaction.AUTO, cp437, false, false); + + try + { + // detect when a TEXT Compaction is applied to a non text input + checkEncodeAutoWithSpecialChars("€ 123,45", Compaction.TEXT); + } + catch (WriterException e) + { + Assert.That(e.Message, Is.Not.Null); + Assert.That(e.Message.Contains("8364"), Is.True); + Assert.That(e.Message.Contains("Compaction.TEXT"), Is.True); + Assert.That(e.Message.Contains("Compaction.AUTO"), Is.True); + } + + try + { + // detect when a TEXT Compaction is applied to a non text input + var input = "Hello! " + (char)128; + checkEncodeAutoWithSpecialChars(input, Compaction.TEXT); + } + catch (WriterException e) + { + Assert.That(e.Message, Is.Not.Null); + Assert.That(e.Message.Contains("128"), Is.True); + Assert.That(e.Message.Contains("Compaction.TEXT"), Is.True); + Assert.That(e.Message.Contains("Compaction.AUTO"), Is.True); + } + + try + { + // detect when a TEXT Compaction is applied to a non text input + // https://github.com/zxing/zxing/issues/1761 + var content = "€ 123,45"; + var hints = new System.Collections.Generic.Dictionary(); + hints[EncodeHintType.ERROR_CORRECTION] = 4; + hints[EncodeHintType.PDF417_DIMENSIONS] = new Dimensions(7, 7, 1, 300); + hints[EncodeHintType.MARGIN] = 0; + hints[EncodeHintType.CHARACTER_SET] = "ISO-8859-15"; + hints[EncodeHintType.PDF417_COMPACTION] = Compaction.TEXT; + + (new MultiFormatWriter()).encode(content, BarcodeFormat.PDF_417, 200, 100, hints); + } + catch (WriterException e) + { + Assert.That(e.Message, Is.Not.Null); + Assert.That(e.Message.Contains("8364"), Is.True); + Assert.That(e.Message.Contains("Compaction.TEXT"), Is.True); + Assert.That(e.Message.Contains("Compaction.AUTO"), Is.True); + } + } + + public String checkEncodeAutoWithSpecialChars(String input, Compaction compaction) + { + return PDF417HighLevelEncoder.encodeHighLevel(input, compaction, Encoding.UTF8, false, false); + } + + [Test] + public void testCheckCharset() + { + var input = "Hello!"; + var errorMessage = Guid.NewGuid().ToString(); + + // no exception + PDF417HighLevelEncoder.checkCharset(input, 255, errorMessage); + PDF417HighLevelEncoder.checkCharset(input, 1255, errorMessage); + PDF417HighLevelEncoder.checkCharset(input, 111, errorMessage); + + try + { + // should throw an exception for character 'o' because it exceeds upper limit 110 + PDF417HighLevelEncoder.checkCharset(input, 110, errorMessage); + } + catch (WriterException e) + { + Assert.That(e.Message, Is.Not.Null); + Assert.That(e.Message.Contains("111"), Is.True); + Assert.That(e.Message.Contains(errorMessage), Is.True); + } } [Test]