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