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 "BC_OneDReader.h"
29 #include "BC_OnedCode39Reader.h"
30 const FX_CHAR* CBC_OnedCode39Reader::ALPHABET_STRING =
31     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
32 const FX_CHAR* CBC_OnedCode39Reader::CHECKSUM_STRING =
33     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
34 const int32_t CBC_OnedCode39Reader::CHARACTER_ENCODINGS[44] = {
35     0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124,
36     0x064, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C,
37     0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007,
38     0x106, 0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0,
39     0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A};
40 const int32_t CBC_OnedCode39Reader::ASTERISK_ENCODING = 0x094;
CBC_OnedCode39Reader()41 CBC_OnedCode39Reader::CBC_OnedCode39Reader()
42     : m_usingCheckDigit(FALSE), m_extendedMode(FALSE) {
43 }
CBC_OnedCode39Reader(FX_BOOL usingCheckDigit)44 CBC_OnedCode39Reader::CBC_OnedCode39Reader(FX_BOOL usingCheckDigit)
45     : m_usingCheckDigit(usingCheckDigit), m_extendedMode(FALSE) {
46 }
CBC_OnedCode39Reader(FX_BOOL usingCheckDigit,FX_BOOL extendedMode)47 CBC_OnedCode39Reader::CBC_OnedCode39Reader(FX_BOOL usingCheckDigit,
48                                            FX_BOOL extendedMode)
49     : m_usingCheckDigit(usingCheckDigit), m_extendedMode(extendedMode) {
50 }
~CBC_OnedCode39Reader()51 CBC_OnedCode39Reader::~CBC_OnedCode39Reader() {}
DecodeRow(int32_t rowNumber,CBC_CommonBitArray * row,int32_t hints,int32_t & e)52 CFX_ByteString CBC_OnedCode39Reader::DecodeRow(int32_t rowNumber,
53                                                CBC_CommonBitArray* row,
54                                                int32_t hints,
55                                                int32_t& e) {
56   CFX_Int32Array* start = FindAsteriskPattern(row, e);
57   BC_EXCEPTION_CHECK_ReturnValue(e, "");
58   int32_t nextStart = (*start)[1];
59   if (start != NULL) {
60     delete start;
61     start = NULL;
62   }
63   int32_t end = row->GetSize();
64   while (nextStart < end && !row->Get(nextStart)) {
65     nextStart++;
66   }
67   CFX_ByteString result;
68   CFX_Int32Array counters;
69   counters.SetSize(9);
70   FX_CHAR decodedChar;
71   int32_t lastStart;
72   do {
73     RecordPattern(row, nextStart, &counters, e);
74     BC_EXCEPTION_CHECK_ReturnValue(e, "");
75     int32_t pattern = ToNarrowWidePattern(&counters);
76     if (pattern < 0) {
77       e = BCExceptionNotFound;
78       return "";
79     }
80     decodedChar = PatternToChar(pattern, e);
81     BC_EXCEPTION_CHECK_ReturnValue(e, "");
82     result += decodedChar;
83     lastStart = nextStart;
84     for (int32_t i = 0; i < counters.GetSize(); i++) {
85       nextStart += counters[i];
86     }
87     while (nextStart < end && !row->Get(nextStart)) {
88       nextStart++;
89     }
90   } while (decodedChar != '*');
91   result = result.Mid(0, result.GetLength() - 1);
92   int32_t lastPatternSize = 0;
93   for (int32_t j = 0; j < counters.GetSize(); j++) {
94     lastPatternSize += counters[j];
95   }
96   if (m_usingCheckDigit) {
97     int32_t max = result.GetLength() - 1;
98     int32_t total = 0;
99     int32_t len = (int32_t)strlen(ALPHABET_STRING);
100     for (int32_t k = 0; k < max; k++) {
101       for (int32_t j = 0; j < len; j++)
102         if (ALPHABET_STRING[j] == result[k]) {
103           total += j;
104         }
105     }
106     if (result[max] != (ALPHABET_STRING)[total % 43]) {
107       e = BCExceptionChecksumException;
108       return "";
109     }
110     result = result.Mid(0, result.GetLength() - 1);
111   }
112   if (result.GetLength() == 0) {
113     e = BCExceptionNotFound;
114     return "";
115   }
116   if (m_extendedMode) {
117     CFX_ByteString bytestr = DecodeExtended(result, e);
118     BC_EXCEPTION_CHECK_ReturnValue(e, "");
119     return bytestr;
120   } else {
121     return result;
122   }
123 }
FindAsteriskPattern(CBC_CommonBitArray * row,int32_t & e)124 CFX_Int32Array* CBC_OnedCode39Reader::FindAsteriskPattern(
125     CBC_CommonBitArray* row,
126     int32_t& e) {
127   int32_t width = row->GetSize();
128   int32_t rowOffset = 0;
129   while (rowOffset < width) {
130     if (row->Get(rowOffset)) {
131       break;
132     }
133     rowOffset++;
134   }
135   int32_t counterPosition = 0;
136   CFX_Int32Array counters;
137   counters.SetSize(9);
138   int32_t patternStart = rowOffset;
139   FX_BOOL isWhite = FALSE;
140   int32_t patternLength = counters.GetSize();
141   for (int32_t i = rowOffset; i < width; i++) {
142     FX_BOOL pixel = row->Get(i);
143     if (pixel ^ isWhite) {
144       counters[counterPosition]++;
145     } else {
146       if (counterPosition == patternLength - 1) {
147         if (ToNarrowWidePattern(&counters) == ASTERISK_ENCODING) {
148           FX_BOOL bT1 =
149               row->IsRange(std::max(0, patternStart - (i - patternStart) / 2),
150                            patternStart, FALSE, e);
151           BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
152           if (bT1) {
153             CFX_Int32Array* result = new CFX_Int32Array;
154             result->SetSize(2);
155             (*result)[0] = patternStart;
156             (*result)[1] = i;
157             return result;
158           }
159         }
160         patternStart += counters[0] + counters[1];
161         for (int32_t y = 2; y < patternLength; y++) {
162           counters[y - 2] = counters[y];
163         }
164         counters[patternLength - 2] = 0;
165         counters[patternLength - 1] = 0;
166         counterPosition--;
167       } else {
168         counterPosition++;
169       }
170       counters[counterPosition] = 1;
171       isWhite = !isWhite;
172     }
173   }
174   e = BCExceptionNotFound;
175   return NULL;
176 }
ToNarrowWidePattern(CFX_Int32Array * counters)177 int32_t CBC_OnedCode39Reader::ToNarrowWidePattern(CFX_Int32Array* counters) {
178   int32_t numCounters = counters->GetSize();
179   int32_t maxNarrowCounter = 0;
180   int32_t wideCounters;
181   do {
182 #undef max
183     int32_t minCounter = FXSYS_IntMax;
184     for (int32_t i = 0; i < numCounters; i++) {
185       int32_t counter = (*counters)[i];
186       if (counter < minCounter && counter > maxNarrowCounter) {
187         minCounter = counter;
188       }
189     }
190     maxNarrowCounter = minCounter;
191     wideCounters = 0;
192     int32_t totalWideCountersWidth = 0;
193     int32_t pattern = 0;
194     for (int32_t j = 0; j < numCounters; j++) {
195       int32_t counter = (*counters)[j];
196       if ((*counters)[j] > maxNarrowCounter) {
197         pattern |= 1 << (numCounters - 1 - j);
198         wideCounters++;
199         totalWideCountersWidth += counter;
200       }
201     }
202     if (wideCounters == 3) {
203       for (int32_t k = 0; k < numCounters && wideCounters > 0; k++) {
204         int32_t counter = (*counters)[k];
205         if ((*counters)[k] > maxNarrowCounter) {
206           wideCounters--;
207           if ((counter << 1) >= totalWideCountersWidth) {
208             return -1;
209           }
210         }
211       }
212       return pattern;
213     }
214   } while (wideCounters > 3);
215   return -1;
216 }
PatternToChar(int32_t pattern,int32_t & e)217 FX_CHAR CBC_OnedCode39Reader::PatternToChar(int32_t pattern, int32_t& e) {
218   for (int32_t i = 0; i < 44; i++) {
219     if (CHARACTER_ENCODINGS[i] == pattern) {
220       return (ALPHABET_STRING)[i];
221     }
222   }
223   e = BCExceptionNotFound;
224   return 0;
225 }
DecodeExtended(CFX_ByteString & encoded,int32_t & e)226 CFX_ByteString CBC_OnedCode39Reader::DecodeExtended(CFX_ByteString& encoded,
227                                                     int32_t& e) {
228   int32_t length = encoded.GetLength();
229   CFX_ByteString decoded;
230   FX_CHAR c, next;
231   for (int32_t i = 0; i < length; i++) {
232     c = encoded[i];
233     if (c == '+' || c == '$' || c == '%' || c == '/') {
234       next = encoded[i + 1];
235       FX_CHAR decodedChar = '\0';
236       switch (c) {
237         case '+':
238           if (next >= 'A' && next <= 'Z') {
239             decodedChar = (FX_CHAR)(next + 32);
240           } else {
241             e = BCExceptionFormatException;
242             return "";
243           }
244           break;
245         case '$':
246           if (next >= 'A' && next <= 'Z') {
247             decodedChar = (FX_CHAR)(next - 64);
248           } else {
249             e = BCExceptionFormatException;
250             return "";
251           }
252           break;
253         case '%':
254           if (next >= 'A' && next <= 'E') {
255             decodedChar = (FX_CHAR)(next - 38);
256           } else if (next >= 'F' && next <= 'J') {
257             decodedChar = (FX_CHAR)(next - 11);
258           } else if (next >= 'K' && next <= 'O' && next != 'M' && next != 'N') {
259             decodedChar = (FX_CHAR)(next + 16);
260           } else if (next >= 'P' && next <= 'S') {
261             decodedChar = (FX_CHAR)(next + 43);
262           } else if (next == 'U') {
263             decodedChar = (FX_CHAR)0;
264           } else if (next == 'V') {
265             decodedChar = (FX_CHAR)64;
266           } else if (next == 'W') {
267             decodedChar = (FX_CHAR)96;
268           } else if (next == 'T' || next == 'X' || next == 'Y' || next == 'Z') {
269             decodedChar = (FX_CHAR)127;
270           } else {
271             e = BCExceptionFormatException;
272             return "";
273           }
274           break;
275         case '/':
276           if (next >= 'A' && next <= 'O') {
277             decodedChar = (FX_CHAR)(next - 32);
278           } else if (next == 'Z') {
279             decodedChar = ':';
280           } else {
281             e = BCExceptionFormatException;
282             return "";
283           }
284           break;
285       }
286       decoded += decodedChar;
287       i++;
288     } else {
289       decoded += c;
290     }
291   }
292   return decoded;
293 }
294