Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / xfa / src / fxbarcode / src / BC_C40Encoder.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_Dimension.h"\r
10 #include "include/BC_CommonBitMatrix.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_HighLevelEncoder.h"\r
15 #include "include/BC_C40Encoder.h"\r
16 CBC_C40Encoder::CBC_C40Encoder()\r
17 {\r
18 }\r
19 CBC_C40Encoder::~CBC_C40Encoder()\r
20 {\r
21 }\r
22 FX_INT32 CBC_C40Encoder::getEncodingMode()\r
23 {\r
24     return C40_ENCODATION;\r
25 }\r
26 void CBC_C40Encoder::Encode(CBC_EncoderContext &context, FX_INT32 &e)\r
27 {\r
28     CFX_WideString buffer;\r
29     while (context.hasMoreCharacters()) {\r
30         FX_WCHAR c = context.getCurrentChar();\r
31         context.m_pos++;\r
32         FX_INT32 lastCharSize = encodeChar(c, buffer, e);\r
33         if (e != BCExceptionNO) {\r
34             return;\r
35         }\r
36         FX_INT32 unwritten = (buffer.GetLength() / 3) * 2;\r
37         FX_INT32 curCodewordCount = context.getCodewordCount() + unwritten;\r
38         context.updateSymbolInfo(curCodewordCount, e);\r
39         if (e != BCExceptionNO) {\r
40             return;\r
41         }\r
42         FX_INT32 available = context.m_symbolInfo->m_dataCapacity - curCodewordCount;\r
43         if (!context.hasMoreCharacters()) {\r
44             CFX_WideString removed;\r
45             if ((buffer.GetLength() % 3) == 2) {\r
46                 if (available < 2 || available > 2) {\r
47                     lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize, e);\r
48                     if (e != BCExceptionNO) {\r
49                         return;\r
50                     }\r
51                 }\r
52             }\r
53             while ((buffer.GetLength() % 3) == 1\r
54                     && ((lastCharSize <= 3 && available != 1) || lastCharSize > 3)) {\r
55                 lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize, e);\r
56                 if (e != BCExceptionNO) {\r
57                     return;\r
58                 }\r
59             }\r
60             break;\r
61         }\r
62         FX_INT32 count = buffer.GetLength();\r
63         if ((count % 3) == 0) {\r
64             FX_INT32 newMode = CBC_HighLevelEncoder::lookAheadTest(context.m_msg, context.m_pos, getEncodingMode());\r
65             if (newMode != getEncodingMode()) {\r
66                 context.signalEncoderChange(newMode);\r
67                 break;\r
68             }\r
69         }\r
70     }\r
71     handleEOD(context, buffer, e);\r
72 }\r
73 void CBC_C40Encoder::writeNextTriplet(CBC_EncoderContext &context, CFX_WideString &buffer)\r
74 {\r
75     context.writeCodewords(encodeToCodewords(buffer, 0));\r
76     buffer.Delete(0, 3);\r
77 }\r
78 void CBC_C40Encoder::handleEOD(CBC_EncoderContext &context, CFX_WideString &buffer, FX_INT32 &e)\r
79 {\r
80     FX_INT32 unwritten = (buffer.GetLength() / 3) * 2;\r
81     FX_INT32 rest = buffer.GetLength() % 3;\r
82     FX_INT32 curCodewordCount = context.getCodewordCount() + unwritten;\r
83     context.updateSymbolInfo(curCodewordCount, e);\r
84     if (e != BCExceptionNO) {\r
85         return;\r
86     }\r
87     FX_INT32 available = context.m_symbolInfo->m_dataCapacity - curCodewordCount;\r
88     if (rest == 2) {\r
89         buffer += (FX_WCHAR)'\0';\r
90         while (buffer.GetLength() >= 3) {\r
91             writeNextTriplet(context, buffer);\r
92         }\r
93         if (context.hasMoreCharacters()) {\r
94             context.writeCodeword(CBC_HighLevelEncoder::C40_UNLATCH);\r
95         }\r
96     } else if (available == 1 && rest == 1) {\r
97         while (buffer.GetLength() >= 3) {\r
98             writeNextTriplet(context, buffer);\r
99         }\r
100         if (context.hasMoreCharacters()) {\r
101             context.writeCodeword(CBC_HighLevelEncoder::C40_UNLATCH);\r
102         }\r
103         context.m_pos--;\r
104     } else if (rest == 0) {\r
105         while (buffer.GetLength() >= 3) {\r
106             writeNextTriplet(context, buffer);\r
107         }\r
108         if (available > 0 || context.hasMoreCharacters()) {\r
109             context.writeCodeword(CBC_HighLevelEncoder::C40_UNLATCH);\r
110         }\r
111     } else {\r
112         e = BCExceptionIllegalStateUnexpectedCase;\r
113         return;\r
114     }\r
115     context.signalEncoderChange(ASCII_ENCODATION);\r
116 }\r
117 FX_INT32 CBC_C40Encoder::encodeChar(FX_WCHAR c, CFX_WideString &sb, FX_INT32 &e)\r
118 {\r
119     if (c == ' ') {\r
120         sb += (FX_WCHAR)'\3';\r
121         return 1;\r
122     } else if ((c >= '0') && (c <= '9')) {\r
123         sb += (FX_WCHAR)(c - 48 + 4);\r
124         return 1;\r
125     } else if ((c >= 'A') && (c <= 'Z')) {\r
126         sb += (FX_WCHAR)(c - 65 + 14);\r
127         return 1;\r
128     } else if ((c >= '\0') && (c <= 0x1f)) {\r
129         sb += (FX_WCHAR)'\0';\r
130         sb += c;\r
131         return 2;\r
132     } else if ((c >= '!') && (c <= '/')) {\r
133         sb += (FX_WCHAR)'\1';\r
134         sb += (FX_WCHAR)(c - 33);\r
135         return 2;\r
136     } else if ((c >= ':') && (c <= '@')) {\r
137         sb += (FX_WCHAR)'\1';\r
138         sb += (FX_WCHAR)(c - 58 + 15);\r
139         return 2;\r
140     } else if ((c >= '[') && (c <= '_')) {\r
141         sb += (FX_WCHAR)'\1';\r
142         sb += (FX_WCHAR)(c - 91 + 22);\r
143         return 2;\r
144     } else if ((c >= 60) && (c <= 0x7f)) {\r
145         sb += (FX_WCHAR)'\2';\r
146         sb += (FX_WCHAR)(c - 96);\r
147         return 2;\r
148     } else if (c >= 80) {\r
149         sb += (FX_WCHAR)'\1';\r
150         sb += (FX_WCHAR)0x001e;\r
151         FX_INT32 len = 2;\r
152         len += encodeChar((c - 128), sb, e);\r
153         BC_EXCEPTION_CHECK_ReturnValue(e,  0);\r
154         return len;\r
155     } else {\r
156         e = BCExceptionIllegalArgument;\r
157         return 0;\r
158     }\r
159 }\r
160 FX_INT32 CBC_C40Encoder::backtrackOneCharacter(CBC_EncoderContext &context, CFX_WideString &buffer, CFX_WideString &removed, FX_INT32 lastCharSize, FX_INT32 &e)\r
161 {\r
162     FX_INT32 count = buffer.GetLength();\r
163     buffer.Delete(count - lastCharSize, count);\r
164     context.m_pos--;\r
165     FX_WCHAR c = context.getCurrentChar();\r
166     lastCharSize = encodeChar(c, removed, e);\r
167     BC_EXCEPTION_CHECK_ReturnValue(e,  -1);\r
168     context.resetSymbolInfo();\r
169     return lastCharSize;\r
170 }\r
171 CFX_WideString CBC_C40Encoder::encodeToCodewords(CFX_WideString sb, FX_INT32 startPos)\r
172 {\r
173     FX_WCHAR c1 = sb.GetAt(startPos);\r
174     FX_WCHAR c2 = sb.GetAt(startPos + 1);\r
175     FX_WCHAR c3 = sb.GetAt(startPos + 2);\r
176     FX_INT32 v = (1600 * c1) + (40 * c2) + c3 + 1;\r
177     FX_WCHAR cw1 = (FX_WCHAR) (v / 256);\r
178     FX_WCHAR cw2 = (FX_WCHAR) (v % 256);\r
179     CFX_WideString b1(cw1);\r
180     CFX_WideString b2(cw2);\r
181     return b1 + b2;\r
182 }\r