Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_OneDimReader.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_OneDimReader.h"\r
12 const FX_INT32 CBC_OneDimReader::MAX_AVG_VARIANCE = (FX_INT32)(256 * 0.48f);\r
13 const FX_INT32 CBC_OneDimReader::MAX_INDIVIDUAL_VARIANCE = (FX_INT32)(256 * 0.7f);\r
14 const FX_INT32 CBC_OneDimReader::START_END_PATTERN[3] = {1, 1, 1};\r
15 const FX_INT32 CBC_OneDimReader::MIDDLE_PATTERN[5] = {1, 1, 1, 1, 1};\r
16 const FX_INT32 CBC_OneDimReader::L_PATTERNS[10][4] = {\r
17     {3, 2, 1, 1},\r
18     {2, 2, 2, 1},\r
19     {2, 1, 2, 2},\r
20     {1, 4, 1, 1},\r
21     {1, 1, 3, 2},\r
22     {1, 2, 3, 1},\r
23     {1, 1, 1, 4},\r
24     {1, 3, 1, 2},\r
25     {1, 2, 1, 3},\r
26     {3, 1, 1, 2}\r
27 };\r
28 const FX_INT32 CBC_OneDimReader::L_AND_G_PATTERNS[20][4] = {\r
29     {3, 2, 1, 1},\r
30     {2, 2, 2, 1},\r
31     {2, 1, 2, 2},\r
32     {1, 4, 1, 1},\r
33     {1, 1, 3, 2},\r
34     {1, 2, 3, 1},\r
35     {1, 1, 1, 4},\r
36     {1, 3, 1, 2},\r
37     {1, 2, 1, 3},\r
38     {3, 1, 1, 2},\r
39     {1, 1, 2, 3},\r
40     {1, 2, 2, 2},\r
41     {2, 2, 1, 2},\r
42     {1, 1, 4, 1},\r
43     {2, 3, 1, 1},\r
44     {1, 3, 2, 1},\r
45     {4, 1, 1, 1},\r
46     {2, 1, 3, 1},\r
47     {3, 1, 2, 1},\r
48     {2, 1, 1, 3}\r
49 };\r
50 CBC_OneDimReader::CBC_OneDimReader()\r
51 {\r
52 }\r
53 CBC_OneDimReader::~CBC_OneDimReader()\r
54 {\r
55 }\r
56 CFX_Int32Array *CBC_OneDimReader::FindStartGuardPattern(CBC_CommonBitArray *row, FX_INT32 &e)\r
57 {\r
58     FX_BOOL foundStart = FALSE;\r
59     CFX_Int32Array *startRange = NULL;\r
60     CFX_Int32Array startEndPattern;\r
61     startEndPattern.SetSize(3);\r
62     startEndPattern[0] = START_END_PATTERN[0];\r
63     startEndPattern[1] = START_END_PATTERN[1];\r
64     startEndPattern[2] = START_END_PATTERN[2];\r
65     FX_INT32 nextStart = 0;\r
66     while (!foundStart) {\r
67         if(startRange != NULL) {\r
68             delete startRange;\r
69             startRange = NULL;\r
70         }\r
71         startRange = FindGuardPattern(row, nextStart, FALSE, &startEndPattern, e);\r
72         BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
73         FX_INT32 start = (*startRange)[0];\r
74         nextStart = (*startRange)[1];\r
75         if (start <= 1) {\r
76             break;\r
77         }\r
78         FX_INT32 quietStart = start - (nextStart - start);\r
79         if (quietStart >= 0) {\r
80             FX_BOOL booT = row->IsRange(quietStart, start, FALSE, e);\r
81             BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
82             foundStart = booT;\r
83         }\r
84     }\r
85     return startRange;\r
86 }\r
87 CFX_ByteString CBC_OneDimReader::DecodeRow(FX_INT32 rowNumber, CBC_CommonBitArray *row, FX_INT32 hints, FX_INT32 &e)\r
88 {\r
89     CFX_Int32Array* StartPattern = FindStartGuardPattern(row, e);\r
90     BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
91     CBC_AutoPtr<CFX_Int32Array > result(StartPattern);\r
92     CFX_ByteString temp = DecodeRow(rowNumber, row, result.get(), hints, e);\r
93     BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
94     return temp;\r
95 }\r
96 CFX_ByteString CBC_OneDimReader::DecodeRow(FX_INT32 rowNumber, CBC_CommonBitArray *row, CFX_Int32Array *startGuardRange, FX_INT32 hints, FX_INT32 &e)\r
97 {\r
98     CFX_ByteString result;\r
99     FX_INT32 endStart = DecodeMiddle(row, startGuardRange, result, e);\r
100     BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
101     FX_BOOL b = CheckChecksum(result, e);\r
102     BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
103     if (!b) {\r
104         e = BCExceptionChecksumException;\r
105         return "";\r
106     }\r
107     return result;\r
108 }\r
109 FX_BOOL CBC_OneDimReader::CheckChecksum(CFX_ByteString &s, FX_INT32 &e)\r
110 {\r
111     FX_BOOL temp = CheckStandardUPCEANChecksum(s, e);\r
112     BC_EXCEPTION_CHECK_ReturnValue(e, FALSE);\r
113     return temp;\r
114 }\r
115 FX_BOOL CBC_OneDimReader::CheckStandardUPCEANChecksum(CFX_ByteString &s, FX_INT32 &e)\r
116 {\r
117     FX_INT32 length = s.GetLength();\r
118     if (length == 0) {\r
119         return FALSE;\r
120     }\r
121     FX_INT32 sum = 0;\r
122     for (FX_INT32 i = length - 2; i >= 0; i -= 2) {\r
123         FX_INT32 digit = (FX_INT32) s[i] - (FX_INT32) '0';\r
124         if (digit < 0 || digit > 9) {\r
125             e = BCExceptionFormatException;\r
126             return FALSE;\r
127         }\r
128         sum += digit;\r
129     }\r
130     sum *= 3;\r
131     for (FX_INT32 j = length - 1; j >= 0; j -= 2) {\r
132         FX_INT32 digit = (FX_INT32) s[j] - (FX_INT32) '0';\r
133         if (digit < 0 || digit > 9) {\r
134             e = BCExceptionFormatException;\r
135             return FALSE;\r
136         }\r
137         sum += digit;\r
138     }\r
139     return sum % 10 == 0;\r
140 }\r
141 CFX_Int32Array *CBC_OneDimReader::DecodeEnd(CBC_CommonBitArray* row, FX_INT32 endStart, FX_INT32 &e)\r
142 {\r
143     CFX_Int32Array startEndPattern;\r
144     startEndPattern.Add(START_END_PATTERN[0]);\r
145     startEndPattern.Add(START_END_PATTERN[1]);\r
146     startEndPattern.Add(START_END_PATTERN[2]);\r
147     CFX_Int32Array* FindGuard = FindGuardPattern(row, endStart, FALSE, &startEndPattern, e);\r
148     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
149     return FindGuard;\r
150 }\r
151 CFX_Int32Array *CBC_OneDimReader::FindGuardPattern(CBC_CommonBitArray *row, FX_INT32 rowOffset, FX_BOOL whiteFirst, CFX_Int32Array *pattern, FX_INT32 &e)\r
152 {\r
153     FX_INT32 patternLength = pattern->GetSize();\r
154     CFX_Int32Array counters;\r
155     counters.SetSize(patternLength);\r
156     FX_INT32 width = row->GetSize();\r
157     FX_BOOL isWhite = FALSE;\r
158     while (rowOffset < width) {\r
159         isWhite = !row->Get(rowOffset);\r
160         if (whiteFirst == isWhite) {\r
161             break;\r
162         }\r
163         rowOffset++;\r
164     }\r
165     FX_INT32 counterPosition = 0;\r
166     FX_INT32 patternStart = rowOffset;\r
167     for (FX_INT32 x = rowOffset; x < width; x++) {\r
168         FX_BOOL pixel = row->Get(x);\r
169         if (pixel ^ isWhite) {\r
170             counters[counterPosition]++;\r
171         } else {\r
172             if (counterPosition == patternLength - 1) {\r
173                 if (PatternMatchVariance(&counters, &(*pattern)[0], MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {\r
174                     CFX_Int32Array *result = FX_NEW CFX_Int32Array();\r
175                     result->SetSize(2);\r
176                     (*result)[0] = patternStart;\r
177                     (*result)[1] = x;\r
178                     return result;\r
179                 }\r
180                 patternStart += counters[0] + counters[1];\r
181                 for (FX_INT32 y = 2; y < patternLength; y++) {\r
182                     counters[y - 2] = counters[y];\r
183                 }\r
184                 counters[patternLength - 2] = 0;\r
185                 counters[patternLength - 1] = 0;\r
186                 counterPosition--;\r
187             } else {\r
188                 counterPosition++;\r
189             }\r
190             counters[counterPosition] = 1;\r
191             isWhite = !isWhite;\r
192         }\r
193     }\r
194     e = BCExceptionNotFound;\r
195     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
196     return NULL;\r
197 }\r
198 FX_INT32 CBC_OneDimReader::DecodeDigit(CBC_CommonBitArray *row, CFX_Int32Array *counters, FX_INT32 rowOffset, const FX_INT32* patterns, FX_INT32 patternLength, FX_INT32 &e)\r
199 {\r
200     RecordPattern(row, rowOffset, counters, e);\r
201     BC_EXCEPTION_CHECK_ReturnValue(e, 0);\r
202     FX_INT32 bestVariance = MAX_AVG_VARIANCE;\r
203     FX_INT32 bestMatch = -1;\r
204     FX_INT32 max = patternLength;\r
205     for (FX_INT32 i = 0; i < max; i++) {\r
206         FX_INT32 variance = PatternMatchVariance(counters, &patterns[i * 4], MAX_INDIVIDUAL_VARIANCE);\r
207         if (variance < bestVariance) {\r
208             bestVariance = variance;\r
209             bestMatch = i;\r
210         }\r
211     }\r
212     if (bestMatch >= 0) {\r
213         return bestMatch;\r
214     } else {\r
215         e = BCExceptionNotFound;\r
216         return 0;\r
217     }\r
218     return 0;\r
219 }\r