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