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_OnedCode128Reader.h"
30 const int32_t CBC_OnedCode128Reader::CODE_PATTERNS[107][7] = {
31 {2, 1, 2, 2, 2, 2, 0}, {2, 2, 2, 1, 2, 2, 0}, {2, 2, 2, 2, 2, 1, 0},
32 {1, 2, 1, 2, 2, 3, 0}, {1, 2, 1, 3, 2, 2, 0}, {1, 3, 1, 2, 2, 2, 0},
33 {1, 2, 2, 2, 1, 3, 0}, {1, 2, 2, 3, 1, 2, 0}, {1, 3, 2, 2, 1, 2, 0},
34 {2, 2, 1, 2, 1, 3, 0}, {2, 2, 1, 3, 1, 2, 0}, {2, 3, 1, 2, 1, 2, 0},
35 {1, 1, 2, 2, 3, 2, 0}, {1, 2, 2, 1, 3, 2, 0}, {1, 2, 2, 2, 3, 1, 0},
36 {1, 1, 3, 2, 2, 2, 0}, {1, 2, 3, 1, 2, 2, 0}, {1, 2, 3, 2, 2, 1, 0},
37 {2, 2, 3, 2, 1, 1, 0}, {2, 2, 1, 1, 3, 2, 0}, {2, 2, 1, 2, 3, 1, 0},
38 {2, 1, 3, 2, 1, 2, 0}, {2, 2, 3, 1, 1, 2, 0}, {3, 1, 2, 1, 3, 1, 0},
39 {3, 1, 1, 2, 2, 2, 0}, {3, 2, 1, 1, 2, 2, 0}, {3, 2, 1, 2, 2, 1, 0},
40 {3, 1, 2, 2, 1, 2, 0}, {3, 2, 2, 1, 1, 2, 0}, {3, 2, 2, 2, 1, 1, 0},
41 {2, 1, 2, 1, 2, 3, 0}, {2, 1, 2, 3, 2, 1, 0}, {2, 3, 2, 1, 2, 1, 0},
42 {1, 1, 1, 3, 2, 3, 0}, {1, 3, 1, 1, 2, 3, 0}, {1, 3, 1, 3, 2, 1, 0},
43 {1, 1, 2, 3, 1, 3, 0}, {1, 3, 2, 1, 1, 3, 0}, {1, 3, 2, 3, 1, 1, 0},
44 {2, 1, 1, 3, 1, 3, 0}, {2, 3, 1, 1, 1, 3, 0}, {2, 3, 1, 3, 1, 1, 0},
45 {1, 1, 2, 1, 3, 3, 0}, {1, 1, 2, 3, 3, 1, 0}, {1, 3, 2, 1, 3, 1, 0},
46 {1, 1, 3, 1, 2, 3, 0}, {1, 1, 3, 3, 2, 1, 0}, {1, 3, 3, 1, 2, 1, 0},
47 {3, 1, 3, 1, 2, 1, 0}, {2, 1, 1, 3, 3, 1, 0}, {2, 3, 1, 1, 3, 1, 0},
48 {2, 1, 3, 1, 1, 3, 0}, {2, 1, 3, 3, 1, 1, 0}, {2, 1, 3, 1, 3, 1, 0},
49 {3, 1, 1, 1, 2, 3, 0}, {3, 1, 1, 3, 2, 1, 0}, {3, 3, 1, 1, 2, 1, 0},
50 {3, 1, 2, 1, 1, 3, 0}, {3, 1, 2, 3, 1, 1, 0}, {3, 3, 2, 1, 1, 1, 0},
51 {3, 1, 4, 1, 1, 1, 0}, {2, 2, 1, 4, 1, 1, 0}, {4, 3, 1, 1, 1, 1, 0},
52 {1, 1, 1, 2, 2, 4, 0}, {1, 1, 1, 4, 2, 2, 0}, {1, 2, 1, 1, 2, 4, 0},
53 {1, 2, 1, 4, 2, 1, 0}, {1, 4, 1, 1, 2, 2, 0}, {1, 4, 1, 2, 2, 1, 0},
54 {1, 1, 2, 2, 1, 4, 0}, {1, 1, 2, 4, 1, 2, 0}, {1, 2, 2, 1, 1, 4, 0},
55 {1, 2, 2, 4, 1, 1, 0}, {1, 4, 2, 1, 1, 2, 0}, {1, 4, 2, 2, 1, 1, 0},
56 {2, 4, 1, 2, 1, 1, 0}, {2, 2, 1, 1, 1, 4, 0}, {4, 1, 3, 1, 1, 1, 0},
57 {2, 4, 1, 1, 1, 2, 0}, {1, 3, 4, 1, 1, 1, 0}, {1, 1, 1, 2, 4, 2, 0},
58 {1, 2, 1, 1, 4, 2, 0}, {1, 2, 1, 2, 4, 1, 0}, {1, 1, 4, 2, 1, 2, 0},
59 {1, 2, 4, 1, 1, 2, 0}, {1, 2, 4, 2, 1, 1, 0}, {4, 1, 1, 2, 1, 2, 0},
60 {4, 2, 1, 1, 1, 2, 0}, {4, 2, 1, 2, 1, 1, 0}, {2, 1, 2, 1, 4, 1, 0},
61 {2, 1, 4, 1, 2, 1, 0}, {4, 1, 2, 1, 2, 1, 0}, {1, 1, 1, 1, 4, 3, 0},
62 {1, 1, 1, 3, 4, 1, 0}, {1, 3, 1, 1, 4, 1, 0}, {1, 1, 4, 1, 1, 3, 0},
63 {1, 1, 4, 3, 1, 1, 0}, {4, 1, 1, 1, 1, 3, 0}, {4, 1, 1, 3, 1, 1, 0},
64 {1, 1, 3, 1, 4, 1, 0}, {1, 1, 4, 1, 3, 1, 0}, {3, 1, 1, 1, 4, 1, 0},
65 {4, 1, 1, 1, 3, 1, 0}, {2, 1, 1, 4, 1, 2, 0}, {2, 1, 1, 2, 1, 4, 0},
66 {2, 1, 1, 2, 3, 2, 0}, {2, 3, 3, 1, 1, 1, 2}};
67 const int32_t CBC_OnedCode128Reader::MAX_AVG_VARIANCE = (int32_t)(256 * 0.25f);
68 const int32_t CBC_OnedCode128Reader::MAX_INDIVIDUAL_VARIANCE =
69 (int32_t)(256 * 0.7f);
70 const int32_t CBC_OnedCode128Reader::CODE_SHIFT = 98;
71 const int32_t CBC_OnedCode128Reader::CODE_CODE_C = 99;
72 const int32_t CBC_OnedCode128Reader::CODE_CODE_B = 100;
73 const int32_t CBC_OnedCode128Reader::CODE_CODE_A = 101;
74 const int32_t CBC_OnedCode128Reader::CODE_FNC_1 = 102;
75 const int32_t CBC_OnedCode128Reader::CODE_FNC_2 = 97;
76 const int32_t CBC_OnedCode128Reader::CODE_FNC_3 = 96;
77 const int32_t CBC_OnedCode128Reader::CODE_FNC_4_A = 101;
78 const int32_t CBC_OnedCode128Reader::CODE_FNC_4_B = 100;
79 const int32_t CBC_OnedCode128Reader::CODE_START_A = 103;
80 const int32_t CBC_OnedCode128Reader::CODE_START_B = 104;
81 const int32_t CBC_OnedCode128Reader::CODE_START_C = 105;
82 const int32_t CBC_OnedCode128Reader::CODE_STOP = 106;
CBC_OnedCode128Reader()83 CBC_OnedCode128Reader::CBC_OnedCode128Reader() {}
~CBC_OnedCode128Reader()84 CBC_OnedCode128Reader::~CBC_OnedCode128Reader() {}
FindStartPattern(CBC_CommonBitArray * row,int32_t & e)85 CFX_Int32Array* CBC_OnedCode128Reader::FindStartPattern(CBC_CommonBitArray* row,
86 int32_t& e) {
87 int32_t width = row->GetSize();
88 int32_t rowOffset = 0;
89 while (rowOffset < width) {
90 if (row->Get(rowOffset)) {
91 break;
92 }
93 rowOffset++;
94 }
95 int32_t counterPosition = 0;
96 CFX_Int32Array counters;
97 counters.SetSize(6);
98 int32_t patternStart = rowOffset;
99 FX_BOOL isWhite = FALSE;
100 int32_t patternLength = counters.GetSize();
101 for (int32_t i = rowOffset; i < width; i++) {
102 FX_BOOL pixel = row->Get(i);
103 if (pixel ^ isWhite) {
104 counters[counterPosition]++;
105 } else {
106 if (counterPosition == patternLength - 1) {
107 int32_t bestVariance = MAX_AVG_VARIANCE;
108 int32_t bestMatch = -1;
109 for (int32_t startCode = CODE_START_A; startCode <= CODE_START_C;
110 startCode++) {
111 int32_t variance = PatternMatchVariance(
112 &counters, &CODE_PATTERNS[startCode][0], MAX_INDIVIDUAL_VARIANCE);
113 if (variance < bestVariance) {
114 bestVariance = variance;
115 bestMatch = startCode;
116 }
117 }
118 if (bestMatch >= 0) {
119 FX_BOOL btemp2 =
120 row->IsRange(std::max(0, patternStart - (i - patternStart) / 2),
121 patternStart, FALSE, e);
122 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
123 if (btemp2) {
124 CFX_Int32Array* result = new CFX_Int32Array;
125 result->SetSize(3);
126 (*result)[0] = patternStart;
127 (*result)[1] = i;
128 (*result)[2] = bestMatch;
129 return result;
130 }
131 }
132 patternStart += counters[0] + counters[1];
133 for (int32_t y = 2; y < patternLength; y++) {
134 counters[y - 2] = counters[y];
135 }
136 counters[patternLength - 2] = 0;
137 counters[patternLength - 1] = 0;
138 counterPosition--;
139 } else {
140 counterPosition++;
141 }
142 counters[counterPosition] = 1;
143 isWhite = !isWhite;
144 }
145 }
146 e = BCExceptionNotFound;
147 return NULL;
148 }
DecodeCode(CBC_CommonBitArray * row,CFX_Int32Array * counters,int32_t rowOffset,int32_t & e)149 int32_t CBC_OnedCode128Reader::DecodeCode(CBC_CommonBitArray* row,
150 CFX_Int32Array* counters,
151 int32_t rowOffset,
152 int32_t& e) {
153 RecordPattern(row, rowOffset, counters, e);
154 BC_EXCEPTION_CHECK_ReturnValue(e, 0);
155 int32_t bestVariance = MAX_AVG_VARIANCE;
156 int32_t bestMatch = -1;
157 for (int32_t d = 0; d < 107; d++) {
158 int32_t variance = PatternMatchVariance(counters, &CODE_PATTERNS[d][0],
159 MAX_INDIVIDUAL_VARIANCE);
160 if (variance < bestVariance) {
161 bestVariance = variance;
162 bestMatch = d;
163 }
164 }
165 if (bestMatch >= 0) {
166 return bestMatch;
167 } else {
168 e = BCExceptionNotFound;
169 return 0;
170 }
171 return 0;
172 }
DecodeRow(int32_t rowNumber,CBC_CommonBitArray * row,int32_t hints,int32_t & e)173 CFX_ByteString CBC_OnedCode128Reader::DecodeRow(int32_t rowNumber,
174 CBC_CommonBitArray* row,
175 int32_t hints,
176 int32_t& e) {
177 CFX_Int32Array* startPatternInfo = FindStartPattern(row, e);
178 BC_EXCEPTION_CHECK_ReturnValue(e, "");
179 int32_t startCode = (*startPatternInfo)[2];
180 int32_t codeSet;
181 switch (startCode) {
182 case 103:
183 codeSet = CODE_CODE_A;
184 break;
185 case 104:
186 codeSet = CODE_CODE_B;
187 break;
188 case 105:
189 codeSet = CODE_CODE_C;
190 break;
191 default:
192 if (startPatternInfo != NULL) {
193 startPatternInfo->RemoveAll();
194 delete startPatternInfo;
195 startPatternInfo = NULL;
196 }
197 e = BCExceptionFormatException;
198 return "";
199 }
200 FX_BOOL done = FALSE;
201 FX_BOOL isNextShifted = FALSE;
202 CFX_ByteString result;
203 int32_t lastStart = (*startPatternInfo)[0];
204 int32_t nextStart = (*startPatternInfo)[1];
205 if (startPatternInfo != NULL) {
206 startPatternInfo->RemoveAll();
207 delete startPatternInfo;
208 startPatternInfo = NULL;
209 }
210 CFX_Int32Array counters;
211 counters.SetSize(6);
212 int32_t lastCode = 0;
213 int32_t code = 0;
214 int32_t checksumTotal = startCode;
215 int32_t multiplier = 0;
216 FX_BOOL lastCharacterWasPrintable = TRUE;
217 while (!done) {
218 FX_BOOL unshift = isNextShifted;
219 isNextShifted = FALSE;
220 lastCode = code;
221 code = DecodeCode(row, &counters, nextStart, e);
222 BC_EXCEPTION_CHECK_ReturnValue(e, "");
223 if (code != CODE_STOP) {
224 lastCharacterWasPrintable = TRUE;
225 }
226 if (code != CODE_STOP) {
227 multiplier++;
228 checksumTotal += multiplier * code;
229 }
230 lastStart = nextStart;
231 for (int32_t i = 0; i < counters.GetSize(); i++) {
232 nextStart += counters[i];
233 }
234 switch (code) {
235 case 103:
236 case 104:
237 case 105:
238 e = BCExceptionFormatException;
239 return "";
240 }
241 switch (codeSet) {
242 case 101:
243 if (code < 64) {
244 result += (FX_CHAR)(' ' + code);
245 } else if (code < 96) {
246 result += (FX_CHAR)(code - 64);
247 } else {
248 if (code != CODE_STOP) {
249 lastCharacterWasPrintable = FALSE;
250 }
251 switch (code) {
252 case 102:
253 case 97:
254 case 96:
255 case 101:
256 break;
257 case 98:
258 isNextShifted = TRUE;
259 codeSet = CODE_CODE_B;
260 break;
261 case 100:
262 codeSet = CODE_CODE_B;
263 break;
264 case 99:
265 codeSet = CODE_CODE_C;
266 break;
267 case 106:
268 done = TRUE;
269 break;
270 }
271 }
272 break;
273 case 100:
274 if (code < 96) {
275 result += (FX_CHAR)(' ' + code);
276 } else {
277 if (code != CODE_STOP) {
278 lastCharacterWasPrintable = FALSE;
279 }
280 switch (code) {
281 case 102:
282 case 97:
283 case 96:
284 case 100:
285 break;
286 case 98:
287 isNextShifted = TRUE;
288 codeSet = CODE_CODE_A;
289 break;
290 case 101:
291 codeSet = CODE_CODE_A;
292 break;
293 case 99:
294 codeSet = CODE_CODE_C;
295 break;
296 case 106:
297 done = TRUE;
298 break;
299 }
300 }
301 break;
302 case 99:
303 if (code < 100) {
304 if (code < 10) {
305 result += '0';
306 }
307 FX_CHAR temp[128];
308 #if defined(_FX_WINAPI_PARTITION_APP_)
309 sprintf_s(temp, 128, "%d", code);
310 #else
311 sprintf(temp, "%d", code);
312 #endif
313 result += temp;
314 } else {
315 if (code != CODE_STOP) {
316 lastCharacterWasPrintable = FALSE;
317 }
318 switch (code) {
319 case 102:
320 break;
321 case 101:
322 codeSet = CODE_CODE_A;
323 break;
324 case 100:
325 codeSet = CODE_CODE_B;
326 break;
327 case 106:
328 done = TRUE;
329 break;
330 }
331 }
332 break;
333 }
334 if (unshift) {
335 codeSet = codeSet == CODE_CODE_A ? CODE_CODE_B : CODE_CODE_A;
336 }
337 }
338 int32_t width = row->GetSize();
339 while (nextStart < width && row->Get(nextStart)) {
340 nextStart++;
341 }
342 FX_BOOL boolT1 = row->IsRange(
343 nextStart, std::min(width, nextStart + (nextStart - lastStart) / 2),
344 FALSE, e);
345 BC_EXCEPTION_CHECK_ReturnValue(e, "");
346 if (!boolT1) {
347 e = BCExceptionNotFound;
348 return "";
349 }
350 checksumTotal -= multiplier * lastCode;
351 if (checksumTotal % 103 != lastCode) {
352 e = BCExceptionChecksumException;
353 return "";
354 }
355 int32_t resultLength = result.GetLength();
356 if (resultLength > 0 && lastCharacterWasPrintable) {
357 if (codeSet == CODE_CODE_C) {
358 result = result.Mid(0, result.GetLength() - 2);
359 } else {
360 result = result.Mid(0, result.GetLength() - 1);
361 }
362 }
363 if (result.GetLength() == 0) {
364 e = BCExceptionFormatException;
365 return "";
366 }
367 return result;
368 }
369