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