1 /*
2 
3  gg_utf8.c -- locale charset handling
4 
5  version 5.0, 2020 August 1
6 
7  Author: Sandro Furieri a.furieri@lqt.it
8 
9  ------------------------------------------------------------------------------
10 
11  Version: MPL 1.1/GPL 2.0/LGPL 2.1
12 
13  The contents of this file are subject to the Mozilla Public License Version
14  1.1 (the "License"); you may not use this file except in compliance with
15  the License. You may obtain a copy of the License at
16  http://www.mozilla.org/MPL/
17 
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22 
23 The Original Code is the SpatiaLite library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2008-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Contributor(s):
31 
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43 
44 */
45 
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <errno.h>
51 
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57 
58 #include <spatialite/sqlite.h>
59 #include <spatialite/gaiaaux.h>
60 #include <spatialite_private.h>
61 
62 #if OMIT_ICONV == 0		/* ICONV is absolutely required */
63 
64 #if defined(__MINGW32__) || defined(_WIN32)
65 #define LIBICONV_STATIC
66 #include <iconv.h>
67 #define LIBCHARSET_STATIC
68 #ifdef _MSC_VER
69 /* <localcharset.h> isn't supported on OSGeo4W */
70 /* applying a tricky workaround to fix this issue */
71 extern const char *locale_charset (void);
72 #else /* sane Windows - not OSGeo4W */
73 #include <localcharset.h>
74 #endif /* end localcharset */
75 #else /* not MINGW32 - WIN32 */
76 #if defined(__APPLE__) || defined(__ANDROID__)
77 #include <iconv.h>
78 #include <localcharset.h>
79 #else /* neither Mac OsX nor Android */
80 #include <iconv.h>
81 #include <langinfo.h>
82 #endif
83 #endif
84 
85 GAIAAUX_DECLARE const char *
gaiaGetLocaleCharset()86 gaiaGetLocaleCharset ()
87 {
88 /* identifies the locale charset */
89 #if defined(__MINGW32__) || defined(_WIN32)
90     return locale_charset ();
91 #else /* not MINGW32 - WIN32 */
92 #if defined(__APPLE__) || defined(__ANDROID__)
93     return locale_charset ();
94 #else /* neither Mac OsX nor Android */
95     return nl_langinfo (CODESET);
96 #endif
97 #endif
98 }
99 
100 GAIAAUX_DECLARE int
gaiaConvertCharset(char ** buf,const char * fromCs,const char * toCs)101 gaiaConvertCharset (char **buf, const char *fromCs, const char *toCs)
102 {
103 /* converting a string from a charset to another "on-the-fly" */
104     char *utf8buf;
105 #if !defined(__MINGW32__) && defined(_WIN32)
106     const char *pBuf;
107 #else /* not WIN32 */
108     char *pBuf;
109 #endif
110     size_t len;
111     size_t utf8len;
112     char *pUtf8buf;
113     int maxlen;
114     iconv_t cvt = iconv_open (toCs, fromCs);
115     if (cvt == (iconv_t) (-1))
116 	goto unsupported;
117     len = strlen (*buf);
118     if (len == 0)
119       {
120 	  /* empty string */
121 	  utf8buf = sqlite3_malloc (1);
122 	  *utf8buf = '\0';
123 	  sqlite3_free (*buf);
124 	  *buf = utf8buf;
125 	  iconv_close (cvt);
126 	  return 1;
127       }
128     maxlen = len * 4;
129     utf8len = maxlen;
130     pBuf = *buf;
131     utf8buf = sqlite3_malloc (utf8len);
132     pUtf8buf = utf8buf;
133     if (iconv (cvt, &pBuf, &len, &pUtf8buf, &utf8len) == (size_t) (-1))
134 	goto error;
135     utf8buf[maxlen - utf8len] = '\0';
136     sqlite3_free (*buf);
137     *buf = utf8buf;
138     iconv_close (cvt);
139     return 1;
140   error:
141     iconv_close (cvt);
142     sqlite3_free (*buf);
143     *buf = NULL;
144   unsupported:
145     return 0;
146 }
147 
148 GAIAAUX_DECLARE void *
gaiaCreateUTF8Converter(const char * fromCS)149 gaiaCreateUTF8Converter (const char *fromCS)
150 {
151 /* creating a UTF8 converter and returning an opaque reference to it */
152     iconv_t cvt = iconv_open ("UTF-8", fromCS);
153     if (cvt == (iconv_t) (-1))
154 	return NULL;
155     return cvt;
156 }
157 
158 GAIAAUX_DECLARE void
gaiaFreeUTF8Converter(void * cvtCS)159 gaiaFreeUTF8Converter (void *cvtCS)
160 {
161 /* destroying a UTF8 converter */
162     if (cvtCS)
163 	iconv_close (cvtCS);
164 }
165 
166 GAIAAUX_DECLARE char *
gaiaConvertToUTF8(void * cvtCS,const char * buf,int buflen,int * err)167 gaiaConvertToUTF8 (void *cvtCS, const char *buf, int buflen, int *err)
168 {
169 /* converting a string to UTF8 */
170     char *utf8buf = 0;
171 #if !defined(__MINGW32__) && defined(_WIN32)
172     const char *pBuf;
173 #else
174     char *pBuf;
175 #endif
176     size_t len;
177     size_t utf8len;
178     int maxlen = buflen * 4;
179     char *pUtf8buf;
180     *err = 0;
181     if (!cvtCS)
182       {
183 	  *err = 1;
184 	  return NULL;
185       }
186     utf8buf = malloc (maxlen);
187     len = buflen;
188     utf8len = maxlen;
189     pBuf = (char *) buf;
190     pUtf8buf = utf8buf;
191     if (iconv (cvtCS, &pBuf, &len, &pUtf8buf, &utf8len) == (size_t) (-1))
192       {
193 	  free (utf8buf);
194 	  *err = 1;
195 	  return NULL;
196       }
197     utf8buf[maxlen - utf8len] = '\0';
198     return utf8buf;
199 }
200 
201 SPATIALITE_PRIVATE char *
url_toUtf8(const char * url,const char * in_charset)202 url_toUtf8 (const char *url, const char *in_charset)
203 {
204 /* converting an URL to UTF-8 */
205     iconv_t cvt;
206     size_t len;
207     size_t utf8len;
208     int maxlen;
209     char *utf8buf;
210     char *pUtf8buf;
211 #if !defined(__MINGW32__) && defined(_WIN32)
212     const char *pBuf = url;
213 #else /* not WIN32 */
214     char *pBuf = (char *) url;
215 #endif
216 
217     if (url == NULL || in_charset == NULL)
218 	return NULL;
219     cvt = iconv_open ("UTF-8", in_charset);
220     if (cvt == (iconv_t) (-1))
221 	goto unsupported;
222     len = strlen (url);
223     maxlen = len * 4;
224     utf8len = maxlen;
225     utf8buf = malloc (maxlen);
226     pUtf8buf = utf8buf;
227     if (iconv (cvt, &pBuf, &len, &pUtf8buf, &utf8len) == (size_t) (-1))
228 	goto error;
229     utf8buf[maxlen - utf8len] = '\0';
230     iconv_close (cvt);
231     return utf8buf;
232 
233   error:
234     iconv_close (cvt);
235     free (utf8buf);
236   unsupported:
237     return NULL;
238 }
239 
240 SPATIALITE_PRIVATE char *
url_fromUtf8(const char * url,const char * out_charset)241 url_fromUtf8 (const char *url, const char *out_charset)
242 {
243 /* converting an URL from UTF-8 */
244     iconv_t cvt;
245     size_t len;
246     size_t utf8len;
247     int maxlen;
248     char *utf8buf;
249     char *pUtf8buf;
250 #if !defined(__MINGW32__) && defined(_WIN32)
251     const char *pBuf = url;
252 #else /* not WIN32 */
253     char *pBuf = (char *) url;
254 #endif
255 
256     if (url == NULL || out_charset == NULL)
257 	return NULL;
258     cvt = iconv_open (out_charset, "UTF-8");
259     if (cvt == (iconv_t) (-1))
260 	goto unsupported;
261     len = strlen (url);
262     maxlen = len * 4;
263     utf8len = maxlen;
264     utf8buf = malloc (maxlen);
265     pUtf8buf = utf8buf;
266     if (iconv (cvt, &pBuf, &len, &pUtf8buf, &utf8len) == (size_t) (-1))
267 	goto error;
268     utf8buf[maxlen - utf8len] = '\0';
269     iconv_close (cvt);
270     return utf8buf;
271 
272   error:
273     iconv_close (cvt);
274     free (utf8buf);
275   unsupported:
276     return NULL;
277 }
278 
279 #else
280 GAIAAUX_DECLARE char *
gaiaConvertToUTF8(void * cvtCS,const char * buf,int buflen,int * err)281 gaiaConvertToUTF8 (void *cvtCS, const char *buf, int buflen, int *err)
282 {
283 	if (cvtCS == NULL || buf == NULL || err == NULL || buflen == 0)
284     return NULL;
285     return NULL;
286 }
287 #endif /* ICONV enabled/disabled */
288