Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_OnedCodaBarReader.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_OnedCode39Reader.h"\r
11 #include "include/BC_CommonBitArray.h"\r
12 #include "include/BC_OnedCodaBarReader.h"\r
13 FX_LPCSTR CBC_OnedCodaBarReader::ALPHABET_STRING = "0123456789-$:/.+ABCDTN";\r
14 const FX_INT32 CBC_OnedCodaBarReader::CHARACTER_ENCODINGS[22] = {\r
15     0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048,\r
16     0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E,\r
17     0x01A, 0x029\r
18 };\r
19 const FX_INT32 CBC_OnedCodaBarReader::minCharacterLength = 3;\r
20 const FX_CHAR CBC_OnedCodaBarReader::STARTEND_ENCODING[8] = {'E', '*', 'A', 'B', 'C', 'D', 'T', 'N'};\r
21 CBC_OnedCodaBarReader::CBC_OnedCodaBarReader()\r
22 {\r
23 }\r
24 CBC_OnedCodaBarReader::~CBC_OnedCodaBarReader()\r
25 {\r
26 }\r
27 CFX_ByteString CBC_OnedCodaBarReader::DecodeRow(FX_INT32 rowNumber, CBC_CommonBitArray *row, FX_INT32 hints, FX_INT32 &e)\r
28 {\r
29     CFX_Int32Array *int32Ptr = FindAsteriskPattern(row, e);\r
30     BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
31     CBC_AutoPtr<CFX_Int32Array> start(int32Ptr);\r
32     (*start)[1] = 0;\r
33     FX_INT32 nextStart = (*start)[1];\r
34     FX_INT32 end = row->GetSize();\r
35     while (nextStart < end && !row->Get(nextStart)) {\r
36         nextStart++;\r
37     }\r
38     CFX_ByteString result;\r
39     CFX_Int32Array counters;\r
40     counters.SetSize(7);\r
41     FX_CHAR decodedChar;\r
42     FX_INT32 lastStart;\r
43     do {\r
44         RecordPattern(row, nextStart, &counters, e);\r
45         BC_EXCEPTION_CHECK_ReturnValue(e, "");\r
46         decodedChar = ToNarrowWidePattern(&counters);\r
47         if (decodedChar == '!') {\r
48             e = BCExceptionNotFound;\r
49             return "";\r
50         }\r
51         result += decodedChar;\r
52         lastStart = nextStart;\r
53         for (FX_INT32 i = 0; i < counters.GetSize(); i++) {\r
54             nextStart += counters[i];\r
55         }\r
56         while (nextStart < end && !row->Get(nextStart)) {\r
57             nextStart++;\r
58         }\r
59     } while (nextStart < end);\r
60     FX_INT32 lastPatternSize = 0;\r
61     for (FX_INT32 j = 0; j < counters.GetSize(); j++) {\r
62         lastPatternSize += counters[j];\r
63     }\r
64     FX_INT32 whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize;\r
65     if (nextStart != end && (whiteSpaceAfterEnd / 2 < lastPatternSize)) {\r
66         e = BCExceptionNotFound;\r
67         return "";\r
68     }\r
69     if (result.GetLength() < 2) {\r
70         e = BCExceptionNotFound;\r
71         return "";\r
72     }\r
73     FX_CHAR startchar = result[0];\r
74     if (!ArrayContains(STARTEND_ENCODING, startchar)) {\r
75         e =  BCExceptionNotFound;\r
76         return "";\r
77     }\r
78     FX_INT32 len = result.GetLength();\r
79     CFX_ByteString temp = result;\r
80     for (FX_INT32 k = 1; k < result.GetLength(); k++) {\r
81         if (ArrayContains(STARTEND_ENCODING, result[k])) {\r
82             if ((k + 1) != result.GetLength()) {\r
83                 result.Delete(1, k);\r
84                 k = 1;\r
85             }\r
86         }\r
87     }\r
88     if (result.GetLength() < 5) {\r
89         FX_INT32 index = temp.Find(result.Mid(1, result.GetLength() - 1));\r
90         if (index == len - (result.GetLength() - 1)) {\r
91             e = BCExceptionNotFound;\r
92             return "";\r
93         }\r
94     }\r
95     if (result.GetLength() > minCharacterLength) {\r
96         result = result.Mid(1, result.GetLength() - 2);\r
97     } else {\r
98         e = BCExceptionNotFound;\r
99         return "";\r
100     }\r
101     return result;\r
102 }\r
103 CFX_Int32Array *CBC_OnedCodaBarReader::FindAsteriskPattern(CBC_CommonBitArray *row, FX_INT32 &e)\r
104 {\r
105     FX_INT32 width = row->GetSize();\r
106     FX_INT32 rowOffset = 0;\r
107     while (rowOffset < width) {\r
108         if (row->Get(rowOffset)) {\r
109             break;\r
110         }\r
111         rowOffset++;\r
112     }\r
113     FX_INT32 counterPosition = 0;\r
114     CFX_Int32Array counters;\r
115     counters.SetSize(7);\r
116     FX_INT32 patternStart = rowOffset;\r
117     FX_BOOL isWhite = FALSE;\r
118     FX_INT32 patternLength = counters.GetSize();\r
119     for (FX_INT32 i = rowOffset; i < width; i++) {\r
120         FX_BOOL pixel = row->Get(i);\r
121         if (pixel ^ isWhite) {\r
122             counters[counterPosition]++;\r
123         } else {\r
124             if (counterPosition == patternLength - 1) {\r
125                 if (ArrayContains(STARTEND_ENCODING, ToNarrowWidePattern(&counters))) {\r
126                     FX_BOOL btemp3 = row->IsRange(FX_MAX(0, patternStart - (i - patternStart) / 2), patternStart, FALSE, e);\r
127                     BC_EXCEPTION_CHECK_ReturnValue(e, NULL);\r
128                     if (btemp3) {\r
129                         CFX_Int32Array *result = FX_NEW CFX_Int32Array();\r
130                         result->SetSize(2);\r
131                         (*result)[0] = patternStart;\r
132                         (*result)[1] = i;\r
133                         return result;\r
134                     }\r
135                 }\r
136                 patternStart += counters[0] + counters[1];\r
137                 for (FX_INT32 y = 2; y < patternLength; y++) {\r
138                     counters[y - 2] = counters[y];\r
139                 }\r
140                 counters[patternLength - 2] = 0;\r
141                 counters[patternLength - 1] = 0;\r
142                 counterPosition--;\r
143             } else {\r
144                 counterPosition++;\r
145             }\r
146             counters[counterPosition] = 1;\r
147             isWhite = !isWhite;\r
148         }\r
149     }\r
150     e = BCExceptionNotFound;\r
151     return NULL;\r
152 }\r
153 FX_BOOL CBC_OnedCodaBarReader::ArrayContains(const FX_CHAR array[], FX_CHAR key)\r
154 {\r
155     for(FX_INT32 i = 0; i < 8; i++) {\r
156         if(array[i] == key) {\r
157             return TRUE;\r
158         }\r
159     }\r
160     return FALSE;\r
161 }\r
162 FX_CHAR CBC_OnedCodaBarReader::ToNarrowWidePattern(CFX_Int32Array *counter)\r
163 {\r
164     FX_INT32 numCounters = counter->GetSize();\r
165     if (numCounters < 1) {\r
166         return '!';\r
167     }\r
168     FX_INT32 averageCounter = 0;\r
169     FX_INT32 totalCounters = 0;\r
170     for (FX_INT32 i = 0; i < numCounters; i++) {\r
171         totalCounters += (*counter)[i];\r
172     }\r
173     averageCounter = totalCounters / numCounters;\r
174     FX_INT32 pattern = 0;\r
175     FX_INT32 wideCounters = 0;\r
176     for (FX_INT32 j = 0; j < numCounters; j++) {\r
177         if ((*counter)[j] > averageCounter) {\r
178             pattern |= 1 << (numCounters - 1 - j);\r
179             wideCounters++;\r
180         }\r
181     }\r
182     if ((wideCounters == 2) || (wideCounters == 3)) {\r
183         for (FX_INT32 k = 0; k < 22; k++) {\r
184             if (CHARACTER_ENCODINGS[k] == pattern) {\r
185                 return (ALPHABET_STRING)[k];\r
186             }\r
187         }\r
188     }\r
189     return '!';\r
190 }\r