Began removing the excessive use of exceptions in the 1D readers by drawing
[zxing.git] / cpp / core / src / zxing / oned / UPCEReader.cpp
1 /*
2  *  UPCEReader.cpp
3  *  ZXing
4  *
5  *  Copyright 2010 ZXing authors All rights reserved.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include "UPCEReader.h"
21 #include <zxing/ReaderException.h>
22
23 namespace zxing {
24         namespace oned {
25
26                 /**
27                  * The pattern that marks the middle, and end, of a UPC-E pattern.
28                  * There is no "second half" to a UPC-E barcode.
29                  */
30                 static const int MIDDLE_END_PATTERN[6] = {1, 1, 1, 1, 1, 1};
31
32                 /**
33                  * See {@link #L_AND_G_PATTERNS}; these values similarly represent patterns of
34                  * even-odd parity encodings of digits that imply both the number system (0 or 1)
35                  * used, and the check digit.
36                  */
37                 static const int NUMSYS_AND_CHECK_DIGIT_PATTERNS[2][10] = {
38                         {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25},
39                         {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}
40                 };
41
42                 UPCEReader::UPCEReader() {
43                 }
44
45                 int UPCEReader::decodeMiddle(Ref<BitArray> row, int startRange[], int startRangeLen,
46                     std::string& resultString) {
47                         const int countersLen = 4;
48                         int counters[countersLen] = { 0, 0, 0, 0 };
49
50                         int end = row->getSize();
51                         int rowOffset = startRange[1];
52
53                         int lgPatternFound = 0;
54
55                         for (int x = 0; x < 6 && rowOffset < end; x++) {
56                                 int bestMatch = decodeDigit(row, counters, countersLen, rowOffset,
57                                     UPC_EAN_PATTERNS_L_AND_G_PATTERNS);
58                                 resultString.append(1, (char) ('0' + bestMatch % 10));
59                                 for (int i = 0; i < countersLen; i++) {
60                                         rowOffset += counters[i];
61                                 }
62                                 if (bestMatch >= 10) {
63                                         lgPatternFound |= 1 << (5 - x);
64                                 }
65                         }
66
67                         determineNumSysAndCheckDigit(resultString, lgPatternFound);
68
69                         return rowOffset;
70                 }
71
72                 int* UPCEReader::decodeEnd(Ref<BitArray> row, int endStart) {
73                         return findGuardPattern(row, endStart, true, MIDDLE_END_PATTERN,
74                             sizeof(MIDDLE_END_PATTERN) / sizeof(int));
75                 }
76
77                 bool UPCEReader::checkChecksum(std::string s){
78                         return UPCEANReader::checkChecksum(convertUPCEtoUPCA(s));
79                 }
80
81
82                 void UPCEReader::determineNumSysAndCheckDigit(std::string& resultString, int lgPatternFound) {
83                         for (int numSys = 0; numSys <= 1; numSys++) {
84                                 for (int d = 0; d < 10; d++) {
85                                         if (lgPatternFound == NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) {
86                                                 resultString.insert(0, 1, (char) ('0' + numSys));
87                                                 resultString.append(1, (char) ('0' + d));
88                                                 return;
89                                         }
90                                 }
91                         }
92                         throw ReaderException("determineNumSysAndCheckDigit exception");
93                 }
94
95                 /**
96                  * Expands a UPC-E value back into its full, equivalent UPC-A code value.
97                  *
98                  * @param upce UPC-E code as string of digits
99                  * @return equivalent UPC-A code as string of digits
100                  */
101                 std::string UPCEReader::convertUPCEtoUPCA(std::string upce) {
102                         std::string result;
103                         result.append(1, upce[0]);
104                         char lastChar = upce[6];
105                         switch (lastChar) {
106                                 case '0':
107                                 case '1':
108                                 case '2':
109                                         result.append(upce.substr(1,2));
110                                         result.append(1, lastChar);
111                                         result.append("0000");
112                                         result.append(upce.substr(3,3));
113                                         break;
114                                 case '3':
115                                         result.append(upce.substr(1,3));
116                                         result.append("00000");
117                                         result.append(upce.substr(4,2));
118                                         break;
119                                 case '4':
120                                         result.append(upce.substr(1,4));
121                                         result.append("00000");
122                                         result.append(1, upce[5]);
123                                         break;
124                                 default:
125                                         result.append(upce.substr(1,5));
126                                         result.append("0000");
127                                         result.append(1, lastChar);
128                                         break;
129                         }
130                         result.append(1, upce[7]);
131                         return result;
132                 }
133
134
135                 BarcodeFormat UPCEReader::getBarcodeFormat() {
136                         return BarcodeFormat_UPC_E;
137                 }
138         }
139 }