00d3d0dff8c542d236ddcd992439b4fbeb0a20e4
[scilab.git] / scilab / modules / localization / src / cpp / UTF8.cpp
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  * Copyright (C) 2015 - Scilab Enterprises - Calixte DENIZET
6  *
7  * This file must be used under the terms of the CeCILL.
8  * This source file is licensed as described in the file COPYING, which
9  * you should have received as part of this distribution.  The terms
10  * are also available at
11  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
12  *
13  */
14
15 #ifndef _MSC_VER
16 #include <iconv.h>
17 #include <errno.h>
18 #endif
19
20 #include <cstdlib>
21
22 #include "UTF8.hxx"
23
24 #ifdef _MSC_VER
25 #include <Windows.h>
26 #endif
27
28 namespace scilab
29 {
30
31 #ifdef _MSC_VER // Windows
32
33 std::string UTF8::toUTF8(const std::wstring & wstr)
34 {
35     char * buf = nullptr;
36     DWORD dwFlags = 0;
37     DWORD size = 0;
38
39     if (wstr.empty())
40     {
41         return std::string();
42     }
43
44     size = WideCharToMultiByte(CP_UTF8, dwFlags, wstr.c_str(), -1, nullptr, 0, nullptr, 0);
45     if (size == 0)
46     {
47         return std::string();
48     }
49
50     buf = new char[size];
51     size = WideCharToMultiByte(CP_UTF8, dwFlags, wstr.c_str(), -1, buf, size, nullptr, 0);
52     if (size <= 0)
53     {
54         delete[] buf;
55         return std::string();
56     }
57
58     std::string str(buf, buf + size);
59     delete[] buf;
60
61     return str;
62 }
63
64 std::wstring UTF8::toWide(const std::string & str)
65 {
66     wchar_t *_buf = NULL;
67     DWORD dwFlags = 0;
68     UINT codePage = CP_ACP;
69
70     if (str.empty())
71     {
72         return std::wstring();
73     }
74
75     if (IsValidUTF8(str.c_str()))
76     {
77         codePage = CP_UTF8;
78     }
79
80     int nwide = MultiByteToWideChar(codePage, dwFlags, str.c_str(), -1, nullptr, 0);
81     if (nwide == 0)
82     {
83         return std::wstring();
84     }
85
86     wchar_t * buf = new wchar_t[nwide];
87     if (MultiByteToWideChar(codePage, dwFlags, str.c_str(), -1, buf, nwide) == 0)
88     {
89         delete[] buf;
90         return std::wstring();
91     }
92
93     std::wstring wstr(buf, buf + nwide);
94     delete[] buf;
95
96     return wstr;
97 }
98
99 #else
100 #ifdef __APPLE__ // Mac OS_X
101
102 std::string UTF8::toUTF8(const std::wstring & wstr)
103 {
104     size_t iCharLen = 0;
105     wchar_t *pwstr = _wide;
106     char* pchar = NULL;
107
108     if (wstr.empty())
109     {
110         return std::string();
111     }
112
113     const int iMaxLen = (int)wstr.size() * MB_CUR_MAX ;
114
115     char * pchar = new char[iMaxLen];
116     size_t iCharLen = wcstombs(pchar, wstr.c_str(), iMaxLen);
117     if (iCharLen == (size_t)(-1) )
118     {
119         delete[] pchar;
120         return std::string();
121     }
122
123     std::string str(pchar, pchar + iMaxLen);
124     delete[] pchar;
125
126     return str;
127 }
128
129 std::wstring UTF8::toWide(const std::string & str)
130 {
131     wchar_t *_buf = NULL;
132
133     if (str.empty())
134     {
135         return std::wstring();
136     }
137
138     mbstate_t ps;
139     memset (&ps, 0x00, sizeof(ps));
140
141     const char * psz = str.c_str();
142     size_t pszLen = mbsrtowcs(nullptr, &psz, 0, &ps);
143
144     if (pszLen == (size_t)(-1))
145     {
146         return std::wstring();
147     }
148
149     wchar_t * buf = new wchar_t[pszLen];
150     pszLen = mbsrtowcs(buf, &psz, str.size(), &ps);
151     if (pszLen == (size_t)(-1))
152     {
153         delete[] buf;
154         return std::wstring();
155     }
156
157     std::wstring wstr(buf, buf + pszLen);
158     delete[] buf;
159
160     return wstr;
161 }
162
163 #else // Linux
164
165 std::string UTF8::toUTF8(const std::wstring & wstr)
166 {
167     if (wstr.empty())
168     {
169         return std::string();
170     }
171
172     char * pIn = (char *)wstr.c_str();
173     size_t iLeftIn = wstr.size() * sizeof(wchar_t);
174     size_t iLeftOut = iLeftIn + sizeof(wchar_t);
175     char * pOut = new char[iLeftOut];
176     char * pOutSave = pOut;
177     iconv_t cd = iconv_open("UTF-8", "WCHAR_T");
178
179     size_t iSize = iconv(cd, &pIn, &iLeftIn, &pOut, &iLeftOut);
180     iconv_close(cd);
181     if (iSize == (size_t)(-1))
182     {
183         delete[] pOutSave;
184         return std::string();
185     }
186
187     std::string str(pOutSave, pOut);
188     delete[] pOutSave;
189
190     return str;
191 }
192
193 std::wstring UTF8::toWide(const std::string & str)
194 {
195     if (str.empty())
196     {
197         return std::wstring();
198     }
199
200     char * pIn = (char *)str.c_str();
201     size_t iLeftIn = str.size();
202     size_t iLeftOut = (iLeftIn + 1) * sizeof(wchar_t);
203     wchar_t * pOut = new wchar_t[iLeftOut];
204     wchar_t * pOutSave = pOut;
205     iconv_t cd = iconv_open("WCHAR_T", "UTF-8");
206
207     size_t iSize = iconv(cd, &pIn, &iLeftIn, (char **)&pOut, &iLeftOut);
208     iconv_close(cd);
209     if (iSize == (size_t)(-1))
210     {
211         cd = iconv_open("WCHAR_T", "ISO_8859-1");
212         pIn = (char *)str.c_str();
213         iLeftIn = str.size();
214         iLeftOut = (iLeftIn + 1) * sizeof(wchar_t);
215         pOut = pOutSave;
216
217         iSize = iconv(cd, &pIn, &iLeftIn, (char **)&pOut, &iLeftOut);
218         iconv_close(cd);
219         if (iSize == (size_t)(-1))
220         {
221             return std::wstring();
222         }
223     }
224
225     std::wstring wstr(pOutSave, pOut);
226     delete[] pOutSave;
227
228     return wstr;
229 }
230
231 #endif
232 #endif
233
234 int UTF8::ReadUTF8Character(const char * str, int * nBytes)
235 {
236     const unsigned char* s = (const unsigned char*)(str);
237     unsigned char c = s[0];
238
239     if (c < 0x80)
240     {
241         *nBytes = 1;
242         return c;
243     }
244     else if (c < 0xC2)
245     {
246         return -1;
247     }
248     else if (c < 0xE0)
249     {
250         if (s[1] == 0 || (s[1] ^ 0x80) >= 0x40)
251         {
252             return -1;
253         }
254         *nBytes = 2;
255         return ((s[0] & 0x1F) << 6) + (s[1] ^ 0x80);
256     }
257     else if (c < 0xF0)
258     {
259         if (s[1] == 0 || s[2] == 0 || (s[1] ^ 0x80) >= 0x40
260                 || (s[2] ^ 0x80) >= 0x40 || (c == 0xE0 && s[1] < 0xA0))
261         {
262             return -1;
263         }
264         *nBytes = 3;
265         return ((s[0] & 0xF) << 12) + ((s[1] ^ 0x80) << 6) + (s[2] ^ 0x80);
266     }
267     else if (c < 0xF5)
268     {
269         if (s[1] == 0 || s[2] == 0 || s[3] == 0 || (s[1] ^ 0x80) >= 0x40
270                 || (s[2] ^ 0x80) >= 0x40 || (s[3] ^ 0x80) >= 0x40
271                 || (c == 0xF0 && s[1] < 0x90) || (c == 0xF4 && s[1] > 0x8F))
272         {
273             return -1;
274         }
275         *nBytes = 4;
276         return ((s[0] & 0x07) << 18) + ((s[1] ^ 0x80) << 12) + ((s[2] ^ 0x80) << 6)
277                + (s[3] ^ 0x80);
278     }
279     else
280     {
281         return -1;
282     }
283 }
284
285 bool UTF8::IsValidUTF8(const char*  pStText)
286 {
287     const char* s = pStText;
288     while (*s != 0)
289     {
290         int nBytes = 0;
291         if (ReadUTF8Character(s, &nBytes) < 0)
292         {
293             return false;
294         }
295         s += nBytes;
296     }
297
298     return true;
299 }
300
301 } // namespace scilab