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