SDL  2.0
SDL_iconv.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 #if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS)
23 #define SDL_DISABLE_ANALYZE_MACROS 1
24 #endif
25 
26 #include "../SDL_internal.h"
27 
28 /* This file contains portable iconv functions for SDL */
29 
30 #include "SDL_stdinc.h"
31 #include "SDL_endian.h"
32 
33 #ifdef HAVE_ICONV
34 
35 /* Depending on which standard the iconv() was implemented with,
36  iconv() may or may not use const char ** for the inbuf param.
37  If we get this wrong, it's just a warning, so no big deal.
38 */
39 #if defined(_XGP6) || defined(__APPLE__) || \
40  (defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) || \
41  (defined(_NEWLIB_VERSION)))
42 #define ICONV_INBUF_NONCONST
43 #endif
44 
45 #include <errno.h>
46 
47 SDL_COMPILE_TIME_ASSERT(iconv_t, sizeof (iconv_t) <= sizeof (SDL_iconv_t));
48 
49 SDL_iconv_t
50 SDL_iconv_open(const char *tocode, const char *fromcode)
51 {
52  return (SDL_iconv_t) ((size_t) iconv_open(tocode, fromcode));
53 }
54 
55 int
56 SDL_iconv_close(SDL_iconv_t cd)
57 {
58  return iconv_close((iconv_t) ((size_t) cd));
59 }
60 
61 size_t
62 SDL_iconv(SDL_iconv_t cd,
63  const char **inbuf, size_t * inbytesleft,
64  char **outbuf, size_t * outbytesleft)
65 {
66  size_t retCode;
67 #ifdef ICONV_INBUF_NONCONST
68  retCode = iconv((iconv_t) ((size_t) cd), (char **) inbuf, inbytesleft, outbuf, outbytesleft);
69 #else
70  retCode = iconv((iconv_t) ((size_t) cd), inbuf, inbytesleft, outbuf, outbytesleft);
71 #endif
72  if (retCode == (size_t) - 1) {
73  switch (errno) {
74  case E2BIG:
75  return SDL_ICONV_E2BIG;
76  case EILSEQ:
77  return SDL_ICONV_EILSEQ;
78  case EINVAL:
79  return SDL_ICONV_EINVAL;
80  default:
81  return SDL_ICONV_ERROR;
82  }
83  }
84  return retCode;
85 }
86 
87 #else
88 
89 /* Lots of useful information on Unicode at:
90  http://www.cl.cam.ac.uk/~mgk25/unicode.html
91 */
92 
93 #define UNICODE_BOM 0xFEFF
94 
95 #define UNKNOWN_ASCII '?'
96 #define UNKNOWN_UNICODE 0xFFFD
97 
98 enum
99 {
104  ENCODING_UTF16, /* Needs byte order marker */
107  ENCODING_UTF32, /* Needs byte order marker */
114 };
115 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
116 #define ENCODING_UTF16NATIVE ENCODING_UTF16BE
117 #define ENCODING_UTF32NATIVE ENCODING_UTF32BE
118 #define ENCODING_UCS2NATIVE ENCODING_UCS2BE
119 #define ENCODING_UCS4NATIVE ENCODING_UCS4BE
120 #else
121 #define ENCODING_UTF16NATIVE ENCODING_UTF16LE
122 #define ENCODING_UTF32NATIVE ENCODING_UTF32LE
123 #define ENCODING_UCS2NATIVE ENCODING_UCS2LE
124 #define ENCODING_UCS4NATIVE ENCODING_UCS4LE
125 #endif
126 
128 {
129  int src_fmt;
130  int dst_fmt;
131 };
132 
133 static struct
134 {
135  const char *name;
136  int format;
137 } encodings[] = {
138 /* *INDENT-OFF* */
139  { "ASCII", ENCODING_ASCII },
140  { "US-ASCII", ENCODING_ASCII },
141  { "8859-1", ENCODING_LATIN1 },
142  { "ISO-8859-1", ENCODING_LATIN1 },
143  { "UTF8", ENCODING_UTF8 },
144  { "UTF-8", ENCODING_UTF8 },
145  { "UTF16", ENCODING_UTF16 },
146  { "UTF-16", ENCODING_UTF16 },
147  { "UTF16BE", ENCODING_UTF16BE },
148  { "UTF-16BE", ENCODING_UTF16BE },
149  { "UTF16LE", ENCODING_UTF16LE },
150  { "UTF-16LE", ENCODING_UTF16LE },
151  { "UTF32", ENCODING_UTF32 },
152  { "UTF-32", ENCODING_UTF32 },
153  { "UTF32BE", ENCODING_UTF32BE },
154  { "UTF-32BE", ENCODING_UTF32BE },
155  { "UTF32LE", ENCODING_UTF32LE },
156  { "UTF-32LE", ENCODING_UTF32LE },
157  { "UCS2", ENCODING_UCS2BE },
158  { "UCS-2", ENCODING_UCS2BE },
159  { "UCS-2LE", ENCODING_UCS2LE },
160  { "UCS-2BE", ENCODING_UCS2BE },
161  { "UCS-2-INTERNAL", ENCODING_UCS2NATIVE },
162  { "UCS4", ENCODING_UCS4BE },
163  { "UCS-4", ENCODING_UCS4BE },
164  { "UCS-4LE", ENCODING_UCS4LE },
165  { "UCS-4BE", ENCODING_UCS4BE },
166  { "UCS-4-INTERNAL", ENCODING_UCS4NATIVE },
167 /* *INDENT-ON* */
168 };
169 
170 static const char *
171 getlocale(char *buffer, size_t bufsize)
172 {
173  const char *lang;
174  char *ptr;
175 
176  lang = SDL_getenv("LC_ALL");
177  if (!lang) {
178  lang = SDL_getenv("LC_CTYPE");
179  }
180  if (!lang) {
181  lang = SDL_getenv("LC_MESSAGES");
182  }
183  if (!lang) {
184  lang = SDL_getenv("LANG");
185  }
186  if (!lang || !*lang || SDL_strcmp(lang, "C") == 0) {
187  lang = "ASCII";
188  }
189 
190  /* We need to trim down strings like "en_US.UTF-8@blah" to "UTF-8" */
191  ptr = SDL_strchr(lang, '.');
192  if (ptr != NULL) {
193  lang = ptr + 1;
194  }
195 
196  SDL_strlcpy(buffer, lang, bufsize);
197  ptr = SDL_strchr(buffer, '@');
198  if (ptr != NULL) {
199  *ptr = '\0'; /* chop end of string. */
200  }
201 
202  return buffer;
203 }
204 
205 SDL_iconv_t
206 SDL_iconv_open(const char *tocode, const char *fromcode)
207 {
210  int i;
211  char fromcode_buffer[64];
212  char tocode_buffer[64];
213 
214  if (!fromcode || !*fromcode) {
215  fromcode = getlocale(fromcode_buffer, sizeof(fromcode_buffer));
216  }
217  if (!tocode || !*tocode) {
218  tocode = getlocale(tocode_buffer, sizeof(tocode_buffer));
219  }
220  for (i = 0; i < SDL_arraysize(encodings); ++i) {
221  if (SDL_strcasecmp(fromcode, encodings[i].name) == 0) {
222  src_fmt = encodings[i].format;
223  if (dst_fmt != ENCODING_UNKNOWN) {
224  break;
225  }
226  }
227  if (SDL_strcasecmp(tocode, encodings[i].name) == 0) {
228  dst_fmt = encodings[i].format;
229  if (src_fmt != ENCODING_UNKNOWN) {
230  break;
231  }
232  }
233  }
234  if (src_fmt != ENCODING_UNKNOWN && dst_fmt != ENCODING_UNKNOWN) {
235  SDL_iconv_t cd = (SDL_iconv_t) SDL_malloc(sizeof(*cd));
236  if (cd) {
237  cd->src_fmt = src_fmt;
238  cd->dst_fmt = dst_fmt;
239  return cd;
240  }
241  }
242  return (SDL_iconv_t) - 1;
243 }
244 
245 size_t
246 SDL_iconv(SDL_iconv_t cd,
247  const char **inbuf, size_t * inbytesleft,
248  char **outbuf, size_t * outbytesleft)
249 {
250  /* For simplicity, we'll convert everything to and from UCS-4 */
251  const char *src;
252  char *dst;
253  size_t srclen, dstlen;
254  Uint32 ch = 0;
255  size_t total;
256 
257  if (!inbuf || !*inbuf) {
258  /* Reset the context */
259  return 0;
260  }
261  if (!outbuf || !*outbuf || !outbytesleft || !*outbytesleft) {
262  return SDL_ICONV_E2BIG;
263  }
264  src = *inbuf;
265  srclen = (inbytesleft ? *inbytesleft : 0);
266  dst = *outbuf;
267  dstlen = *outbytesleft;
268 
269  switch (cd->src_fmt) {
270  case ENCODING_UTF16:
271  /* Scan for a byte order marker */
272  {
273  Uint8 *p = (Uint8 *) src;
274  size_t n = srclen / 2;
275  while (n) {
276  if (p[0] == 0xFF && p[1] == 0xFE) {
277  cd->src_fmt = ENCODING_UTF16BE;
278  break;
279  } else if (p[0] == 0xFE && p[1] == 0xFF) {
280  cd->src_fmt = ENCODING_UTF16LE;
281  break;
282  }
283  p += 2;
284  --n;
285  }
286  if (n == 0) {
287  /* We can't tell, default to host order */
288  cd->src_fmt = ENCODING_UTF16NATIVE;
289  }
290  }
291  break;
292  case ENCODING_UTF32:
293  /* Scan for a byte order marker */
294  {
295  Uint8 *p = (Uint8 *) src;
296  size_t n = srclen / 4;
297  while (n) {
298  if (p[0] == 0xFF && p[1] == 0xFE &&
299  p[2] == 0x00 && p[3] == 0x00) {
300  cd->src_fmt = ENCODING_UTF32BE;
301  break;
302  } else if (p[0] == 0x00 && p[1] == 0x00 &&
303  p[2] == 0xFE && p[3] == 0xFF) {
304  cd->src_fmt = ENCODING_UTF32LE;
305  break;
306  }
307  p += 4;
308  --n;
309  }
310  if (n == 0) {
311  /* We can't tell, default to host order */
312  cd->src_fmt = ENCODING_UTF32NATIVE;
313  }
314  }
315  break;
316  }
317 
318  switch (cd->dst_fmt) {
319  case ENCODING_UTF16:
320  /* Default to host order, need to add byte order marker */
321  if (dstlen < 2) {
322  return SDL_ICONV_E2BIG;
323  }
324  *(Uint16 *) dst = UNICODE_BOM;
325  dst += 2;
326  dstlen -= 2;
327  cd->dst_fmt = ENCODING_UTF16NATIVE;
328  break;
329  case ENCODING_UTF32:
330  /* Default to host order, need to add byte order marker */
331  if (dstlen < 4) {
332  return SDL_ICONV_E2BIG;
333  }
334  *(Uint32 *) dst = UNICODE_BOM;
335  dst += 4;
336  dstlen -= 4;
337  cd->dst_fmt = ENCODING_UTF32NATIVE;
338  break;
339  }
340 
341  total = 0;
342  while (srclen > 0) {
343  /* Decode a character */
344  switch (cd->src_fmt) {
345  case ENCODING_ASCII:
346  {
347  Uint8 *p = (Uint8 *) src;
348  ch = (Uint32) (p[0] & 0x7F);
349  ++src;
350  --srclen;
351  }
352  break;
353  case ENCODING_LATIN1:
354  {
355  Uint8 *p = (Uint8 *) src;
356  ch = (Uint32) p[0];
357  ++src;
358  --srclen;
359  }
360  break;
361  case ENCODING_UTF8: /* RFC 3629 */
362  {
363  Uint8 *p = (Uint8 *) src;
364  size_t left = 0;
365  SDL_bool overlong = SDL_FALSE;
366  if (p[0] >= 0xFC) {
367  if ((p[0] & 0xFE) != 0xFC) {
368  /* Skip illegal sequences
369  return SDL_ICONV_EILSEQ;
370  */
371  ch = UNKNOWN_UNICODE;
372  } else {
373  if (p[0] == 0xFC && srclen > 1 && (p[1] & 0xFC) == 0x80) {
374  overlong = SDL_TRUE;
375  }
376  ch = (Uint32) (p[0] & 0x01);
377  left = 5;
378  }
379  } else if (p[0] >= 0xF8) {
380  if ((p[0] & 0xFC) != 0xF8) {
381  /* Skip illegal sequences
382  return SDL_ICONV_EILSEQ;
383  */
384  ch = UNKNOWN_UNICODE;
385  } else {
386  if (p[0] == 0xF8 && srclen > 1 && (p[1] & 0xF8) == 0x80) {
387  overlong = SDL_TRUE;
388  }
389  ch = (Uint32) (p[0] & 0x03);
390  left = 4;
391  }
392  } else if (p[0] >= 0xF0) {
393  if ((p[0] & 0xF8) != 0xF0) {
394  /* Skip illegal sequences
395  return SDL_ICONV_EILSEQ;
396  */
397  ch = UNKNOWN_UNICODE;
398  } else {
399  if (p[0] == 0xF0 && srclen > 1 && (p[1] & 0xF0) == 0x80) {
400  overlong = SDL_TRUE;
401  }
402  ch = (Uint32) (p[0] & 0x07);
403  left = 3;
404  }
405  } else if (p[0] >= 0xE0) {
406  if ((p[0] & 0xF0) != 0xE0) {
407  /* Skip illegal sequences
408  return SDL_ICONV_EILSEQ;
409  */
410  ch = UNKNOWN_UNICODE;
411  } else {
412  if (p[0] == 0xE0 && srclen > 1 && (p[1] & 0xE0) == 0x80) {
413  overlong = SDL_TRUE;
414  }
415  ch = (Uint32) (p[0] & 0x0F);
416  left = 2;
417  }
418  } else if (p[0] >= 0xC0) {
419  if ((p[0] & 0xE0) != 0xC0) {
420  /* Skip illegal sequences
421  return SDL_ICONV_EILSEQ;
422  */
423  ch = UNKNOWN_UNICODE;
424  } else {
425  if ((p[0] & 0xDE) == 0xC0) {
426  overlong = SDL_TRUE;
427  }
428  ch = (Uint32) (p[0] & 0x1F);
429  left = 1;
430  }
431  } else {
432  if ((p[0] & 0x80) != 0x00) {
433  /* Skip illegal sequences
434  return SDL_ICONV_EILSEQ;
435  */
436  ch = UNKNOWN_UNICODE;
437  } else {
438  ch = (Uint32) p[0];
439  }
440  }
441  ++src;
442  --srclen;
443  if (srclen < left) {
444  return SDL_ICONV_EINVAL;
445  }
446  while (left--) {
447  ++p;
448  if ((p[0] & 0xC0) != 0x80) {
449  /* Skip illegal sequences
450  return SDL_ICONV_EILSEQ;
451  */
452  ch = UNKNOWN_UNICODE;
453  break;
454  }
455  ch <<= 6;
456  ch |= (p[0] & 0x3F);
457  ++src;
458  --srclen;
459  }
460  if (overlong) {
461  /* Potential security risk
462  return SDL_ICONV_EILSEQ;
463  */
464  ch = UNKNOWN_UNICODE;
465  }
466  if ((ch >= 0xD800 && ch <= 0xDFFF) ||
467  (ch == 0xFFFE || ch == 0xFFFF) || ch > 0x10FFFF) {
468  /* Skip illegal sequences
469  return SDL_ICONV_EILSEQ;
470  */
471  ch = UNKNOWN_UNICODE;
472  }
473  }
474  break;
475  case ENCODING_UTF16BE: /* RFC 2781 */
476  {
477  Uint8 *p = (Uint8 *) src;
478  Uint16 W1, W2;
479  if (srclen < 2) {
480  return SDL_ICONV_EINVAL;
481  }
482  W1 = ((Uint16) p[0] << 8) | (Uint16) p[1];
483  src += 2;
484  srclen -= 2;
485  if (W1 < 0xD800 || W1 > 0xDFFF) {
486  ch = (Uint32) W1;
487  break;
488  }
489  if (W1 > 0xDBFF) {
490  /* Skip illegal sequences
491  return SDL_ICONV_EILSEQ;
492  */
493  ch = UNKNOWN_UNICODE;
494  break;
495  }
496  if (srclen < 2) {
497  return SDL_ICONV_EINVAL;
498  }
499  p = (Uint8 *) src;
500  W2 = ((Uint16) p[0] << 8) | (Uint16) p[1];
501  src += 2;
502  srclen -= 2;
503  if (W2 < 0xDC00 || W2 > 0xDFFF) {
504  /* Skip illegal sequences
505  return SDL_ICONV_EILSEQ;
506  */
507  ch = UNKNOWN_UNICODE;
508  break;
509  }
510  ch = (((Uint32) (W1 & 0x3FF) << 10) |
511  (Uint32) (W2 & 0x3FF)) + 0x10000;
512  }
513  break;
514  case ENCODING_UTF16LE: /* RFC 2781 */
515  {
516  Uint8 *p = (Uint8 *) src;
517  Uint16 W1, W2;
518  if (srclen < 2) {
519  return SDL_ICONV_EINVAL;
520  }
521  W1 = ((Uint16) p[1] << 8) | (Uint16) p[0];
522  src += 2;
523  srclen -= 2;
524  if (W1 < 0xD800 || W1 > 0xDFFF) {
525  ch = (Uint32) W1;
526  break;
527  }
528  if (W1 > 0xDBFF) {
529  /* Skip illegal sequences
530  return SDL_ICONV_EILSEQ;
531  */
532  ch = UNKNOWN_UNICODE;
533  break;
534  }
535  if (srclen < 2) {
536  return SDL_ICONV_EINVAL;
537  }
538  p = (Uint8 *) src;
539  W2 = ((Uint16) p[1] << 8) | (Uint16) p[0];
540  src += 2;
541  srclen -= 2;
542  if (W2 < 0xDC00 || W2 > 0xDFFF) {
543  /* Skip illegal sequences
544  return SDL_ICONV_EILSEQ;
545  */
546  ch = UNKNOWN_UNICODE;
547  break;
548  }
549  ch = (((Uint32) (W1 & 0x3FF) << 10) |
550  (Uint32) (W2 & 0x3FF)) + 0x10000;
551  }
552  break;
553  case ENCODING_UCS2LE:
554  {
555  Uint8 *p = (Uint8 *) src;
556  if (srclen < 2) {
557  return SDL_ICONV_EINVAL;
558  }
559  ch = ((Uint32) p[1] << 8) | (Uint32) p[0];
560  src += 2;
561  srclen -= 2;
562  }
563  break;
564  case ENCODING_UCS2BE:
565  {
566  Uint8 *p = (Uint8 *) src;
567  if (srclen < 2) {
568  return SDL_ICONV_EINVAL;
569  }
570  ch = ((Uint32) p[0] << 8) | (Uint32) p[1];
571  src += 2;
572  srclen -= 2;
573  }
574  break;
575  case ENCODING_UCS4BE:
576  case ENCODING_UTF32BE:
577  {
578  Uint8 *p = (Uint8 *) src;
579  if (srclen < 4) {
580  return SDL_ICONV_EINVAL;
581  }
582  ch = ((Uint32) p[0] << 24) |
583  ((Uint32) p[1] << 16) |
584  ((Uint32) p[2] << 8) | (Uint32) p[3];
585  src += 4;
586  srclen -= 4;
587  }
588  break;
589  case ENCODING_UCS4LE:
590  case ENCODING_UTF32LE:
591  {
592  Uint8 *p = (Uint8 *) src;
593  if (srclen < 4) {
594  return SDL_ICONV_EINVAL;
595  }
596  ch = ((Uint32) p[3] << 24) |
597  ((Uint32) p[2] << 16) |
598  ((Uint32) p[1] << 8) | (Uint32) p[0];
599  src += 4;
600  srclen -= 4;
601  }
602  break;
603  }
604 
605  /* Encode a character */
606  switch (cd->dst_fmt) {
607  case ENCODING_ASCII:
608  {
609  Uint8 *p = (Uint8 *) dst;
610  if (dstlen < 1) {
611  return SDL_ICONV_E2BIG;
612  }
613  if (ch > 0x7F) {
614  *p = UNKNOWN_ASCII;
615  } else {
616  *p = (Uint8) ch;
617  }
618  ++dst;
619  --dstlen;
620  }
621  break;
622  case ENCODING_LATIN1:
623  {
624  Uint8 *p = (Uint8 *) dst;
625  if (dstlen < 1) {
626  return SDL_ICONV_E2BIG;
627  }
628  if (ch > 0xFF) {
629  *p = UNKNOWN_ASCII;
630  } else {
631  *p = (Uint8) ch;
632  }
633  ++dst;
634  --dstlen;
635  }
636  break;
637  case ENCODING_UTF8: /* RFC 3629 */
638  {
639  Uint8 *p = (Uint8 *) dst;
640  if (ch > 0x10FFFF) {
641  ch = UNKNOWN_UNICODE;
642  }
643  if (ch <= 0x7F) {
644  if (dstlen < 1) {
645  return SDL_ICONV_E2BIG;
646  }
647  *p = (Uint8) ch;
648  ++dst;
649  --dstlen;
650  } else if (ch <= 0x7FF) {
651  if (dstlen < 2) {
652  return SDL_ICONV_E2BIG;
653  }
654  p[0] = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
655  p[1] = 0x80 | (Uint8) (ch & 0x3F);
656  dst += 2;
657  dstlen -= 2;
658  } else if (ch <= 0xFFFF) {
659  if (dstlen < 3) {
660  return SDL_ICONV_E2BIG;
661  }
662  p[0] = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
663  p[1] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
664  p[2] = 0x80 | (Uint8) (ch & 0x3F);
665  dst += 3;
666  dstlen -= 3;
667  } else if (ch <= 0x1FFFFF) {
668  if (dstlen < 4) {
669  return SDL_ICONV_E2BIG;
670  }
671  p[0] = 0xF0 | (Uint8) ((ch >> 18) & 0x07);
672  p[1] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
673  p[2] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
674  p[3] = 0x80 | (Uint8) (ch & 0x3F);
675  dst += 4;
676  dstlen -= 4;
677  } else if (ch <= 0x3FFFFFF) {
678  if (dstlen < 5) {
679  return SDL_ICONV_E2BIG;
680  }
681  p[0] = 0xF8 | (Uint8) ((ch >> 24) & 0x03);
682  p[1] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
683  p[2] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
684  p[3] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
685  p[4] = 0x80 | (Uint8) (ch & 0x3F);
686  dst += 5;
687  dstlen -= 5;
688  } else {
689  if (dstlen < 6) {
690  return SDL_ICONV_E2BIG;
691  }
692  p[0] = 0xFC | (Uint8) ((ch >> 30) & 0x01);
693  p[1] = 0x80 | (Uint8) ((ch >> 24) & 0x3F);
694  p[2] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
695  p[3] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
696  p[4] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
697  p[5] = 0x80 | (Uint8) (ch & 0x3F);
698  dst += 6;
699  dstlen -= 6;
700  }
701  }
702  break;
703  case ENCODING_UTF16BE: /* RFC 2781 */
704  {
705  Uint8 *p = (Uint8 *) dst;
706  if (ch > 0x10FFFF) {
707  ch = UNKNOWN_UNICODE;
708  }
709  if (ch < 0x10000) {
710  if (dstlen < 2) {
711  return SDL_ICONV_E2BIG;
712  }
713  p[0] = (Uint8) (ch >> 8);
714  p[1] = (Uint8) ch;
715  dst += 2;
716  dstlen -= 2;
717  } else {
718  Uint16 W1, W2;
719  if (dstlen < 4) {
720  return SDL_ICONV_E2BIG;
721  }
722  ch = ch - 0x10000;
723  W1 = 0xD800 | (Uint16) ((ch >> 10) & 0x3FF);
724  W2 = 0xDC00 | (Uint16) (ch & 0x3FF);
725  p[0] = (Uint8) (W1 >> 8);
726  p[1] = (Uint8) W1;
727  p[2] = (Uint8) (W2 >> 8);
728  p[3] = (Uint8) W2;
729  dst += 4;
730  dstlen -= 4;
731  }
732  }
733  break;
734  case ENCODING_UTF16LE: /* RFC 2781 */
735  {
736  Uint8 *p = (Uint8 *) dst;
737  if (ch > 0x10FFFF) {
738  ch = UNKNOWN_UNICODE;
739  }
740  if (ch < 0x10000) {
741  if (dstlen < 2) {
742  return SDL_ICONV_E2BIG;
743  }
744  p[1] = (Uint8) (ch >> 8);
745  p[0] = (Uint8) ch;
746  dst += 2;
747  dstlen -= 2;
748  } else {
749  Uint16 W1, W2;
750  if (dstlen < 4) {
751  return SDL_ICONV_E2BIG;
752  }
753  ch = ch - 0x10000;
754  W1 = 0xD800 | (Uint16) ((ch >> 10) & 0x3FF);
755  W2 = 0xDC00 | (Uint16) (ch & 0x3FF);
756  p[1] = (Uint8) (W1 >> 8);
757  p[0] = (Uint8) W1;
758  p[3] = (Uint8) (W2 >> 8);
759  p[2] = (Uint8) W2;
760  dst += 4;
761  dstlen -= 4;
762  }
763  }
764  break;
765  case ENCODING_UCS2BE:
766  {
767  Uint8 *p = (Uint8 *) dst;
768  if (ch > 0xFFFF) {
769  ch = UNKNOWN_UNICODE;
770  }
771  if (dstlen < 2) {
772  return SDL_ICONV_E2BIG;
773  }
774  p[0] = (Uint8) (ch >> 8);
775  p[1] = (Uint8) ch;
776  dst += 2;
777  dstlen -= 2;
778  }
779  break;
780  case ENCODING_UCS2LE:
781  {
782  Uint8 *p = (Uint8 *) dst;
783  if (ch > 0xFFFF) {
784  ch = UNKNOWN_UNICODE;
785  }
786  if (dstlen < 2) {
787  return SDL_ICONV_E2BIG;
788  }
789  p[1] = (Uint8) (ch >> 8);
790  p[0] = (Uint8) ch;
791  dst += 2;
792  dstlen -= 2;
793  }
794  break;
795  case ENCODING_UTF32BE:
796  if (ch > 0x10FFFF) {
797  ch = UNKNOWN_UNICODE;
798  }
799  case ENCODING_UCS4BE:
800  if (ch > 0x7FFFFFFF) {
801  ch = UNKNOWN_UNICODE;
802  }
803  {
804  Uint8 *p = (Uint8 *) dst;
805  if (dstlen < 4) {
806  return SDL_ICONV_E2BIG;
807  }
808  p[0] = (Uint8) (ch >> 24);
809  p[1] = (Uint8) (ch >> 16);
810  p[2] = (Uint8) (ch >> 8);
811  p[3] = (Uint8) ch;
812  dst += 4;
813  dstlen -= 4;
814  }
815  break;
816  case ENCODING_UTF32LE:
817  if (ch > 0x10FFFF) {
818  ch = UNKNOWN_UNICODE;
819  }
820  case ENCODING_UCS4LE:
821  if (ch > 0x7FFFFFFF) {
822  ch = UNKNOWN_UNICODE;
823  }
824  {
825  Uint8 *p = (Uint8 *) dst;
826  if (dstlen < 4) {
827  return SDL_ICONV_E2BIG;
828  }
829  p[3] = (Uint8) (ch >> 24);
830  p[2] = (Uint8) (ch >> 16);
831  p[1] = (Uint8) (ch >> 8);
832  p[0] = (Uint8) ch;
833  dst += 4;
834  dstlen -= 4;
835  }
836  break;
837  }
838 
839  /* Update state */
840  *inbuf = src;
841  *inbytesleft = srclen;
842  *outbuf = dst;
843  *outbytesleft = dstlen;
844  ++total;
845  }
846  return total;
847 }
848 
849 int
850 SDL_iconv_close(SDL_iconv_t cd)
851 {
852  if (cd != (SDL_iconv_t)-1) {
853  SDL_free(cd);
854  }
855  return 0;
856 }
857 
858 #endif /* !HAVE_ICONV */
859 
860 char *
861 SDL_iconv_string(const char *tocode, const char *fromcode, const char *inbuf,
862  size_t inbytesleft)
863 {
864  SDL_iconv_t cd;
865  char *string;
866  size_t stringsize;
867  char *outbuf;
868  size_t outbytesleft;
869  size_t retCode = 0;
870 
871  cd = SDL_iconv_open(tocode, fromcode);
872  if (cd == (SDL_iconv_t) - 1) {
873  /* See if we can recover here (fixes iconv on Solaris 11) */
874  if (!tocode || !*tocode) {
875  tocode = "UTF-8";
876  }
877  if (!fromcode || !*fromcode) {
878  fromcode = "UTF-8";
879  }
880  cd = SDL_iconv_open(tocode, fromcode);
881  }
882  if (cd == (SDL_iconv_t) - 1) {
883  return NULL;
884  }
885 
886  stringsize = inbytesleft > 4 ? inbytesleft : 4;
887  string = SDL_malloc(stringsize);
888  if (!string) {
889  SDL_iconv_close(cd);
890  return NULL;
891  }
892  outbuf = string;
893  outbytesleft = stringsize;
894  SDL_memset(outbuf, 0, 4);
895 
896  while (inbytesleft > 0) {
897  retCode = SDL_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
898  switch (retCode) {
899  case SDL_ICONV_E2BIG:
900  {
901  char *oldstring = string;
902  stringsize *= 2;
903  string = SDL_realloc(string, stringsize);
904  if (!string) {
905  SDL_iconv_close(cd);
906  return NULL;
907  }
908  outbuf = string + (outbuf - oldstring);
909  outbytesleft = stringsize - (outbuf - string);
910  SDL_memset(outbuf, 0, 4);
911  }
912  break;
913  case SDL_ICONV_EILSEQ:
914  /* Try skipping some input data - not perfect, but... */
915  ++inbuf;
916  --inbytesleft;
917  break;
918  case SDL_ICONV_EINVAL:
919  case SDL_ICONV_ERROR:
920  /* We can't continue... */
921  inbytesleft = 0;
922  break;
923  }
924  }
925  SDL_iconv_close(cd);
926 
927  return string;
928 }
929 
930 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_strlcpy
GLenum GLenum dst
int SDL_iconv_close(SDL_iconv_t cd)
Definition: SDL_iconv.c:850
GLdouble n
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
GLsizei const GLchar *const * string
#define SDL_ICONV_EILSEQ
Definition: SDL_stdinc.h:463
#define UNKNOWN_UNICODE
Definition: SDL_iconv.c:96
GLfloat GLfloat p
SDL_iconv_t SDL_iconv_open(const char *tocode, const char *fromcode)
Definition: SDL_iconv.c:206
const char * name
Definition: SDL_iconv.c:135
GLuint const GLchar * name
#define SDL_realloc
#define SDL_strcasecmp
GLenum GLuint GLsizei bufsize
#define SDL_strchr
SDL_bool
Definition: SDL_stdinc.h:126
unsigned int size_t
#define UNICODE_BOM
Definition: SDL_iconv.c:93
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
void SDL_free(void *mem)
char * SDL_iconv_string(const char *tocode, const char *fromcode, const char *inbuf, size_t inbytesleft)
Definition: SDL_iconv.c:861
#define SDL_ICONV_E2BIG
Definition: SDL_stdinc.h:462
#define ENCODING_UTF32NATIVE
Definition: SDL_iconv.c:117
#define SDL_ICONV_EINVAL
Definition: SDL_stdinc.h:464
GLint left
#define SDL_getenv
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:42
#define NULL
Definition: begin_code.h:143
#define ENCODING_UCS2NATIVE
Definition: SDL_iconv.c:118
#define ENCODING_UCS4NATIVE
Definition: SDL_iconv.c:119
static struct @24 encodings[]
SDL_COMPILE_TIME_ASSERT(size, CountTo >0)
#define UNKNOWN_ASCII
Definition: SDL_iconv.c:95
GLuint buffer
uint16_t Uint16
An unsigned 16-bit integer type.
Definition: SDL_stdinc.h:147
#define SDL_ICONV_ERROR
Definition: SDL_stdinc.h:461
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define SDL_malloc
#define SDL_strcmp
size_t SDL_iconv(SDL_iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
Definition: SDL_iconv.c:246
#define ENCODING_UTF16NATIVE
Definition: SDL_iconv.c:116
int format
Definition: SDL_iconv.c:136
GLenum src
#define SDL_memset
static const char * getlocale(char *buffer, size_t bufsize)
Definition: SDL_iconv.c:171