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