Committed C# port from Mohamad
[zxing.git] / csharp / oned / UPCEReader.cs
diff --git a/csharp/oned/UPCEReader.cs b/csharp/oned/UPCEReader.cs
new file mode 100755 (executable)
index 0000000..bed8653
--- /dev/null
@@ -0,0 +1,151 @@
+/*\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
+namespace com.google.zxing.oned\r
+{\r
+    using System.Text;\r
+    using com.google.zxing.common;\r
+    /**\r
+     * <p>Implements decoding of the UPC-E format.</p>\r
+     * <p/>\r
+     * <p><a href="http://www.barcodeisland.com/upce.phtml">This</a> is a great reference for\r
+     * UPC-E information.</p>\r
+     *\r
+     * @author Sean Owen\r
+     */\r
+\r
+\r
+    public sealed class UPCEReader : AbstractUPCEANReader\r
+    { \r
+           /**\r
+           * The pattern that marks the middle, and end, of a UPC-E pattern.\r
+           * There is no "second half" to a UPC-E barcode.\r
+           */\r
+          private int[] MIDDLE_END_PATTERN = new int[]{1, 1, 1, 1, 1, 1};\r
+\r
+          /**\r
+           * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of\r
+           * even-odd parity encodings of digits that imply both the number system (0 or 1)\r
+           * used, and the check digit.\r
+           */\r
+          private static int[][] NUMSYS_AND_CHECK_DIGIT_PATTERNS = new int[][]{\r
+              new int[]{0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},\r
+              new int[]{0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}\r
+          };\r
+\r
+          private int[] decodeMiddleCounters;\r
+\r
+          public UPCEReader() {\r
+            decodeMiddleCounters = new int[4];\r
+          }\r
+\r
+          protected override int decodeMiddle(BitArray row, int[] startRange, StringBuilder result) {\r
+            int[] counters = decodeMiddleCounters;\r
+            counters[0] = 0;\r
+            counters[1] = 0;\r
+            counters[2] = 0;\r
+            counters[3] = 0;\r
+            int end = row.getSize();\r
+            int rowOffset = startRange[1];\r
+\r
+            int lgPatternFound = 0;\r
+\r
+            for (int x = 0; x < 6 && rowOffset < end; x++) {\r
+              int bestMatch = decodeDigit(row, counters, rowOffset, L_AND_G_PATTERNS);\r
+              result.Append((char) ('0' + bestMatch % 10));\r
+              for (int i = 0; i < counters.Length; i++) {\r
+                rowOffset += counters[i];\r
+              }\r
+              if (bestMatch >= 10) {\r
+                lgPatternFound |= 1 << (5 - x);\r
+              }\r
+            }\r
+\r
+            determineNumSysAndCheckDigit(result, lgPatternFound);\r
+\r
+            return rowOffset;\r
+          }\r
+\r
+          public int[] decodeEnd(BitArray row, int endStart) {\r
+            return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN);\r
+          }\r
+\r
+          public bool checkChecksum(string s) {\r
+              return base.checkChecksum(convertUPCEtoUPCA(s));\r
+          }\r
+\r
+          private static void determineNumSysAndCheckDigit(StringBuilder resultString, int lgPatternFound)\r
+              {\r
+\r
+            for (int numSys = 0; numSys <= 1; numSys++) {\r
+              for (int d = 0; d < 10; d++) {\r
+                if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) {\r
+                  resultString.Insert(0, (char) ('0' + numSys));\r
+                  resultString.Append((char) ('0' + d));\r
+                  return;\r
+                }\r
+              }\r
+            }\r
+            throw new ReaderException();\r
+          }\r
+\r
+          public override BarcodeFormat getBarcodeFormat() {\r
+            return BarcodeFormat.UPC_E;  \r
+          }\r
+\r
+          /**\r
+           * Expands a UPC-E value back into its full, equivalent UPC-A code value.\r
+           *\r
+           * @param upce UPC-E code as string of digits\r
+           * @return equivalent UPC-A code as string of digits\r
+           */\r
+          public static string convertUPCEtoUPCA(string upce) {\r
+            char[] upceChars = new char[6];\r
+            SupportClass.GetCharsFromString(upce, 1, 7, upceChars, 0);\r
+            StringBuilder result = new StringBuilder(12);\r
+            result.Append(upce[0]);\r
+            char lastChar = upceChars[5];\r
+            switch (lastChar) {\r
+              case '0':\r
+              case '1':\r
+              case '2':\r
+                result.Append(upceChars, 0, 2);\r
+                result.Append(lastChar);\r
+                result.Append("0000");\r
+                result.Append(upceChars, 2, 3);\r
+                break;\r
+              case '3':\r
+                result.Append(upceChars, 0, 3);\r
+                result.Append("00000");\r
+                result.Append(upceChars, 3, 2);\r
+                break;\r
+              case '4':\r
+                result.Append(upceChars, 0, 4);\r
+                result.Append("00000");\r
+                result.Append(upceChars[4]);\r
+                break;\r
+              default:\r
+                result.Append(upceChars, 0, 5);\r
+                result.Append("0000");\r
+                result.Append(lastChar);\r
+                break;\r
+            }\r
+            result.Append(upce[7]);\r
+            return result.ToString();\r
+          }\r
+    \r
+    \r
+    }\r
+\r
+\r
+}\r