Home | History | Annotate | Download | only in pdf417
      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     ',', ':', '#', '-', '.', '$', '/', '+', '%', '*', '=', '^'};
     58 void CBC_DecodedBitStreamPaser::Initialize() {}
     59 void CBC_DecodedBitStreamPaser::Finalize() {}
     60 CBC_DecodedBitStreamPaser::CBC_DecodedBitStreamPaser() {}
     61 CBC_DecodedBitStreamPaser::~CBC_DecodedBitStreamPaser() {}
     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 }
    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 }
    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 }
    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 }
    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 }
    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 }
    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