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