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