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