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