Home | History | Annotate | Download | only in datamatrix
      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 2006-2007 Jeremias Maerki.
      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 "xfa/src/fxbarcode/barcode.h"
     24 #include "xfa/src/fxbarcode/BC_Dimension.h"
     25 #include "xfa/src/fxbarcode/BC_UtilCodingConvert.h"
     26 #include "xfa/src/fxbarcode/common/BC_CommonBitMatrix.h"
     27 #include "BC_Encoder.h"
     28 #include "BC_SymbolShapeHint.h"
     29 #include "BC_SymbolInfo.h"
     30 #include "BC_EncoderContext.h"
     31 #include "BC_C40Encoder.h"
     32 #include "BC_TextEncoder.h"
     33 #include "BC_X12Encoder.h"
     34 #include "BC_EdifactEncoder.h"
     35 #include "BC_Base256Encoder.h"
     36 #include "BC_ASCIIEncoder.h"
     37 #include "BC_HighLevelEncoder.h"
     38 #define Integer_MAX_VALUE 2147483647
     39 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_C40 = 230;
     40 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_BASE256 = 231;
     41 FX_WCHAR CBC_HighLevelEncoder::UPPER_SHIFT = 235;
     42 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_ANSIX12 = 238;
     43 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_TEXT = 239;
     44 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_EDIFACT = 240;
     45 FX_WCHAR CBC_HighLevelEncoder::C40_UNLATCH = 254;
     46 FX_WCHAR CBC_HighLevelEncoder::X12_UNLATCH = 254;
     47 FX_WCHAR CBC_HighLevelEncoder::PAD = 129;
     48 FX_WCHAR CBC_HighLevelEncoder::MACRO_05 = 236;
     49 FX_WCHAR CBC_HighLevelEncoder::MACRO_06 = 237;
     50 const wchar_t* CBC_HighLevelEncoder::MACRO_05_HEADER = L"[)>05";
     51 const wchar_t* CBC_HighLevelEncoder::MACRO_06_HEADER = L"[)>06";
     52 const wchar_t CBC_HighLevelEncoder::MACRO_TRAILER = 0x0004;
     53 CBC_HighLevelEncoder::CBC_HighLevelEncoder() {}
     54 CBC_HighLevelEncoder::~CBC_HighLevelEncoder() {}
     55 CFX_ByteArray& CBC_HighLevelEncoder::getBytesForMessage(CFX_WideString msg) {
     56   CFX_ByteString bytestr;
     57   CBC_UtilCodingConvert::UnicodeToUTF8(msg, bytestr);
     58   for (int32_t i = 0; i < bytestr.GetLength(); i++) {
     59     m_bytearray.Add(bytestr.GetAt(i));
     60   }
     61   return m_bytearray;
     62 }
     63 CFX_WideString CBC_HighLevelEncoder::encodeHighLevel(CFX_WideString msg,
     64                                                      CFX_WideString ecLevel,
     65                                                      int32_t& e) {
     66   return encodeHighLevel(msg, ecLevel, FORCE_NONE, NULL, NULL, e);
     67 }
     68 CFX_WideString CBC_HighLevelEncoder::encodeHighLevel(CFX_WideString msg,
     69                                                      CFX_WideString ecLevel,
     70                                                      SymbolShapeHint shape,
     71                                                      CBC_Dimension* minSize,
     72                                                      CBC_Dimension* maxSize,
     73                                                      int32_t& e) {
     74   CBC_EncoderContext context(msg, ecLevel, e);
     75   BC_EXCEPTION_CHECK_ReturnValue(e, (FX_WCHAR*)"");
     76   context.setSymbolShape(shape);
     77   context.setSizeConstraints(minSize, maxSize);
     78   if ((msg.Mid(0, 6) == MACRO_05_HEADER) &&
     79       (msg.Mid(msg.GetLength() - 1, 1) == MACRO_TRAILER)) {
     80     context.writeCodeword(MACRO_05);
     81     context.setSkipAtEnd(2);
     82     context.m_pos += 6;
     83   } else if ((msg.Mid(0, 6) == MACRO_06_HEADER) &&
     84              (msg.Mid(msg.GetLength() - 1, 1) == MACRO_TRAILER)) {
     85     context.writeCodeword(MACRO_06);
     86     context.setSkipAtEnd(2);
     87     context.m_pos += 6;
     88   }
     89   CFX_PtrArray encoders;
     90   encoders.Add(new CBC_ASCIIEncoder());
     91   encoders.Add(new CBC_C40Encoder());
     92   encoders.Add(new CBC_TextEncoder());
     93   encoders.Add(new CBC_X12Encoder());
     94   encoders.Add(new CBC_EdifactEncoder());
     95   encoders.Add(new CBC_Base256Encoder());
     96   int32_t encodingMode = ASCII_ENCODATION;
     97   while (context.hasMoreCharacters()) {
     98     ((CBC_Encoder*)encoders.GetAt(encodingMode))->Encode(context, e);
     99     if (e != BCExceptionNO) {
    100       for (int32_t i = 0; i < encoders.GetSize(); i++) {
    101         delete (CBC_Encoder*)encoders.GetAt(i);
    102       }
    103       encoders.RemoveAll();
    104       return (FX_WCHAR*)"";
    105     }
    106     if (context.m_newEncoding >= 0) {
    107       encodingMode = context.m_newEncoding;
    108       context.resetEncoderSignal();
    109     }
    110   }
    111   int32_t len = context.m_codewords.GetLength();
    112   context.updateSymbolInfo(e);
    113   if (e != BCExceptionNO) {
    114     for (int32_t i = 0; i < encoders.GetSize(); i++) {
    115       delete (CBC_Encoder*)encoders.GetAt(i);
    116     }
    117     encoders.RemoveAll();
    118     return (FX_WCHAR*)"";
    119   }
    120   int32_t capacity = context.m_symbolInfo->m_dataCapacity;
    121   if (len < capacity) {
    122     if (encodingMode != ASCII_ENCODATION &&
    123         encodingMode != BASE256_ENCODATION) {
    124       context.writeCodeword(0x00fe);
    125     }
    126   }
    127   CFX_WideString codewords = context.m_codewords;
    128   if (codewords.GetLength() < capacity) {
    129     codewords += PAD;
    130   }
    131   while (codewords.GetLength() < capacity) {
    132     codewords += (randomize253State(PAD, codewords.GetLength() + 1));
    133   }
    134   for (int32_t i = 0; i < encoders.GetSize(); i++) {
    135     delete (CBC_Encoder*)encoders.GetAt(i);
    136   }
    137   encoders.RemoveAll();
    138   return codewords;
    139 }
    140 int32_t CBC_HighLevelEncoder::lookAheadTest(CFX_WideString msg,
    141                                             int32_t startpos,
    142                                             int32_t currentMode) {
    143   if (startpos >= msg.GetLength()) {
    144     return currentMode;
    145   }
    146   CFX_FloatArray charCounts;
    147   if (currentMode == ASCII_ENCODATION) {
    148     charCounts.Add(0);
    149     charCounts.Add(1);
    150     charCounts.Add(1);
    151     charCounts.Add(1);
    152     charCounts.Add(1);
    153     charCounts.Add(1.25f);
    154   } else {
    155     charCounts.Add(1);
    156     charCounts.Add(2);
    157     charCounts.Add(2);
    158     charCounts.Add(2);
    159     charCounts.Add(2);
    160     charCounts.Add(2.25f);
    161     charCounts[currentMode] = 0;
    162   }
    163   int32_t charsProcessed = 0;
    164   while (TRUE) {
    165     if ((startpos + charsProcessed) == msg.GetLength()) {
    166       FX_DWORD min = Integer_MAX_VALUE;
    167       CFX_ByteArray mins;
    168       mins.SetSize(6);
    169       CFX_Int32Array intCharCounts;
    170       intCharCounts.SetSize(6);
    171       min = findMinimums(charCounts, intCharCounts, min, mins);
    172       int32_t minCount = getMinimumCount(mins);
    173       if (intCharCounts[ASCII_ENCODATION] == min) {
    174         return ASCII_ENCODATION;
    175       }
    176       if (minCount == 1 && mins[BASE256_ENCODATION] > 0) {
    177         return BASE256_ENCODATION;
    178       }
    179       if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) {
    180         return EDIFACT_ENCODATION;
    181       }
    182       if (minCount == 1 && mins[TEXT_ENCODATION] > 0) {
    183         return TEXT_ENCODATION;
    184       }
    185       if (minCount == 1 && mins[X12_ENCODATION] > 0) {
    186         return X12_ENCODATION;
    187       }
    188       return C40_ENCODATION;
    189     }
    190     FX_WCHAR c = msg.GetAt(startpos + charsProcessed);
    191     charsProcessed++;
    192     if (isDigit(c)) {
    193       charCounts[ASCII_ENCODATION] += 0.5;
    194     } else if (isExtendedASCII(c)) {
    195       charCounts[ASCII_ENCODATION] =
    196           (FX_FLOAT)ceil(charCounts[ASCII_ENCODATION]);
    197       charCounts[ASCII_ENCODATION] += 2;
    198     } else {
    199       charCounts[ASCII_ENCODATION] =
    200           (FX_FLOAT)ceil(charCounts[ASCII_ENCODATION]);
    201       charCounts[ASCII_ENCODATION]++;
    202     }
    203     if (isNativeC40(c)) {
    204       charCounts[C40_ENCODATION] += 2.0f / 3.0f;
    205     } else if (isExtendedASCII(c)) {
    206       charCounts[C40_ENCODATION] += 8.0f / 3.0f;
    207     } else {
    208       charCounts[C40_ENCODATION] += 4.0f / 3.0f;
    209     }
    210     if (isNativeText(c)) {
    211       charCounts[TEXT_ENCODATION] += 2.0f / 3.0f;
    212     } else if (isExtendedASCII(c)) {
    213       charCounts[TEXT_ENCODATION] += 8.0f / 3.0f;
    214     } else {
    215       charCounts[TEXT_ENCODATION] += 4.0f / 3.0f;
    216     }
    217     if (isNativeX12(c)) {
    218       charCounts[X12_ENCODATION] += 2.0f / 3.0f;
    219     } else if (isExtendedASCII(c)) {
    220       charCounts[X12_ENCODATION] += 13.0f / 3.0f;
    221     } else {
    222       charCounts[X12_ENCODATION] += 10.0f / 3.0f;
    223     }
    224     if (isNativeEDIFACT(c)) {
    225       charCounts[EDIFACT_ENCODATION] += 3.0f / 4.0f;
    226     } else if (isExtendedASCII(c)) {
    227       charCounts[EDIFACT_ENCODATION] += 17.0f / 4.0f;
    228     } else {
    229       charCounts[EDIFACT_ENCODATION] += 13.0f / 4.0f;
    230     }
    231     if (isSpecialB256(c)) {
    232       charCounts[BASE256_ENCODATION] += 4;
    233     } else {
    234       charCounts[BASE256_ENCODATION]++;
    235     }
    236     if (charsProcessed >= 4) {
    237       CFX_Int32Array intCharCounts;
    238       intCharCounts.SetSize(6);
    239       CFX_ByteArray mins;
    240       mins.SetSize(6);
    241       findMinimums(charCounts, intCharCounts, Integer_MAX_VALUE, mins);
    242       int32_t minCount = getMinimumCount(mins);
    243       if (intCharCounts[ASCII_ENCODATION] < intCharCounts[BASE256_ENCODATION] &&
    244           intCharCounts[ASCII_ENCODATION] < intCharCounts[C40_ENCODATION] &&
    245           intCharCounts[ASCII_ENCODATION] < intCharCounts[TEXT_ENCODATION] &&
    246           intCharCounts[ASCII_ENCODATION] < intCharCounts[X12_ENCODATION] &&
    247           intCharCounts[ASCII_ENCODATION] < intCharCounts[EDIFACT_ENCODATION]) {
    248         return ASCII_ENCODATION;
    249       }
    250       if (intCharCounts[BASE256_ENCODATION] < intCharCounts[ASCII_ENCODATION] ||
    251           (mins[C40_ENCODATION] + mins[TEXT_ENCODATION] + mins[X12_ENCODATION] +
    252            mins[EDIFACT_ENCODATION]) == 0) {
    253         return BASE256_ENCODATION;
    254       }
    255       if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) {
    256         return EDIFACT_ENCODATION;
    257       }
    258       if (minCount == 1 && mins[TEXT_ENCODATION] > 0) {
    259         return TEXT_ENCODATION;
    260       }
    261       if (minCount == 1 && mins[X12_ENCODATION] > 0) {
    262         return X12_ENCODATION;
    263       }
    264       if (intCharCounts[C40_ENCODATION] + 1 < intCharCounts[ASCII_ENCODATION] &&
    265           intCharCounts[C40_ENCODATION] + 1 <
    266               intCharCounts[BASE256_ENCODATION] &&
    267           intCharCounts[C40_ENCODATION] + 1 <
    268               intCharCounts[EDIFACT_ENCODATION] &&
    269           intCharCounts[C40_ENCODATION] + 1 < intCharCounts[TEXT_ENCODATION]) {
    270         if (intCharCounts[C40_ENCODATION] < intCharCounts[X12_ENCODATION]) {
    271           return C40_ENCODATION;
    272         }
    273         if (intCharCounts[C40_ENCODATION] == intCharCounts[X12_ENCODATION]) {
    274           int32_t p = startpos + charsProcessed + 1;
    275           while (p < msg.GetLength()) {
    276             FX_WCHAR tc = msg.GetAt(p);
    277             if (isX12TermSep(tc)) {
    278               return X12_ENCODATION;
    279             }
    280             if (!isNativeX12(tc)) {
    281               break;
    282             }
    283             p++;
    284           }
    285           return C40_ENCODATION;
    286         }
    287       }
    288     }
    289   }
    290 }
    291 FX_BOOL CBC_HighLevelEncoder::isDigit(FX_WCHAR ch) {
    292   return ch >= '0' && ch <= '9';
    293 }
    294 FX_BOOL CBC_HighLevelEncoder::isExtendedASCII(FX_WCHAR ch) {
    295   return ch >= 128 && ch <= 255;
    296 }
    297 int32_t CBC_HighLevelEncoder::determineConsecutiveDigitCount(CFX_WideString msg,
    298                                                              int32_t startpos) {
    299   int32_t count = 0;
    300   int32_t len = msg.GetLength();
    301   int32_t idx = startpos;
    302   if (idx < len) {
    303     FX_WCHAR ch = msg.GetAt(idx);
    304     while (isDigit(ch) && idx < len) {
    305       count++;
    306       idx++;
    307       if (idx < len) {
    308         ch = msg.GetAt(idx);
    309       }
    310     }
    311   }
    312   return count;
    313 }
    314 void CBC_HighLevelEncoder::illegalCharacter(FX_WCHAR c, int32_t& e) {
    315   e = BCExceptionIllegalArgument;
    316 }
    317 FX_WCHAR CBC_HighLevelEncoder::randomize253State(FX_WCHAR ch,
    318                                                  int32_t codewordPosition) {
    319   int32_t pseudoRandom = ((149 * codewordPosition) % 253) + 1;
    320   int32_t tempVariable = ch + pseudoRandom;
    321   return tempVariable <= 254 ? (FX_WCHAR)tempVariable
    322                              : (FX_WCHAR)(tempVariable - 254);
    323 }
    324 int32_t CBC_HighLevelEncoder::findMinimums(CFX_FloatArray& charCounts,
    325                                            CFX_Int32Array& intCharCounts,
    326                                            int32_t min,
    327                                            CFX_ByteArray& mins) {
    328   for (int32_t l = 0; l < mins.GetSize(); l++) {
    329     mins[l] = (uint8_t)0;
    330   }
    331   for (int32_t i = 0; i < 6; i++) {
    332     intCharCounts[i] = (int32_t)ceil(charCounts[i]);
    333     int32_t current = intCharCounts[i];
    334     if (min > current) {
    335       min = current;
    336       for (int32_t j = 0; j < mins.GetSize(); j++) {
    337         mins[j] = (uint8_t)0;
    338       }
    339     }
    340     if (min == current) {
    341       mins[i]++;
    342     }
    343   }
    344   return min;
    345 }
    346 int32_t CBC_HighLevelEncoder::getMinimumCount(CFX_ByteArray& mins) {
    347   int32_t minCount = 0;
    348   for (int32_t i = 0; i < 6; i++) {
    349     minCount += mins[i];
    350   }
    351   return minCount;
    352 }
    353 FX_BOOL CBC_HighLevelEncoder::isNativeC40(FX_WCHAR ch) {
    354   return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
    355 }
    356 FX_BOOL CBC_HighLevelEncoder::isNativeText(FX_WCHAR ch) {
    357   return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
    358 }
    359 FX_BOOL CBC_HighLevelEncoder::isNativeX12(FX_WCHAR ch) {
    360   return isX12TermSep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') ||
    361          (ch >= 'A' && ch <= 'Z');
    362 }
    363 FX_BOOL CBC_HighLevelEncoder::isX12TermSep(FX_WCHAR ch) {
    364   return (ch == '\r') || (ch == '*') || (ch == '>');
    365 }
    366 FX_BOOL CBC_HighLevelEncoder::isNativeEDIFACT(FX_WCHAR ch) {
    367   return ch >= ' ' && ch <= '^';
    368 }
    369 FX_BOOL CBC_HighLevelEncoder::isSpecialB256(FX_WCHAR ch) {
    370   return FALSE;
    371 }
    372