This commit is contained in:
TheXamlGuy
2024-04-26 23:05:36 +01:00
parent 9f90ef693d
commit bc55c4649b
206 changed files with 3106 additions and 3204 deletions
@@ -1,48 +1,46 @@
using System;
namespace Gma.QrCodeNet.Encoding.DataEncodation;
public static class CharCountIndicatorTable
{
/// <remarks>ISO/IEC 18004:2000 Table 3 Page 18</remarks>
public static int[] GetCharCountIndicatorSet()
{
return new int[] { 8, 16, 16 };
}
/// <remarks>ISO/IEC 18004:2000 Table 3 Page 18</remarks>
public static int[] GetCharCountIndicatorSet()
{
return new int[] { 8, 16, 16 };
}
public static int GetBitCountInCharCountIndicator(int version)
{
int[] charCountIndicatorSet = GetCharCountIndicatorSet();
int versionGroup = GetVersionGroup(version);
public static int GetBitCountInCharCountIndicator(int version)
{
int[] charCountIndicatorSet = GetCharCountIndicatorSet();
int versionGroup = GetVersionGroup(version);
return charCountIndicatorSet[versionGroup];
}
return charCountIndicatorSet[versionGroup];
}
/// <summary>
/// Used to define length of the Character Count Indicator <see cref="GetBitCountInCharCountIndicator"/>
/// </summary>
/// <returns>Returns the 0 based index of the row from Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator. </returns>
private static int GetVersionGroup(int version)
{
if (version > 40)
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
else if (version >= 27)
{
return 2;
}
else if (version >= 10)
{
return 1;
}
else if (version > 0)
{
return 0;
}
else
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
}
}
/// <summary>
/// Used to define length of the Character Count Indicator <see cref="GetBitCountInCharCountIndicator"/>
/// </summary>
/// <returns>Returns the 0 based index of the row from Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator. </returns>
private static int GetVersionGroup(int version)
{
if (version > 40)
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
else if (version >= 27)
{
return 2;
}
else if (version >= 10)
{
return 1;
}
else if (version > 0)
{
return 0;
}
else
{
throw new InvalidOperationException($"Unexpected version: {version}.");
}
}
}
@@ -1,4 +1,3 @@
using System;
using Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
using Gma.QrCodeNet.Encoding.Terminate;
using Gma.QrCodeNet.Encoding.Versions;
@@ -10,53 +9,53 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
/// Which uses sub functions under several different namespaces</remarks>
internal static class DataEncode
{
internal static EncodationStruct Encode(string content, ErrorCorrectionLevel ecLevel)
{
RecognitionStruct recognitionResult = InputRecognise.Recognise(content);
EncoderBase encoderBase = CreateEncoder(recognitionResult.EncodingName);
internal static EncodationStruct Encode(string content, ErrorCorrectionLevel ecLevel)
{
RecognitionStruct recognitionResult = InputRecognise.Recognise(content);
EncoderBase encoderBase = CreateEncoder(recognitionResult.EncodingName);
BitList encodeContent = encoderBase.GetDataBits(content);
BitList encodeContent = encoderBase.GetDataBits(content);
int encodeContentLength = encodeContent.Count;
int encodeContentLength = encodeContent.Count;
VersionControlStruct vcStruct =
VersionControl.InitialSetup(encodeContentLength, ecLevel, recognitionResult.EncodingName);
VersionControlStruct vcStruct =
VersionControl.InitialSetup(encodeContentLength, ecLevel, recognitionResult.EncodingName);
BitList dataCodewords = new();
BitList dataCodewords = new();
// Eci header
if (vcStruct.IsContainECI && vcStruct.ECIHeader is { })
{
dataCodewords.Add(vcStruct.ECIHeader);
}
// Eci header
if (vcStruct.IsContainECI && vcStruct.ECIHeader is { })
{
dataCodewords.Add(vcStruct.ECIHeader);
}
// Header
dataCodewords.Add(encoderBase.GetModeIndicator());
int numLetter = encodeContentLength >> 3;
dataCodewords.Add(encoderBase.GetCharCountIndicator(numLetter, vcStruct.VersionDetail.Version));
// Header
dataCodewords.Add(encoderBase.GetModeIndicator());
int numLetter = encodeContentLength >> 3;
dataCodewords.Add(encoderBase.GetCharCountIndicator(numLetter, vcStruct.VersionDetail.Version));
// Data
dataCodewords.Add(encodeContent);
// Data
dataCodewords.Add(encodeContent);
// Terminator Padding
dataCodewords.TerminateBites(dataCodewords.Count, vcStruct.VersionDetail.NumDataBytes);
// Terminator Padding
dataCodewords.TerminateBites(dataCodewords.Count, vcStruct.VersionDetail.NumDataBytes);
int dataCodewordsCount = dataCodewords.Count;
if ((dataCodewordsCount & 0x7) != 0)
{
throw new ArgumentException($"{nameof(dataCodewords)} is not byte sized.");
}
else if (dataCodewordsCount >> 3 != vcStruct.VersionDetail.NumDataBytes)
{
throw new ArgumentException($"{nameof(dataCodewords)} num of bytes not equal to {nameof(vcStruct.VersionDetail.NumDataBytes)} for current version");
}
int dataCodewordsCount = dataCodewords.Count;
if ((dataCodewordsCount & 0x7) != 0)
{
throw new ArgumentException($"{nameof(dataCodewords)} is not byte sized.");
}
else if (dataCodewordsCount >> 3 != vcStruct.VersionDetail.NumDataBytes)
{
throw new ArgumentException($"{nameof(dataCodewords)} num of bytes not equal to {nameof(vcStruct.VersionDetail.NumDataBytes)} for current version");
}
var encStruct = new EncodationStruct(vcStruct, dataCodewords);
return encStruct;
}
var encStruct = new EncodationStruct(vcStruct, dataCodewords);
return encStruct;
}
private static EncoderBase CreateEncoder(string encodingName)
{
return new EightBitByteEncoder(encodingName);
}
}
private static EncoderBase CreateEncoder(string encodingName)
{
return new EightBitByteEncoder(encodingName);
}
}
@@ -1,255 +1,252 @@
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.DataEncodation;
public sealed class ECISet
{
/// <summary>
/// ISO/IEC 18004:2006 Chapter 6.4.2 Mode indicator = 0111 Page 23
/// </summary>
private const int ECIMode = 7;
/// <summary>
/// ISO/IEC 18004:2006 Chapter 6.4.2 Mode indicator = 0111 Page 23
/// </summary>
private const int ECIMode = 7;
private const int ECIIndicatorNumBits = 4;
private const int ECIIndicatorNumBits = 4;
private Dictionary<string, int>? _nameToValue;
private Dictionary<int, string>? _valueToName;
private Dictionary<string, int>? _nameToValue;
private Dictionary<int, string>? _valueToName;
/// <summary>
/// Initialize ECI Set.
/// </summary>
/// <param name="option">AppendOption is enum under ECISet
/// Use NameToValue during Encode. ValueToName during Decode</param>
internal ECISet(AppendOption option)
{
Initialize(option);
}
/// <summary>
/// Initialize ECI Set.
/// </summary>
/// <param name="option">AppendOption is enum under ECISet
/// Use NameToValue during Encode. ValueToName during Decode</param>
internal ECISet(AppendOption option)
{
Initialize(option);
}
public enum AppendOption
{
NameToValue,
ValueToName,
Both
}
public enum AppendOption
{
NameToValue,
ValueToName,
Both
}
/// <summary>
/// Length indicator for number of ECI codewords
/// </summary>
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.
/// 1 codeword length = 0. Any additional codeword add 1 to front. Eg: 3 = 110</remarks>
/// <description>Bits required for each one is:
/// one = 1, two = 2, three = 3</description>
private enum ECICodewordsLength
{
One = 0,
Two = 2,
Three = 6
}
/// <summary>
/// Length indicator for number of ECI codewords
/// </summary>
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.
/// 1 codeword length = 0. Any additional codeword add 1 to front. Eg: 3 = 110</remarks>
/// <description>Bits required for each one is:
/// one = 1, two = 2, three = 3</description>
private enum ECICodewordsLength
{
One = 0,
Two = 2,
Three = 6
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of Codewords(Byte) for ECI Assignment Value</returns>
private static int NumOfCodewords(int eCIValue)
{
if (eCIValue is >= 0 and <= 127)
{
return 1;
}
else if (eCIValue is > 127 and <= 16383)
{
return 2;
}
else if (eCIValue is > 16383 and <= 999999)
{
return 3;
}
else
{
throw new ArgumentOutOfRangeException($"{nameof(eCIValue)} should be in range: 0 to 999999.");
}
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of Codewords(Byte) for ECI Assignment Value</returns>
private static int NumOfCodewords(int eCIValue)
{
if (eCIValue is >= 0 and <= 127)
{
return 1;
}
else if (eCIValue is > 127 and <= 16383)
{
return 2;
}
else if (eCIValue is > 16383 and <= 999999)
{
return 3;
}
else
{
throw new ArgumentOutOfRangeException($"{nameof(eCIValue)} should be in range: 0 to 999999.");
}
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Assignment Value</returns>
private static int NumOfAssignmentBits(int eCIValue) => NumOfCodewords(eCIValue) * 8;
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Assignment Value</returns>
private static int NumOfAssignmentBits(int eCIValue) => NumOfCodewords(eCIValue) * 8;
private void AppendECI(string name, int value, AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue?.Add(name, value);
break;
private void AppendECI(string name, int value, AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue?.Add(name, value);
break;
case AppendOption.ValueToName:
_valueToName?.Add(value, name);
break;
case AppendOption.ValueToName:
_valueToName?.Add(value, name);
break;
case AppendOption.Both:
_nameToValue?.Add(name, value);
_valueToName?.Add(value, name);
break;
case AppendOption.Both:
_nameToValue?.Add(name, value);
_valueToName?.Add(value, name);
break;
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
}
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
}
private void Initialize(AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue = new Dictionary<string, int>();
break;
private void Initialize(AppendOption option)
{
switch (option)
{
case AppendOption.NameToValue:
_nameToValue = new Dictionary<string, int>();
break;
case AppendOption.ValueToName:
_valueToName = new Dictionary<int, string>();
break;
case AppendOption.ValueToName:
_valueToName = new Dictionary<int, string>();
break;
case AppendOption.Both:
_nameToValue = new Dictionary<string, int>();
_valueToName = new Dictionary<int, string>();
break;
case AppendOption.Both:
_nameToValue = new Dictionary<string, int>();
_valueToName = new Dictionary<int, string>();
break;
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
default:
throw new InvalidOperationException($"There is no such {nameof(AppendOption)}.");
}
// ECI table. Source 01 URL: http://strokescribe.com/en/ECI.html
// ECI table. Source 02 URL: http://lab.must.or.kr/Extended-Channel-Interpretations-ECI-Encoding.ashx
// ToDo. Fill up remaining missing table.
AppendECI("iso-8859-1", 1, option);
AppendECI("IBM437", 2, option);
// ECI table. Source 01 URL: http://strokescribe.com/en/ECI.html
// ECI table. Source 02 URL: http://lab.must.or.kr/Extended-Channel-Interpretations-ECI-Encoding.ashx
// ToDo. Fill up remaining missing table.
AppendECI("iso-8859-1", 1, option);
AppendECI("IBM437", 2, option);
// AppendECI("iso-8859-1", 3, option); //ECI value 1 is default encoding.
AppendECI("iso-8859-2", 4, option);
AppendECI("iso-8859-3", 5, option);
AppendECI("iso-8859-4", 6, option);
AppendECI("iso-8859-5", 7, option);
AppendECI("iso-8859-6", 8, option);
AppendECI("iso-8859-7", 9, option);
AppendECI("iso-8859-8", 10, option);
AppendECI("iso-8859-9", 11, option);
AppendECI("windows-874", 13, option);
AppendECI("iso-8859-13", 15, option);
AppendECI("iso-8859-15", 17, option);
AppendECI("shift_jis", 20, option);
AppendECI("utf-8", 26, option);
}
// AppendECI("iso-8859-1", 3, option); //ECI value 1 is default encoding.
AppendECI("iso-8859-2", 4, option);
AppendECI("iso-8859-3", 5, option);
AppendECI("iso-8859-4", 6, option);
AppendECI("iso-8859-5", 7, option);
AppendECI("iso-8859-6", 8, option);
AppendECI("iso-8859-7", 9, option);
AppendECI("iso-8859-8", 10, option);
AppendECI("iso-8859-9", 11, option);
AppendECI("windows-874", 13, option);
AppendECI("iso-8859-13", 15, option);
AppendECI("iso-8859-15", 17, option);
AppendECI("shift_jis", 20, option);
AppendECI("utf-8", 26, option);
}
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Header</returns>
internal static int NumOfECIHeaderBits(int eCIValue) => NumOfAssignmentBits(eCIValue) + 4;
/// <remarks>ISO/IEC 18004:2006E ECI Designator Page 24</remarks>
/// <param name="eCIValue">Range: 0 ~ 999999</param>
/// <returns>Number of bits for ECI Header</returns>
internal static int NumOfECIHeaderBits(int eCIValue) => NumOfAssignmentBits(eCIValue) + 4;
internal int GetECIValueByName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
internal int GetECIValueByName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
if (_nameToValue!.TryGetValue(encodingName, out int eCIValue))
{
return eCIValue;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain encoding: {encodingName}.");
}
}
if (_nameToValue!.TryGetValue(encodingName, out int eCIValue))
{
return eCIValue;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain encoding: {encodingName}.");
}
}
internal string GetECINameByValue(int eCIValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
internal string GetECINameByValue(int eCIValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
if (_valueToName!.TryGetValue(eCIValue, out var eCIName))
{
return eCIName;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain value: {eCIValue}.");
}
}
if (_valueToName!.TryGetValue(eCIValue, out var eCIName))
{
return eCIName;
}
else
{
throw new ArgumentOutOfRangeException($"ECI does not contain value: {eCIValue}.");
}
}
/// <returns>ECI table in Dictionary collection</returns>
public Dictionary<string, int>? GetECITable()
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
/// <returns>ECI table in Dictionary collection</returns>
public Dictionary<string, int>? GetECITable()
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
return _nameToValue;
}
return _nameToValue;
}
public bool ContainsECIName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
public bool ContainsECIName(string encodingName)
{
if (_nameToValue is null)
{
Initialize(AppendOption.NameToValue);
}
return _nameToValue!.ContainsKey(encodingName);
}
return _nameToValue!.ContainsKey(encodingName);
}
public bool ContainsECIValue(int eciValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
public bool ContainsECIValue(int eciValue)
{
if (_valueToName is null)
{
Initialize(AppendOption.ValueToName);
}
return _valueToName!.ContainsKey(eciValue);
}
return _valueToName!.ContainsKey(eciValue);
}
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.</remarks>
internal BitList GetECIHeader(string encodingName)
{
int eciValue = GetECIValueByName(encodingName);
/// <remarks>ISO/IEC 18004:2006 Chapter 6.4.2 Page 24.</remarks>
internal BitList GetECIHeader(string encodingName)
{
int eciValue = GetECIValueByName(encodingName);
BitList dataBits = new()
{
{ ECIMode, ECIIndicatorNumBits }
};
BitList dataBits = new()
{
{ ECIMode, ECIIndicatorNumBits }
};
int eciAssignmentByte = NumOfCodewords(eciValue);
int eciAssignmentByte = NumOfCodewords(eciValue);
// Number of bits = Num codewords indicator + codeword value = Number of codewords * 8
// Chapter 6.4.2.1 ECI Designator ISOIEC 18004:2006 Page 24
int eciAssignmentBits;
switch (eciAssignmentByte)
{
case 1:
// Indicator = 0. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.One, 1);
eciAssignmentBits = (eciAssignmentByte * 8) - 1;
break;
// Number of bits = Num codewords indicator + codeword value = Number of codewords * 8
// Chapter 6.4.2.1 ECI Designator ISOIEC 18004:2006 Page 24
int eciAssignmentBits;
switch (eciAssignmentByte)
{
case 1:
// Indicator = 0. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.One, 1);
eciAssignmentBits = (eciAssignmentByte * 8) - 1;
break;
case 2:
// Indicator = 10. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Two, 2);
eciAssignmentBits = (eciAssignmentByte * 8) - 2;
break;
case 2:
// Indicator = 10. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Two, 2);
eciAssignmentBits = (eciAssignmentByte * 8) - 2;
break;
case 3:
// Indicator = 110. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Three, 3);
eciAssignmentBits = (eciAssignmentByte * 8) - 3;
break;
case 3:
// Indicator = 110. Page 24. Chapter 6.4.2.1
dataBits.Add((int)ECICodewordsLength.Three, 3);
eciAssignmentBits = (eciAssignmentByte * 8) - 3;
break;
default:
throw new InvalidOperationException("Assignment Codewords should be either 1, 2 or 3.");
}
default:
throw new InvalidOperationException("Assignment Codewords should be either 1, 2 or 3.");
}
dataBits.Add(eciValue, eciAssignmentBits);
dataBits.Add(eciValue, eciAssignmentBits);
return dataBits;
}
}
return dataBits;
}
}
@@ -1,5 +1,3 @@
using System;
namespace Gma.QrCodeNet.Encoding.DataEncodation;
/// <summary>
@@ -14,67 +12,67 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
/// <remarks>ISO/IEC 18004:2000 Chapter 8.4.4 Page 22</remarks>
internal class EightBitByteEncoder : EncoderBase
{
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
private const string DefaultEncoding = QRCodeConstantVariable.DefaultEncoding;
/// <summary>
/// Bitcount, Chapter 8.4.4, P.24
/// </summary>
private const int EightBitByteBitcount = 8;
/// <summary>
/// Bitcount, Chapter 8.4.4, P.24
/// </summary>
private const int EightBitByteBitcount = 8;
/// <summary>
/// EightBitByte encoder's encoding will change according to different region
/// </summary>
/// <param name="encoding">Default encoding is "iso-8859-1"</param>
internal EightBitByteEncoder(string encoding) : base()
{
Encoding = encoding ?? DefaultEncoding;
}
/// <summary>
/// EightBitByte encoder's encoding will change according to different region
/// </summary>
/// <param name="encoding">Default encoding is "iso-8859-1"</param>
internal EightBitByteEncoder(string encoding) : base()
{
Encoding = encoding ?? DefaultEncoding;
}
internal EightBitByteEncoder() : base()
{
Encoding = DefaultEncoding;
}
internal EightBitByteEncoder() : base()
{
Encoding = DefaultEncoding;
}
internal string Encoding { get; private set; }
internal string Encoding { get; private set; }
protected byte[] EncodeContent(string content, string encoding) => System.Text.Encoding.GetEncoding(encoding).GetBytes(content);
protected byte[] EncodeContent(string content, string encoding) => System.Text.Encoding.GetEncoding(encoding).GetBytes(content);
internal override BitList GetDataBits(string content)
{
var eciSet = new ECISet(ECISet.AppendOption.NameToValue);
if (!eciSet.ContainsECIName(Encoding))
{
throw new ArgumentOutOfRangeException(
nameof(Encoding),
$"Current ECI table does not support this encoding. Please check {nameof(ECISet)} class for more info.");
}
internal override BitList GetDataBits(string content)
{
var eciSet = new ECISet(ECISet.AppendOption.NameToValue);
if (!eciSet.ContainsECIName(Encoding))
{
throw new ArgumentOutOfRangeException(
nameof(Encoding),
$"Current ECI table does not support this encoding. Please check {nameof(ECISet)} class for more info.");
}
byte[] contentBytes = EncodeContent(content, Encoding);
byte[] contentBytes = EncodeContent(content, Encoding);
return GetDataBitsByByteArray(contentBytes, Encoding);
}
return GetDataBitsByByteArray(contentBytes, Encoding);
}
internal BitList GetDataBitsByByteArray(byte[] encodeContent, string encodingName)
{
var dataBits = new BitList();
internal BitList GetDataBitsByByteArray(byte[] encodeContent, string encodingName)
{
var dataBits = new BitList();
// Current plan for UTF8 support is put Byte order Mark in front of content byte.
// Also include ECI header before encoding header. Which will be add with encoding header.
if (encodingName == "utf-8")
{
byte[] utf8BOM = QRCodeConstantVariable.UTF8ByteOrderMark;
for (int index = 0; index < utf8BOM.Length; index++)
{
dataBits.Add(utf8BOM[index], EightBitByteBitcount);
}
}
// Current plan for UTF8 support is put Byte order Mark in front of content byte.
// Also include ECI header before encoding header. Which will be add with encoding header.
if (encodingName == "utf-8")
{
byte[] utf8BOM = QRCodeConstantVariable.UTF8ByteOrderMark;
for (int index = 0; index < utf8BOM.Length; index++)
{
dataBits.Add(utf8BOM[index], EightBitByteBitcount);
}
}
for (int index = 0; index < encodeContent.Length; index++)
{
dataBits.Add(encodeContent[index], EightBitByteBitcount);
}
return dataBits;
}
for (int index = 0; index < encodeContent.Length; index++)
{
dataBits.Add(encodeContent[index], EightBitByteBitcount);
}
return dataBits;
}
protected override int GetBitCountInCharCountIndicator(int version) => CharCountIndicatorTable.GetBitCountInCharCountIndicator(version);
}
protected override int GetBitCountInCharCountIndicator(int version) => CharCountIndicatorTable.GetBitCountInCharCountIndicator(version);
}
@@ -4,12 +4,12 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
internal struct EncodationStruct
{
internal EncodationStruct(VersionControlStruct vcStruct, BitList dataCodewords)
{
VersionDetail = vcStruct.VersionDetail;
DataCodewords = dataCodewords;
}
internal EncodationStruct(VersionControlStruct vcStruct, BitList dataCodewords)
{
VersionDetail = vcStruct.VersionDetail;
DataCodewords = dataCodewords;
}
internal VersionDetail VersionDetail { get; set; }
internal BitList DataCodewords { get; set; }
}
internal VersionDetail VersionDetail { get; set; }
internal BitList DataCodewords { get; set; }
}
@@ -2,45 +2,45 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation;
public abstract class EncoderBase
{
internal EncoderBase()
{
}
internal EncoderBase()
{
}
protected virtual int GetDataLength(string content) => content.Length;
protected virtual int GetDataLength(string content) => content.Length;
/// <summary>
/// Returns the bit representation of input data.
/// </summary>
internal abstract BitList GetDataBits(string content);
/// <summary>
/// Returns the bit representation of input data.
/// </summary>
internal abstract BitList GetDataBits(string content);
/// <summary>
/// Returns bit representation of Modevalue.
/// </summary>
/// <remarks>See Chapter 8.4 Data encodation, Table 2 — Mode indicators</remarks>
internal BitList GetModeIndicator()
{
BitList modeIndicatorBits = new()
{
{ 0001 << 2, 4 }
};
return modeIndicatorBits;
}
/// <summary>
/// Returns bit representation of Modevalue.
/// </summary>
/// <remarks>See Chapter 8.4 Data encodation, Table 2 — Mode indicators</remarks>
internal BitList GetModeIndicator()
{
BitList modeIndicatorBits = new()
{
{ 0001 << 2, 4 }
};
return modeIndicatorBits;
}
internal BitList GetCharCountIndicator(int characterCount, int version)
{
BitList characterCountBits = new();
int bitCount = GetBitCountInCharCountIndicator(version);
characterCountBits.Add(characterCount, bitCount);
return characterCountBits;
}
internal BitList GetCharCountIndicator(int characterCount, int version)
{
BitList characterCountBits = new();
int bitCount = GetBitCountInCharCountIndicator(version);
characterCountBits.Add(characterCount, bitCount);
return characterCountBits;
}
/// <summary>
/// Defines the length of the Character Count Indicator,
/// which varies according to the mode and the symbol version in use
/// </summary>
/// <returns>Number of bits in Character Count Indicator.</returns>
/// <remarks>
/// See Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator.
/// </remarks>
protected abstract int GetBitCountInCharCountIndicator(int version);
}
/// <summary>
/// Defines the length of the Character Count Indicator,
/// which varies according to the mode and the symbol version in use
/// </summary>
/// <returns>Number of bits in Character Count Indicator.</returns>
/// <remarks>
/// See Chapter 8.4 Data encodation, Table 3 — Number of bits in Character Count Indicator.
/// </remarks>
protected abstract int GetBitCountInCharCountIndicator(int version);
}
@@ -1,57 +1,54 @@
using System;
using System.Collections.Generic;
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
public static class InputRecognise
{
public static RecognitionStruct Recognise(string content)
{
string encodingName = EightBitByteRecognision(content, 0, content.Length);
return new RecognitionStruct(encodingName);
}
public static RecognitionStruct Recognise(string content)
{
string encodingName = EightBitByteRecognision(content, 0, content.Length);
return new RecognitionStruct(encodingName);
}
private static string EightBitByteRecognision(string content, int startPos, int contentLength)
{
if(string.IsNullOrEmpty(content))
private static string EightBitByteRecognision(string content, int startPos, int contentLength)
{
if (string.IsNullOrEmpty(content))
throw new ArgumentNullException(nameof(content));
var eciSets = new ECISet(ECISet.AppendOption.NameToValue);
var eciSets = new ECISet(ECISet.AppendOption.NameToValue);
Dictionary<string, int>? eciSet = eciSets.GetECITable();
Dictionary<string, int>? eciSet = eciSets.GetECITable();
if(eciSet == null)
if (eciSet == null)
return string.Empty;
// we will not check for utf8 encoding.
eciSet.Remove(QRCodeConstantVariable.UTF8Encoding);
eciSet.Remove(QRCodeConstantVariable.DefaultEncoding);
// we will not check for utf8 encoding.
eciSet.Remove(QRCodeConstantVariable.UTF8Encoding);
eciSet.Remove(QRCodeConstantVariable.DefaultEncoding);
int scanPos = startPos;
int scanPos = startPos;
// default encoding as priority
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, QRCodeConstantVariable.DefaultEncoding, scanPos, contentLength);
if (scanPos == -1)
{
return QRCodeConstantVariable.DefaultEncoding;
}
// default encoding as priority
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, QRCodeConstantVariable.DefaultEncoding, scanPos, contentLength);
if (scanPos == -1)
{
return QRCodeConstantVariable.DefaultEncoding;
}
foreach (KeyValuePair<string, int> kvp in eciSet)
{
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, kvp.Key, scanPos, contentLength);
if (scanPos == -1)
{
return kvp.Key;
}
}
foreach (KeyValuePair<string, int> kvp in eciSet)
{
scanPos = ModeEncodeCheck.TryEncodeEightBitByte(content, kvp.Key, scanPos, contentLength);
if (scanPos == -1)
{
return kvp.Key;
}
}
if (scanPos == -1)
{
throw new ArgumentException("foreach Loop check give wrong result.");
}
else
{
return QRCodeConstantVariable.UTF8Encoding;
}
}
}
if (scanPos == -1)
{
throw new ArgumentException("foreach Loop check give wrong result.");
}
else
{
return QRCodeConstantVariable.UTF8Encoding;
}
}
}
@@ -1,72 +1,70 @@
using System;
namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
public static class ModeEncodeCheck
{
/// <summary>
/// Encoding.GetEncoding.GetBytes will transform char to 0x3F if that char not belong to current encoding table.
/// 0x3F is '?'
/// </summary>
private const int QuestionMarkChar = 0x3F;
/// <summary>
/// Encoding.GetEncoding.GetBytes will transform char to 0x3F if that char not belong to current encoding table.
/// 0x3F is '?'
/// </summary>
private const int QuestionMarkChar = 0x3F;
/// <summary>
/// Use given encoding to check input string from starting position. If encoding table is suitable solution.
/// it will return -1. Else it will return failed encoding position.
/// </summary>
/// <param name="content">Input string</param>
/// <param name="encodingName">Encoding name. Check ECI table</param>
/// <returns>Returns -1 if from starting position to end encoding success. Else returns fail position</returns>
internal static int TryEncodeEightBitByte(string content, string encodingName, int startingPosition, int contentLength)
{
if (string.IsNullOrEmpty(content))
{
throw new IndexOutOfRangeException("Input cannot be null or empty.");
}
/// <summary>
/// Use given encoding to check input string from starting position. If encoding table is suitable solution.
/// it will return -1. Else it will return failed encoding position.
/// </summary>
/// <param name="content">Input string</param>
/// <param name="encodingName">Encoding name. Check ECI table</param>
/// <returns>Returns -1 if from starting position to end encoding success. Else returns fail position</returns>
internal static int TryEncodeEightBitByte(string content, string encodingName, int startingPosition, int contentLength)
{
if (string.IsNullOrEmpty(content))
{
throw new IndexOutOfRangeException("Input cannot be null or empty.");
}
System.Text.Encoding encoding;
try
{
encoding = System.Text.Encoding.GetEncoding(encodingName);
}
catch (ArgumentException)
{
return startingPosition;
}
System.Text.Encoding encoding;
try
{
encoding = System.Text.Encoding.GetEncoding(encodingName);
}
catch (ArgumentException)
{
return startingPosition;
}
char[] currentChar = new char[1];
byte[] bytes;
char[] currentChar = new char[1];
byte[] bytes;
for (int index = startingPosition; index < contentLength; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
for (int index = startingPosition; index < contentLength; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
for (int index = 0; index < startingPosition; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
for (int index = 0; index < startingPosition; index++)
{
currentChar[0] = content[index];
bytes = encoding.GetBytes(currentChar);
int length = bytes.Length;
if (currentChar[0] != '?' && length == 1 && bytes[0] == QuestionMarkChar)
{
return index;
}
else if (length > 1)
{
return index;
}
}
return -1;
}
}
return -1;
}
}
@@ -2,11 +2,11 @@ namespace Gma.QrCodeNet.Encoding.DataEncodation.InputRecognition;
public struct RecognitionStruct
{
public RecognitionStruct(string encodingName)
: this()
{
EncodingName = encodingName;
}
public RecognitionStruct(string encodingName)
: this()
{
EncodingName = encodingName;
}
public string EncodingName { get; private set; }
}
public string EncodingName { get; private set; }
}