Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Fix character encoding when EciMode is specified #514

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 11 additions & 31 deletions QRCoder/QRCodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1015,19 +1015,7 @@ private static int GetCountIndicatorLength(int version, EncodingMode encMode)

private static int GetDataLength(EncodingMode encoding, string plainText, string codedText, bool forceUtf8)
{
return forceUtf8 || IsUtf8(encoding, plainText, forceUtf8) ? (codedText.Length / 8) : plainText.Length;
}

private static bool IsUtf8(EncodingMode encoding, string plainText, bool forceUtf8)
{
return (encoding == EncodingMode.Byte && (!IsValidISO(plainText) || forceUtf8));
}

private static bool IsValidISO(string input)
{
var bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(input);
var result = Encoding.GetEncoding("ISO-8859-1").GetString(bytes);
return String.Equals(input, result);
return encoding == EncodingMode.Byte ? (codedText.Length / 8) : plainText.Length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return encoding == EncodingMode.Byte ? (codedText.Length / 8) : plainText.Length;
return encoding == EncodingMode.Byte ? (int)((uint)codedText.Length / 8) : plainText.Length;

do we care about such things here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes; we certainly can optimize this PR also.

I need to come back to this PR; but for now I was leaving it alone until I'm finished with performance PRs.

}

private static string PlainTextToBinary(string plainText, EncodingMode encMode, EciMode eciMode, bool utf8BOM, bool forceUtf8)
Expand Down Expand Up @@ -1100,37 +1088,30 @@ private string PlainTextToBinaryECI(string plainText)
return codeText;
}

private static string ConvertToIso8859(string value, string Iso = "ISO-8859-2")
{
Encoding iso = Encoding.GetEncoding(Iso);
Encoding utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(value);
byte[] isoBytes = Encoding.Convert(utf8, iso, utfBytes);
return iso.GetString(isoBytes);
}

private static string PlainTextToBinaryByte(string plainText, EciMode eciMode, bool utf8BOM, bool forceUtf8)
{
byte[] codeBytes;
var codeText = string.Empty;

if (IsValidISO(plainText) && !forceUtf8)
codeBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(plainText);
if (eciMode == EciMode.Utf8 || (eciMode == EciMode.Default && forceUtf8))
codeBytes = utf8BOM ? Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(plainText)).ToArray() : Encoding.UTF8.GetBytes(plainText);
else
{
switch(eciMode)
{
case EciMode.Default: // per spec, ISO-8859-1 is default
case EciMode.Iso8859_1:
codeBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(ConvertToIso8859(plainText, "ISO-8859-1"));
#if NET5_0_OR_GREATER
codeBytes = Encoding.Latin1.GetBytes(plainText);
#else
codeBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(plainText);
#endif
break;
case EciMode.Iso8859_2:
codeBytes = Encoding.GetEncoding("ISO-8859-2").GetBytes(ConvertToIso8859(plainText, "ISO-8859-2"));
codeBytes = Encoding.GetEncoding("ISO-8859-2").GetBytes(plainText);
break;
case EciMode.Default:
case EciMode.Utf8:
default:
codeBytes = utf8BOM ? Encoding.UTF8.GetPreamble().Concat(Encoding.UTF8.GetBytes(plainText)).ToArray() : Encoding.UTF8.GetBytes(plainText);
break;
throw new ArgumentOutOfRangeException(nameof(eciMode));
}
}

Expand All @@ -1140,7 +1121,6 @@ private static string PlainTextToBinaryByte(string plainText, EciMode eciMode, b
return codeText;
}


