Fix Mac OS X string conversion (re-use 5.5 branch version) to make macros (de)seraliz...
[scilab.git] / scilab / modules / localization / src / c / charEncoding.c
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2008 - Yung-Jang Lee
4 * Copyright (C) 2009 - DIGITEO - Antoine ELIAS , Allan CORNET
5 *
6 * This file must be used under the terms of the CeCILL.
7 * This source file is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution.  The terms
9 * are also available at
10 * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
11 *
12 */
13 /*--------------------------------------------------------------------------*/
14 #ifndef _MSC_VER
15 #include <iconv.h>
16 #include <errno.h>
17 #endif
18
19 #include <wchar.h>
20 #include <wctype.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <locale.h>
25
26 #include "charEncoding.h"
27 #include "sci_malloc.h"
28 /*--------------------------------------------------------------------------*/
29 #ifdef _MSC_VER
30 #include <Windows.h>
31
32 char *wide_string_to_UTF8(const wchar_t *_wide)
33 {
34     char *buf = NULL;
35     DWORD size = 0;
36     DWORD dwFlags = 0;
37
38     if ((wchar_t *)NULL == _wide)
39     {
40         return (char *)NULL;
41     }
42     size = WideCharToMultiByte(CP_UTF8, dwFlags, _wide, -1, NULL, 0, NULL, 0);
43     if (size == 0)
44     {
45         return (char *)NULL;
46     }
47     buf = (char*)MALLOC(sizeof(char) * size);
48     if (buf)
49     {
50         WideCharToMultiByte(CP_UTF8, dwFlags, _wide, -1, buf, size, NULL, 0);
51         if (size <= 0)
52         {
53             FREE(buf);
54             return (char *)NULL;
55         }
56     }
57
58     buf[size - 1] = '\0';
59     return buf;
60 }
61 /*--------------------------------------------------------------------------*/
62 wchar_t *to_wide_string(const char *_UTFStr)
63 {
64     int nwide = 0;
65     wchar_t *_buf = NULL;
66     DWORD dwFlags = 0;
67     UINT codePage = CP_ACP;
68
69     if (_UTFStr == NULL)
70     {
71         return NULL;
72     }
73
74     if (IsValidUTF8(_UTFStr))
75     {
76         codePage = CP_UTF8;
77     }
78
79     nwide = MultiByteToWideChar(codePage, dwFlags, _UTFStr, -1, NULL, 0);
80     if (nwide == 0)
81     {
82         return NULL;
83     }
84
85     _buf = (wchar_t *)MALLOC(nwide * sizeof(wchar_t));
86     if (_buf == NULL)
87     {
88         return NULL;
89     }
90
91     if (MultiByteToWideChar(codePage, dwFlags, _UTFStr, -1, _buf, nwide) == 0)
92     {
93         FREE(_buf);
94         _buf = NULL;
95     }
96
97     _buf[nwide - 1] = L'\0';
98     return _buf;
99 }
100 /*--------------------------------------------------------------------------*/
101 int wcstat(char* filename, struct _stat *st)
102 {
103     int stat_result = 0;
104     wchar_t *wfilename = to_wide_string(filename);
105     stat_result = _wstat(wfilename, st);
106     FREE(wfilename);
107     return stat_result;
108 }
109 /*--------------------------------------------------------------------------*/
110 #else
111 /*--------------------------------------------------------------------------*/
112 #ifdef __APPLE__ // Mac OS X
113 /*--------------------------------------------------------------------------*/
114 char *wide_string_to_UTF8(const wchar_t *_wide)
115 {
116     size_t iCharLen = 0;
117     wchar_t *pwstr = _wide;
118     char* pchar = NULL;
119     /* The value of MB_CUR_MAX is the maximum number of bytes
120     in a multibyte character for the current locale. */
121     int iMaxLen =  0;
122
123     if (_wide == NULL)
124     {
125         return NULL;
126     }
127
128     iMaxLen =  (int)wcslen(_wide) * MB_CUR_MAX ;
129
130     pchar = (char*) MALLOC(( iMaxLen + 1) * sizeof(char));
131     if (pchar == NULL)
132     {
133         return NULL;
134     }
135     iCharLen = wcstombs (pchar, pwstr, iMaxLen);
136     if ( iCharLen == (size_t)(-1) )
137     {
138         if (pchar)
139         {
140             FREE(pchar);
141             pchar = NULL;
142         }
143         return NULL;
144     }
145     pchar[iCharLen] = '\0';
146     return pchar;
147 }
148 /*--------------------------------------------------------------------------*/
149 wchar_t *to_wide_string(const char *_UTFStr)
150 {
151     wchar_t *_buf = NULL;
152     size_t pszLen = 0;
153     char *psz = _UTFStr;
154     mbstate_t ps;
155
156     if (_UTFStr == NULL)
157     {
158         return NULL;
159     }
160
161     memset (&ps, 0x00, sizeof(ps));
162     pszLen = mbsrtowcs(NULL, (const char**)&psz, 0, &ps);
163
164     if ( pszLen == (size_t)(-1) )
165     {
166         return NULL;
167     }
168
169     _buf = (wchar_t*)MALLOC((pszLen + 1) * sizeof(wchar_t));
170     if (_buf == NULL)
171     {
172         return NULL;
173     }
174
175     pszLen = mbsrtowcs(_buf, (const char**)&psz, (int)strlen(psz), &ps);
176
177     if ( pszLen == (size_t)(-1) )
178     {
179         FREE(_buf);
180         return NULL;
181     }
182     else
183     {
184         _buf[pszLen] = L'\0';
185     }
186     return _buf;
187 }
188 /*--------------------------------------------------------------------------*/
189 #else // Linux
190 /*--------------------------------------------------------------------------*/
191 char *wide_string_to_UTF8(const wchar_t *_wide)
192 {
193     char* pOutSave = NULL;
194     wchar_t* pSaveIn = NULL;
195     size_t iSize = 0;
196     size_t iLeftIn = 0;
197     size_t iLeftOut = 0;
198     char* pOut = NULL;
199     iconv_t cd_UTF16_to_UTF8 = iconv_open("UTF-8", "WCHAR_T");
200
201     if (_wide == NULL)
202     {
203         return NULL;
204     }
205
206     pSaveIn = (wchar_t*)_wide;
207     iLeftIn = wcslen(_wide) * sizeof(wchar_t);
208
209     iLeftOut = iLeftIn + (1 * sizeof(wchar_t));
210     pOut = (char*)MALLOC(iLeftOut);
211     memset(pOut, 0x00, iLeftOut);
212     pOutSave = pOut;
213
214     iSize = iconv(cd_UTF16_to_UTF8, (char**)&pSaveIn, &iLeftIn, &pOut, &iLeftOut);
215     iconv_close(cd_UTF16_to_UTF8);
216     if (iSize == (size_t)(-1))
217     {
218         return NULL;
219     }
220
221     return pOutSave;
222 }
223 /*--------------------------------------------------------------------------*/
224 wchar_t *to_wide_string(const char *_UTFStr)
225 {
226     wchar_t* pOutSave = NULL;
227     char* pInSave = NULL;
228     size_t iSize = 0;
229     size_t iLeftIn = 0;
230     size_t iLeftOut = 0;
231
232     wchar_t* pOut = NULL;
233
234     iconv_t cd_UTF8_to_UTF16 = iconv_open("WCHAR_T", "UTF-8");
235
236     if (_UTFStr == NULL)
237     {
238         return NULL;
239     }
240
241     iLeftIn = strlen(_UTFStr);
242     pInSave = (char*)_UTFStr;
243
244     iLeftOut = (iLeftIn + 1) * sizeof(wchar_t);
245     pOut = (wchar_t*)MALLOC(iLeftOut);
246     memset(pOut, 0x00, iLeftOut);
247     pOutSave = pOut;
248
249     iSize = iconv(cd_UTF8_to_UTF16, (char**)&_UTFStr, &iLeftIn, (char**)&pOut, &iLeftOut);
250     iconv_close(cd_UTF8_to_UTF16);
251     if (iSize == (size_t)(-1))
252     {
253         iconv_t cd_ISO8851_to_UTF16 = iconv_open("WCHAR_T", "ISO_8859-1");
254
255         _UTFStr = pInSave;
256         iLeftIn = strlen(_UTFStr);
257
258         iLeftOut = (iLeftIn + 1) * sizeof(wchar_t);
259         pOut = pOutSave;
260         memset(pOut, 0x00, iLeftOut);
261
262
263         iSize = iconv(cd_ISO8851_to_UTF16, (char**)&_UTFStr, &iLeftIn, (char**)&pOut, &iLeftOut);
264         iconv_close(cd_ISO8851_to_UTF16);
265         if (iSize == (size_t)(-1))
266         {
267             return NULL;
268         }
269     }
270
271     return pOutSave;
272 }
273 /*--------------------------------------------------------------------------*/
274 #endif
275 /*--------------------------------------------------------------------------*/
276 int wcstat(char* filename, struct stat *st)
277 {
278     return stat(filename, st);
279 }
280 /*--------------------------------------------------------------------------*/
281 #endif
282 /*--------------------------------------------------------------------------*/
283 static int ReadUTF8Character(const char* str, int *nBytes)
284 {
285     const unsigned char* s = (const unsigned char*)(str);
286     unsigned char c = s[0];
287
288     if (c < 0x80)
289     {
290         *nBytes = 1;
291         return c;
292     }
293     else if (c < 0xC2)
294     {
295         return -1;
296     }
297     else if (c < 0xE0)
298     {
299         if (s[1] == 0 || (s[1] ^ 0x80) >= 0x40)
300         {
301             return -1;
302         }
303         *nBytes = 2;
304         return ((s[0] & 0x1F) << 6) + (s[1] ^ 0x80);
305     }
306     else if (c < 0xF0)
307     {
308         if (s[1] == 0 || s[2] == 0 || (s[1] ^ 0x80) >= 0x40
309                 || (s[2] ^ 0x80) >= 0x40 || (c == 0xE0 && s[1] < 0xA0))
310         {
311             return -1;
312         }
313         *nBytes = 3;
314         return ((s[0] & 0xF) << 12) + ((s[1] ^ 0x80) << 6) + (s[2] ^ 0x80);
315     }
316     else if (c < 0xF5)
317     {
318         if (s[1] == 0 || s[2] == 0 || s[3] == 0 || (s[1] ^ 0x80) >= 0x40
319                 || (s[2] ^ 0x80) >= 0x40 || (s[3] ^ 0x80) >= 0x40
320                 || (c == 0xF0 && s[1] < 0x90) || (c == 0xF4 && s[1] > 0x8F))
321         {
322             return -1;
323         }
324         *nBytes = 4;
325         return ((s[0] & 0x07) << 18) + ((s[1] ^ 0x80) << 12) + ((s[2] ^ 0x80) << 6)
326                + (s[3] ^ 0x80);
327     }
328     else
329     {
330         return -1;
331     }
332 }
333 /*--------------------------------------------------------------------------*/
334 BOOL IsValidUTF8(const char*  pStText)
335 {
336     const char* s =  pStText;
337     while (*s != 0)
338     {
339         int nBytes = 0;
340         if (ReadUTF8Character(s, &nBytes) < 0)
341         {
342             return FALSE;
343         }
344         s += nBytes;
345     }
346
347     return TRUE;
348 }
349 /*--------------------------------------------------------------------------*/