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