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