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 2009 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 "BC_PDF417DecodedBitStreamParser.h"
24
25 #include <stdlib.h>
26
27 #include "xfa/src/fxbarcode/BC_DecoderResult.h"
28 #include "xfa/src/fxbarcode/barcode.h"
29 #include "xfa/src/fxbarcode/common/BC_CommonDecoderResult.h"
30 #include "BC_PDF417ResultMetadata.h"
31 #include "third_party/bigint/BigIntegerLibrary.hh"
32
33 #define TEXT_COMPACTION_MODE_LATCH 900
34 #define BYTE_COMPACTION_MODE_LATCH 901
35 #define NUMERIC_COMPACTION_MODE_LATCH 902
36 #define BYTE_COMPACTION_MODE_LATCH_6 924
37 #define BEGIN_MACRO_PDF417_CONTROL_BLOCK 928
38 #define BEGIN_MACRO_PDF417_OPTIONAL_FIELD 923
39 #define MACRO_PDF417_TERMINATOR 922
40 #define MODE_SHIFT_TO_BYTE_COMPACTION_MODE 913
41
42 int32_t CBC_DecodedBitStreamPaser::MAX_NUMERIC_CODEWORDS = 15;
43 int32_t CBC_DecodedBitStreamPaser::NUMBER_OF_SEQUENCE_CODEWORDS = 2;
44 int32_t CBC_DecodedBitStreamPaser::PL = 25;
45 int32_t CBC_DecodedBitStreamPaser::LL = 27;
46 int32_t CBC_DecodedBitStreamPaser::AS = 27;
47 int32_t CBC_DecodedBitStreamPaser::ML = 28;
48 int32_t CBC_DecodedBitStreamPaser::AL = 28;
49 int32_t CBC_DecodedBitStreamPaser::PS = 29;
50 int32_t CBC_DecodedBitStreamPaser::PAL = 29;
51 FX_CHAR CBC_DecodedBitStreamPaser::PUNCT_CHARS[29] = {
52 ';', '<', '>', '@', '[', '\\', '}', '_', '`', '~',
53 '!', '\r', '\t', ',', ':', '\n', '-', '.', '$', '/',
54 '"', '|', '*', '(', ')', '?', '{', '}', '\''};
55 FX_CHAR CBC_DecodedBitStreamPaser::MIXED_CHARS[30] = {
56 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&', '\r', '\t',
57 ',', ':', '#', '-', '.', '$', '/', '+', '%', '*', '=', '^'};
Initialize()58 void CBC_DecodedBitStreamPaser::Initialize() {}
Finalize()59 void CBC_DecodedBitStreamPaser::Finalize() {}
CBC_DecodedBitStreamPaser()60 CBC_DecodedBitStreamPaser::CBC_DecodedBitStreamPaser() {}
~CBC_DecodedBitStreamPaser()61 CBC_DecodedBitStreamPaser::~CBC_DecodedBitStreamPaser() {}
decode(CFX_Int32Array & codewords,CFX_ByteString ecLevel,int32_t & e)62 CBC_CommonDecoderResult* CBC_DecodedBitStreamPaser::decode(
63 CFX_Int32Array& codewords,
64 CFX_ByteString ecLevel,
65 int32_t& e) {
66 CFX_ByteString result;
67 int32_t codeIndex = 1;
68 int32_t code = codewords.GetAt(codeIndex);
69 codeIndex++;
70 CBC_PDF417ResultMetadata* resultMetadata = new CBC_PDF417ResultMetadata;
71 while (codeIndex < codewords[0]) {
72 switch (code) {
73 case TEXT_COMPACTION_MODE_LATCH:
74 codeIndex = textCompaction(codewords, codeIndex, result);
75 break;
76 case BYTE_COMPACTION_MODE_LATCH:
77 codeIndex = byteCompaction(code, codewords, codeIndex, result);
78 break;
79 case NUMERIC_COMPACTION_MODE_LATCH:
80 codeIndex = numericCompaction(codewords, codeIndex, result, e);
81 BC_EXCEPTION_CHECK_ReturnValue(e, NULL);
82 break;
83 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
84 codeIndex = byteCompaction(code, codewords, codeIndex, result);
85 break;
86 case BYTE_COMPACTION_MODE_LATCH_6:
87 codeIndex = byteCompaction(code, codewords, codeIndex, result);
88 break;
89 case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
90 codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata, e);
91 if (e != BCExceptionNO) {
92 delete resultMetadata;
93 return NULL;
94 }
95 break;
96 default:
97 codeIndex--;
98 codeIndex = textCompaction(codewords, codeIndex, result);
99 break;
100 }
101 if (codeIndex < codewords.GetSize()) {
102 code = codewords[codeIndex++];
103 } else {
104 e = BCExceptionFormatInstance;
105 delete resultMetadata;
106 return NULL;
107 }
108 }
109 if (result.GetLength() == 0) {
110 e = BCExceptionFormatInstance;
111 delete resultMetadata;
112 return NULL;
113 }
114 CFX_ByteArray rawBytes;
115 CFX_PtrArray byteSegments;
116 CBC_CommonDecoderResult* tempCd = new CBC_CommonDecoderResult();
117 tempCd->Init(rawBytes, result, byteSegments, ecLevel, e);
118 if (e != BCExceptionNO) {
119 delete resultMetadata;
120 return NULL;
121 }
122 tempCd->setOther(resultMetadata);
123 return tempCd;
124 }
decodeMacroBlock(CFX_Int32Array & codewords,int32_t codeIndex,CBC_PDF417ResultMetadata * resultMetadata,int32_t & e)125 int32_t CBC_DecodedBitStreamPaser::decodeMacroBlock(
126 CFX_Int32Array& codewords,
127 int32_t codeIndex,
128 CBC_PDF417ResultMetadata* resultMetadata,
129 int32_t& e) {
130 if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) {
131 e = BCExceptionFormatInstance;
132 return -1;
133 }
134 CFX_Int32Array segmentIndexArray;
135 segmentIndexArray.SetSize(NUMBER_OF_SEQUENCE_CODEWORDS);
136 for (int32_t i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) {
137 segmentIndexArray.SetAt(i, codewords[codeIndex]);
138 }
139 CFX_ByteString str =
140 decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS, e);
141 BC_EXCEPTION_CHECK_ReturnValue(e, -1);
142 resultMetadata->setSegmentIndex(atoi(str.GetBuffer(str.GetLength())));
143 CFX_ByteString fileId;
144 codeIndex = textCompaction(codewords, codeIndex, fileId);
145 resultMetadata->setFileId(fileId);
146 if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) {
147 codeIndex++;
148 CFX_Int32Array additionalOptionCodeWords;
149 additionalOptionCodeWords.SetSize(codewords[0] - codeIndex);
150 int32_t additionalOptionCodeWordsIndex = 0;
151 FX_BOOL end = FALSE;
152 while ((codeIndex < codewords[0]) && !end) {
153 int32_t code = codewords[codeIndex++];
154 if (code < TEXT_COMPACTION_MODE_LATCH) {
155 additionalOptionCodeWords[additionalOptionCodeWordsIndex++] = code;
156 } else {
157 switch (code) {
158 case MACRO_PDF417_TERMINATOR:
159 resultMetadata->setLastSegment(TRUE);
160 codeIndex++;
161 end = TRUE;
162 break;
163 default:
164 e = BCExceptionFormatInstance;
165 return -1;
166 }
167 }
168 }
169 CFX_Int32Array array;
170 array.SetSize(additionalOptionCodeWordsIndex);
171 array.Copy(additionalOptionCodeWords);
172 resultMetadata->setOptionalData(array);
173 } else if (codewords[codeIndex] == MACRO_PDF417_TERMINATOR) {
174 resultMetadata->setLastSegment(TRUE);
175 codeIndex++;
176 }
177 return codeIndex;
178 }
textCompaction(CFX_Int32Array & codewords,int32_t codeIndex,CFX_ByteString & result)179 int32_t CBC_DecodedBitStreamPaser::textCompaction(CFX_Int32Array& codewords,
180 int32_t codeIndex,
181 CFX_ByteString& result) {
182 CFX_Int32Array textCompactionData;
183 textCompactionData.SetSize((codewords[0] - codeIndex) << 1);
184 CFX_Int32Array byteCompactionData;
185 byteCompactionData.SetSize((codewords[0] - codeIndex) << 1);
186 int32_t index = 0;
187 FX_BOOL end = FALSE;
188 while ((codeIndex < codewords[0]) && !end) {
189 int32_t code = codewords[codeIndex++];
190 if (code < TEXT_COMPACTION_MODE_LATCH) {
191 textCompactionData[index] = code / 30;
192 textCompactionData[index + 1] = code % 30;
193 index += 2;
194 } else {
195 switch (code) {
196 case TEXT_COMPACTION_MODE_LATCH:
197 textCompactionData[index++] = TEXT_COMPACTION_MODE_LATCH;
198 break;
199 case BYTE_COMPACTION_MODE_LATCH:
200 codeIndex--;
201 end = TRUE;
202 break;
203 case NUMERIC_COMPACTION_MODE_LATCH:
204 codeIndex--;
205 end = TRUE;
206 break;
207 case BEGIN_MACRO_PDF417_CONTROL_BLOCK:
208 codeIndex--;
209 end = TRUE;
210 break;
211 case BEGIN_MACRO_PDF417_OPTIONAL_FIELD:
212 codeIndex--;
213 end = TRUE;
214 break;
215 case MACRO_PDF417_TERMINATOR:
216 codeIndex--;
217 end = TRUE;
218 break;
219 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE:
220 textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE;
221 code = codewords[codeIndex++];
222 byteCompactionData[index] = code;
223 index++;
224 break;
225 case BYTE_COMPACTION_MODE_LATCH_6:
226 codeIndex--;
227 end = TRUE;
228 break;
229 }
230 }
231 }
232 decodeTextCompaction(textCompactionData, byteCompactionData, index, result);
233 return codeIndex;
234 }
decodeTextCompaction(CFX_Int32Array & textCompactionData,CFX_Int32Array & byteCompactionData,int32_t length,CFX_ByteString & result)235 void CBC_DecodedBitStreamPaser::decodeTextCompaction(
236 CFX_Int32Array& textCompactionData,
237 CFX_Int32Array& byteCompactionData,
238 int32_t length,
239 CFX_ByteString& result) {
240 Mode subMode = ALPHA;
241 Mode priorToShiftMode = ALPHA;
242 int32_t i = 0;
243 while (i < length) {
244 int32_t subModeCh = textCompactionData[i];
245 FX_CHAR ch = 0;
246 switch (subMode) {
247 case ALPHA:
248 if (subModeCh < 26) {
249 ch = (FX_CHAR)('A' + subModeCh);
250 } else {
251 if (subModeCh == 26) {
252 ch = ' ';
253 } else if (subModeCh == LL) {
254 subMode = LOWER;
255 } else if (subModeCh == ML) {
256 subMode = MIXED;
257 } else if (subModeCh == PS) {
258 priorToShiftMode = subMode;
259 subMode = PUNCT_SHIFT;
260 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
261 result += (FX_CHAR)byteCompactionData[i];
262 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
263 subMode = ALPHA;
264 }
265 }
266 break;
267 case LOWER:
268 if (subModeCh < 26) {
269 ch = (FX_CHAR)('a' + subModeCh);
270 } else {
271 if (subModeCh == 26) {
272 ch = ' ';
273 } else if (subModeCh == AS) {
274 priorToShiftMode = subMode;
275 subMode = ALPHA_SHIFT;
276 } else if (subModeCh == ML) {
277 subMode = MIXED;
278 } else if (subModeCh == PS) {
279 priorToShiftMode = subMode;
280 subMode = PUNCT_SHIFT;
281 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
282 result += (FX_CHAR)byteCompactionData[i];
283 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
284 subMode = ALPHA;
285 }
286 }
287 break;
288 case MIXED:
289 if (subModeCh < PL) {
290 ch = MIXED_CHARS[subModeCh];
291 } else {
292 if (subModeCh == PL) {
293 subMode = PUNCT;
294 } else if (subModeCh == 26) {
295 ch = ' ';
296 } else if (subModeCh == LL) {
297 subMode = LOWER;
298 } else if (subModeCh == AL) {
299 subMode = ALPHA;
300 } else if (subModeCh == PS) {
301 priorToShiftMode = subMode;
302 subMode = PUNCT_SHIFT;
303 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
304 result += (FX_CHAR)byteCompactionData[i];
305 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
306 subMode = ALPHA;
307 }
308 }
309 break;
310 case PUNCT:
311 if (subModeCh < PAL) {
312 ch = PUNCT_CHARS[subModeCh];
313 } else {
314 if (subModeCh == PAL) {
315 subMode = ALPHA;
316 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
317 result += (FX_CHAR)byteCompactionData[i];
318 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
319 subMode = ALPHA;
320 }
321 }
322 break;
323 case ALPHA_SHIFT:
324 subMode = priorToShiftMode;
325 if (subModeCh < 26) {
326 ch = (FX_CHAR)('A' + subModeCh);
327 } else {
328 if (subModeCh == 26) {
329 ch = ' ';
330 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
331 subMode = ALPHA;
332 }
333 }
334 break;
335 case PUNCT_SHIFT:
336 subMode = priorToShiftMode;
337 if (subModeCh < PAL) {
338 ch = PUNCT_CHARS[subModeCh];
339 } else {
340 if (subModeCh == PAL) {
341 subMode = ALPHA;
342 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) {
343 result += (FX_CHAR)byteCompactionData[i];
344 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) {
345 subMode = ALPHA;
346 }
347 }
348 break;
349 }
350 if (ch != 0) {
351 result += ch;
352 }
353 i++;
354 }
355 }
byteCompaction(int32_t mode,CFX_Int32Array & codewords,int32_t codeIndex,CFX_ByteString & result)356 int32_t CBC_DecodedBitStreamPaser::byteCompaction(int32_t mode,
357 CFX_Int32Array& codewords,
358 int32_t codeIndex,
359 CFX_ByteString& result) {
360 if (mode == BYTE_COMPACTION_MODE_LATCH) {
361 int32_t count = 0;
362 int64_t value = 0;
363 FX_WORD* decodedData = FX_Alloc(FX_WORD, 6);
364 CFX_Int32Array byteCompactedCodewords;
365 byteCompactedCodewords.SetSize(6);
366 FX_BOOL end = FALSE;
367 int32_t nextCode = codewords[codeIndex++];
368 while ((codeIndex < codewords[0]) && !end) {
369 byteCompactedCodewords[count++] = nextCode;
370 value = 900 * value + nextCode;
371 nextCode = codewords[codeIndex++];
372 if (nextCode == TEXT_COMPACTION_MODE_LATCH ||
373 nextCode == BYTE_COMPACTION_MODE_LATCH ||
374 nextCode == NUMERIC_COMPACTION_MODE_LATCH ||
375 nextCode == BYTE_COMPACTION_MODE_LATCH_6 ||
376 nextCode == BEGIN_MACRO_PDF417_CONTROL_BLOCK ||
377 nextCode == BEGIN_MACRO_PDF417_OPTIONAL_FIELD ||
378 nextCode == MACRO_PDF417_TERMINATOR) {
379 codeIndex--;
380 end = TRUE;
381 } else {
382 if ((count % 5 == 0) && (count > 0)) {
383 int32_t j = 0;
384 for (; j < 6; ++j) {
385 decodedData[5 - j] = (FX_WORD)(value % 256);
386 value >>= 8;
387 }
388 for (j = 0; j < 6; ++j) {
389 result += (FX_CHAR)decodedData[j];
390 }
391 count = 0;
392 }
393 }
394 }
395 FX_Free(decodedData);
396 if (codeIndex == codewords[0] && nextCode < TEXT_COMPACTION_MODE_LATCH) {
397 byteCompactedCodewords[count++] = nextCode;
398 }
399 for (int32_t i = 0; i < count; i++) {
400 result += (FX_CHAR)(FX_WORD)byteCompactedCodewords[i];
401 }
402 } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) {
403 int32_t count = 0;
404 int64_t value = 0;
405 FX_BOOL end = FALSE;
406 while (codeIndex < codewords[0] && !end) {
407 int32_t code = codewords[codeIndex++];
408 if (code < TEXT_COMPACTION_MODE_LATCH) {
409 count++;
410 value = 900 * value + code;
411 } else {
412 if (code == TEXT_COMPACTION_MODE_LATCH ||
413 code == BYTE_COMPACTION_MODE_LATCH ||
414 code == NUMERIC_COMPACTION_MODE_LATCH ||
415 code == BYTE_COMPACTION_MODE_LATCH_6 ||
416 code == BEGIN_MACRO_PDF417_CONTROL_BLOCK ||
417 code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD ||
418 code == MACRO_PDF417_TERMINATOR) {
419 codeIndex--;
420 end = TRUE;
421 }
422 }
423 if ((count % 5 == 0) && (count > 0)) {
424 FX_WORD* decodedData = FX_Alloc(FX_WORD, 6);
425 int32_t j = 0;
426 for (; j < 6; ++j) {
427 decodedData[5 - j] = (FX_WORD)(value & 0xFF);
428 value >>= 8;
429 }
430 for (j = 0; j < 6; ++j) {
431 result += (FX_CHAR)decodedData[j];
432 }
433 count = 0;
434 FX_Free(decodedData);
435 }
436 }
437 }
438 return codeIndex;
439 }
numericCompaction(CFX_Int32Array & codewords,int32_t codeIndex,CFX_ByteString & result,int32_t & e)440 int32_t CBC_DecodedBitStreamPaser::numericCompaction(CFX_Int32Array& codewords,
441 int32_t codeIndex,
442 CFX_ByteString& result,
443 int32_t& e) {
444 int32_t count = 0;
445 FX_BOOL end = FALSE;
446 CFX_Int32Array numericCodewords;
447 numericCodewords.SetSize(MAX_NUMERIC_CODEWORDS);
448 while (codeIndex < codewords[0] && !end) {
449 int32_t code = codewords[codeIndex++];
450 if (codeIndex == codewords[0]) {
451 end = TRUE;
452 }
453 if (code < TEXT_COMPACTION_MODE_LATCH) {
454 numericCodewords[count] = code;
455 count++;
456 } else {
457 if (code == TEXT_COMPACTION_MODE_LATCH ||
458 code == BYTE_COMPACTION_MODE_LATCH ||
459 code == BYTE_COMPACTION_MODE_LATCH_6 ||
460 code == BEGIN_MACRO_PDF417_CONTROL_BLOCK ||
461 code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD ||
462 code == MACRO_PDF417_TERMINATOR) {
463 codeIndex--;
464 end = TRUE;
465 }
466 }
467 if (count % MAX_NUMERIC_CODEWORDS == 0 ||
468 code == NUMERIC_COMPACTION_MODE_LATCH || end) {
469 CFX_ByteString s = decodeBase900toBase10(numericCodewords, count, e);
470 BC_EXCEPTION_CHECK_ReturnValue(e, -1);
471 result += s;
472 count = 0;
473 }
474 }
475 return codeIndex;
476 }
decodeBase900toBase10(CFX_Int32Array & codewords,int32_t count,int32_t & e)477 CFX_ByteString CBC_DecodedBitStreamPaser::decodeBase900toBase10(
478 CFX_Int32Array& codewords,
479 int32_t count,
480 int32_t& e) {
481 BigInteger result = 0;
482 BigInteger nineHundred(900);
483 for (int32_t i = 0; i < count; i++) {
484 result = result * nineHundred + BigInteger(codewords[i]);
485 }
486 CFX_ByteString resultString(bigIntegerToString(result).c_str());
487 if (resultString.GetAt(0) != '1') {
488 e = BCExceptionFormatInstance;
489 return ' ';
490 }
491 return resultString.Mid(1, resultString.GetLength() - 1);
492 }
493