Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include "rtl/textcvt.h"
23 : #include "sal/types.h"
24 :
25 : #include "context.hxx"
26 : #include "converter.hxx"
27 : #include "convertgb18030.hxx"
28 : #include "tenchelp.hxx"
29 : #include "unichars.hxx"
30 :
31 : namespace {
32 :
33 : enum ImplGb18030ToUnicodeState
34 : {
35 : IMPL_GB_18030_TO_UNICODE_STATE_0,
36 : IMPL_GB_18030_TO_UNICODE_STATE_1,
37 : IMPL_GB_18030_TO_UNICODE_STATE_2,
38 : IMPL_GB_18030_TO_UNICODE_STATE_3
39 : };
40 :
41 : struct ImplGb18030ToUnicodeContext
42 : {
43 : ImplGb18030ToUnicodeState m_eState;
44 : sal_uInt32 m_nCode;
45 : };
46 :
47 : }
48 :
49 10 : void * ImplCreateGb18030ToUnicodeContext()
50 : {
51 10 : ImplGb18030ToUnicodeContext * pContext = new ImplGb18030ToUnicodeContext;
52 10 : pContext->m_eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
53 10 : return pContext;
54 : }
55 :
56 0 : void ImplResetGb18030ToUnicodeContext(void * pContext)
57 : {
58 0 : if (pContext)
59 : static_cast< ImplGb18030ToUnicodeContext * >(pContext)->m_eState
60 0 : = IMPL_GB_18030_TO_UNICODE_STATE_0;
61 0 : }
62 :
63 10 : void ImplDestroyGb18030ToUnicodeContext(void * pContext)
64 : {
65 10 : delete static_cast< ImplGb18030ToUnicodeContext * >(pContext);
66 10 : }
67 :
68 404 : sal_Size ImplConvertGb18030ToUnicode(void const * pData,
69 : void * pContext,
70 : char const * pSrcBuf,
71 : sal_Size nSrcBytes,
72 : sal_Unicode * pDestBuf,
73 : sal_Size nDestChars,
74 : sal_uInt32 nFlags,
75 : sal_uInt32 * pInfo,
76 : sal_Size * pSrcCvtBytes)
77 : {
78 : sal_Unicode const * pGb18030Data
79 404 : = static_cast< ImplGb18030ConverterData const * >(pData)->m_pGb18030ToUnicodeData;
80 : ImplGb180302000ToUnicodeRange const * pGb18030Ranges
81 : = static_cast< ImplGb18030ConverterData const * >(pData)->
82 404 : m_pGb18030ToUnicodeRanges;
83 404 : ImplGb18030ToUnicodeState eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
84 404 : sal_uInt32 nCode = 0;
85 404 : sal_uInt32 nInfo = 0;
86 404 : sal_Size nConverted = 0;
87 404 : sal_Unicode * pDestBufPtr = pDestBuf;
88 404 : sal_Unicode * pDestBufEnd = pDestBuf + nDestChars;
89 :
90 404 : if (pContext)
91 : {
92 197 : eState = static_cast< ImplGb18030ToUnicodeContext * >(pContext)->m_eState;
93 197 : nCode = static_cast< ImplGb18030ToUnicodeContext * >(pContext)->m_nCode;
94 : }
95 :
96 1115 : for (; nConverted < nSrcBytes; ++nConverted)
97 : {
98 713 : bool bUndefined = true;
99 713 : sal_uInt32 nChar = *reinterpret_cast<unsigned char const *>(pSrcBuf++);
100 713 : switch (eState)
101 : {
102 : case IMPL_GB_18030_TO_UNICODE_STATE_0:
103 393 : if (nChar < 0x80)
104 21 : if (pDestBufPtr != pDestBufEnd)
105 21 : *pDestBufPtr++ = (sal_Unicode) nChar;
106 : else
107 0 : goto no_output;
108 372 : else if (nChar == 0x80)
109 0 : goto bad_input;
110 372 : else if (nChar <= 0xFE)
111 : {
112 372 : nCode = nChar - 0x81;
113 372 : eState = IMPL_GB_18030_TO_UNICODE_STATE_1;
114 : }
115 : else
116 : {
117 0 : bUndefined = false;
118 0 : goto bad_input;
119 : }
120 393 : break;
121 :
122 : case IMPL_GB_18030_TO_UNICODE_STATE_1:
123 280 : if (nChar >= 0x30 && nChar <= 0x39)
124 : {
125 32 : nCode = nCode * 10 + (nChar - 0x30);
126 32 : eState = IMPL_GB_18030_TO_UNICODE_STATE_2;
127 : }
128 248 : else if ((nChar >= 0x40 && nChar <= 0x7E)
129 104 : || (nChar >= 0x80 && nChar <= 0xFE))
130 : {
131 246 : nCode = nCode * 190 + (nChar <= 0x7E ? nChar - 0x40 :
132 246 : nChar - 0x80 + 63);
133 246 : if (pDestBufPtr != pDestBufEnd)
134 246 : *pDestBufPtr++ = pGb18030Data[nCode];
135 : else
136 0 : goto no_output;
137 246 : eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
138 : }
139 : else
140 : {
141 2 : bUndefined = false;
142 2 : goto bad_input;
143 : }
144 278 : break;
145 :
146 : case IMPL_GB_18030_TO_UNICODE_STATE_2:
147 24 : if (nChar >= 0x81 && nChar <= 0xFE)
148 : {
149 24 : nCode = nCode * 126 + (nChar - 0x81);
150 24 : eState = IMPL_GB_18030_TO_UNICODE_STATE_3;
151 : }
152 : else
153 : {
154 0 : bUndefined = false;
155 0 : goto bad_input;
156 : }
157 24 : break;
158 :
159 : case IMPL_GB_18030_TO_UNICODE_STATE_3:
160 16 : if (nChar >= 0x30 && nChar <= 0x39)
161 : {
162 16 : nCode = nCode * 10 + (nChar - 0x30);
163 :
164 : // 90 30 81 30 to E3 32 9A 35 maps to U+10000 to U+10FFFF:
165 16 : if (nCode >= 189000 && nCode <= 1237575)
166 8 : if (pDestBufEnd - pDestBufPtr >= 2)
167 : {
168 4 : nCode -= 189000 - 0x10000;
169 : *pDestBufPtr++
170 4 : = (sal_Unicode) ImplGetHighSurrogate(nCode);
171 : *pDestBufPtr++
172 4 : = (sal_Unicode) ImplGetLowSurrogate(nCode);
173 : }
174 : else
175 0 : goto no_output;
176 : else
177 : {
178 : ImplGb180302000ToUnicodeRange const * pRange
179 12 : = pGb18030Ranges;
180 12 : sal_uInt32 nFirstNonRange = 0;
181 : for (;;)
182 : {
183 12 : if (pRange->m_nNonRangeDataIndex == -1)
184 0 : goto bad_input;
185 12 : else if (nCode < pRange->m_nFirstLinear)
186 : {
187 6 : if (pDestBufPtr != pDestBufEnd)
188 : *pDestBufPtr++
189 : = pGb18030Data[
190 : pRange->m_nNonRangeDataIndex
191 6 : + (nCode - nFirstNonRange)];
192 : else
193 0 : goto no_output;
194 6 : break;
195 : }
196 6 : else if (nCode < pRange->m_nPastLinear)
197 : {
198 6 : if (pDestBufPtr != pDestBufEnd)
199 : *pDestBufPtr++
200 : = (sal_Unicode)
201 : (pRange->m_nFirstUnicode
202 : + (nCode
203 : - pRange->
204 6 : m_nFirstLinear));
205 : else
206 0 : goto no_output;
207 6 : break;
208 : }
209 0 : nFirstNonRange = (pRange++)->m_nPastLinear;
210 0 : }
211 : }
212 16 : eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
213 : }
214 : else
215 : {
216 0 : bUndefined = false;
217 0 : goto bad_input;
218 : }
219 16 : break;
220 : }
221 711 : continue;
222 :
223 : bad_input:
224 2 : switch (sal::detail::textenc::handleBadInputTextToUnicodeConversion(
225 : bUndefined, true, 0, nFlags, &pDestBufPtr, pDestBufEnd,
226 2 : &nInfo))
227 : {
228 : case sal::detail::textenc::BAD_INPUT_STOP:
229 2 : eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
230 2 : break;
231 :
232 : case sal::detail::textenc::BAD_INPUT_CONTINUE:
233 0 : eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
234 0 : continue;
235 :
236 : case sal::detail::textenc::BAD_INPUT_NO_OUTPUT:
237 0 : goto no_output;
238 : }
239 2 : break;
240 :
241 : no_output:
242 0 : --pSrcBuf;
243 0 : nInfo |= RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
244 0 : break;
245 : }
246 :
247 404 : if (eState != IMPL_GB_18030_TO_UNICODE_STATE_0
248 202 : && (nInfo & (RTL_TEXTTOUNICODE_INFO_ERROR
249 : | RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL))
250 : == 0)
251 : {
252 202 : if ((nFlags & RTL_TEXTTOUNICODE_FLAGS_FLUSH) == 0)
253 202 : nInfo |= RTL_TEXTTOUNICODE_INFO_SRCBUFFERTOSMALL;
254 : else
255 0 : switch (sal::detail::textenc::handleBadInputTextToUnicodeConversion(
256 : false, true, 0, nFlags, &pDestBufPtr, pDestBufEnd,
257 0 : &nInfo))
258 : {
259 : case sal::detail::textenc::BAD_INPUT_STOP:
260 : case sal::detail::textenc::BAD_INPUT_CONTINUE:
261 0 : eState = IMPL_GB_18030_TO_UNICODE_STATE_0;
262 0 : break;
263 :
264 : case sal::detail::textenc::BAD_INPUT_NO_OUTPUT:
265 0 : nInfo |= RTL_TEXTTOUNICODE_INFO_DESTBUFFERTOSMALL;
266 0 : break;
267 : }
268 : }
269 :
270 404 : if (pContext)
271 : {
272 197 : static_cast< ImplGb18030ToUnicodeContext * >(pContext)->m_eState = eState;
273 197 : static_cast< ImplGb18030ToUnicodeContext * >(pContext)->m_nCode = nCode;
274 : }
275 404 : if (pInfo)
276 404 : *pInfo = nInfo;
277 404 : if (pSrcCvtBytes)
278 404 : *pSrcCvtBytes = nConverted;
279 :
280 404 : return pDestBufPtr - pDestBuf;
281 : }
282 :
283 7 : sal_Size ImplConvertUnicodeToGb18030(void const * pData,
284 : void * pContext,
285 : sal_Unicode const * pSrcBuf,
286 : sal_Size nSrcChars,
287 : char * pDestBuf,
288 : sal_Size nDestBytes,
289 : sal_uInt32 nFlags,
290 : sal_uInt32 * pInfo,
291 : sal_Size * pSrcCvtChars)
292 : {
293 : sal_uInt32 const * pGb18030Data
294 : = static_cast< ImplGb18030ConverterData const * >(pData)->
295 7 : m_pUnicodeToGb18030Data;
296 : ImplUnicodeToGb180302000Range const * pGb18030Ranges
297 : = static_cast< ImplGb18030ConverterData const * >(pData)->
298 7 : m_pUnicodeToGb18030Ranges;
299 7 : sal_Unicode nHighSurrogate = 0;
300 7 : sal_uInt32 nInfo = 0;
301 7 : sal_Size nConverted = 0;
302 7 : char * pDestBufPtr = pDestBuf;
303 7 : char * pDestBufEnd = pDestBuf + nDestBytes;
304 :
305 7 : if (pContext)
306 : nHighSurrogate
307 4 : = static_cast<ImplUnicodeToTextContext *>(pContext)->m_nHighSurrogate;
308 :
309 25 : for (; nConverted < nSrcChars; ++nConverted)
310 : {
311 18 : bool bUndefined = true;
312 18 : sal_uInt32 nChar = *pSrcBuf++;
313 18 : if (nHighSurrogate == 0)
314 : {
315 16 : if (ImplIsHighSurrogate(nChar))
316 : {
317 2 : nHighSurrogate = (sal_Unicode) nChar;
318 2 : continue;
319 : }
320 : }
321 2 : else if (ImplIsLowSurrogate(nChar))
322 2 : nChar = ImplCombineSurrogates(nHighSurrogate, nChar);
323 : else
324 : {
325 0 : bUndefined = false;
326 0 : goto bad_input;
327 : }
328 :
329 16 : if (ImplIsLowSurrogate(nChar) || ImplIsNoncharacter(nChar))
330 : {
331 0 : bUndefined = false;
332 0 : goto bad_input;
333 : }
334 :
335 16 : if (nChar < 0x80)
336 8 : if (pDestBufPtr != pDestBufEnd)
337 8 : *pDestBufPtr++ = static_cast< char >(nChar);
338 : else
339 0 : goto no_output;
340 8 : else if (nChar < 0x10000)
341 : {
342 6 : ImplUnicodeToGb180302000Range const * pRange = pGb18030Ranges;
343 6 : sal_Unicode nFirstNonRange = 0x80;
344 : for (;;)
345 : {
346 23 : if (nChar < pRange->m_nFirstUnicode)
347 : {
348 : sal_uInt32 nCode
349 : = pGb18030Data[pRange->m_nNonRangeDataIndex
350 4 : + (nChar - nFirstNonRange)];
351 8 : if (pDestBufEnd - pDestBufPtr
352 4 : >= (nCode <= 0xFFFF ? 2 : 4))
353 : {
354 4 : if (nCode > 0xFFFF)
355 : {
356 2 : *pDestBufPtr++ = static_cast< char >(nCode >> 24);
357 2 : *pDestBufPtr++ = static_cast< char >(nCode >> 16 & 0xFF);
358 : }
359 4 : *pDestBufPtr++ = static_cast< char >(nCode >> 8 & 0xFF);
360 4 : *pDestBufPtr++ = static_cast< char >(nCode & 0xFF);
361 : }
362 : else
363 0 : goto no_output;
364 4 : break;
365 : }
366 19 : else if (nChar <= pRange->m_nLastUnicode)
367 : {
368 2 : if (pDestBufEnd - pDestBufPtr >= 4)
369 : {
370 : sal_uInt32 nCode
371 : = pRange->m_nFirstLinear
372 2 : + (nChar - pRange->m_nFirstUnicode);
373 2 : *pDestBufPtr++ = static_cast< char >(nCode / 12600 + 0x81);
374 : *pDestBufPtr++
375 2 : = static_cast< char >(nCode / 1260 % 10 + 0x30);
376 2 : *pDestBufPtr++ = static_cast< char >(nCode / 10 % 126 + 0x81);
377 2 : *pDestBufPtr++ = static_cast< char >(nCode % 10 + 0x30);
378 : }
379 : else
380 0 : goto no_output;
381 2 : break;
382 : }
383 : nFirstNonRange
384 17 : = (sal_Unicode) ((pRange++)->m_nLastUnicode + 1);
385 17 : }
386 : }
387 : else
388 2 : if (pDestBufEnd - pDestBufPtr >= 4)
389 : {
390 2 : sal_uInt32 nCode = nChar - 0x10000;
391 2 : *pDestBufPtr++ = static_cast< char >(nCode / 12600 + 0x90);
392 2 : *pDestBufPtr++ = static_cast< char >(nCode / 1260 % 10 + 0x30);
393 2 : *pDestBufPtr++ = static_cast< char >(nCode / 10 % 126 + 0x81);
394 2 : *pDestBufPtr++ = static_cast< char >(nCode % 10 + 0x30);
395 : }
396 : else
397 0 : goto no_output;
398 16 : nHighSurrogate = 0;
399 16 : continue;
400 :
401 : bad_input:
402 0 : switch (sal::detail::textenc::handleBadInputUnicodeToTextConversion(
403 : bUndefined, nChar, nFlags, &pDestBufPtr, pDestBufEnd,
404 0 : &nInfo, NULL, 0, NULL))
405 : {
406 : case sal::detail::textenc::BAD_INPUT_STOP:
407 0 : nHighSurrogate = 0;
408 0 : break;
409 :
410 : case sal::detail::textenc::BAD_INPUT_CONTINUE:
411 0 : nHighSurrogate = 0;
412 0 : continue;
413 :
414 : case sal::detail::textenc::BAD_INPUT_NO_OUTPUT:
415 0 : goto no_output;
416 : }
417 0 : break;
418 :
419 : no_output:
420 0 : --pSrcBuf;
421 0 : nInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
422 0 : break;
423 : }
424 :
425 7 : if (nHighSurrogate != 0
426 0 : && (nInfo & (RTL_UNICODETOTEXT_INFO_ERROR
427 : | RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL))
428 : == 0)
429 : {
430 0 : if ((nFlags & RTL_UNICODETOTEXT_FLAGS_FLUSH) != 0)
431 0 : nInfo |= RTL_UNICODETOTEXT_INFO_SRCBUFFERTOSMALL;
432 : else
433 0 : switch (sal::detail::textenc::handleBadInputUnicodeToTextConversion(
434 : false, 0, nFlags, &pDestBufPtr, pDestBufEnd, &nInfo,
435 0 : NULL, 0, NULL))
436 : {
437 : case sal::detail::textenc::BAD_INPUT_STOP:
438 : case sal::detail::textenc::BAD_INPUT_CONTINUE:
439 0 : nHighSurrogate = 0;
440 0 : break;
441 :
442 : case sal::detail::textenc::BAD_INPUT_NO_OUTPUT:
443 0 : nInfo |= RTL_UNICODETOTEXT_INFO_DESTBUFFERTOSMALL;
444 0 : break;
445 : }
446 : }
447 :
448 7 : if (pContext)
449 : static_cast<ImplUnicodeToTextContext *>(pContext)->m_nHighSurrogate
450 4 : = nHighSurrogate;
451 7 : if (pInfo)
452 7 : *pInfo = nInfo;
453 7 : if (pSrcCvtChars)
454 7 : *pSrcCvtChars = nConverted;
455 :
456 7 : return pDestBufPtr - pDestBuf;
457 : }
458 :
459 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|