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 2006 Jeremias Maerki in part, and ZXing Authors in part | |
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_PDF417HighLevelEncoder.h" | |
24 | |
25 #include "third_party/bigint/BigIntegerLibrary.hh" | |
26 #include "xfa/src/fxbarcode/BC_UtilCodingConvert.h" | |
27 #include "xfa/src/fxbarcode/pdf417/BC_PDF417Compaction.h" | |
28 #include "xfa/src/fxbarcode/utils.h" | |
29 | |
30 #define SUBMODE_ALPHA 0 | |
31 #define SUBMODE_LOWER 1 | |
32 #define SUBMODE_MIXED 2 | |
33 | |
34 int32_t CBC_PDF417HighLevelEncoder::TEXT_COMPACTION = 0; | |
35 int32_t CBC_PDF417HighLevelEncoder::BYTE_COMPACTION = 1; | |
36 int32_t CBC_PDF417HighLevelEncoder::NUMERIC_COMPACTION = 2; | |
37 int32_t CBC_PDF417HighLevelEncoder::SUBMODE_PUNCTUATION = 3; | |
38 int32_t CBC_PDF417HighLevelEncoder::LATCH_TO_TEXT = 900; | |
39 int32_t CBC_PDF417HighLevelEncoder::LATCH_TO_BYTE_PADDED = 901; | |
40 int32_t CBC_PDF417HighLevelEncoder::LATCH_TO_NUMERIC = 902; | |
41 int32_t CBC_PDF417HighLevelEncoder::SHIFT_TO_BYTE = 913; | |
42 int32_t CBC_PDF417HighLevelEncoder::LATCH_TO_BYTE = 924; | |
43 uint8_t CBC_PDF417HighLevelEncoder::TEXT_MIXED_RAW[] = { | |
44 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58, | |
45 35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0}; | |
46 uint8_t CBC_PDF417HighLevelEncoder::TEXT_PUNCTUATION_RAW[] = { | |
47 59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58, | |
48 10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0}; | |
49 int32_t CBC_PDF417HighLevelEncoder::MIXED[128] = {0}; | |
50 int32_t CBC_PDF417HighLevelEncoder::PUNCTUATION[128] = {0}; | |
51 | |
52 void CBC_PDF417HighLevelEncoder::Initialize() { | |
53 Inverse(); | |
54 } | |
55 void CBC_PDF417HighLevelEncoder::Finalize() {} | |
56 CFX_WideString CBC_PDF417HighLevelEncoder::encodeHighLevel( | |
57 CFX_WideString wideMsg, | |
58 Compaction compaction, | |
59 int32_t& e) { | |
60 CFX_ByteString bytes; | |
61 CBC_UtilCodingConvert::UnicodeToUTF8(wideMsg, bytes); | |
62 CFX_WideString msg; | |
63 int32_t len = bytes.GetLength(); | |
64 for (int32_t i = 0; i < len; i++) { | |
65 FX_WCHAR ch = (FX_WCHAR)(bytes.GetAt(i) & 0xff); | |
66 if (ch == '?' && bytes.GetAt(i) != '?') { | |
67 e = BCExceptionCharactersOutsideISO88591Encoding; | |
68 return (FX_WCHAR*)""; | |
69 } | |
70 msg += ch; | |
71 } | |
72 CFX_ByteArray byteArr; | |
73 for (int32_t k = 0; k < bytes.GetLength(); k++) { | |
74 byteArr.Add(bytes.GetAt(k)); | |
75 } | |
76 CFX_WideString sb; | |
77 len = msg.GetLength(); | |
78 int32_t p = 0; | |
79 int32_t textSubMode = SUBMODE_ALPHA; | |
80 if (compaction == TEXT) { | |
81 encodeText(msg, p, len, sb, textSubMode); | |
82 } else if (compaction == BYTES) { | |
83 encodeBinary(&byteArr, p, byteArr.GetSize(), BYTE_COMPACTION, sb); | |
84 } else if (compaction == NUMERIC) { | |
85 sb += (FX_WCHAR)LATCH_TO_NUMERIC; | |
86 encodeNumeric(msg, p, len, sb); | |
87 } else { | |
88 int32_t encodingMode = LATCH_TO_TEXT; | |
89 while (p < len) { | |
90 int32_t n = determineConsecutiveDigitCount(msg, p); | |
91 if (n >= 13) { | |
92 sb += (FX_WCHAR)LATCH_TO_NUMERIC; | |
93 encodingMode = NUMERIC_COMPACTION; | |
94 textSubMode = SUBMODE_ALPHA; | |
95 encodeNumeric(msg, p, n, sb); | |
96 p += n; | |
97 } else { | |
98 int32_t t = determineConsecutiveTextCount(msg, p); | |
99 if (t >= 5 || n == len) { | |
100 if (encodingMode != TEXT_COMPACTION) { | |
101 sb += (FX_WCHAR)LATCH_TO_TEXT; | |
102 encodingMode = TEXT_COMPACTION; | |
103 textSubMode = SUBMODE_ALPHA; | |
104 } | |
105 textSubMode = encodeText(msg, p, t, sb, textSubMode); | |
106 p += t; | |
107 } else { | |
108 int32_t b = determineConsecutiveBinaryCount(msg, &byteArr, p, e); | |
109 BC_EXCEPTION_CHECK_ReturnValue(e, (FX_WCHAR)' '); | |
110 if (b == 0) { | |
111 b = 1; | |
112 } | |
113 if (b == 1 && encodingMode == TEXT_COMPACTION) { | |
114 encodeBinary(&byteArr, p, 1, TEXT_COMPACTION, sb); | |
115 } else { | |
116 encodeBinary(&byteArr, p, b, encodingMode, sb); | |
117 encodingMode = BYTE_COMPACTION; | |
118 textSubMode = SUBMODE_ALPHA; | |
119 } | |
120 p += b; | |
121 } | |
122 } | |
123 } | |
124 } | |
125 return sb; | |
126 } | |
127 | |
128 void CBC_PDF417HighLevelEncoder::Inverse() { | |
129 for (size_t l = 0; l < FX_ArraySize(MIXED); ++l) | |
130 MIXED[l] = -1; | |
131 | |
132 for (uint8_t i = 0; i < FX_ArraySize(TEXT_MIXED_RAW); ++i) { | |
133 uint8_t b = TEXT_MIXED_RAW[i]; | |
134 if (b != 0) | |
135 MIXED[b] = i; | |
136 } | |
137 | |
138 for (size_t l = 0; l < FX_ArraySize(PUNCTUATION); ++l) | |
139 PUNCTUATION[l] = -1; | |
140 | |
141 for (uint8_t i = 0; i < FX_ArraySize(TEXT_PUNCTUATION_RAW); ++i) { | |
142 uint8_t b = TEXT_PUNCTUATION_RAW[i]; | |
143 if (b != 0) | |
144 PUNCTUATION[b] = i; | |
145 } | |
146 } | |
147 | |
148 int32_t CBC_PDF417HighLevelEncoder::encodeText(CFX_WideString msg, | |
149 int32_t startpos, | |
150 int32_t count, | |
151 CFX_WideString& sb, | |
152 int32_t initialSubmode) { | |
153 CFX_WideString tmp; | |
154 int32_t submode = initialSubmode; | |
155 int32_t idx = 0; | |
156 while (TRUE) { | |
157 FX_WCHAR ch = msg.GetAt(startpos + idx); | |
158 switch (submode) { | |
159 case SUBMODE_ALPHA: | |
160 if (isAlphaUpper(ch)) { | |
161 if (ch == ' ') { | |
162 tmp += (FX_WCHAR)26; | |
163 } else { | |
164 tmp += (FX_WCHAR)(ch - 65); | |
165 } | |
166 } else { | |
167 if (isAlphaLower(ch)) { | |
168 submode = SUBMODE_LOWER; | |
169 tmp += (FX_WCHAR)27; | |
170 continue; | |
171 } else if (isMixed(ch)) { | |
172 submode = SUBMODE_MIXED; | |
173 tmp += (FX_WCHAR)28; | |
174 continue; | |
175 } else { | |
176 tmp += (FX_WCHAR)29; | |
177 tmp += PUNCTUATION[ch]; | |
178 break; | |
179 } | |
180 } | |
181 break; | |
182 case SUBMODE_LOWER: | |
183 if (isAlphaLower(ch)) { | |
184 if (ch == ' ') { | |
185 tmp += (FX_WCHAR)26; | |
186 } else { | |
187 tmp += (FX_WCHAR)(ch - 97); | |
188 } | |
189 } else { | |
190 if (isAlphaUpper(ch)) { | |
191 tmp += (FX_WCHAR)27; | |
192 tmp += (FX_WCHAR)(ch - 65); | |
193 break; | |
194 } else if (isMixed(ch)) { | |
195 submode = SUBMODE_MIXED; | |
196 tmp += (FX_WCHAR)28; | |
197 continue; | |
198 } else { | |
199 tmp += (FX_WCHAR)29; | |
200 tmp += PUNCTUATION[ch]; | |
201 break; | |
202 } | |
203 } | |
204 break; | |
205 case SUBMODE_MIXED: | |
206 if (isMixed(ch)) { | |
207 tmp += MIXED[ch]; | |
208 } else { | |
209 if (isAlphaUpper(ch)) { | |
210 submode = SUBMODE_ALPHA; | |
211 tmp += (FX_WCHAR)28; | |
212 continue; | |
213 } else if (isAlphaLower(ch)) { | |
214 submode = SUBMODE_LOWER; | |
215 tmp += (FX_WCHAR)27; | |
216 continue; | |
217 } else { | |
218 if (startpos + idx + 1 < count) { | |
219 FX_WCHAR next = msg.GetAt(startpos + idx + 1); | |
220 if (isPunctuation(next)) { | |
221 submode = SUBMODE_PUNCTUATION; | |
222 tmp += (FX_WCHAR)25; | |
223 continue; | |
224 } | |
225 } | |
226 tmp += (FX_WCHAR)29; | |
227 tmp += PUNCTUATION[ch]; | |
228 } | |
229 } | |
230 break; | |
231 default: | |
232 if (isPunctuation(ch)) { | |
233 tmp += PUNCTUATION[ch]; | |
234 } else { | |
235 submode = SUBMODE_ALPHA; | |
236 tmp += (FX_WCHAR)29; | |
237 continue; | |
238 } | |
239 } | |
240 idx++; | |
241 if (idx >= count) { | |
242 break; | |
243 } | |
244 } | |
245 FX_WCHAR h = 0; | |
246 int32_t len = tmp.GetLength(); | |
247 for (int32_t i = 0; i < len; i++) { | |
248 FX_BOOL odd = (i % 2) != 0; | |
249 if (odd) { | |
250 h = (FX_WCHAR)((h * 30) + tmp.GetAt(i)); | |
251 sb += h; | |
252 } else { | |
253 h = tmp.GetAt(i); | |
254 } | |
255 } | |
256 if ((len % 2) != 0) { | |
257 sb += (FX_WCHAR)((h * 30) + 29); | |
258 } | |
259 return submode; | |
260 } | |
261 void CBC_PDF417HighLevelEncoder::encodeBinary(CFX_ByteArray* bytes, | |
262 int32_t startpos, | |
263 int32_t count, | |
264 int32_t startmode, | |
265 CFX_WideString& sb) { | |
266 if (count == 1 && startmode == TEXT_COMPACTION) { | |
267 sb += (FX_WCHAR)SHIFT_TO_BYTE; | |
268 } | |
269 int32_t idx = startpos; | |
270 int32_t i = 0; | |
271 if (count >= 6) { | |
272 sb += (FX_WCHAR)LATCH_TO_BYTE; | |
273 FX_WCHAR chars[5]; | |
274 while ((startpos + count - idx) >= 6) { | |
275 int64_t t = 0; | |
276 for (i = 0; i < 6; i++) { | |
277 t <<= 8; | |
278 t += bytes->GetAt(idx + i) & 0xff; | |
279 } | |
280 for (i = 0; i < 5; i++) { | |
281 chars[i] = (FX_WCHAR)(t % 900); | |
282 t /= 900; | |
283 } | |
284 for (i = 4; i >= 0; i--) { | |
285 sb += (chars[i]); | |
286 } | |
287 idx += 6; | |
288 } | |
289 } | |
290 if (idx < startpos + count) { | |
291 sb += (FX_WCHAR)LATCH_TO_BYTE_PADDED; | |
292 } | |
293 for (i = idx; i < startpos + count; i++) { | |
294 int32_t ch = bytes->GetAt(i) & 0xff; | |
295 sb += (FX_WCHAR)ch; | |
296 } | |
297 } | |
298 void CBC_PDF417HighLevelEncoder::encodeNumeric(CFX_WideString msg, | |
299 int32_t startpos, | |
300 int32_t count, | |
301 CFX_WideString& sb) { | |
302 int32_t idx = 0; | |
303 BigInteger num900 = 900; | |
304 while (idx < count) { | |
305 CFX_WideString tmp; | |
306 int32_t len = 44 < count - idx ? 44 : count - idx; | |
307 CFX_ByteString part = | |
308 ((FX_WCHAR)'1' + msg.Mid(startpos + idx, len)).UTF8Encode(); | |
309 BigInteger bigint = stringToBigInteger(part.c_str()); | |
310 do { | |
311 int32_t c = (bigint % num900).toInt(); | |
312 tmp += (FX_WCHAR)(c); | |
313 bigint = bigint / num900; | |
314 } while (!bigint.isZero()); | |
315 for (int32_t i = tmp.GetLength() - 1; i >= 0; i--) { | |
316 sb += tmp.GetAt(i); | |
317 } | |
318 idx += len; | |
319 } | |
320 } | |
321 FX_BOOL CBC_PDF417HighLevelEncoder::isDigit(FX_WCHAR ch) { | |
322 return ch >= '0' && ch <= '9'; | |
323 } | |
324 FX_BOOL CBC_PDF417HighLevelEncoder::isAlphaUpper(FX_WCHAR ch) { | |
325 return ch == ' ' || (ch >= 'A' && ch <= 'Z'); | |
326 } | |
327 FX_BOOL CBC_PDF417HighLevelEncoder::isAlphaLower(FX_WCHAR ch) { | |
328 return ch == ' ' || (ch >= 'a' && ch <= 'z'); | |
329 } | |
330 FX_BOOL CBC_PDF417HighLevelEncoder::isMixed(FX_WCHAR ch) { | |
331 return MIXED[ch] != -1; | |
332 } | |
333 FX_BOOL CBC_PDF417HighLevelEncoder::isPunctuation(FX_WCHAR ch) { | |
334 return PUNCTUATION[ch] != -1; | |
335 } | |
336 FX_BOOL CBC_PDF417HighLevelEncoder::isText(FX_WCHAR ch) { | |
337 return ch == '\t' || ch == '\n' || ch == '\r' || (ch >= 32 && ch <= 126); | |
338 } | |
339 int32_t CBC_PDF417HighLevelEncoder::determineConsecutiveDigitCount( | |
340 CFX_WideString msg, | |
341 int32_t startpos) { | |
342 int32_t count = 0; | |
343 int32_t len = msg.GetLength(); | |
344 int32_t idx = startpos; | |
345 if (idx < len) { | |
346 FX_WCHAR ch = msg.GetAt(idx); | |
347 while (isDigit(ch) && idx < len) { | |
348 count++; | |
349 idx++; | |
350 if (idx < len) { | |
351 ch = msg.GetAt(idx); | |
352 } | |
353 } | |
354 } | |
355 return count; | |
356 } | |
357 int32_t CBC_PDF417HighLevelEncoder::determineConsecutiveTextCount( | |
358 CFX_WideString msg, | |
359 int32_t startpos) { | |
360 int32_t len = msg.GetLength(); | |
361 int32_t idx = startpos; | |
362 while (idx < len) { | |
363 FX_WCHAR ch = msg.GetAt(idx); | |
364 int32_t numericCount = 0; | |
365 while (numericCount < 13 && isDigit(ch) && idx < len) { | |
366 numericCount++; | |
367 idx++; | |
368 if (idx < len) { | |
369 ch = msg.GetAt(idx); | |
370 } | |
371 } | |
372 if (numericCount >= 13) { | |
373 return idx - startpos - numericCount; | |
374 } | |
375 if (numericCount > 0) { | |
376 continue; | |
377 } | |
378 ch = msg.GetAt(idx); | |
379 if (!isText(ch)) { | |
380 break; | |
381 } | |
382 idx++; | |
383 } | |
384 return idx - startpos; | |
385 } | |
386 int32_t CBC_PDF417HighLevelEncoder::determineConsecutiveBinaryCount( | |
387 CFX_WideString msg, | |
388 CFX_ByteArray* bytes, | |
389 int32_t startpos, | |
390 int32_t& e) { | |
391 int32_t len = msg.GetLength(); | |
392 int32_t idx = startpos; | |
393 while (idx < len) { | |
394 FX_WCHAR ch = msg.GetAt(idx); | |
395 int32_t numericCount = 0; | |
396 while (numericCount < 13 && isDigit(ch)) { | |
397 numericCount++; | |
398 int32_t i = idx + numericCount; | |
399 if (i >= len) { | |
400 break; | |
401 } | |
402 ch = msg.GetAt(i); | |
403 } | |
404 if (numericCount >= 13) { | |
405 return idx - startpos; | |
406 } | |
407 int32_t textCount = 0; | |
408 while (textCount < 5 && isText(ch)) { | |
409 textCount++; | |
410 int32_t i = idx + textCount; | |
411 if (i >= len) { | |
412 break; | |
413 } | |
414 ch = msg.GetAt(i); | |
415 } | |
416 if (textCount >= 5) { | |
417 return idx - startpos; | |
418 } | |
419 ch = msg.GetAt(idx); | |
420 if (bytes->GetAt(idx) == 63 && ch != '?') { | |
421 e = BCExceptionNonEncodableCharacterDetected; | |
422 return -1; | |
423 } | |
424 idx++; | |
425 } | |
426 return idx - startpos; | |
427 } | |
OLD | NEW |