diff --git a/.idea/.idea.auspostcode.dir/.idea/workspace.xml b/.idea/.idea.auspostcode.dir/.idea/workspace.xml
index e3bdc7c..610d25d 100644
--- a/.idea/.idea.auspostcode.dir/.idea/workspace.xml
+++ b/.idea/.idea.auspostcode.dir/.idea/workspace.xml
@@ -20,12 +20,9 @@
-
-
-
-
+
@@ -40,6 +37,7 @@
+
1602593942454
-
+
1602597326777
@@ -150,86 +148,86 @@
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
diff --git a/Barcode.cs b/Barcode.cs
index 57f0d87..f3d65e7 100644
--- a/Barcode.cs
+++ b/Barcode.cs
@@ -5,14 +5,27 @@ using System.Text.RegularExpressions;
namespace AusPostCode {
public class Barcode {
- public enum BarcodeFragment {
- FormatControlCode,
- SortingCode,
- CustomerInformation,
- ErrorCorrection,
+ private readonly struct BarcodeFragment {
+ public EncodingFormat TypicalFormat { get; }
+ public int Length { get;}
+ public int Offset { get; }
+
+ public BarcodeFragment(EncodingFormat typicalFormat, int length, int offset) {
+ TypicalFormat = typicalFormat;
+ Length = length;
+ Offset = offset;
+ }
}
- public enum EncodingFormat {
+ private readonly Dictionary _fragments = new Dictionary {
+ ["FormatControlCode"] = new BarcodeFragment(EncodingFormat.N, 4, 2),
+ ["SortingCode"] = new BarcodeFragment(EncodingFormat.N, 16, 6),
+ ["CustomerInformation2"] = new BarcodeFragment(EncodingFormat.C, 16, 22),
+ ["CustomerInformation3"] = new BarcodeFragment(EncodingFormat.C, 31, 22),
+ ["ErrorCorrection"] = new BarcodeFragment(EncodingFormat.BarToDecimal, 12, - 16),
+ };
+
+ private enum EncodingFormat {
N,
C,
BarToDecimal,
@@ -20,7 +33,7 @@ namespace AusPostCode {
private int _formatCode;
- public Dictionary FormatTable = new Dictionary {
+ private readonly Dictionary _formatTable = new Dictionary {
[0] = "Null Customer Barcode",
[11] = "Standard Customer Barcode",
[52] = "Customer Business Reply Paid",
@@ -45,31 +58,82 @@ namespace AusPostCode {
}
// process Format Control Code
- _formatCode = int.Parse(Decode(GetFragment(BarcodeFragment.FormatControlCode), EncodingFormat.N));
+ _formatCode = int.Parse(GetFragment(_fragments["FormatControlCode"]));
Console.WriteLine(Format);
// process Sorting Code Field
- SortingCode = int.Parse(Decode(GetFragment(BarcodeFragment.SortingCode), EncodingFormat.N));
+ SortingCode = int.Parse(GetFragment(_fragments["SortingCode"]));
Console.WriteLine($"Sorting code: {SortingCode}");
+
+ // process Customer Information, if necessary
+ // TODO: actually do this, and get a code to test it on. also, ensure that customer codes are the right length
+ if (_formatCode == 59) {
+ Console.WriteLine("This code has a Customer Information field, but I don't know how to process that yet 0uo");
+ } else if (_formatCode == 62) {
+ Console.WriteLine("This code has a Customer Information field, but I don't know how to process that yet 0uo");
+ }
+
+ // process Reed-Solomon Error Correction Bars
+ // TODO: actually validate the barcode
+ Console.WriteLine(BaseConversion.FromBase(GetFragment(_fragments["ErrorCorrection"]), 64));
+
}
public int SortingCode { get; set; }
public int CustomerInformation { get; set; }
- public string Format => FormatTable.ContainsKey(_formatCode) ? FormatTable[_formatCode] : $"Unknown ({_formatCode})";
- private List Warnings { get; set; } = new List();
- private string Code { get; set; }
+ public string Format => _formatTable.ContainsKey(_formatCode) ? _formatTable[_formatCode] : $"Unknown ({_formatCode})";
+ private List Warnings { get; } = new List();
+ private string Code { get; }
- private string GetFragment(BarcodeFragment barcodeFragment) {
- return barcodeFragment switch {
- BarcodeFragment.FormatControlCode => Code.Substring(2, 4),
- BarcodeFragment.SortingCode => Code.Substring(6, 16),
- BarcodeFragment.CustomerInformation when _formatCode == 59 => Code.Substring(22, 16),
- BarcodeFragment.CustomerInformation when _formatCode == 62 => Code.Substring(22, 31),
- BarcodeFragment.CustomerInformation => null, // format doesn't support the customer information field
- BarcodeFragment.ErrorCorrection => Code.Substring(Code.Length - 15,
- 12), // the error correction bars are always immediately before the stop bars
- _ => throw new ArgumentOutOfRangeException(nameof(barcodeFragment), barcodeFragment, null),
- };
+ private string GetFragment(BarcodeFragment fragment, bool decode = true) {
+ var data = Code.Substring(fragment.Offset < 0 ? Code.Length + fragment.Offset : fragment.Offset, fragment.Length);
+
+ if (!decode) {
+ return data;
+ }
+
+ // bool badData;
+ var chunkLength = fragment.TypicalFormat == EncodingFormat.N ? 2 : 3;
+ var rx = new Regex("^[0123]+$");
+ var sb = new StringBuilder();
+ if (!rx.IsMatch(data)) {
+ throw new ArgumentException("Input length must be a quaternary number.", nameof(data));
+ }
+
+ for (var i = 0; i < data.Length; i += chunkLength) {
+ var chunk = data.Substring(i, chunkLength);
+
+ switch (fragment.TypicalFormat) {
+ case EncodingFormat.N:
+ // format N supports the digits 0 through 9, and nothing else.
+ // digits 0 through 8 are stored as their ternary representations, while 9 is stored as "30".
+
+ if (chunk == "30") {
+ sb.Append(9);
+ }
+ else if (chunk.Contains("3")) {
+ // not a ternary number
+ throw new ArgumentException($"{chunk} is not a valid identifier for format {data.ToString()}.");
+ }
+ else {
+ sb.Append(BaseConversion.FromBase(chunk, 3));
+ }
+ break;
+
+ case EncodingFormat.C:
+ break;
+
+ case EncodingFormat.BarToDecimal:
+ var digitInt = BaseConversion.FromBase(chunk, 4);
+ sb.Insert(0, BaseConversion.ToBase(digitInt, 64));
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(fragment.TypicalFormat), fragment.TypicalFormat, null);
+ }
+ }
+
+ return sb.ToString();
}
private static string Decode(string input, EncodingFormat format) {
diff --git a/BaseConversion.cs b/BaseConversion.cs
index bb2dbf9..3c49a84 100644
--- a/BaseConversion.cs
+++ b/BaseConversion.cs
@@ -6,7 +6,7 @@ namespace AusPostCode {
public static class BaseConversion {
// honestly surprised c# doesn't do this out of the box
- private static readonly char[] Characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
+ private static readonly char[] Characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-=".ToCharArray();
// thanks to https://stackoverflow.com/a/35004409
private static readonly Dictionary CharacterIndices =
diff --git a/Program.cs b/Program.cs
index 1da76be..83835fa 100644
--- a/Program.cs
+++ b/Program.cs
@@ -22,8 +22,15 @@ using CommandLine;
namespace AusPostCode {
internal class Program {
private static void Main(string[] args) {
- Console.WriteLine("Hello World!");
+ // test code consisting of the following:
+ // - start bars
+ // - fcc of 0101 == 11 == standard customer barcode
+ // - sorting code of 2112011202120020 == 75152506
+ // - a filler bar of 3
+ // - a reed-solomon code of 001101103221 == 10826817
+ // - end bars
const string testCode = "1301012112011202120020300110110322113";
+
var barcode = new Barcode(testCode);
}