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