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