1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 // Original code is licensed as follows:
7 /*
8 * Copyright 2008 ZXing authors
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #include <algorithm>
24
25 #include "xfa/src/fxbarcode/barcode.h"
26 #include "xfa/src/fxbarcode/BC_Reader.h"
27 #include "xfa/src/fxbarcode/common/BC_CommonBitArray.h"
28 #include "BC_OneDReader.h"
29 #include "BC_OnedCode39Reader.h"
30 const FX_CHAR* CBC_OnedCode39Reader::ALPHABET_STRING =
31 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
32 const FX_CHAR* CBC_OnedCode39Reader::CHECKSUM_STRING =
33 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
34 const int32_t CBC_OnedCode39Reader::CHARACTER_ENCODINGS[44] = {
35 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124,
36 0x064, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C,
37 0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007,
38 0x106, 0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0,
39 0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A};
40 const int32_t CBC_OnedCode39Reader::ASTERISK_ENCODING = 0x094;
CBC_OnedCode39Reader()41 CBC_OnedCode39Reader::CBC_OnedCode39Reader()
42 : m_usingCheckDigit(FALSE), m_extendedMode(FALSE) {
43 }
CBC_OnedCode39Reader(FX_BOOL usingCheckDigit)44 CBC_OnedCode39Reader::CBC_OnedCode39Reader(FX_BOOL usingCheckDigit)
45 : m_usingCheckDigit(usingCheckDigit), m_extendedMode(FALSE) {
46 }
CBC_OnedCode39Reader(FX_BOOL usingCheckDigit,FX_BOOL extendedMode)47 CBC_OnedCode39Reader::CBC_OnedCode39Reader(FX_BOOL usingCheckDigit,
48 FX_BOOL extendedMode)
49 : m_usingCheckDigit(usingCheckDigit), m_extendedMode(extendedMode) {
50 }
~CBC_OnedCode39Reader()51 CBC_OnedCode39Reader::~CBC_OnedCode39Reader() {}
DecodeRow(int32_t rowNumber,CBC_CommonBitArray * row,int32_t hints,int32_t & e)52 CFX_ByteString CBC_OnedCode39Reader::DecodeRow(int32_t rowNumber,
53 CBC_CommonBitArray* row,
54 int32_t hints,
55 int32_t& e) {
56 CFX_Int32Array* start = FindAsteriskPattern(row, e);
57 BC_EXCEPTION_CHECK_ReturnValue(e, "");
58 int32_t nextStart = (*start)[1];
59 if (start != NULL) {
60 delete start;
61 start = NULL;
62 }
63 int32_t end = row->GetSize();
64 while (nextStart < end && !row->Get(nextStart)) {
65 nextStart++;
66 }
67 CFX_ByteString result;
68 CFX_Int32Array counters;
69 counters.SetSize(9);
70 FX_CHAR decodedChar;
71 int32_t lastStart;
72 do {
73 RecordPattern(row, nextStart, &counters, e);
74 BC_EXCEPTION_CHECK_ReturnValue(e, "");
75 int32_t pattern = ToNarrowWidePattern(&counters);
76 if (pattern < 0) {
77 e = BCExceptionNotFound;
78 return "";
79 }
80 decodedChar = PatternToChar(pattern, e);
81 BC_EXCEPTION_CHECK_ReturnValue(e, "");
82 result += decodedChar;
83 lastStart = nextStart;
84 for (int32_t i = 0; i < counters.GetSize(); i++) {
85 nextStart += counters[i];
86 }
87 while (nextStart < end && !row->Get(nextStart)) {
88 nextStart++;
89 }
90 } while (decodedChar != '*');
91 result = result.Mid(0, result.GetLength() - 1);
92 int32_t lastPatternSize = 0;
93 for (int32_t j = 0; j < counters.GetSize(); j++) {
94 lastPatternSize += counters[j];
95 }
96 if (m_usingCheckDigit) {
97 int32_t max = result.GetLength() - 1;
98 int32_t total = 0;
99 int32_t len = (int32_t)strlen(ALPHABET_STRING);
100 for (int32_t k = 0; k < max; k++) {
101 for (int32_t j = 0; j < len; j++)
102 if (ALPHABET_STRING[j] == result[k]) {
103 total += j;
104 }
105 }
106 if (result[max] != (ALPHABET_STRING)[total % 43]) {
107 e = BCExceptionChecksumException;
108 return "";
109 }
110 result = result.Mid(0, result.GetLength() - 1);
111 }
112 if (result.GetLength() == 0) {
113 e = BCExceptionNotFound;
114 return "";
115 }
116 if (m_extendedMode) {
117 CFX_ByteString bytestr = DecodeExtended(result, e);
118 BC_EXCEPTION_CHECK_ReturnValue(e, "");
119 return bytestr;
120 } else {
121 return result;
122 }
123 }
FindAsteriskPattern(CBC_CommonBitArray * row,int32_t & e)124 CFX_Int32Array* CBC_OnedCode39Reader::FindAsteriskPattern(
125 CBC_CommonBitArray* row,
126 int32_t& e) {
127 int32_t width = row->GetSize();
128 int32_t rowOffset = 0;
129 while (rowOffset < width) {
130 if (row->Get(rowOffset)) {
131 break;
132 }
133 rowOffset++;
134 }
135 int32_t counterPosition = 0;
136 CFX_Int32Array counters;
137 counters.SetSize(9);
138 int32_t patternStart = rowOffset;
139 FX_BOOL isWhite = FALSE;
140 int32_t patternLength = counters.GetSize();
141 for (int32_t i = rowOffset; i < width; i++) {
142 FX_BOOL pixel = row->Get(i);
143 if (pixel ^ isWhite) {
144 counters[counterPosition]++;
145 } else {
146 if (counterPosition == patternLength - 1) {
147 if (ToNarrowWidePattern(&counters) == ASTERISK_ENCODING) {
148 FX_BOOL bT1 =
149 row->IsRange(std::max(0, patternStart - (i - patternStart) / 2),
150 patternStart, FALSE, e);
151 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
152 if (bT1) {
153 CFX_Int32Array* result = new CFX_Int32Array;
154 result->SetSize(2);
155 (*result)[0] = patternStart;
156 (*result)[1] = i;
157 return result;
158 }
159 }
160 patternStart += counters[0] + counters[1];
161 for (int32_t y = 2; y < patternLength; y++) {
162 counters[y - 2] = counters[y];
163 }
164 counters[patternLength - 2] = 0;
165 counters[patternLength - 1] = 0;
166 counterPosition--;
167 } else {
168 counterPosition++;
169 }
170 counters[counterPosition] = 1;
171 isWhite = !isWhite;
172 }
173 }
174 e = BCExceptionNotFound;
175 return NULL;
176 }
ToNarrowWidePattern(CFX_Int32Array * counters)177 int32_t CBC_OnedCode39Reader::ToNarrowWidePattern(CFX_Int32Array* counters) {
178 int32_t numCounters = counters->GetSize();
179 int32_t maxNarrowCounter = 0;
180 int32_t wideCounters;
181 do {
182 #undef max
183 int32_t minCounter = FXSYS_IntMax;
184 for (int32_t i = 0; i < numCounters; i++) {
185 int32_t counter = (*counters)[i];
186 if (counter < minCounter && counter > maxNarrowCounter) {
187 minCounter = counter;
188 }
189 }
190 maxNarrowCounter = minCounter;
191 wideCounters = 0;
192 int32_t totalWideCountersWidth = 0;
193 int32_t pattern = 0;
194 for (int32_t j = 0; j < numCounters; j++) {
195 int32_t counter = (*counters)[j];
196 if ((*counters)[j] > maxNarrowCounter) {
197 pattern |= 1 << (numCounters - 1 - j);
198 wideCounters++;
199 totalWideCountersWidth += counter;
200 }
201 }
202 if (wideCounters == 3) {
203 for (int32_t k = 0; k < numCounters && wideCounters > 0; k++) {
204 int32_t counter = (*counters)[k];
205 if ((*counters)[k] > maxNarrowCounter) {
206 wideCounters--;
207 if ((counter << 1) >= totalWideCountersWidth) {
208 return -1;
209 }
210 }
211 }
212 return pattern;
213 }
214 } while (wideCounters > 3);
215 return -1;
216 }
PatternToChar(int32_t pattern,int32_t & e)217 FX_CHAR CBC_OnedCode39Reader::PatternToChar(int32_t pattern, int32_t& e) {
218 for (int32_t i = 0; i < 44; i++) {
219 if (CHARACTER_ENCODINGS[i] == pattern) {
220 return (ALPHABET_STRING)[i];
221 }
222 }
223 e = BCExceptionNotFound;
224 return 0;
225 }
DecodeExtended(CFX_ByteString & encoded,int32_t & e)226 CFX_ByteString CBC_OnedCode39Reader::DecodeExtended(CFX_ByteString& encoded,
227 int32_t& e) {
228 int32_t length = encoded.GetLength();
229 CFX_ByteString decoded;
230 FX_CHAR c, next;
231 for (int32_t i = 0; i < length; i++) {
232 c = encoded[i];
233 if (c == '+' || c == '$' || c == '%' || c == '/') {
234 next = encoded[i + 1];
235 FX_CHAR decodedChar = '\0';
236 switch (c) {
237 case '+':
238 if (next >= 'A' && next <= 'Z') {
239 decodedChar = (FX_CHAR)(next + 32);
240 } else {
241 e = BCExceptionFormatException;
242 return "";
243 }
244 break;
245 case '$':
246 if (next >= 'A' && next <= 'Z') {
247 decodedChar = (FX_CHAR)(next - 64);
248 } else {
249 e = BCExceptionFormatException;
250 return "";
251 }
252 break;
253 case '%':
254 if (next >= 'A' && next <= 'E') {
255 decodedChar = (FX_CHAR)(next - 38);
256 } else if (next >= 'F' && next <= 'J') {
257 decodedChar = (FX_CHAR)(next - 11);
258 } else if (next >= 'K' && next <= 'O' && next != 'M' && next != 'N') {
259 decodedChar = (FX_CHAR)(next + 16);
260 } else if (next >= 'P' && next <= 'S') {
261 decodedChar = (FX_CHAR)(next + 43);
262 } else if (next == 'U') {
263 decodedChar = (FX_CHAR)0;
264 } else if (next == 'V') {
265 decodedChar = (FX_CHAR)64;
266 } else if (next == 'W') {
267 decodedChar = (FX_CHAR)96;
268 } else if (next == 'T' || next == 'X' || next == 'Y' || next == 'Z') {
269 decodedChar = (FX_CHAR)127;
270 } else {
271 e = BCExceptionFormatException;
272 return "";
273 }
274 break;
275 case '/':
276 if (next >= 'A' && next <= 'O') {
277 decodedChar = (FX_CHAR)(next - 32);
278 } else if (next == 'Z') {
279 decodedChar = ':';
280 } else {
281 e = BCExceptionFormatException;
282 return "";
283 }
284 break;
285 }
286 decoded += decodedChar;
287 i++;
288 } else {
289 decoded += c;
290 }
291 }
292 return decoded;
293 }
294