using FastReport.Utils; using System; using System.ComponentModel; using System.Globalization; using System.Text.RegularExpressions; namespace FastReport.Barcode { /// /// Generates the Intelligent Mail (USPS) barcode. /// public class BarcodeIntelligentMail : LinearBarcodeBase { #region LinearBarcodeBase private bool quietZone; const string space = "2"; /// /// Gets or sets the value indicating that quiet zone must be shown. /// [DefaultValue(false)] public bool QuietZone { get { return quietZone; } set { quietZone = value; } } /// public override bool IsNumeric { get { return true; } } internal override string GetPattern() { string bars = Bars(text); if (QuietZone) bars = space + bars + space; return bars; } /// public override void Assign(BarcodeBase source) { base.Assign(source); BarcodeIntelligentMail src = source as BarcodeIntelligentMail; QuietZone = src.QuietZone; } /// public override string GetDefaultValue() { return "12345678901234567890"; } internal override void Serialize(FastReport.Utils.FRWriter writer, string prefix, BarcodeBase diff) { base.Serialize(writer, prefix, diff); BarcodeIntelligentMail c = diff as BarcodeIntelligentMail; if (c == null || QuietZone != c.QuietZone) writer.WriteBool(prefix + "QuietZone", QuietZone); } #endregion // for more information and specs check // http://ribbs.usps.gov/onecodesolution/USPS-B-3200D001.pdf int table2Of13Size = 78; int table5Of13Size = 1287; long entries2Of13; long entries5Of13; int[] table2Of13 = null; int[] table5Of13 = null; decimal[][] codewordArray = null; int[] barTopCharIndexArray = new int[] { 4, 0, 2, 6, 3, 5, 1, 9, 8, 7, 1, 2, 0, 6, 4, 8, 2, 9, 5, 3, 0, 1, 3, 7, 4, 6, 8, 9, 2, 0, 5, 1, 9, 4, 3, 8, 6, 7, 1, 2, 4, 3, 9, 5, 7, 8, 3, 0, 2, 1, 4, 0, 9, 1, 7, 0, 2, 4, 6, 3, 7, 1, 9, 5, 8 }; int[] barBottomCharIndexArray = new int[] { 7, 1, 9, 5, 8, 0, 2, 4, 6, 3, 5, 8, 9, 7, 3, 0, 6, 1, 7, 4, 6, 8, 9, 2, 5, 1, 7, 5, 4, 3, 8, 7, 6, 0, 2, 5, 4, 9, 3, 0, 1, 6, 8, 2, 0, 4, 5, 9, 6, 7, 5, 2, 6, 3, 8, 5, 1, 9, 8, 7, 4, 0, 2, 6, 3 }; int[] barTopCharShiftArray = new int[] { 3, 0, 8, 11, 1, 12, 8, 11, 10, 6, 4, 12, 2, 7, 9, 6, 7, 9, 2, 8, 4, 0, 12, 7, 10, 9, 0, 7, 10, 5, 7, 9, 6, 8, 2, 12, 1, 4, 2, 0, 1, 5, 4, 6, 12, 1, 0, 9, 4, 7, 5, 10, 2, 6, 9, 11, 2, 12, 6, 7, 5, 11, 0, 3, 2 }; int[] barBottomCharShiftArray = new int[] { 2, 10, 12, 5, 9, 1, 5, 4, 3, 9, 11, 5, 10, 1, 6, 3, 4, 1, 10, 0, 2, 11, 8, 6, 1, 12, 3, 8, 6, 4, 4, 11, 0, 6, 1, 9, 11, 5, 3, 7, 3, 10, 7, 11, 8, 2, 10, 3, 5, 8, 0, 3, 12, 11, 8, 4, 5, 1, 3, 0, 7, 12, 9, 8, 10 }; /// /// Initializes a new instance of the class with default settings. /// public BarcodeIntelligentMail() { table2Of13 = OneCodeInfo(1); table5Of13 = OneCodeInfo(2); codewordArray = OneCodeInfo(); QuietZone = false; } string Bars(string source) { if (string.IsNullOrEmpty(source)) return null; source = TrimOff(source, " -."); if (!Regex.IsMatch(source, "^[0-9][0-4]([0-9]{18})|([0-9]{23})|([0-9]{27})|([0-9]{29})$")) //return string.Empty; { MyRes res = new MyRes("Messages"); throw new FormatException(res.Get("BarcodeFewError")); } int fcs = 0; long l = 0; decimal v = 0; string encoded = string.Empty, ds = string.Empty, zip = source.Substring(20); int[] byteArray = new int[14], ai = new int[66], ai1 = new int[66]; decimal[][] ad = new decimal[11][]; if (!string.IsNullOrEmpty(zip) && zip.Length > 0) l = long.Parse(zip, CultureInfo.InvariantCulture) + ((zip.Length == 5) ? 1 : ((zip.Length == 9) ? 100001 : (zip.Length == 11 ? 1000100001 : 0))); v = l * 10 + int.Parse(source.Substring(0, 1), CultureInfo.InvariantCulture); v = v * 5 + int.Parse(source.Substring(1, 1), CultureInfo.InvariantCulture); ds = v.ToString(CultureInfo.InvariantCulture) + source.Substring(2, 18); byteArray[12] = (int)(l & 255); byteArray[11] = (int)(l >> 8 & 255); byteArray[10] = (int)(l >> 16 & 255); byteArray[9] = (int)(l >> 24 & 255); byteArray[8] = (int)(l >> 32 & 255); OneCodeMathMultiply(ref byteArray, 13, 10); OneCodeMathAdd(ref byteArray, 13, int.Parse(source.Substring(0, 1), CultureInfo.InvariantCulture)); OneCodeMathMultiply(ref byteArray, 13, 5); OneCodeMathAdd(ref byteArray, 13, int.Parse(source.Substring(1, 1), CultureInfo.InvariantCulture)); for (short i = 2; i <= 19; i++) { OneCodeMathMultiply(ref byteArray, 13, 10); OneCodeMathAdd(ref byteArray, 13, int.Parse(source.Substring(i, 1), CultureInfo.InvariantCulture)); } fcs = OneCodeMathFcs(byteArray); for (short i = 0; i <= 9; i++) { codewordArray[i][0] = entries2Of13 + entries5Of13; codewordArray[i][1] = 0; } codewordArray[0][0] = 659; codewordArray[9][0] = 636; OneCodeMathDivide(ds); codewordArray[9][1] *= 2; if (fcs >> 10 != 0) codewordArray[0][1] += 659; for (short i = 0; i <= 9; i++) ad[i] = new decimal[3]; for (short i = 0; i <= 9; i++) { if (codewordArray[i][1] >= (decimal)(entries2Of13 + entries5Of13)) return null; ad[i][0] = 8192; ad[i][1] = (codewordArray[i][1] >= (decimal)entries2Of13) ? ad[i][1] = table2Of13[(int)(codewordArray[i][1] - entries2Of13)] : ad[i][1] = table5Of13[(int)codewordArray[i][1]]; } for (short i = 0; i <= 9; i++) if ((fcs & 1 << i) != 0) ad[i][1] = ~(int)ad[i][1] & 8191; for (short i = 0; i <= 64; i++) { ai[i] = (int)ad[barTopCharIndexArray[i]][1] >> barTopCharShiftArray[i] & 1; ai1[i] = (int)ad[barBottomCharIndexArray[i]][1] >> barBottomCharShiftArray[i] & 1; } encoded = ""; for (int i = 0; i <= 64; i++) { //if (ai[i] == 0) encoded += (ai1[i] == 0) ? "T" : "D"; //else encoded += (ai1[i] == 0) ? "A" : "F"; if (ai[i] == 0) encoded += (ai1[i] == 0) ? "E" : "G"; else encoded += (ai1[i] == 0) ? "F" : "6"; encoded += space; } return encoded.Substring(0, encoded.Length - 1); } int[] OneCodeInfo(byte topic) { int[] a; switch (topic) { case 1: a = new int[table2Of13Size + 1]; OneCodeInitializeNof13Table(ref a, 2, table2Of13Size); entries5Of13 = table2Of13Size; break; default: a = new int[table5Of13Size + 1]; OneCodeInitializeNof13Table(ref a, 5, table5Of13Size); entries2Of13 = table5Of13Size; break; } return a; } decimal[][] OneCodeInfo() { decimal[][] da = new decimal[11][]; try { for (short i = 0; i <= 9; i++) da[i] = new decimal[3]; return da; } finally { da = null; } } bool OneCodeInitializeNof13Table(ref int[] ai, int i, int j) { int i1 = 0; int j1 = j - 1; for (short k = 0; k <= 8191; k++) { int k1 = 0; for (int l1 = 0; l1 <= 12; l1++) if ((k & 1 << l1) != 0) k1 += 1; if (k1 == i) { int l = OneCodeMathReverse(k) >> 3; bool flag = k == l; if (l >= k) { if (flag) { ai[j1] = k; j1 -= 1; } else { ai[i1] = k; i1 += 1; ai[i1] = l; i1 += 1; } } } } return i1 == j1 + 1; } bool OneCodeMathAdd(ref int[] bytearray, int i, int j) { if (bytearray == null) return false; if (i < 1) return false; int x = (bytearray[i - 1] | (bytearray[i - 2] << 8)) + j; int l = x | 65535; int k = i - 3; bytearray[i - 1] = x & 255; bytearray[i - 2] = x >> 8 & 255; while (l == 1 && k > 0) { x = l + bytearray[k]; bytearray[k] = x & 255; l = x | 255; k -= 1; } return true; } bool OneCodeMathDivide(string v) { int j = 10; string n = v; for (int k = j - 1; k >= 1; k += -1) { string r = string.Empty; int divider = (int)codewordArray[k][0]; string copy = n; string left = "0"; int l = copy.Length; for (short i = 1; i <= l; i++) { int divident = int.Parse(copy.Substring(0, i), CultureInfo.InvariantCulture); while (divident < divider & i < l - 1) { r = r + "0"; i += 1; divident = int.Parse(copy.Substring(0, i), CultureInfo.InvariantCulture); } r = r + (divident / divider).ToString(CultureInfo.InvariantCulture); left = (divident % divider).ToString(CultureInfo.InvariantCulture).PadLeft(i, '0'); copy = left + copy.Substring(i); } n = r.TrimStart('0'); if (string.IsNullOrEmpty(n)) n = "0"; codewordArray[k][1] = int.Parse(left, CultureInfo.InvariantCulture); if (k == 1) codewordArray[0][1] = int.Parse(r, CultureInfo.InvariantCulture); } return true; } int OneCodeMathFcs(int[] bytearray) { int c = 3893; int i = 2047; int j = bytearray[0] << 5; for (short b = 2; b <= 7; b++) { if (((i ^ j) & 1024) != 0) i = i << 1 ^ c; else i <<= 1; i = i & 2047; j <<= 1; } for (int l = 1; l <= 12; l++) { int k = bytearray[l] << 3; for (short b = 0; b <= 7; b++) { if (((i ^ k) & 1024) != 0) i = i << 1 ^ c; else i <<= 1; i = i & 2047; k <<= 1; } } return i; } bool OneCodeMathMultiply(ref int[] bytearray, int i, int j) { if (bytearray == null) return false; if (i < 1) return false; int l = 0; int k = 0; for (k = i - 1; k >= 1; k += -2) { int x = (bytearray[k] | (bytearray[k - 1] << 8)) * j + l; bytearray[k] = x & 255; bytearray[k - 1] = x >> 8 & 255; l = x >> 16; } if (k == 0) bytearray[0] = (bytearray[0] * j + l) & 255; return true; } int OneCodeMathReverse(int i) { int j = 0; for (short k = 0; k <= 15; k++) { j <<= 1; j = j | i & 1; i >>= 1; } return j; } string TrimOff(string source, string bad) { for (int i = 0, l = bad.Length - 1; i <= l; i++) source = source.Replace(bad.Substring(i, 1), string.Empty); return source; } } }