--- /dev/null
+/*\r
+* Copyright 2008 ZXing authors\r
+*\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*/\r
+using System;\r
+using ReaderException = com.google.zxing.ReaderException;\r
+using BitSource = com.google.zxing.common.BitSource;\r
+using DecoderResult = com.google.zxing.common.DecoderResult;\r
+namespace com.google.zxing.datamatrix.decoder\r
+{\r
+ \r
+ /// <summary> <p>Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes\r
+ /// in one Data Matrix Code. This class decodes the bits back into text.</p>\r
+ /// \r
+ /// <p>See ISO 16022:2006, 5.2.1 - 5.2.9.2</p>\r
+ /// \r
+ /// </summary>\r
+ /// <author> bbrown@google.com (Brian Brown)\r
+ /// </author>\r
+ /// <author> Sean Owen\r
+ /// </author>\r
+ /// <author>www.Redivivus.in (suraj.supekar@redivivus.in) - Ported from ZXING Java Source \r
+ /// </author>\r
+ sealed class DecodedBitStreamParser\r
+ {\r
+ \r
+ /// <summary> See ISO 16022:2006, Annex C Table C.1\r
+ /// The C40 Basic Character Set (*'s used for placeholders for the shift values)\r
+ /// </summary>\r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'C40_BASIC_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
+ private static readonly char[] C40_BASIC_SET_CHARS = new char[]{'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};\r
+ \r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'C40_SHIFT2_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
+ private static readonly char[] C40_SHIFT2_SET_CHARS = new char[]{'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_'};\r
+ \r
+ /// <summary> See ISO 16022:2006, Annex C Table C.2\r
+ /// The Text Basic Character Set (*'s used for placeholders for the shift values)\r
+ /// </summary>\r
+ //UPGRADE_NOTE: Final was removed from the declaration of 'TEXT_BASIC_SET_CHARS'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1003'"\r
+ private static readonly char[] TEXT_BASIC_SET_CHARS = new char[]{'*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};\r
+ \r
+ private static char[] TEXT_SHIFT3_SET_CHARS = new char[]{'\'', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (char) 127};\r
+ \r
+ private const int PAD_ENCODE = 0; // Not really an encoding\r
+ private const int ASCII_ENCODE = 1;\r
+ private const int C40_ENCODE = 2;\r
+ private const int TEXT_ENCODE = 3;\r
+ private const int ANSIX12_ENCODE = 4;\r
+ private const int EDIFACT_ENCODE = 5;\r
+ private const int BASE256_ENCODE = 6;\r
+ \r
+ private DecodedBitStreamParser()\r
+ {\r
+ }\r
+ \r
+ internal static DecoderResult decode(sbyte[] bytes)\r
+ {\r
+ BitSource bits = new BitSource(bytes);\r
+ System.Text.StringBuilder result = new System.Text.StringBuilder(100);\r
+ System.Text.StringBuilder resultTrailer = new System.Text.StringBuilder(0);\r
+ System.Collections.ArrayList byteSegments = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(1));\r
+ int mode = ASCII_ENCODE;\r
+ do \r
+ {\r
+ if (mode == ASCII_ENCODE)\r
+ {\r
+ mode = decodeAsciiSegment(bits, result, resultTrailer);\r
+ }\r
+ else\r
+ {\r
+ switch (mode)\r
+ {\r
+ \r
+ case C40_ENCODE: \r
+ decodeC40Segment(bits, result);\r
+ break;\r
+ \r
+ case TEXT_ENCODE: \r
+ decodeTextSegment(bits, result);\r
+ break;\r
+ \r
+ case ANSIX12_ENCODE: \r
+ decodeAnsiX12Segment(bits, result);\r
+ break;\r
+ \r
+ case EDIFACT_ENCODE: \r
+ decodeEdifactSegment(bits, result);\r
+ break;\r
+ \r
+ case BASE256_ENCODE: \r
+ decodeBase256Segment(bits, result, byteSegments);\r
+ break;\r
+ \r
+ default: \r
+ throw ReaderException.Instance;\r
+ \r
+ }\r
+ mode = ASCII_ENCODE;\r
+ }\r
+ }\r
+ while (mode != PAD_ENCODE && bits.available() > 0);\r
+ if (resultTrailer.Length > 0)\r
+ {\r
+ result.Append(resultTrailer.ToString());\r
+ }\r
+ return new DecoderResult(bytes, result.ToString(), (byteSegments.Count == 0)?null:byteSegments, null);\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, 5.2.3 and Annex C, Table C.2</summary>\r
+ private static int decodeAsciiSegment(BitSource bits, System.Text.StringBuilder result, System.Text.StringBuilder resultTrailer)\r
+ {\r
+ bool upperShift = false;\r
+ do \r
+ {\r
+ int oneByte = bits.readBits(8);\r
+ if (oneByte == 0)\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ else if (oneByte <= 128)\r
+ {\r
+ // ASCII data (ASCII value + 1)\r
+ oneByte = upperShift?(oneByte + 128):oneByte;\r
+ upperShift = false;\r
+ result.Append((char) (oneByte - 1));\r
+ return ASCII_ENCODE;\r
+ }\r
+ else if (oneByte == 129)\r
+ {\r
+ // Pad\r
+ return PAD_ENCODE;\r
+ }\r
+ else if (oneByte <= 229)\r
+ {\r
+ // 2-digit data 00-99 (Numeric Value + 130)\r
+ int value_Renamed = oneByte - 130;\r
+ if (value_Renamed < 10)\r
+ {\r
+ // padd with '0' for single digit values\r
+ result.Append('0');\r
+ }\r
+ result.Append(value_Renamed);\r
+ }\r
+ else if (oneByte == 230)\r
+ {\r
+ // Latch to C40 encodation\r
+ return C40_ENCODE;\r
+ }\r
+ else if (oneByte == 231)\r
+ {\r
+ // Latch to Base 256 encodation\r
+ return BASE256_ENCODE;\r
+ }\r
+ else if (oneByte == 232)\r
+ {\r
+ // FNC1\r
+ //throw ReaderException.getInstance();\r
+ // Ignore this symbol for now\r
+ }\r
+ else if (oneByte == 233)\r
+ {\r
+ // Structured Append\r
+ //throw ReaderException.getInstance();\r
+ // Ignore this symbol for now\r
+ }\r
+ else if (oneByte == 234)\r
+ {\r
+ // Reader Programming\r
+ //throw ReaderException.getInstance();\r
+ // Ignore this symbol for now\r
+ }\r
+ else if (oneByte == 235)\r
+ {\r
+ // Upper Shift (shift to Extended ASCII)\r
+ upperShift = true;\r
+ }\r
+ else if (oneByte == 236)\r
+ {\r
+ // 05 Macro\r
+ result.Append("[)>\u001E05\u001D");\r
+ resultTrailer.Insert(0, "\u001E\u0004");\r
+ }\r
+ else if (oneByte == 237)\r
+ {\r
+ // 06 Macro\r
+ result.Append("[)>\u001E06\u001D");\r
+ resultTrailer.Insert(0, "\u001E\u0004");\r
+ }\r
+ else if (oneByte == 238)\r
+ {\r
+ // Latch to ANSI X12 encodation\r
+ return ANSIX12_ENCODE;\r
+ }\r
+ else if (oneByte == 239)\r
+ {\r
+ // Latch to Text encodation\r
+ return TEXT_ENCODE;\r
+ }\r
+ else if (oneByte == 240)\r
+ {\r
+ // Latch to EDIFACT encodation\r
+ return EDIFACT_ENCODE;\r
+ }\r
+ else if (oneByte == 241)\r
+ {\r
+ // ECI Character\r
+ // TODO(bbrown): I think we need to support ECI\r
+ //throw ReaderException.getInstance();\r
+ // Ignore this symbol for now\r
+ }\r
+ else if (oneByte >= 242)\r
+ {\r
+ // Not to be used in ASCII encodation\r
+ throw ReaderException.Instance;\r
+ }\r
+ }\r
+ while (bits.available() > 0);\r
+ return ASCII_ENCODE;\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, 5.2.5 and Annex C, Table C.1</summary>\r
+ private static void decodeC40Segment(BitSource bits, System.Text.StringBuilder result)\r
+ {\r
+ // Three C40 values are encoded in a 16-bit value as\r
+ // (1600 * C1) + (40 * C2) + C3 + 1\r
+ // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time\r
+ bool upperShift = false;\r
+ \r
+ int[] cValues = new int[3];\r
+ do \r
+ {\r
+ // If there is only one byte left then it will be encoded as ASCII\r
+ if (bits.available() == 8)\r
+ {\r
+ return ;\r
+ }\r
+ int firstByte = bits.readBits(8);\r
+ if (firstByte == 254)\r
+ {\r
+ // Unlatch codeword\r
+ return ;\r
+ }\r
+ \r
+ parseTwoBytes(firstByte, bits.readBits(8), cValues);\r
+ \r
+ int shift = 0;\r
+ for (int i = 0; i < 3; i++)\r
+ {\r
+ int cValue = cValues[i];\r
+ switch (shift)\r
+ {\r
+ \r
+ case 0: \r
+ if (cValue < 3)\r
+ {\r
+ shift = cValue + 1;\r
+ }\r
+ else\r
+ {\r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (C40_BASIC_SET_CHARS[cValue] + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(C40_BASIC_SET_CHARS[cValue]);\r
+ }\r
+ }\r
+ break;\r
+ \r
+ case 1: \r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (cValue + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(cValue);\r
+ }\r
+ shift = 0;\r
+ break;\r
+ \r
+ case 2: \r
+ if (cValue < 27)\r
+ {\r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(C40_SHIFT2_SET_CHARS[cValue]);\r
+ }\r
+ }\r
+ else if (cValue == 27)\r
+ {\r
+ // FNC1\r
+ throw ReaderException.Instance;\r
+ }\r
+ else if (cValue == 30)\r
+ {\r
+ // Upper Shift\r
+ upperShift = true;\r
+ }\r
+ else\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ shift = 0;\r
+ break;\r
+ \r
+ case 3: \r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (cValue + 224));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append((char) (cValue + 96));\r
+ }\r
+ shift = 0;\r
+ break;\r
+ \r
+ default: \r
+ throw ReaderException.Instance;\r
+ \r
+ }\r
+ }\r
+ }\r
+ while (bits.available() > 0);\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, 5.2.6 and Annex C, Table C.2</summary>\r
+ private static void decodeTextSegment(BitSource bits, System.Text.StringBuilder result)\r
+ {\r
+ // Three Text values are encoded in a 16-bit value as\r
+ // (1600 * C1) + (40 * C2) + C3 + 1\r
+ // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time\r
+ bool upperShift = false;\r
+ \r
+ int[] cValues = new int[3];\r
+ do \r
+ {\r
+ // If there is only one byte left then it will be encoded as ASCII\r
+ if (bits.available() == 8)\r
+ {\r
+ return ;\r
+ }\r
+ int firstByte = bits.readBits(8);\r
+ if (firstByte == 254)\r
+ {\r
+ // Unlatch codeword\r
+ return ;\r
+ }\r
+ \r
+ parseTwoBytes(firstByte, bits.readBits(8), cValues);\r
+ \r
+ int shift = 0;\r
+ for (int i = 0; i < 3; i++)\r
+ {\r
+ int cValue = cValues[i];\r
+ switch (shift)\r
+ {\r
+ \r
+ case 0: \r
+ if (cValue < 3)\r
+ {\r
+ shift = cValue + 1;\r
+ }\r
+ else\r
+ {\r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (TEXT_BASIC_SET_CHARS[cValue] + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(TEXT_BASIC_SET_CHARS[cValue]);\r
+ }\r
+ }\r
+ break;\r
+ \r
+ case 1: \r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (cValue + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(cValue);\r
+ }\r
+ shift = 0;\r
+ break;\r
+ \r
+ case 2: \r
+ // Shift 2 for Text is the same encoding as C40\r
+ if (cValue < 27)\r
+ {\r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (C40_SHIFT2_SET_CHARS[cValue] + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(C40_SHIFT2_SET_CHARS[cValue]);\r
+ }\r
+ }\r
+ else if (cValue == 27)\r
+ {\r
+ // FNC1\r
+ throw ReaderException.Instance;\r
+ }\r
+ else if (cValue == 30)\r
+ {\r
+ // Upper Shift\r
+ upperShift = true;\r
+ }\r
+ else\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ shift = 0;\r
+ break;\r
+ \r
+ case 3: \r
+ if (upperShift)\r
+ {\r
+ result.Append((char) (TEXT_SHIFT3_SET_CHARS[cValue] + 128));\r
+ upperShift = false;\r
+ }\r
+ else\r
+ {\r
+ result.Append(TEXT_SHIFT3_SET_CHARS[cValue]);\r
+ }\r
+ shift = 0;\r
+ break;\r
+ \r
+ default: \r
+ throw ReaderException.Instance;\r
+ \r
+ }\r
+ }\r
+ }\r
+ while (bits.available() > 0);\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, 5.2.7</summary>\r
+ private static void decodeAnsiX12Segment(BitSource bits, System.Text.StringBuilder result)\r
+ {\r
+ // Three ANSI X12 values are encoded in a 16-bit value as\r
+ // (1600 * C1) + (40 * C2) + C3 + 1\r
+ \r
+ int[] cValues = new int[3];\r
+ do \r
+ {\r
+ // If there is only one byte left then it will be encoded as ASCII\r
+ if (bits.available() == 8)\r
+ {\r
+ return ;\r
+ }\r
+ int firstByte = bits.readBits(8);\r
+ if (firstByte == 254)\r
+ {\r
+ // Unlatch codeword\r
+ return ;\r
+ }\r
+ \r
+ parseTwoBytes(firstByte, bits.readBits(8), cValues);\r
+ \r
+ for (int i = 0; i < 3; i++)\r
+ {\r
+ int cValue = cValues[i];\r
+ if (cValue == 0)\r
+ {\r
+ // X12 segment terminator <CR>\r
+ result.Append('\r');\r
+ }\r
+ else if (cValue == 1)\r
+ {\r
+ // X12 segment separator *\r
+ result.Append('*');\r
+ }\r
+ else if (cValue == 2)\r
+ {\r
+ // X12 sub-element separator >\r
+ result.Append('>');\r
+ }\r
+ else if (cValue == 3)\r
+ {\r
+ // space\r
+ result.Append(' ');\r
+ }\r
+ else if (cValue < 14)\r
+ {\r
+ // 0 - 9\r
+ result.Append((char) (cValue + 44));\r
+ }\r
+ else if (cValue < 40)\r
+ {\r
+ // A - Z\r
+ result.Append((char) (cValue + 51));\r
+ }\r
+ else\r
+ {\r
+ throw ReaderException.Instance;\r
+ }\r
+ }\r
+ }\r
+ while (bits.available() > 0);\r
+ }\r
+ \r
+ private static void parseTwoBytes(int firstByte, int secondByte, int[] result)\r
+ {\r
+ int fullBitValue = (firstByte << 8) + secondByte - 1;\r
+ int temp = fullBitValue / 1600;\r
+ result[0] = temp;\r
+ fullBitValue -= temp * 1600;\r
+ temp = fullBitValue / 40;\r
+ result[1] = temp;\r
+ result[2] = fullBitValue - temp * 40;\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, 5.2.8 and Annex C Table C.3</summary>\r
+ private static void decodeEdifactSegment(BitSource bits, System.Text.StringBuilder result)\r
+ {\r
+ bool unlatch = false;\r
+ do \r
+ {\r
+ // If there is only two or less bytes left then it will be encoded as ASCII\r
+ if (bits.available() <= 16)\r
+ {\r
+ return ;\r
+ }\r
+ \r
+ for (int i = 0; i < 4; i++)\r
+ {\r
+ int edifactValue = bits.readBits(6);\r
+ \r
+ // Check for the unlatch character\r
+ if (edifactValue == 0x2B67)\r
+ {\r
+ // 011111\r
+ unlatch = true;\r
+ // If we encounter the unlatch code then continue reading because the Codeword triple\r
+ // is padded with 0's\r
+ }\r
+ \r
+ if (!unlatch)\r
+ {\r
+ if ((edifactValue & 32) == 0)\r
+ {\r
+ // no 1 in the leading (6th) bit\r
+ edifactValue |= 64; // Add a leading 01 to the 6 bit binary value\r
+ }\r
+ result.Append(edifactValue);\r
+ }\r
+ }\r
+ }\r
+ while (!unlatch && bits.available() > 0);\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, 5.2.9 and Annex B, B.2</summary>\r
+ private static void decodeBase256Segment(BitSource bits, System.Text.StringBuilder result, System.Collections.ArrayList byteSegments)\r
+ {\r
+ // Figure out how long the Base 256 Segment is.\r
+ int d1 = bits.readBits(8);\r
+ int count;\r
+ if (d1 == 0)\r
+ {\r
+ // Read the remainder of the symbol\r
+ count = bits.available() / 8;\r
+ }\r
+ else if (d1 < 250)\r
+ {\r
+ count = d1;\r
+ }\r
+ else\r
+ {\r
+ count = 250 * (d1 - 249) + bits.readBits(8);\r
+ }\r
+ sbyte[] bytes = new sbyte[count];\r
+ for (int i = 0; i < count; i++)\r
+ {\r
+ bytes[i] = unrandomize255State(bits.readBits(8), i);\r
+ }\r
+ byteSegments.Add(SupportClass.ToByteArray(bytes));\r
+ try\r
+ {\r
+ //UPGRADE_TODO: The differences in the Format of parameters for constructor 'java.lang.String.String' may cause compilation errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1092'"\r
+ result.Append(System.Text.Encoding.GetEncoding("ISO8859_1").GetString(SupportClass.ToByteArray(bytes)));\r
+ }\r
+ catch (System.IO.IOException uee)\r
+ {\r
+ //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"\r
+ throw new System.SystemException("Platform does not support required encoding: " + uee);\r
+ }\r
+ }\r
+ \r
+ /// <summary> See ISO 16022:2006, Annex B, B.2</summary>\r
+ private static sbyte unrandomize255State(int randomizedBase256Codeword, int base256CodewordPosition)\r
+ {\r
+ int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1;\r
+ int tempVariable = randomizedBase256Codeword - pseudoRandomNumber;\r
+ return (sbyte) (tempVariable >= 0?tempVariable:(tempVariable + 256));\r
+ }\r
+ }\r
+}
\ No newline at end of file