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