efc0037cc853a39b8e3befceae680746b6b8fdfd
[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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
8  *
9  * This file is hereby licensed under the terms of the GNU GPL v2.0,
10  * pursuant to article 5.3.4 of the CeCILL v.2.1.
11  * This file was originally licensed under the terms of the CeCILL v2.1,
12  * and continues to be available under such terms.
13  * For more information, see the COPYING file which you should have received
14  * along with this program.
15  *
16  */
17
18 #ifndef _MSC_VER
19 #include <iconv.h>
20 #include <errno.h>
21 #include <string.h>
22 #endif
23
24 #include <cstdlib>
25
26 #include "UTF8.hxx"
27
28 #ifdef _MSC_VER
29 #include <Windows.h>
30 #endif
31
32 namespace scilab
33 {
34
35 #ifdef _MSC_VER // Windows
36
37 std::string UTF8::toUTF8(const std::wstring & wstr)
38 {
39     char * buf = nullptr;
40     DWORD dwFlags = 0;
41     DWORD size = 0;
42
43     if (wstr.empty())
44     {
45         return std::string();
46     }
47
48     size = WideCharToMultiByte(CP_UTF8, dwFlags, wstr.c_str(), (int)wstr.size(), nullptr, 0, nullptr, 0);
49     if (size == 0)
50     {
51         return std::string();
52     }
53
54     buf = new char[size];
55     size = WideCharToMultiByte(CP_UTF8, dwFlags, wstr.c_str(), (int)wstr.size(), buf, size, nullptr, 0);
56     if (size <= 0)
57     {
58         delete[] buf;
59         return std::string();
60     }
61
62     std::string str(buf, buf + size);
63     delete[] buf;
64
65     return str;
66 }
67
68 std::wstring UTF8::toWide(const std::string & str)
69 {
70     wchar_t *_buf = NULL;
71     DWORD dwFlags = 0;
72     UINT codePage = CP_ACP;
73
74     if (str.empty())
75     {
76         return std::wstring();
77     }
78
79     if (IsValidUTF8(str.c_str()))
80     {
81         codePage = CP_UTF8;
82     }
83
84     int nwide = MultiByteToWideChar(codePage, dwFlags, str.c_str(), (int)str.size(), nullptr, 0);
85     if (nwide == 0)
86     {
87         return std::wstring();
88     }
89
90     wchar_t * buf = new wchar_t[nwide];
91     if (MultiByteToWideChar(codePage, dwFlags, str.c_str(), (int)str.size(), buf, nwide) == 0)
92     {
93         delete[] buf;
94         return std::wstring();
95     }
96
97     std::wstring wstr(buf, buf + nwide);
98     delete[] buf;
99
100     return wstr;
101 }
102
103 #else
104 #ifdef __APPLE__ // Mac OS_X
105
106 std::string UTF8::toUTF8(const std::wstring & wstr)
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