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