Merge to XFA: Remove typdefs for pointer types in fx_system.h.
[pdfium.git] / xfa / src / fxbarcode / oned / BC_OnedCodaBarReader.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 // Original code is licensed as follows:\r
7 /*\r
8  * Copyright 2008 ZXing authors\r
9  *\r
10  * Licensed under the Apache License, Version 2.0 (the "License");\r
11  * you may not use this file except in compliance with the License.\r
12  * You may obtain a copy of the License at\r
13  *\r
14  *      http://www.apache.org/licenses/LICENSE-2.0\r
15  *\r
16  * Unless required by applicable law or agreed to in writing, software\r
17  * distributed under the License is distributed on an "AS IS" BASIS,\r
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
19  * See the License for the specific language governing permissions and\r
20  * limitations under the License.\r
21  */\r
22 \r
23 #include "../barcode.h"\r
24 #include "../BC_Reader.h"\r
25 #include "../common/BC_CommonBitArray.h"\r
26 #include "../oned/BC_OneDReader.h"\r
27 #include "../oned/BC_OnedCode39Reader.h"\r
28 #include "../oned/BC_OnedCodaBarReader.h"\r
29 const FX_CHAR* CBC_OnedCodaBarReader::ALPHABET_STRING = "0123456789-$:/.+ABCDTN";\r
30 const int32_t CBC_OnedCodaBarReader::CHARACTER_ENCODINGS[22] = {\r
31     0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048,\r
32     0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E,\r
33     0x01A, 0x029\r
34 };\r
35 const int32_t CBC_OnedCodaBarReader::minCharacterLength = 3;\r
36 const FX_CHAR CBC_OnedCodaBarReader::STARTEND_ENCODING[8] = {'E', '*', 'A', 'B', 'C', 'D', 'T', 'N'};\r
37 CBC_OnedCodaBarReader::CBC_OnedCodaBarReader()\r
38 {\r
39 }\r
40 CBC_OnedCodaBarReader::~CBC_OnedCodaBarReader()\r
41 {\r
42 }\r
43 CFX_ByteString CBC_OnedCodaBarReader::DecodeRow(int32_t rowNumber, CBC_CommonBitArray *row, int32_t hints, int32_t &e)\r
44 {\r
45     CFX_Int32Array *int32Ptr = FindAsteriskPattern(row, e);\r
46     BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
47     CBC_AutoPtr<CFX_Int32Array> start(int32Ptr);\r
48     (*start)[1] = 0;\r
49     int32_t nextStart = (*start)[1];\r
50     int32_t end = row->GetSize();\r
51     while (nextStart < end && !row->Get(nextStart)) {\r
52         nextStart++;\r
53     }\r
54     CFX_ByteString result;\r
55     CFX_Int32Array counters;\r
56     counters.SetSize(7);\r
57     FX_CHAR decodedChar;\r
58     int32_t lastStart;\r
59     do {\r
60         RecordPattern(row, nextStart, &counters, e);\r
61         BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
62         decodedChar = ToNarrowWidePattern(&counters);\r
63         if (decodedChar == '!') {\r
64             e = BCExceptionNotFound;\r
65             return "";\r
66         }\r
67         result += decodedChar;\r
68         lastStart = nextStart;\r
69         for (int32_t i = 0; i < counters.GetSize(); i++) {\r
70             nextStart += counters[i];\r
71         }\r
72         while (nextStart < end && !row->Get(nextStart)) {\r
73             nextStart++;\r
74         }\r
75     } while (nextStart < end);\r
76     int32_t lastPatternSize = 0;\r
77     for (int32_t j = 0; j < counters.GetSize(); j++) {\r
78         lastPatternSize += counters[j];\r
79     }\r
80     int32_t whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;\r
81     if (nextStart != end && (whiteSpaceAfterEnd / 2 < lastPatternSize)) {\r
82         e = BCExceptionNotFound;\r
83         return "";\r
84     }\r
85     if (result.GetLength() < 2) {\r
86         e = BCExceptionNotFound;\r
87         return "";\r
88     }\r
89     FX_CHAR startchar = result[0];\r
90     if (!ArrayContains(STARTEND_ENCODING, startchar)) {\r
91         e =  BCExceptionNotFound;\r
92         return "";\r
93     }\r
94     int32_t len = result.GetLength();\r
95     CFX_ByteString temp = result;\r
96     for (int32_t k = 1; k < result.GetLength(); k++) {\r
97         if (ArrayContains(STARTEND_ENCODING, result[k])) {\r
98             if ((k + 1) != result.GetLength()) {\r
99                 result.Delete(1, k);\r
100                 k = 1;\r
101             }\r
102         }\r
103     }\r
104     if (result.GetLength() < 5) {\r
105         int32_t index = temp.Find(result.Mid(1, result.GetLength() - 1));\r
106         if (index == len - (result.GetLength() - 1)) {\r
107             e = BCExceptionNotFound;\r
108             return "";\r
109         }\r
110     }\r
111     if (result.GetLength() > minCharacterLength) {\r
112         result = result.Mid(1, result.GetLength() - 2);\r
113     } else {\r
114         e = BCExceptionNotFound;\r
115         return "";\r
116     }\r
117     return result;\r
118 }\r
119 CFX_Int32Array *CBC_OnedCodaBarReader::FindAsteriskPattern(CBC_CommonBitArray *row, int32_t &e)\r
120 {\r
121     int32_t width = row->GetSize();\r
122     int32_t rowOffset = 0;\r
123     while (rowOffset < width) {\r
124         if (row->Get(rowOffset)) {\r
125             break;\r
126         }\r
127         rowOffset++;\r
128     }\r
129     int32_t counterPosition = 0;\r
130     CFX_Int32Array counters;\r
131     counters.SetSize(7);\r
132     int32_t patternStart = rowOffset;\r
133     FX_BOOL isWhite = FALSE;\r
134     int32_t patternLength = counters.GetSize();\r
135     for (int32_t i = rowOffset; i < width; i++) {\r
136         FX_BOOL pixel = row->Get(i);\r
137         if (pixel ^ isWhite) {\r
138             counters[counterPosition]++;\r
139         } else {\r
140             if (counterPosition == patternLength - 1) {\r
141                 if (ArrayContains(STARTEND_ENCODING, ToNarrowWidePattern(&counters))) {\r
142                     FX_BOOL btemp3 = row->IsRange(FX_MAX(0, patternStart - (i - patternStart) / 2), patternStart, FALSE, e);\r
143                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
144                     if (btemp3) {\r
145                         CFX_Int32Array *result = FX_NEW CFX_Int32Array();\r
146                         result->SetSize(2);\r
147                         (*result)[0] = patternStart;\r
148                         (*result)[1] = i;\r
149                         return result;\r
150                     }\r
151                 }\r
152                 patternStart += counters[0] + counters[1];\r
153                 for (int32_t y = 2; y < patternLength; y++) {\r
154                     counters[y - 2] = counters[y];\r
155                 }\r
156                 counters[patternLength - 2] = 0;\r
157                 counters[patternLength - 1] = 0;\r
158                 counterPosition--;\r
159             } else {\r
160                 counterPosition++;\r
161             }\r
162             counters[counterPosition] = 1;\r
163             isWhite = !isWhite;\r
164         }\r
165     }\r
166     e = BCExceptionNotFound;\r
167     return NULL;\r
168 }\r
169 FX_BOOL CBC_OnedCodaBarReader::ArrayContains(const FX_CHAR array[], FX_CHAR key)\r
170 {\r
171     for(int32_t i = 0; i < 8; i++) {\r
172         if(array[i] == key) {\r
173             return TRUE;\r
174         }\r
175     }\r
176     return FALSE;\r
177 }\r
178 FX_CHAR CBC_OnedCodaBarReader::ToNarrowWidePattern(CFX_Int32Array *counter)\r
179 {\r
180     int32_t numCounters = counter->GetSize();\r
181     if (numCounters < 1) {\r
182         return '!';\r
183     }\r
184     int32_t averageCounter = 0;\r
185     int32_t totalCounters = 0;\r
186     for (int32_t i = 0; i < numCounters; i++) {\r
187         totalCounters += (*counter)[i];\r
188     }\r
189     averageCounter = totalCounters / numCounters;\r
190     int32_t pattern = 0;\r
191     int32_t wideCounters = 0;\r
192     for (int32_t j = 0; j < numCounters; j++) {\r
193         if ((*counter)[j] > averageCounter) {\r
194             pattern |= 1 << (numCounters - 1 - j);\r
195             wideCounters++;\r
196         }\r
197     }\r
198     if ((wideCounters == 2) || (wideCounters == 3)) {\r
199         for (int32_t k = 0; k < 22; k++) {\r
200             if (CHARACTER_ENCODINGS[k] == pattern) {\r
201                 return (ALPHABET_STRING)[k];\r
202             }\r
203         }\r
204     }\r
205     return '!';\r
206 }\r