Merge to XFA: Use stdint.h types throughout PDFium.
[pdfium.git] / xfa / src / fxbarcode / datamatrix / 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 // Original code is licensed as follows:\r
7 /*\r
8  * Copyright 2006-2007 Jeremias Maerki.\r
9  *\r
10  * Licensed under the Apache License, Version 2.0 (the "License");\r
11  * you may not use this file except in compliance with the License.\r
12  * You may obtain a copy of the License at\r
13  *\r
14  *      http://www.apache.org/licenses/LICENSE-2.0\r
15  *\r
16  * Unless required by applicable law or agreed to in writing, software\r
17  * distributed under the License is distributed on an "AS IS" BASIS,\r
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
19  * See the License for the specific language governing permissions and\r
20  * limitations under the License.\r
21  */\r
22 \r
23 #include "../barcode.h"\r
24 #include "../BC_Dimension.h"\r
25 #include "../common/BC_CommonBitMatrix.h"\r
26 #include "BC_Encoder.h"\r
27 #include "BC_SymbolShapeHint.h"\r
28 #include "BC_SymbolInfo.h"\r
29 #include "BC_EncoderContext.h"\r
30 #include "BC_HighLevelEncoder.h"\r
31 #include "BC_C40Encoder.h"\r
32 CBC_C40Encoder::CBC_C40Encoder()\r
33 {\r
34 }\r
35 CBC_C40Encoder::~CBC_C40Encoder()\r
36 {\r
37 }\r
38 int32_t CBC_C40Encoder::getEncodingMode()\r
39 {\r
40     return C40_ENCODATION;\r
41 }\r
42 void CBC_C40Encoder::Encode(CBC_EncoderContext &context, int32_t &e)\r
43 {\r
44     CFX_WideString buffer;\r
45     while (context.hasMoreCharacters()) {\r
46         FX_WCHAR c = context.getCurrentChar();\r
47         context.m_pos++;\r
48         int32_t lastCharSize = encodeChar(c, buffer, e);\r
49         if (e != BCExceptionNO) {\r
50             return;\r
51         }\r
52         int32_t unwritten = (buffer.GetLength() / 3) * 2;\r
53         int32_t curCodewordCount = context.getCodewordCount() + unwritten;\r
54         context.updateSymbolInfo(curCodewordCount, e);\r
55         if (e != BCExceptionNO) {\r
56             return;\r
57         }\r
58         int32_t available = context.m_symbolInfo->m_dataCapacity - curCodewordCount;\r
59         if (!context.hasMoreCharacters()) {\r
60             CFX_WideString removed;\r
61             if ((buffer.GetLength() % 3) == 2) {\r
62                 if (available < 2 || available > 2) {\r
63                     lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize, e);\r
64                     if (e != BCExceptionNO) {\r
65                         return;\r
66                     }\r
67                 }\r
68             }\r
69             while ((buffer.GetLength() % 3) == 1\r
70                     && ((lastCharSize <= 3 && available != 1) || lastCharSize > 3)) {\r
71                 lastCharSize = backtrackOneCharacter(context, buffer, removed, lastCharSize, e);\r
72                 if (e != BCExceptionNO) {\r
73                     return;\r
74                 }\r
75             }\r
76             break;\r
77         }\r
78         int32_t count = buffer.GetLength();\r
79         if ((count % 3) == 0) {\r
80             int32_t newMode = CBC_HighLevelEncoder::lookAheadTest(context.m_msg, context.m_pos, getEncodingMode());\r
81             if (newMode != getEncodingMode()) {\r
82                 context.signalEncoderChange(newMode);\r
83                 break;\r
84             }\r
85         }\r
86     }\r
87     handleEOD(context, buffer, e);\r
88 }\r
89 void CBC_C40Encoder::writeNextTriplet(CBC_EncoderContext &context, CFX_WideString &buffer)\r
90 {\r
91     context.writeCodewords(encodeToCodewords(buffer, 0));\r
92     buffer.Delete(0, 3);\r
93 }\r
94 void CBC_C40Encoder::handleEOD(CBC_EncoderContext &context, CFX_WideString &buffer, int32_t &e)\r
95 {\r
96     int32_t unwritten = (buffer.GetLength() / 3) * 2;\r
97     int32_t rest = buffer.GetLength() % 3;\r
98     int32_t curCodewordCount = context.getCodewordCount() + unwritten;\r
99     context.updateSymbolInfo(curCodewordCount, e);\r
100     if (e != BCExceptionNO) {\r
101         return;\r
102     }\r
103     int32_t available = context.m_symbolInfo->m_dataCapacity - curCodewordCount;\r
104     if (rest == 2) {\r
105         buffer += (FX_WCHAR)'\0';\r
106         while (buffer.GetLength() >= 3) {\r
107             writeNextTriplet(context, buffer);\r
108         }\r
109         if (context.hasMoreCharacters()) {\r
110             context.writeCodeword(CBC_HighLevelEncoder::C40_UNLATCH);\r
111         }\r
112     } else if (available == 1 && rest == 1) {\r
113         while (buffer.GetLength() >= 3) {\r
114             writeNextTriplet(context, buffer);\r
115         }\r
116         if (context.hasMoreCharacters()) {\r
117             context.writeCodeword(CBC_HighLevelEncoder::C40_UNLATCH);\r
118         }\r
119         context.m_pos--;\r
120     } else if (rest == 0) {\r
121         while (buffer.GetLength() >= 3) {\r
122             writeNextTriplet(context, buffer);\r
123         }\r
124         if (available > 0 || context.hasMoreCharacters()) {\r
125             context.writeCodeword(CBC_HighLevelEncoder::C40_UNLATCH);\r
126         }\r
127     } else {\r
128         e = BCExceptionIllegalStateUnexpectedCase;\r
129         return;\r
130     }\r
131     context.signalEncoderChange(ASCII_ENCODATION);\r
132 }\r
133 int32_t CBC_C40Encoder::encodeChar(FX_WCHAR c, CFX_WideString &sb, int32_t &e)\r
134 {\r
135     if (c == ' ') {\r
136         sb += (FX_WCHAR)'\3';\r
137         return 1;\r
138     } else if ((c >= '0') && (c <= '9')) {\r
139         sb += (FX_WCHAR)(c - 48 + 4);\r
140         return 1;\r
141     } else if ((c >= 'A') && (c <= 'Z')) {\r
142         sb += (FX_WCHAR)(c - 65 + 14);\r
143         return 1;\r
144     } else if ((c >= '\0') && (c <= 0x1f)) {\r
145         sb += (FX_WCHAR)'\0';\r
146         sb += c;\r
147         return 2;\r
148     } else if ((c >= '!') && (c <= '/')) {\r
149         sb += (FX_WCHAR)'\1';\r
150         sb += (FX_WCHAR)(c - 33);\r
151         return 2;\r
152     } else if ((c >= ':') && (c <= '@')) {\r
153         sb += (FX_WCHAR)'\1';\r
154         sb += (FX_WCHAR)(c - 58 + 15);\r
155         return 2;\r
156     } else if ((c >= '[') && (c <= '_')) {\r
157         sb += (FX_WCHAR)'\1';\r
158         sb += (FX_WCHAR)(c - 91 + 22);\r
159         return 2;\r
160     } else if ((c >= 60) && (c <= 0x7f)) {\r
161         sb += (FX_WCHAR)'\2';\r
162         sb += (FX_WCHAR)(c - 96);\r
163         return 2;\r
164     } else if (c >= 80) {\r
165         sb += (FX_WCHAR)'\1';\r
166         sb += (FX_WCHAR)0x001e;\r
167         int32_t len = 2;\r
168         len += encodeChar((c - 128), sb, e);\r
169         BC_EXCEPTION_CHECK_ReturnValue(e,  0);\r
170         return len;\r
171     } else {\r
172         e = BCExceptionIllegalArgument;\r
173         return 0;\r
174     }\r
175 }\r
176 int32_t CBC_C40Encoder::backtrackOneCharacter(CBC_EncoderContext &context, CFX_WideString &buffer, CFX_WideString &removed, int32_t lastCharSize, int32_t &e)\r
177 {\r
178     int32_t count = buffer.GetLength();\r
179     buffer.Delete(count - lastCharSize, count);\r
180     context.m_pos--;\r
181     FX_WCHAR c = context.getCurrentChar();\r
182     lastCharSize = encodeChar(c, removed, e);\r
183     BC_EXCEPTION_CHECK_ReturnValue(e,  -1);\r
184     context.resetSymbolInfo();\r
185     return lastCharSize;\r
186 }\r
187 CFX_WideString CBC_C40Encoder::encodeToCodewords(CFX_WideString sb, int32_t startPos)\r
188 {\r
189     FX_WCHAR c1 = sb.GetAt(startPos);\r
190     FX_WCHAR c2 = sb.GetAt(startPos + 1);\r
191     FX_WCHAR c3 = sb.GetAt(startPos + 2);\r
192     int32_t v = (1600 * c1) + (40 * c2) + c3 + 1;\r
193     FX_WCHAR cw1 = (FX_WCHAR) (v / 256);\r
194     FX_WCHAR cw2 = (FX_WCHAR) (v % 256);\r
195     CFX_WideString b1(cw1);\r
196     CFX_WideString b2(cw2);\r
197     return b1 + b2;\r
198 }\r