OLD | NEW |
| (Empty) |
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 "xfa/src/fxbarcode/pdf417/BC_PDF417DecodedBitStreamParser.h" | |
24 | |
25 #include <stdlib.h> | |
26 | |
27 #include "third_party/bigint/BigIntegerLibrary.hh" | |
28 #include "xfa/src/fxbarcode/BC_DecoderResult.h" | |
29 #include "xfa/src/fxbarcode/common/BC_CommonDecoderResult.h" | |
30 #include "xfa/src/fxbarcode/pdf417/BC_PDF417ResultMetadata.h" | |
31 #include "xfa/src/fxbarcode/utils.h" | |
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 | |
59 void CBC_DecodedBitStreamPaser::Initialize() {} | |
60 void CBC_DecodedBitStreamPaser::Finalize() {} | |
61 CBC_DecodedBitStreamPaser::CBC_DecodedBitStreamPaser() {} | |
62 CBC_DecodedBitStreamPaser::~CBC_DecodedBitStreamPaser() {} | |
63 CBC_CommonDecoderResult* CBC_DecodedBitStreamPaser::decode( | |
64 CFX_Int32Array& codewords, | |
65 CFX_ByteString ecLevel, | |
66 int32_t& e) { | |
67 CFX_ByteString result; | |
68 int32_t codeIndex = 1; | |
69 int32_t code = codewords.GetAt(codeIndex); | |
70 codeIndex++; | |
71 CBC_PDF417ResultMetadata* resultMetadata = new CBC_PDF417ResultMetadata; | |
72 while (codeIndex < codewords[0]) { | |
73 switch (code) { | |
74 case TEXT_COMPACTION_MODE_LATCH: | |
75 codeIndex = textCompaction(codewords, codeIndex, result); | |
76 break; | |
77 case BYTE_COMPACTION_MODE_LATCH: | |
78 codeIndex = byteCompaction(code, codewords, codeIndex, result); | |
79 break; | |
80 case NUMERIC_COMPACTION_MODE_LATCH: | |
81 codeIndex = numericCompaction(codewords, codeIndex, result, e); | |
82 BC_EXCEPTION_CHECK_ReturnValue(e, NULL); | |
83 break; | |
84 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: | |
85 codeIndex = byteCompaction(code, codewords, codeIndex, result); | |
86 break; | |
87 case BYTE_COMPACTION_MODE_LATCH_6: | |
88 codeIndex = byteCompaction(code, codewords, codeIndex, result); | |
89 break; | |
90 case BEGIN_MACRO_PDF417_CONTROL_BLOCK: | |
91 codeIndex = decodeMacroBlock(codewords, codeIndex, resultMetadata, e); | |
92 if (e != BCExceptionNO) { | |
93 delete resultMetadata; | |
94 return NULL; | |
95 } | |
96 break; | |
97 default: | |
98 codeIndex--; | |
99 codeIndex = textCompaction(codewords, codeIndex, result); | |
100 break; | |
101 } | |
102 if (codeIndex < codewords.GetSize()) { | |
103 code = codewords[codeIndex++]; | |
104 } else { | |
105 e = BCExceptionFormatInstance; | |
106 delete resultMetadata; | |
107 return NULL; | |
108 } | |
109 } | |
110 if (result.GetLength() == 0) { | |
111 e = BCExceptionFormatInstance; | |
112 delete resultMetadata; | |
113 return NULL; | |
114 } | |
115 CFX_ByteArray rawBytes; | |
116 CFX_PtrArray byteSegments; | |
117 CBC_CommonDecoderResult* tempCd = new CBC_CommonDecoderResult(); | |
118 tempCd->Init(rawBytes, result, byteSegments, ecLevel, e); | |
119 if (e != BCExceptionNO) { | |
120 delete resultMetadata; | |
121 return NULL; | |
122 } | |
123 tempCd->setOther(resultMetadata); | |
124 return tempCd; | |
125 } | |
126 int32_t CBC_DecodedBitStreamPaser::decodeMacroBlock( | |
127 CFX_Int32Array& codewords, | |
128 int32_t codeIndex, | |
129 CBC_PDF417ResultMetadata* resultMetadata, | |
130 int32_t& e) { | |
131 if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) { | |
132 e = BCExceptionFormatInstance; | |
133 return -1; | |
134 } | |
135 CFX_Int32Array segmentIndexArray; | |
136 segmentIndexArray.SetSize(NUMBER_OF_SEQUENCE_CODEWORDS); | |
137 for (int32_t i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) { | |
138 segmentIndexArray.SetAt(i, codewords[codeIndex]); | |
139 } | |
140 CFX_ByteString str = | |
141 decodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS, e); | |
142 BC_EXCEPTION_CHECK_ReturnValue(e, -1); | |
143 resultMetadata->setSegmentIndex(atoi(str.GetBuffer(str.GetLength()))); | |
144 CFX_ByteString fileId; | |
145 codeIndex = textCompaction(codewords, codeIndex, fileId); | |
146 resultMetadata->setFileId(fileId); | |
147 if (codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) { | |
148 codeIndex++; | |
149 CFX_Int32Array additionalOptionCodeWords; | |
150 additionalOptionCodeWords.SetSize(codewords[0] - codeIndex); | |
151 int32_t additionalOptionCodeWordsIndex = 0; | |
152 FX_BOOL end = FALSE; | |
153 while ((codeIndex < codewords[0]) && !end) { | |
154 int32_t code = codewords[codeIndex++]; | |
155 if (code < TEXT_COMPACTION_MODE_LATCH) { | |
156 additionalOptionCodeWords[additionalOptionCodeWordsIndex++] = code; | |
157 } else { | |
158 switch (code) { | |
159 case MACRO_PDF417_TERMINATOR: | |
160 resultMetadata->setLastSegment(TRUE); | |
161 codeIndex++; | |
162 end = TRUE; | |
163 break; | |
164 default: | |
165 e = BCExceptionFormatInstance; | |
166 return -1; | |
167 } | |
168 } | |
169 } | |
170 CFX_Int32Array array; | |
171 array.SetSize(additionalOptionCodeWordsIndex); | |
172 array.Copy(additionalOptionCodeWords); | |
173 resultMetadata->setOptionalData(array); | |
174 } else if (codewords[codeIndex] == MACRO_PDF417_TERMINATOR) { | |
175 resultMetadata->setLastSegment(TRUE); | |
176 codeIndex++; | |
177 } | |
178 return codeIndex; | |
179 } | |
180 int32_t CBC_DecodedBitStreamPaser::textCompaction(CFX_Int32Array& codewords, | |
181 int32_t codeIndex, | |
182 CFX_ByteString& result) { | |
183 CFX_Int32Array textCompactionData; | |
184 textCompactionData.SetSize((codewords[0] - codeIndex) << 1); | |
185 CFX_Int32Array byteCompactionData; | |
186 byteCompactionData.SetSize((codewords[0] - codeIndex) << 1); | |
187 int32_t index = 0; | |
188 FX_BOOL end = FALSE; | |
189 while ((codeIndex < codewords[0]) && !end) { | |
190 int32_t code = codewords[codeIndex++]; | |
191 if (code < TEXT_COMPACTION_MODE_LATCH) { | |
192 textCompactionData[index] = code / 30; | |
193 textCompactionData[index + 1] = code % 30; | |
194 index += 2; | |
195 } else { | |
196 switch (code) { | |
197 case TEXT_COMPACTION_MODE_LATCH: | |
198 textCompactionData[index++] = TEXT_COMPACTION_MODE_LATCH; | |
199 break; | |
200 case BYTE_COMPACTION_MODE_LATCH: | |
201 codeIndex--; | |
202 end = TRUE; | |
203 break; | |
204 case NUMERIC_COMPACTION_MODE_LATCH: | |
205 codeIndex--; | |
206 end = TRUE; | |
207 break; | |
208 case BEGIN_MACRO_PDF417_CONTROL_BLOCK: | |
209 codeIndex--; | |
210 end = TRUE; | |
211 break; | |
212 case BEGIN_MACRO_PDF417_OPTIONAL_FIELD: | |
213 codeIndex--; | |
214 end = TRUE; | |
215 break; | |
216 case MACRO_PDF417_TERMINATOR: | |
217 codeIndex--; | |
218 end = TRUE; | |
219 break; | |
220 case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: | |
221 textCompactionData[index] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE; | |
222 code = codewords[codeIndex++]; | |
223 byteCompactionData[index] = code; | |
224 index++; | |
225 break; | |
226 case BYTE_COMPACTION_MODE_LATCH_6: | |
227 codeIndex--; | |
228 end = TRUE; | |
229 break; | |
230 } | |
231 } | |
232 } | |
233 decodeTextCompaction(textCompactionData, byteCompactionData, index, result); | |
234 return codeIndex; | |
235 } | |
236 void CBC_DecodedBitStreamPaser::decodeTextCompaction( | |
237 CFX_Int32Array& textCompactionData, | |
238 CFX_Int32Array& byteCompactionData, | |
239 int32_t length, | |
240 CFX_ByteString& result) { | |
241 Mode subMode = ALPHA; | |
242 Mode priorToShiftMode = ALPHA; | |
243 int32_t i = 0; | |
244 while (i < length) { | |
245 int32_t subModeCh = textCompactionData[i]; | |
246 FX_CHAR ch = 0; | |
247 switch (subMode) { | |
248 case ALPHA: | |
249 if (subModeCh < 26) { | |
250 ch = (FX_CHAR)('A' + subModeCh); | |
251 } else { | |
252 if (subModeCh == 26) { | |
253 ch = ' '; | |
254 } else if (subModeCh == LL) { | |
255 subMode = LOWER; | |
256 } else if (subModeCh == ML) { | |
257 subMode = MIXED; | |
258 } else if (subModeCh == PS) { | |
259 priorToShiftMode = subMode; | |
260 subMode = PUNCT_SHIFT; | |
261 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { | |
262 result += (FX_CHAR)byteCompactionData[i]; | |
263 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) { | |
264 subMode = ALPHA; | |
265 } | |
266 } | |
267 break; | |
268 case LOWER: | |
269 if (subModeCh < 26) { | |
270 ch = (FX_CHAR)('a' + subModeCh); | |
271 } else { | |
272 if (subModeCh == 26) { | |
273 ch = ' '; | |
274 } else if (subModeCh == AS) { | |
275 priorToShiftMode = subMode; | |
276 subMode = ALPHA_SHIFT; | |
277 } else if (subModeCh == ML) { | |
278 subMode = MIXED; | |
279 } else if (subModeCh == PS) { | |
280 priorToShiftMode = subMode; | |
281 subMode = PUNCT_SHIFT; | |
282 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { | |
283 result += (FX_CHAR)byteCompactionData[i]; | |
284 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) { | |
285 subMode = ALPHA; | |
286 } | |
287 } | |
288 break; | |
289 case MIXED: | |
290 if (subModeCh < PL) { | |
291 ch = MIXED_CHARS[subModeCh]; | |
292 } else { | |
293 if (subModeCh == PL) { | |
294 subMode = PUNCT; | |
295 } else if (subModeCh == 26) { | |
296 ch = ' '; | |
297 } else if (subModeCh == LL) { | |
298 subMode = LOWER; | |
299 } else if (subModeCh == AL) { | |
300 subMode = ALPHA; | |
301 } else if (subModeCh == PS) { | |
302 priorToShiftMode = subMode; | |
303 subMode = PUNCT_SHIFT; | |
304 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { | |
305 result += (FX_CHAR)byteCompactionData[i]; | |
306 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) { | |
307 subMode = ALPHA; | |
308 } | |
309 } | |
310 break; | |
311 case PUNCT: | |
312 if (subModeCh < PAL) { | |
313 ch = PUNCT_CHARS[subModeCh]; | |
314 } else { | |
315 if (subModeCh == PAL) { | |
316 subMode = ALPHA; | |
317 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { | |
318 result += (FX_CHAR)byteCompactionData[i]; | |
319 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) { | |
320 subMode = ALPHA; | |
321 } | |
322 } | |
323 break; | |
324 case ALPHA_SHIFT: | |
325 subMode = priorToShiftMode; | |
326 if (subModeCh < 26) { | |
327 ch = (FX_CHAR)('A' + subModeCh); | |
328 } else { | |
329 if (subModeCh == 26) { | |
330 ch = ' '; | |
331 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) { | |
332 subMode = ALPHA; | |
333 } | |
334 } | |
335 break; | |
336 case PUNCT_SHIFT: | |
337 subMode = priorToShiftMode; | |
338 if (subModeCh < PAL) { | |
339 ch = PUNCT_CHARS[subModeCh]; | |
340 } else { | |
341 if (subModeCh == PAL) { | |
342 subMode = ALPHA; | |
343 } else if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { | |
344 result += (FX_CHAR)byteCompactionData[i]; | |
345 } else if (subModeCh == TEXT_COMPACTION_MODE_LATCH) { | |
346 subMode = ALPHA; | |
347 } | |
348 } | |
349 break; | |
350 } | |
351 if (ch != 0) { | |
352 result += ch; | |
353 } | |
354 i++; | |
355 } | |
356 } | |
357 int32_t CBC_DecodedBitStreamPaser::byteCompaction(int32_t mode, | |
358 CFX_Int32Array& codewords, | |
359 int32_t codeIndex, | |
360 CFX_ByteString& result) { | |
361 if (mode == BYTE_COMPACTION_MODE_LATCH) { | |
362 int32_t count = 0; | |
363 int64_t value = 0; | |
364 FX_WORD* decodedData = FX_Alloc(FX_WORD, 6); | |
365 CFX_Int32Array byteCompactedCodewords; | |
366 byteCompactedCodewords.SetSize(6); | |
367 FX_BOOL end = FALSE; | |
368 int32_t nextCode = codewords[codeIndex++]; | |
369 while ((codeIndex < codewords[0]) && !end) { | |
370 byteCompactedCodewords[count++] = nextCode; | |
371 value = 900 * value + nextCode; | |
372 nextCode = codewords[codeIndex++]; | |
373 if (nextCode == TEXT_COMPACTION_MODE_LATCH || | |
374 nextCode == BYTE_COMPACTION_MODE_LATCH || | |
375 nextCode == NUMERIC_COMPACTION_MODE_LATCH || | |
376 nextCode == BYTE_COMPACTION_MODE_LATCH_6 || | |
377 nextCode == BEGIN_MACRO_PDF417_CONTROL_BLOCK || | |
378 nextCode == BEGIN_MACRO_PDF417_OPTIONAL_FIELD || | |
379 nextCode == MACRO_PDF417_TERMINATOR) { | |
380 codeIndex--; | |
381 end = TRUE; | |
382 } else { | |
383 if ((count % 5 == 0) && (count > 0)) { | |
384 int32_t j = 0; | |
385 for (; j < 6; ++j) { | |
386 decodedData[5 - j] = (FX_WORD)(value % 256); | |
387 value >>= 8; | |
388 } | |
389 for (j = 0; j < 6; ++j) { | |
390 result += (FX_CHAR)decodedData[j]; | |
391 } | |
392 count = 0; | |
393 } | |
394 } | |
395 } | |
396 FX_Free(decodedData); | |
397 if (codeIndex == codewords[0] && nextCode < TEXT_COMPACTION_MODE_LATCH) { | |
398 byteCompactedCodewords[count++] = nextCode; | |
399 } | |
400 for (int32_t i = 0; i < count; i++) { | |
401 result += (FX_CHAR)(FX_WORD)byteCompactedCodewords[i]; | |
402 } | |
403 } else if (mode == BYTE_COMPACTION_MODE_LATCH_6) { | |
404 int32_t count = 0; | |
405 int64_t value = 0; | |
406 FX_BOOL end = FALSE; | |
407 while (codeIndex < codewords[0] && !end) { | |
408 int32_t code = codewords[codeIndex++]; | |
409 if (code < TEXT_COMPACTION_MODE_LATCH) { | |
410 count++; | |
411 value = 900 * value + code; | |
412 } else { | |
413 if (code == TEXT_COMPACTION_MODE_LATCH || | |
414 code == BYTE_COMPACTION_MODE_LATCH || | |
415 code == NUMERIC_COMPACTION_MODE_LATCH || | |
416 code == BYTE_COMPACTION_MODE_LATCH_6 || | |
417 code == BEGIN_MACRO_PDF417_CONTROL_BLOCK || | |
418 code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD || | |
419 code == MACRO_PDF417_TERMINATOR) { | |
420 codeIndex--; | |
421 end = TRUE; | |
422 } | |
423 } | |
424 if ((count % 5 == 0) && (count > 0)) { | |
425 FX_WORD* decodedData = FX_Alloc(FX_WORD, 6); | |
426 int32_t j = 0; | |
427 for (; j < 6; ++j) { | |
428 decodedData[5 - j] = (FX_WORD)(value & 0xFF); | |
429 value >>= 8; | |
430 } | |
431 for (j = 0; j < 6; ++j) { | |
432 result += (FX_CHAR)decodedData[j]; | |
433 } | |
434 count = 0; | |
435 FX_Free(decodedData); | |
436 } | |
437 } | |
438 } | |
439 return codeIndex; | |
440 } | |
441 int32_t CBC_DecodedBitStreamPaser::numericCompaction(CFX_Int32Array& codewords, | |
442 int32_t codeIndex, | |
443 CFX_ByteString& result, | |
444 int32_t& e) { | |
445 int32_t count = 0; | |
446 FX_BOOL end = FALSE; | |
447 CFX_Int32Array numericCodewords; | |
448 numericCodewords.SetSize(MAX_NUMERIC_CODEWORDS); | |
449 while (codeIndex < codewords[0] && !end) { | |
450 int32_t code = codewords[codeIndex++]; | |
451 if (codeIndex == codewords[0]) { | |
452 end = TRUE; | |
453 } | |
454 if (code < TEXT_COMPACTION_MODE_LATCH) { | |
455 numericCodewords[count] = code; | |
456 count++; | |
457 } else { | |
458 if (code == TEXT_COMPACTION_MODE_LATCH || | |
459 code == BYTE_COMPACTION_MODE_LATCH || | |
460 code == BYTE_COMPACTION_MODE_LATCH_6 || | |
461 code == BEGIN_MACRO_PDF417_CONTROL_BLOCK || | |
462 code == BEGIN_MACRO_PDF417_OPTIONAL_FIELD || | |
463 code == MACRO_PDF417_TERMINATOR) { | |
464 codeIndex--; | |
465 end = TRUE; | |
466 } | |
467 } | |
468 if (count % MAX_NUMERIC_CODEWORDS == 0 || | |
469 code == NUMERIC_COMPACTION_MODE_LATCH || end) { | |
470 CFX_ByteString s = decodeBase900toBase10(numericCodewords, count, e); | |
471 BC_EXCEPTION_CHECK_ReturnValue(e, -1); | |
472 result += s; | |
473 count = 0; | |
474 } | |
475 } | |
476 return codeIndex; | |
477 } | |
478 CFX_ByteString CBC_DecodedBitStreamPaser::decodeBase900toBase10( | |
479 CFX_Int32Array& codewords, | |
480 int32_t count, | |
481 int32_t& e) { | |
482 BigInteger result = 0; | |
483 BigInteger nineHundred(900); | |
484 for (int32_t i = 0; i < count; i++) { | |
485 result = result * nineHundred + BigInteger(codewords[i]); | |
486 } | |
487 CFX_ByteString resultString(bigIntegerToString(result).c_str()); | |
488 if (resultString.GetAt(0) != '1') { | |
489 e = BCExceptionFormatInstance; | |
490 return ' '; | |
491 } | |
492 return resultString.Mid(1, resultString.GetLength() - 1); | |
493 } | |
OLD | NEW |