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-2007 Jeremias Maerki.
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/barcode.h"
24 #include "xfa/src/fxbarcode/BC_Dimension.h"
25 #include "xfa/src/fxbarcode/BC_UtilCodingConvert.h"
26 #include "xfa/src/fxbarcode/common/BC_CommonBitMatrix.h"
27 #include "BC_Encoder.h"
28 #include "BC_SymbolShapeHint.h"
29 #include "BC_SymbolInfo.h"
30 #include "BC_EncoderContext.h"
31 #include "BC_C40Encoder.h"
32 #include "BC_TextEncoder.h"
33 #include "BC_X12Encoder.h"
34 #include "BC_EdifactEncoder.h"
35 #include "BC_Base256Encoder.h"
36 #include "BC_ASCIIEncoder.h"
37 #include "BC_HighLevelEncoder.h"
38 #define Integer_MAX_VALUE 2147483647
39 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_C40 = 230;
40 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_BASE256 = 231;
41 FX_WCHAR CBC_HighLevelEncoder::UPPER_SHIFT = 235;
42 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_ANSIX12 = 238;
43 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_TEXT = 239;
44 FX_WCHAR CBC_HighLevelEncoder::LATCH_TO_EDIFACT = 240;
45 FX_WCHAR CBC_HighLevelEncoder::C40_UNLATCH = 254;
46 FX_WCHAR CBC_HighLevelEncoder::X12_UNLATCH = 254;
47 FX_WCHAR CBC_HighLevelEncoder::PAD = 129;
48 FX_WCHAR CBC_HighLevelEncoder::MACRO_05 = 236;
49 FX_WCHAR CBC_HighLevelEncoder::MACRO_06 = 237;
50 const wchar_t* CBC_HighLevelEncoder::MACRO_05_HEADER = L"[)>05";
51 const wchar_t* CBC_HighLevelEncoder::MACRO_06_HEADER = L"[)>06";
52 const wchar_t CBC_HighLevelEncoder::MACRO_TRAILER = 0x0004;
CBC_HighLevelEncoder()53 CBC_HighLevelEncoder::CBC_HighLevelEncoder() {}
~CBC_HighLevelEncoder()54 CBC_HighLevelEncoder::~CBC_HighLevelEncoder() {}
getBytesForMessage(CFX_WideString msg)55 CFX_ByteArray& CBC_HighLevelEncoder::getBytesForMessage(CFX_WideString msg) {
56   CFX_ByteString bytestr;
57   CBC_UtilCodingConvert::UnicodeToUTF8(msg, bytestr);
58   for (int32_t i = 0; i < bytestr.GetLength(); i++) {
59     m_bytearray.Add(bytestr.GetAt(i));
60   }
61   return m_bytearray;
62 }
encodeHighLevel(CFX_WideString msg,CFX_WideString ecLevel,int32_t & e)63 CFX_WideString CBC_HighLevelEncoder::encodeHighLevel(CFX_WideString msg,
64                                                      CFX_WideString ecLevel,
65                                                      int32_t& e) {
66   return encodeHighLevel(msg, ecLevel, FORCE_NONE, NULL, NULL, e);
67 }
encodeHighLevel(CFX_WideString msg,CFX_WideString ecLevel,SymbolShapeHint shape,CBC_Dimension * minSize,CBC_Dimension * maxSize,int32_t & e)68 CFX_WideString CBC_HighLevelEncoder::encodeHighLevel(CFX_WideString msg,
69                                                      CFX_WideString ecLevel,
70                                                      SymbolShapeHint shape,
71                                                      CBC_Dimension* minSize,
72                                                      CBC_Dimension* maxSize,
73                                                      int32_t& e) {
74   CBC_EncoderContext context(msg, ecLevel, e);
75   BC_EXCEPTION_CHECK_ReturnValue(e, (FX_WCHAR*)"");
76   context.setSymbolShape(shape);
77   context.setSizeConstraints(minSize, maxSize);
78   if ((msg.Mid(0, 6) == MACRO_05_HEADER) &&
79       (msg.Mid(msg.GetLength() - 1, 1) == MACRO_TRAILER)) {
80     context.writeCodeword(MACRO_05);
81     context.setSkipAtEnd(2);
82     context.m_pos += 6;
83   } else if ((msg.Mid(0, 6) == MACRO_06_HEADER) &&
84              (msg.Mid(msg.GetLength() - 1, 1) == MACRO_TRAILER)) {
85     context.writeCodeword(MACRO_06);
86     context.setSkipAtEnd(2);
87     context.m_pos += 6;
88   }
89   CFX_PtrArray encoders;
90   encoders.Add(new CBC_ASCIIEncoder());
91   encoders.Add(new CBC_C40Encoder());
92   encoders.Add(new CBC_TextEncoder());
93   encoders.Add(new CBC_X12Encoder());
94   encoders.Add(new CBC_EdifactEncoder());
95   encoders.Add(new CBC_Base256Encoder());
96   int32_t encodingMode = ASCII_ENCODATION;
97   while (context.hasMoreCharacters()) {
98     ((CBC_Encoder*)encoders.GetAt(encodingMode))->Encode(context, e);
99     if (e != BCExceptionNO) {
100       for (int32_t i = 0; i < encoders.GetSize(); i++) {
101         delete (CBC_Encoder*)encoders.GetAt(i);
102       }
103       encoders.RemoveAll();
104       return (FX_WCHAR*)"";
105     }
106     if (context.m_newEncoding >= 0) {
107       encodingMode = context.m_newEncoding;
108       context.resetEncoderSignal();
109     }
110   }
111   int32_t len = context.m_codewords.GetLength();
112   context.updateSymbolInfo(e);
113   if (e != BCExceptionNO) {
114     for (int32_t i = 0; i < encoders.GetSize(); i++) {
115       delete (CBC_Encoder*)encoders.GetAt(i);
116     }
117     encoders.RemoveAll();
118     return (FX_WCHAR*)"";
119   }
120   int32_t capacity = context.m_symbolInfo->m_dataCapacity;
121   if (len < capacity) {
122     if (encodingMode != ASCII_ENCODATION &&
123         encodingMode != BASE256_ENCODATION) {
124       context.writeCodeword(0x00fe);
125     }
126   }
127   CFX_WideString codewords = context.m_codewords;
128   if (codewords.GetLength() < capacity) {
129     codewords += PAD;
130   }
131   while (codewords.GetLength() < capacity) {
132     codewords += (randomize253State(PAD, codewords.GetLength() + 1));
133   }
134   for (int32_t i = 0; i < encoders.GetSize(); i++) {
135     delete (CBC_Encoder*)encoders.GetAt(i);
136   }
137   encoders.RemoveAll();
138   return codewords;
139 }
lookAheadTest(CFX_WideString msg,int32_t startpos,int32_t currentMode)140 int32_t CBC_HighLevelEncoder::lookAheadTest(CFX_WideString msg,
141                                             int32_t startpos,
142                                             int32_t currentMode) {
143   if (startpos >= msg.GetLength()) {
144     return currentMode;
145   }
146   CFX_FloatArray charCounts;
147   if (currentMode == ASCII_ENCODATION) {
148     charCounts.Add(0);
149     charCounts.Add(1);
150     charCounts.Add(1);
151     charCounts.Add(1);
152     charCounts.Add(1);
153     charCounts.Add(1.25f);
154   } else {
155     charCounts.Add(1);
156     charCounts.Add(2);
157     charCounts.Add(2);
158     charCounts.Add(2);
159     charCounts.Add(2);
160     charCounts.Add(2.25f);
161     charCounts[currentMode] = 0;
162   }
163   int32_t charsProcessed = 0;
164   while (TRUE) {
165     if ((startpos + charsProcessed) == msg.GetLength()) {
166       FX_DWORD min = Integer_MAX_VALUE;
167       CFX_ByteArray mins;
168       mins.SetSize(6);
169       CFX_Int32Array intCharCounts;
170       intCharCounts.SetSize(6);
171       min = findMinimums(charCounts, intCharCounts, min, mins);
172       int32_t minCount = getMinimumCount(mins);
173       if (intCharCounts[ASCII_ENCODATION] == min) {
174         return ASCII_ENCODATION;
175       }
176       if (minCount == 1 && mins[BASE256_ENCODATION] > 0) {
177         return BASE256_ENCODATION;
178       }
179       if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) {
180         return EDIFACT_ENCODATION;
181       }
182       if (minCount == 1 && mins[TEXT_ENCODATION] > 0) {
183         return TEXT_ENCODATION;
184       }
185       if (minCount == 1 && mins[X12_ENCODATION] > 0) {
186         return X12_ENCODATION;
187       }
188       return C40_ENCODATION;
189     }
190     FX_WCHAR c = msg.GetAt(startpos + charsProcessed);
191     charsProcessed++;
192     if (isDigit(c)) {
193       charCounts[ASCII_ENCODATION] += 0.5;
194     } else if (isExtendedASCII(c)) {
195       charCounts[ASCII_ENCODATION] =
196           (FX_FLOAT)ceil(charCounts[ASCII_ENCODATION]);
197       charCounts[ASCII_ENCODATION] += 2;
198     } else {
199       charCounts[ASCII_ENCODATION] =
200           (FX_FLOAT)ceil(charCounts[ASCII_ENCODATION]);
201       charCounts[ASCII_ENCODATION]++;
202     }
203     if (isNativeC40(c)) {
204       charCounts[C40_ENCODATION] += 2.0f / 3.0f;
205     } else if (isExtendedASCII(c)) {
206       charCounts[C40_ENCODATION] += 8.0f / 3.0f;
207     } else {
208       charCounts[C40_ENCODATION] += 4.0f / 3.0f;
209     }
210     if (isNativeText(c)) {
211       charCounts[TEXT_ENCODATION] += 2.0f / 3.0f;
212     } else if (isExtendedASCII(c)) {
213       charCounts[TEXT_ENCODATION] += 8.0f / 3.0f;
214     } else {
215       charCounts[TEXT_ENCODATION] += 4.0f / 3.0f;
216     }
217     if (isNativeX12(c)) {
218       charCounts[X12_ENCODATION] += 2.0f / 3.0f;
219     } else if (isExtendedASCII(c)) {
220       charCounts[X12_ENCODATION] += 13.0f / 3.0f;
221     } else {
222       charCounts[X12_ENCODATION] += 10.0f / 3.0f;
223     }
224     if (isNativeEDIFACT(c)) {
225       charCounts[EDIFACT_ENCODATION] += 3.0f / 4.0f;
226     } else if (isExtendedASCII(c)) {
227       charCounts[EDIFACT_ENCODATION] += 17.0f / 4.0f;
228     } else {
229       charCounts[EDIFACT_ENCODATION] += 13.0f / 4.0f;
230     }
231     if (isSpecialB256(c)) {
232       charCounts[BASE256_ENCODATION] += 4;
233     } else {
234       charCounts[BASE256_ENCODATION]++;
235     }
236     if (charsProcessed >= 4) {
237       CFX_Int32Array intCharCounts;
238       intCharCounts.SetSize(6);
239       CFX_ByteArray mins;
240       mins.SetSize(6);
241       findMinimums(charCounts, intCharCounts, Integer_MAX_VALUE, mins);
242       int32_t minCount = getMinimumCount(mins);
243       if (intCharCounts[ASCII_ENCODATION] < intCharCounts[BASE256_ENCODATION] &&
244           intCharCounts[ASCII_ENCODATION] < intCharCounts[C40_ENCODATION] &&
245           intCharCounts[ASCII_ENCODATION] < intCharCounts[TEXT_ENCODATION] &&
246           intCharCounts[ASCII_ENCODATION] < intCharCounts[X12_ENCODATION] &&
247           intCharCounts[ASCII_ENCODATION] < intCharCounts[EDIFACT_ENCODATION]) {
248         return ASCII_ENCODATION;
249       }
250       if (intCharCounts[BASE256_ENCODATION] < intCharCounts[ASCII_ENCODATION] ||
251           (mins[C40_ENCODATION] + mins[TEXT_ENCODATION] + mins[X12_ENCODATION] +
252            mins[EDIFACT_ENCODATION]) == 0) {
253         return BASE256_ENCODATION;
254       }
255       if (minCount == 1 && mins[EDIFACT_ENCODATION] > 0) {
256         return EDIFACT_ENCODATION;
257       }
258       if (minCount == 1 && mins[TEXT_ENCODATION] > 0) {
259         return TEXT_ENCODATION;
260       }
261       if (minCount == 1 && mins[X12_ENCODATION] > 0) {
262         return X12_ENCODATION;
263       }
264       if (intCharCounts[C40_ENCODATION] + 1 < intCharCounts[ASCII_ENCODATION] &&
265           intCharCounts[C40_ENCODATION] + 1 <
266               intCharCounts[BASE256_ENCODATION] &&
267           intCharCounts[C40_ENCODATION] + 1 <
268               intCharCounts[EDIFACT_ENCODATION] &&
269           intCharCounts[C40_ENCODATION] + 1 < intCharCounts[TEXT_ENCODATION]) {
270         if (intCharCounts[C40_ENCODATION] < intCharCounts[X12_ENCODATION]) {
271           return C40_ENCODATION;
272         }
273         if (intCharCounts[C40_ENCODATION] == intCharCounts[X12_ENCODATION]) {
274           int32_t p = startpos + charsProcessed + 1;
275           while (p < msg.GetLength()) {
276             FX_WCHAR tc = msg.GetAt(p);
277             if (isX12TermSep(tc)) {
278               return X12_ENCODATION;
279             }
280             if (!isNativeX12(tc)) {
281               break;
282             }
283             p++;
284           }
285           return C40_ENCODATION;
286         }
287       }
288     }
289   }
290 }
isDigit(FX_WCHAR ch)291 FX_BOOL CBC_HighLevelEncoder::isDigit(FX_WCHAR ch) {
292   return ch >= '0' && ch <= '9';
293 }
isExtendedASCII(FX_WCHAR ch)294 FX_BOOL CBC_HighLevelEncoder::isExtendedASCII(FX_WCHAR ch) {
295   return ch >= 128 && ch <= 255;
296 }
determineConsecutiveDigitCount(CFX_WideString msg,int32_t startpos)297 int32_t CBC_HighLevelEncoder::determineConsecutiveDigitCount(CFX_WideString msg,
298                                                              int32_t startpos) {
299   int32_t count = 0;
300   int32_t len = msg.GetLength();
301   int32_t idx = startpos;
302   if (idx < len) {
303     FX_WCHAR ch = msg.GetAt(idx);
304     while (isDigit(ch) && idx < len) {
305       count++;
306       idx++;
307       if (idx < len) {
308         ch = msg.GetAt(idx);
309       }
310     }
311   }
312   return count;
313 }
illegalCharacter(FX_WCHAR c,int32_t & e)314 void CBC_HighLevelEncoder::illegalCharacter(FX_WCHAR c, int32_t& e) {
315   e = BCExceptionIllegalArgument;
316 }
randomize253State(FX_WCHAR ch,int32_t codewordPosition)317 FX_WCHAR CBC_HighLevelEncoder::randomize253State(FX_WCHAR ch,
318                                                  int32_t codewordPosition) {
319   int32_t pseudoRandom = ((149 * codewordPosition) % 253) + 1;
320   int32_t tempVariable = ch + pseudoRandom;
321   return tempVariable <= 254 ? (FX_WCHAR)tempVariable
322                              : (FX_WCHAR)(tempVariable - 254);
323 }
findMinimums(CFX_FloatArray & charCounts,CFX_Int32Array & intCharCounts,int32_t min,CFX_ByteArray & mins)324 int32_t CBC_HighLevelEncoder::findMinimums(CFX_FloatArray& charCounts,
325                                            CFX_Int32Array& intCharCounts,
326                                            int32_t min,
327                                            CFX_ByteArray& mins) {
328   for (int32_t l = 0; l < mins.GetSize(); l++) {
329     mins[l] = (uint8_t)0;
330   }
331   for (int32_t i = 0; i < 6; i++) {
332     intCharCounts[i] = (int32_t)ceil(charCounts[i]);
333     int32_t current = intCharCounts[i];
334     if (min > current) {
335       min = current;
336       for (int32_t j = 0; j < mins.GetSize(); j++) {
337         mins[j] = (uint8_t)0;
338       }
339     }
340     if (min == current) {
341       mins[i]++;
342     }
343   }
344   return min;
345 }
getMinimumCount(CFX_ByteArray & mins)346 int32_t CBC_HighLevelEncoder::getMinimumCount(CFX_ByteArray& mins) {
347   int32_t minCount = 0;
348   for (int32_t i = 0; i < 6; i++) {
349     minCount += mins[i];
350   }
351   return minCount;
352 }
isNativeC40(FX_WCHAR ch)353 FX_BOOL CBC_HighLevelEncoder::isNativeC40(FX_WCHAR ch) {
354   return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z');
355 }
isNativeText(FX_WCHAR ch)356 FX_BOOL CBC_HighLevelEncoder::isNativeText(FX_WCHAR ch) {
357   return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z');
358 }
isNativeX12(FX_WCHAR ch)359 FX_BOOL CBC_HighLevelEncoder::isNativeX12(FX_WCHAR ch) {
360   return isX12TermSep(ch) || (ch == ' ') || (ch >= '0' && ch <= '9') ||
361          (ch >= 'A' && ch <= 'Z');
362 }
isX12TermSep(FX_WCHAR ch)363 FX_BOOL CBC_HighLevelEncoder::isX12TermSep(FX_WCHAR ch) {
364   return (ch == '\r') || (ch == '*') || (ch == '>');
365 }
isNativeEDIFACT(FX_WCHAR ch)366 FX_BOOL CBC_HighLevelEncoder::isNativeEDIFACT(FX_WCHAR ch) {
367   return ch >= ' ' && ch <= '^';
368 }
isSpecialB256(FX_WCHAR ch)369 FX_BOOL CBC_HighLevelEncoder::isSpecialB256(FX_WCHAR ch) {
370   return FALSE;
371 }
372