-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Barcode.cs b/Barcode.cs
index b8785fe..57f0d87 100644
--- a/Barcode.cs
+++ b/Barcode.cs
@@ -1,8 +1,26 @@
+using System;
using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
namespace AusPostCode {
public class Barcode {
- public Dictionary FormatTable = new Dictionary() {
+ public enum BarcodeFragment {
+ FormatControlCode,
+ SortingCode,
+ CustomerInformation,
+ ErrorCorrection,
+ }
+
+ public enum EncodingFormat {
+ N,
+ C,
+ BarToDecimal,
+ }
+
+ private int _formatCode;
+
+ public Dictionary FormatTable = new Dictionary {
[0] = "Null Customer Barcode",
[11] = "Standard Customer Barcode",
[52] = "Customer Business Reply Paid",
@@ -10,14 +28,95 @@ namespace AusPostCode {
[62] = "Customer Barcode 3",
[67] = "Customer Business Reply Paid",
[72] = "International Business Reply Paid",
- [77] = "International Business Reply Paid"
+ [77] = "International Business Reply Paid",
};
- public int SortingCode { get; set; }
- public int CustomerInformation { get; set; }
- public string Code { get; set; }
public Barcode(string code) {
Code = code;
+ // - check for start and end bars
+ if (Code.Substring(0, 2) != "13") {
+ Warnings.Add("Couldn't find Start Bars");
+ Code = $"13{Code}";
+ }
+
+ if (Code.Substring(Code.Length - 3, 2) != "13") {
+ Warnings.Add("Couldn't find End Bars");
+ Code = $"{Code}13";
+ }
+
+ // process Format Control Code
+ _formatCode = int.Parse(Decode(GetFragment(BarcodeFragment.FormatControlCode), EncodingFormat.N));
+ Console.WriteLine(Format);
+
+ // process Sorting Code Field
+ SortingCode = int.Parse(Decode(GetFragment(BarcodeFragment.SortingCode), EncodingFormat.N));
+ Console.WriteLine($"Sorting code: {SortingCode}");
+ }
+
+ 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; }
+
+ 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 static string Decode(string input, EncodingFormat format) {
+ // bool badData;
+ var chunkLength = format == EncodingFormat.N ? 2 : 3;
+ if (input.Length % 2 != 0) {
+ throw new ArgumentException($"Input length must be a multiple of {chunkLength}.", nameof(input));
+ }
+
+ var rx = new Regex("^[0123]+$");
+ if (!rx.IsMatch(input)) {
+ throw new ArgumentException("Input length must be a quaternary number.", nameof(input));
+ }
+
+ var sb = new StringBuilder();
+ for (var i = 0; i < input.Length; i += chunkLength) {
+ var chunk = input.Substring(i, chunkLength);
+
+ switch (format) {
+ 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 {format.ToString()}.");
+ }
+ else {
+ sb.Append(BaseConversion.FromBase(chunk, 3));
+ }
+ break;
+
+ case EncodingFormat.C:
+ break;
+
+ case EncodingFormat.BarToDecimal:
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(format), format, null);
+ }
+ }
+
+ return sb.ToString();
}
}
}
diff --git a/BaseConversion.cs b/BaseConversion.cs
new file mode 100644
index 0000000..bb2dbf9
--- /dev/null
+++ b/BaseConversion.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AusPostCode {
+ public static class BaseConversion {
+ // honestly surprised c# doesn't do this out of the box
+
+ private static readonly char[] Characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
+
+ // thanks to https://stackoverflow.com/a/35004409
+ private static readonly Dictionary CharacterIndices =
+ Characters.Select((c, i) => new {Char = c, Index = i}).ToDictionary(c => c.Char, c => c.Index);
+
+ public static string ToBase(int num, int numberBase) {
+ if (numberBase > Characters.Length) {
+ throw new ArgumentOutOfRangeException(
+ nameof(numberBase),
+ $"Base must be below {Characters.Length}"
+ );
+ }
+
+ if (Math.Abs(num) == 0) {
+ return num.ToString();
+ }
+
+ var digits = new List();
+ var negative = num < 0;
+
+ while (num > 0) {
+ digits.Add(Characters[num % numberBase]);
+ num /= numberBase;
+ }
+
+ digits.Reverse();
+ return (negative ? "-" : "") + string.Join("", digits);
+ }
+
+ public static int FromBase(string num, int numberBase) {
+ if (numberBase > Characters.Length) {
+ throw new ArgumentOutOfRangeException(
+ nameof(numberBase),
+ $"Base must be below {Characters.Length}"
+ );
+ }
+
+ var negative = false;
+
+ if (num.StartsWith("-")) {
+ // it's a negative number
+ negative = true;
+ num = num.Substring(1);
+ }
+
+ var x = num.ToCharArray();
+ var result = 0;
+
+ // thanks to https://stackoverflow.com/a/35004409 again for this 0uo
+ for (var i = 0; i < x.Length; i++) {
+ result += CharacterIndices[x[i]] * (int) Math.Pow(numberBase, x.Length - i - 1);
+ }
+
+ if (negative) {
+ result *= -1;
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/Folder.DotSettings.user b/Folder.DotSettings.user
deleted file mode 100644
index 72d83da..0000000
--- a/Folder.DotSettings.user
+++ /dev/null
@@ -1,2 +0,0 @@
-
- True
\ No newline at end of file
diff --git a/Program.cs b/Program.cs
index b99bb3e..1da76be 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,37 +1,36 @@
-/*
-AusPostCode - A program for parsing and creating Australia Post barcodes.
-Copyright (C) 2020 Lynnesbian
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
- */
-
-using System;
-using CommandLine;
-
-namespace AusPostCode {
- internal class Program {
-
- public class Options {
- [Option('d', "decode", Required = false,
- HelpText = "Decode the text passed in, turning it into human readable information.")]
- public bool Decode { get; set; }
- }
-
- private static void Main(string[] args) {
- Console.WriteLine("Hello World!");
- string testCode = "3111961842093257385431";
- var barcode = new Barcode(testCode);
- }
- }
-}
+/*
+AusPostCode - A program for parsing and creating Australia Post barcodes.
+Copyright (C) 2020 Lynnesbian
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+ */
+
+using System;
+using CommandLine;
+
+namespace AusPostCode {
+ internal class Program {
+ private static void Main(string[] args) {
+ Console.WriteLine("Hello World!");
+ const string testCode = "1301012112011202120020300110110322113";
+ var barcode = new Barcode(testCode);
+ }
+
+ public class Options {
+ [Option('d', "decode", Required = false,
+ HelpText = "Decode the text passed in, turning it into human readable information.")]
+ public bool Decode { get; set; }
+ }
+ }
+}