private static Polynom XORPolynoms(Polynom messagePolynom, Polynom resPolynom)
{
var resultPolynom = new Polynom();
Expand Down
31 changes: 31 additions & 0 deletions QRCoderTests/QRGeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Collections;
using System.Text;
using System.IO;

namespace QRCoderTests
{
Expand Down Expand Up @@ -143,6 +144,36 @@ public void can_generate_from_bytes()
var result = string.Join("", qrData.ModuleMatrix.Select(x => x.ToBitString()).ToArray());
result.ShouldBe("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111011001011111110000000010000010010010100000100000000101110101010101011101000000001011101010010010111010000000010111010111000101110100000000100000100000001000001000000001111111010101011111110000000000000000011000000000000000000111100101010010011101000000001011100001001001001110000000010101011111011111110100000000000101000000110000000000000001011001001010100110000000000000000000110001000101000000000111111100110011011110000000001000001001111110111010000000010111010011100100101100000000101110101110010010010000000001011101011010100011000000000010000010110110101000100000000111111101011100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}

[Fact]
[Category("QRGenerator/TextEncoding")]
public void can_encode_latin1()
{
var gen = new QRCodeGenerator();
var qrData = gen.CreateQrCode("https://en.wikipedia.org/wiki/È", QRCodeGenerator.ECCLevel.L);
var result = string.Join("", qrData.ModuleMatrix.Select(x => x.ToBitString()).ToArray());
result.ShouldBe("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111110011110110011111110000000010000010001111111010000010000000010111010110010100010111010000000010111010011000110010111010000000010111010011101110010111010000000010000010010111010010000010000000011111110101010101011111110000000000000000110001110000000000000000011101111101111000110001000000000010110000000011001110000010000000010110110010000100101101110000000010111101000101110110000100000000001101010000111111010010110000000000110000100010001110010010000000010100011000001000101001110000000001001000011011000110100100000000010101011010001011111110000000000000000000100010011000110110000000011111110100001011010110110000000010000010100011101000110010000000010111010101111001111110100000000010111010010001100001111000000000010111010100001100100100010000000010000010100011011000110100000000011111110101011011101000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}

[Fact]
[Category("QRGenerator/TextEncoding")]
public void can_encode_utf_notForced()
{
var gen = new QRCodeGenerator();
var qrData = gen.CreateQrCode("https://en.wikipedia.org/wiki/È", QRCodeGenerator.ECCLevel.L, eciMode: QRCodeGenerator.EciMode.Utf8);
var result = string.Join("", qrData.ModuleMatrix.Select(x => x.ToBitString()).ToArray());
result.ShouldBe("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111110010011001011001111111000000001000001000111011101000100000100000000101110101110111011111010111010000000010111010011101110011101011101000000001011101000100010000010101110100000000100000100100010000110010000010000000011111110101010101010101111111000000000000000011101110111010000000000000000111011111011001111100110001000000000011001101101100110101011010010000000000101011011000100110111100101100000000000010010001000101001011000010000000010110011000010001100111000111000000000010010111011101011110101001000000000011100111101101111101110010000000000010010101011011110000111001011000000001101101000110011010000011011100000000011110001001001001111000000100000000010110111010001001100111001001000000000100110101110001111011100101100000000100110110110100101001111110010000000000000000101111001111100011010000000001111111011111011110010101101100000000100000101010111000011000111110000000010111010101100100010111110000000000001011101001110011011011101100000000000101110101100010111011101000010000000010000010101100001000000110101000000001111111010001000011000001101100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}

[Fact]
[Category("QRGenerator/TextEncoding")]
public void can_encode_utf_forced()
{
var gen = new QRCodeGenerator();
var qrData = gen.CreateQrCode("https://en.wikipedia.org/wiki/È", QRCodeGenerator.ECCLevel.L, forceUtf8: true, eciMode: QRCodeGenerator.EciMode.Utf8);
var result = string.Join("", qrData.ModuleMatrix.Select(x => x.ToBitString()).ToArray());
result.ShouldBe("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111110010011001011001111111000000001000001000111011101000100000100000000101110101110111011111010111010000000010111010011101110011101011101000000001011101000100010000010101110100000000100000100100010000110010000010000000011111110101010101010101111111000000000000000011101110111010000000000000000111011111011001111100110001000000000011001101101100110101011010010000000000101011011000100110111100101100000000000010010001000101001011000010000000010110011000010001100111000111000000000010010111011101011110101001000000000011100111101101111101110010000000000010010101011011110000111001011000000001101101000110011010000011011100000000011110001001001001111000000100000000010110111010001001100111001001000000000100110101110001111011100101100000000100110110110100101001111110010000000000000000101111001111100011010000000001111111011111011110010101101100000000100000101010111000011000111110000000010111010101100100010111110000000000001011101001110011011011101100000000000101110101100010111011101000010000000010000010101100001000000110101000000001111111010001000011000001101100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
}

public static class ExtensionMethods
Expand Down