private static void AddErrorCorrection(StringBuilder barPattern) { // Adds Reed-Solomon error correction. int dataCodewords = 0; byte[] eccBlocks = new byte[4]; byte[] dataBlocks = new byte[31]; // Build the triples data blocks; for (int i = 0; i < barPattern.Length; i += 3, dataCodewords++) { dataBlocks[dataCodewords] = (byte)(ConvertPattern(barPattern[i], 4) + ConvertPattern(barPattern[i + 1], 2) + ConvertPattern(barPattern[i + 2], 0)); } ReedSolomon.RSInitialise(0x43, 4, 1); ReedSolomon.RSEncode(dataCodewords, dataBlocks, eccBlocks); // Append error correction in reverse order. for (int i = 4; i > 0; i--) { barPattern.Append(AusBarTable[(int)eccBlocks[i - 1]]); } }
private static void SecondaryDataCheckOdd(int eccLength, int[] maxiCodewords) { // Handles error correction of odd characters in secondary. int dataLength = 68; if (eccLength == 20) { dataLength = 84; } byte[] dataCodewords = new byte[dataLength]; byte[] eccCodewords = new byte[eccLength]; for (int j = 0; j < dataLength; j++) { if ((j & 1) != 0) // Odd { dataCodewords[(j - 1) / 2] = (byte)maxiCodewords[j + 20]; } } ReedSolomon.RSInitialise(0x43, eccLength, 1); ReedSolomon.RSEncode(dataLength / 2, dataCodewords, eccCodewords); for (int j = 0; j < eccLength; j++) { maxiCodewords[dataLength + (2 * j) + 1 + 20] = eccCodewords[eccLength - 1 - j]; } }
private static void PrimaryDataCheck(int[] maxiCodewords) { // Handles error correction of primary barcodeMessage. int dataLength = 10; int eccLength = 10; byte[] data = new byte[dataLength]; byte[] result = new byte[eccLength]; for (int j = 0; j < dataLength; j++) data[j] = (byte)maxiCodewords[j]; ReedSolomon.RSInitialise(0x43, eccLength, 1); ReedSolomon.RSEncode(dataLength, data, result); for (int j = 0; j < eccLength; j++) maxiCodewords[dataLength + j] = result[eccLength - 1 - j]; }
private void Mailmark() { int inputLength = barcodeData.Length; char barcodeType = 'C'; int formatId = 0; int versionId = 0; int classId = 0; int supplyChainId = 0; int itemId = 0; string postcode = String.Empty; int postcodeType = 0; string pattern = String.Empty; short[] destinationPostcode = new short[112]; short[] aRegister = new short[112]; short[] bRegister = new short[112]; short[] tempRegister = new short[112]; short[] cdvRegister = new short[112]; byte[] data = new byte[26]; int dataTop, dataStep; byte[] check = new byte[7]; short[] extender = new short[27]; int checkCount; StringBuilder barPattern = new StringBuilder(); bool result; if (inputLength > 26) { throw new InvalidDataLengthException("Mailmark: Input data too long."); } if (inputLength <= 22) { for (int i = inputLength; i < 22; i++) { barcodeData = ArrayExtensions.Insert(barcodeData, inputLength, ' '); } inputLength = barcodeData.Length; barcodeType = 'C'; } if (inputLength > 22 && inputLength <= 26) { for (int i = inputLength; i < 26; i++) { barcodeData = ArrayExtensions.Insert(barcodeData, inputLength, ' '); } inputLength = barcodeData.Length; barcodeType = 'L'; } for (int i = 0; i < inputLength; i++) { barcodeData[i] = Char.ToUpper(barcodeData[i], CultureInfo.CurrentCulture); // Make sure all characters are uppercase. if (CharacterSets.Mailmark.IndexOf(barcodeData[i]) == -1) { throw new InvalidDataException("Mailmark: Invalid character in input data."); } } // Format is in the range 0-4. result = int.TryParse((new string(barcodeData, 0, 1)), out formatId); if (!result || formatId < 0 || formatId > 4) { throw new InvalidDataException("Mailmark: Invalid Format character in input data."); } // Version ID is in the range 1-4. result = int.TryParse((new string(barcodeData, 1, 1)), out versionId); versionId--; // Internal field value of 0-3. if (!result || versionId < 0 || versionId > 3) { throw new InvalidDataException("Mailmark: Invalid Version ID character in input data."); } // Class is in the range 0-9 & A-E. result = int.TryParse((new string(barcodeData, 2, 1)), NumberStyles.HexNumber, null, out classId); if (!result || classId < 0 || classId > 14) { throw new InvalidDataException("Mailmark: Invalid Class ID character in input data."); } // Supply Chain ID is 2 digits for barcode C and 6 digits for barcode L int supplyChainLength = (barcodeType == 'C') ? 2 : 6; result = int.TryParse(new string(barcodeData, 3, supplyChainLength), out supplyChainId); if (!result) { throw new InvalidDataException("Mailmark: Invalid Supply Chain ID character in input data."); } // Item ID is 8 digits. result = int.TryParse(new string(barcodeData, 3 + supplyChainLength, 8), out itemId); if (!result) { throw new InvalidDataException("Mailmark: Invalid Item ID character in input data."); } // Seperate Destination Post Code plus DPS field. postcode = new string(barcodeData, 3 + supplyChainLength + 8, 9); // Detect postcode type /* Postcode type is used to select which format of postcode * * 1 = FNFNLLNLS * 2 = FFNNLLNLS * 3 = FFNNNLLNL * 4 = FFNFNLLNL * 5 = FNNLLNLSS * 6 = FNNNLLNLS * 7 = International designation*/ if (postcode == "XY11 ") { postcodeType = 7; } else { if (postcode[7] == ' ') { postcodeType = 5; } else { if (postcode[8] == ' ') { // Types 1, 2 and 6 if (Char.IsDigit(postcode[1])) { if (Char.IsDigit(postcode[2])) { postcodeType = 6; } else { postcodeType = 1; } } else { postcodeType = 2; } } else { // Types 3 and 4 if (Char.IsDigit(postcode[3])) { postcodeType = 3; } else { postcodeType = 4; } } } } // Verify postcode type if (postcodeType != 7) { if (!VerifyPostcode(postcode, postcodeType)) { throw new InvalidDataException("Mailmark: Invalid Postcode in input data."); } } // Convert postcode to internal user field. if (postcodeType != 7) { pattern = postcodeFormat[postcodeType - 1]; BinaryMath.BinaryLoad(bRegister, "0"); for (int i = 0; i < 9; i++) { switch (pattern[i]) { case 'F': BinaryMath.BinaryMultiply(bRegister, "26"); BinaryMath.BinaryLoad(tempRegister, "0"); for (int j = 0; j < 5; j++) { if ((SetF.IndexOf(postcode[i]) & (0x01 << j)) > 0) { tempRegister[j] = 1; } } BinaryMath.BinaryAdd(bRegister, tempRegister); break; case 'L': BinaryMath.BinaryMultiply(bRegister, "20"); BinaryMath.BinaryLoad(tempRegister, "0"); for (int j = 0; j < 5; j++) { if ((SetL.IndexOf(postcode[i]) & (0x01 << j)) > 0) { tempRegister[j] = 1; } } BinaryMath.BinaryAdd(bRegister, tempRegister); break; case 'N': BinaryMath.BinaryMultiply(bRegister, "10"); BinaryMath.BinaryLoad(tempRegister, "0"); for (int j = 0; j < 5; j++) { if ((SetN.IndexOf(postcode[i]) & (0x01 << j)) > 0) { tempRegister[j] = 1; } } BinaryMath.BinaryAdd(bRegister, tempRegister); break; } } // Destination postcode = accumulatorA + accumulatorB. BinaryMath.BinaryLoad(destinationPostcode, "0"); BinaryMath.BinaryAdd(destinationPostcode, bRegister); BinaryMath.BinaryLoad(aRegister, "1"); if (postcodeType == 1) { BinaryMath.BinaryAdd(destinationPostcode, aRegister); } BinaryMath.BinaryLoad(tempRegister, "5408000000"); BinaryMath.BinaryAdd(aRegister, tempRegister); if (postcodeType == 2) { BinaryMath.BinaryAdd(destinationPostcode, aRegister); } BinaryMath.BinaryLoad(tempRegister, "5408000000"); BinaryMath.BinaryAdd(aRegister, tempRegister); if (postcodeType == 3) { BinaryMath.BinaryAdd(destinationPostcode, aRegister); } BinaryMath.BinaryLoad(tempRegister, "54080000000"); BinaryMath.BinaryAdd(aRegister, tempRegister); if (postcodeType == 4) { BinaryMath.BinaryAdd(destinationPostcode, aRegister); } BinaryMath.BinaryLoad(tempRegister, "140608000000"); BinaryMath.BinaryAdd(aRegister, tempRegister); if (postcodeType == 5) { BinaryMath.BinaryAdd(destinationPostcode, aRegister); } BinaryMath.BinaryLoad(tempRegister, "208000000"); BinaryMath.BinaryAdd(aRegister, tempRegister); if (postcodeType == 6) { BinaryMath.BinaryAdd(destinationPostcode, aRegister); } } // Conversion from Internal User Fields to Consolidated Data Value // Set CDV to 0 BinaryMath.BinaryLoad(cdvRegister, "0"); // Add Destination Post Code plus DPS BinaryMath.BinaryAdd(cdvRegister, destinationPostcode); // Multiply by 100,000,000 BinaryMath.BinaryMultiply(cdvRegister, "100000000"); // Add Item ID BinaryMath.BinaryLoad(tempRegister, "0"); for (int i = 0; i < 32; i++) { if ((0x01 & (itemId >> i)) > 0) { tempRegister[i] = 1; } } BinaryMath.BinaryAdd(cdvRegister, tempRegister); if (barcodeType == 'C') { BinaryMath.BinaryMultiply(cdvRegister, "100"); // Barcode C - Multiply by 100 } else { BinaryMath.BinaryMultiply(cdvRegister, "1000000"); // Barcode L - Multiply by 1,000,000 } // Add Supply Chain ID //int scCount = barcodeType == 'C' ? 7 : 20; BinaryMath.BinaryLoad(tempRegister, "0"); for (int i = 0; i < 20; i++) { if ((0x01 & (supplyChainId >> i)) > 0) { tempRegister[i] = 1; } } BinaryMath.BinaryAdd(cdvRegister, tempRegister); // Multiply by 15 BinaryMath.BinaryMultiply(cdvRegister, "15"); // Add Class BinaryMath.BinaryLoad(tempRegister, "0"); for (int i = 0; i < 4; i++) { if ((0x01 & (classId >> i)) > 0) { tempRegister[i] = 1; } } BinaryMath.BinaryAdd(cdvRegister, tempRegister); // Multiply by 5 BinaryMath.BinaryMultiply(cdvRegister, "5"); // Add Format BinaryMath.BinaryLoad(tempRegister, "0"); for (int i = 0; i < 4; i++) { if ((0x01 & (formatId >> i)) > 0) { tempRegister[i] = 1; } } BinaryMath.BinaryAdd(cdvRegister, tempRegister); // Multiply by 4 BinaryMath.BinaryMultiply(cdvRegister, "4"); // Add Version ID BinaryMath.BinaryLoad(tempRegister, "0"); for (int i = 0; i < 4; i++) { if ((0x01 & (versionId >> i)) > 0) { tempRegister[i] = 1; } } BinaryMath.BinaryAdd(cdvRegister, tempRegister); if (barcodeType == 'C') { dataTop = 15; dataStep = 8; checkCount = 6; } else { dataTop = 18; dataStep = 10; checkCount = 7; } // Conversion from Consolidated Data Value to Data Numbers for (int i = 0; i < 112; i++) { bRegister[i] = cdvRegister[i]; } for (int j = dataTop; j >= (dataStep + 1); j--) { for (int i = 0; i < 112; i++) { cdvRegister[i] = bRegister[i]; bRegister[i] = 0; aRegister[i] = 0; } aRegister[96] = 1; for (int i = 91; i >= 0; i--) { bRegister[i] = BinaryMath.IsLarger(cdvRegister, aRegister); if (bRegister[i] == 1) { BinaryMath.BinarySubtract(cdvRegister, aRegister); } BinaryMath.ShiftDown(aRegister); } data[j] = (byte)((cdvRegister[5] * 32) + (cdvRegister[4] * 16) + (cdvRegister[3] * 8) + (cdvRegister[2] * 4) + (cdvRegister[1] * 2) + cdvRegister[0]); } for (int j = dataStep; j >= 0; j--) { for (int i = 0; i < 112; i++) { cdvRegister[i] = bRegister[i]; bRegister[i] = 0; aRegister[i] = 0; } aRegister[95] = 1; aRegister[94] = 1; aRegister[93] = 1; aRegister[92] = 1; for (int i = 91; i >= 0; i--) { bRegister[i] = BinaryMath.IsLarger(cdvRegister, aRegister); if (bRegister[i] == 1) { BinaryMath.BinarySubtract(cdvRegister, aRegister); } BinaryMath.ShiftDown(aRegister); } data[j] = (byte)((cdvRegister[5] * 32) + (cdvRegister[4] * 16) + (cdvRegister[3] * 8) + (cdvRegister[2] * 4) + (cdvRegister[1] * 2) + cdvRegister[0]); } ReedSolomon.RSInitialise(0x25, checkCount, 1); ReedSolomon.RSEncode(dataTop + 1, data, check); // Append check digits to data. for (int i = 1; i <= checkCount; i++) { data[dataTop + i] = check[checkCount - i]; } // Conversion from Data Numbers and Check Numbers to Data Symbols and Check Symbols for (int i = 0; i <= dataStep; i++) { data[i] = dataSymbolEven[data[i]]; } for (int i = dataStep + 1; i <= (dataTop + checkCount); i++) { data[i] = dataSymbolOdd[data[i]]; } // Conversion from Data Symbols and Check Symbols to Extender Groups for (int i = 0; i < inputLength; i++) { if (barcodeType == 'C') { extender[extenderGroupC[i]] = data[i]; } else { extender[extenderGroupL[i]] = data[i]; } } // Conversion from Extender Groups to Bar Identifiers for (int i = 0; i < inputLength; i++) { for (int j = 0; j < 3; j++) { switch (extender[i] & 0x24) { case 0x24: barPattern.Append("F"); break; case 0x20: if (i % 2 > 0) { barPattern.Append("D"); } else { barPattern.Append("A"); } break; case 0x04: if (i % 2 > 0) { barPattern.Append("A"); } else { barPattern.Append("D"); } break; default: barPattern.Append("T"); break; } extender[i] = (short)(extender[i] << 1); } } BuildSymbol(barPattern); barcodeText = new string(barcodeData); }