146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* 246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL - Simple DirectMedia Layer 346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Copyright (C) 1997-2006 Sam Lantinga 446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner This library is free software; you can redistribute it and/or 646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner modify it under the terms of the GNU Lesser General Public 746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner License as published by the Free Software Foundation; either 846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner version 2.1 of the License, or (at your option) any later version. 946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 1046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner This library is distributed in the hope that it will be useful, 1146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner but WITHOUT ANY WARRANTY; without even the implied warranty of 1246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Lesser General Public License for more details. 1446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 1546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner You should have received a copy of the GNU Lesser General Public 1646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner License along with this library; if not, write to the Free Software 1746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 1846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 1946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Sam Lantinga 2046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner slouken@libsdl.org 2146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/ 2246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_config.h" 2346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 2446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* This file contains portable iconv functions for SDL */ 2546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 2646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_stdinc.h" 2746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include "SDL_endian.h" 2846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 2946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef HAVE_ICONV 3046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 3146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Depending on which standard the iconv() was implemented with, 3246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner iconv() may or may not use const char ** for the inbuf param. 3346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner If we get this wrong, it's just a warning, so no big deal. 3446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/ 3546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if defined(_XGP6) || \ 3646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner defined(__GLIBC__) && ((__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)) 3746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define ICONV_INBUF_NONCONST 3846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif 3946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 4046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#include <errno.h> 4146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 4246be48730333120a7b939116cef075e61c12c703David 'Digit' Turnersize_t SDL_iconv(SDL_iconv_t cd, 4346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner const char **inbuf, size_t *inbytesleft, 4446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char **outbuf, size_t *outbytesleft) 4546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 4646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t retCode; 4746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#ifdef ICONV_INBUF_NONCONST 4846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner retCode = iconv(cd, (char **)inbuf, inbytesleft, outbuf, outbytesleft); 4946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else 5046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner retCode = iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft); 5146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif 5246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( retCode == (size_t)-1 ) { 5346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch(errno) { 5446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case E2BIG: 5546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 5646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case EILSEQ: 5746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 5846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case EINVAL: 5946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 6046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner default: 6146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_ERROR; 6246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 6346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 6446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return retCode; 6546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 6646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 6746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else 6846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 6946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner/* Lots of useful information on Unicode at: 7046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner http://www.cl.cam.ac.uk/~mgk25/unicode.html 7146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner*/ 7246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 7346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define UNICODE_BOM 0xFEFF 7446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 7546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define UNKNOWN_ASCII '?' 7646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define UNKNOWN_UNICODE 0xFFFD 7746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 7846be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerenum { 7946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UNKNOWN, 8046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_ASCII, 8146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_LATIN1, 8246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF8, 8346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF16, /* Needs byte order marker */ 8446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF16BE, 8546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF16LE, 8646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF32, /* Needs byte order marker */ 8746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF32BE, 8846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UTF32LE, 8946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UCS2, /* Native byte order assumed */ 9046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ENCODING_UCS4, /* Native byte order assumed */ 9146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}; 9246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#if SDL_BYTEORDER == SDL_BIG_ENDIAN 9346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define ENCODING_UTF16NATIVE ENCODING_UTF16BE 9446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define ENCODING_UTF32NATIVE ENCODING_UTF32BE 9546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#else 9646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define ENCODING_UTF16NATIVE ENCODING_UTF16LE 9746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#define ENCODING_UTF32NATIVE ENCODING_UTF32LE 9846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif 9946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 10046be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstruct _SDL_iconv_t 10146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 10246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int src_fmt; 10346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int dst_fmt; 10446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}; 10546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 10646be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic struct { 10746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner const char *name; 10846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int format; 10946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} encodings[] = { 11046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "ASCII", ENCODING_ASCII }, 11146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "US-ASCII", ENCODING_ASCII }, 11246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "8859-1", ENCODING_LATIN1 }, 11346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "ISO-8859-1", ENCODING_LATIN1 }, 11446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF8", ENCODING_UTF8 }, 11546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-8", ENCODING_UTF8 }, 11646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF16", ENCODING_UTF16 }, 11746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-16", ENCODING_UTF16 }, 11846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF16BE", ENCODING_UTF16BE }, 11946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-16BE", ENCODING_UTF16BE }, 12046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF16LE", ENCODING_UTF16LE }, 12146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-16LE", ENCODING_UTF16LE }, 12246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF32", ENCODING_UTF32 }, 12346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-32", ENCODING_UTF32 }, 12446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF32BE", ENCODING_UTF32BE }, 12546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-32BE", ENCODING_UTF32BE }, 12646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF32LE", ENCODING_UTF32LE }, 12746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UTF-32LE", ENCODING_UTF32LE }, 12846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UCS2", ENCODING_UCS2 }, 12946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UCS-2", ENCODING_UCS2 }, 13046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UCS4", ENCODING_UCS4 }, 13146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { "UCS-4", ENCODING_UCS4 }, 13246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner}; 13346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 13446be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerstatic const char *getlocale(char *buffer, size_t bufsize) 13546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 13646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner const char *lang; 13746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char *ptr; 13846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 13946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lang = SDL_getenv("LC_ALL"); 14046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !lang ) { 14146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lang = SDL_getenv("LC_CTYPE"); 14246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 14346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !lang ) { 14446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lang = SDL_getenv("LC_MESSAGES"); 14546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 14646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !lang ) { 14746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lang = SDL_getenv("LANG"); 14846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 14946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !lang || !*lang || SDL_strcmp(lang, "C") == 0 ) { 15046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lang = "ASCII"; 15146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 15246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 15346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* We need to trim down strings like "en_US.UTF-8@blah" to "UTF-8" */ 15446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ptr = SDL_strchr(lang, '.'); 15546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (ptr != NULL) { 15646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner lang = ptr + 1; 15746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 15846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 15946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_strlcpy(buffer, lang, bufsize); 16046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ptr = SDL_strchr(buffer, '@'); 16146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if (ptr != NULL) { 16246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *ptr = '\0'; /* chop end of string. */ 16346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 16446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 16546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return buffer; 16646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 16746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 16846be48730333120a7b939116cef075e61c12c703David 'Digit' TurnerSDL_iconv_t SDL_iconv_open(const char *tocode, const char *fromcode) 16946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 17046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int src_fmt = ENCODING_UNKNOWN; 17146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int dst_fmt = ENCODING_UNKNOWN; 17246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner int i; 17346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char fromcode_buffer[64]; 17446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char tocode_buffer[64]; 17546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 17646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !fromcode || !*fromcode ) { 17746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner fromcode = getlocale(fromcode_buffer, sizeof(fromcode_buffer)); 17846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 17946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !tocode || !*tocode ) { 18046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner tocode = getlocale(tocode_buffer, sizeof(tocode_buffer)); 18146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 18246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner for ( i = 0; i < SDL_arraysize(encodings); ++i ) { 18346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( SDL_strcasecmp(fromcode, encodings[i].name) == 0 ) { 18446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src_fmt = encodings[i].format; 18546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dst_fmt != ENCODING_UNKNOWN ) { 18646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 18746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 18846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 18946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( SDL_strcasecmp(tocode, encodings[i].name) == 0 ) { 19046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst_fmt = encodings[i].format; 19146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( src_fmt != ENCODING_UNKNOWN ) { 19246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 19346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 19446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 19546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 19646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( src_fmt != ENCODING_UNKNOWN && dst_fmt != ENCODING_UNKNOWN ) { 19746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_iconv_t cd = (SDL_iconv_t)SDL_malloc(sizeof(*cd)); 19846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( cd ) { 19946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = src_fmt; 20046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->dst_fmt = dst_fmt; 20146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return cd; 20246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 20346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 20446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return (SDL_iconv_t)-1; 20546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 20646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 20746be48730333120a7b939116cef075e61c12c703David 'Digit' Turnersize_t SDL_iconv(SDL_iconv_t cd, 20846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner const char **inbuf, size_t *inbytesleft, 20946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char **outbuf, size_t *outbytesleft) 21046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 21146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* For simplicity, we'll convert everything to and from UCS-4 */ 21246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner const char *src; 21346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char *dst; 21446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t srclen, dstlen; 21546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint32 ch = 0; 21646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t total; 21746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 21846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !inbuf || !*inbuf ) { 21946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Reset the context */ 22046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return 0; 22146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 22246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !outbuf || !*outbuf || !outbytesleft || !*outbytesleft ) { 22346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 22446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 22546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src = *inbuf; 22646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen = (inbytesleft ? *inbytesleft : 0); 22746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst = *outbuf; 22846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen = *outbytesleft; 22946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 23046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch ( cd->src_fmt ) { 23146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF16: 23246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Scan for a byte order marker */ 23346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 23446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 23546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t n = srclen / 2; 23646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while ( n ) { 23746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] == 0xFF && p[1] == 0xFE ) { 23846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = ENCODING_UTF16BE; 23946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 24046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( p[0] == 0xFE && p[1] == 0xFF ) { 24146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = ENCODING_UTF16LE; 24246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 24346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 24446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p += 2; 24546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --n; 24646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 24746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( n == 0 ) { 24846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* We can't tell, default to host order */ 24946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = ENCODING_UTF16NATIVE; 25046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 25146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 25246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 25346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF32: 25446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Scan for a byte order marker */ 25546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 25646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 25746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t n = srclen / 4; 25846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while ( n ) { 25946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] == 0xFF && p[1] == 0xFE && 26046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] == 0x00 && p[3] == 0x00 ) { 26146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = ENCODING_UTF32BE; 26246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 26346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( p[0] == 0x00 && p[1] == 0x00 && 26446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] == 0xFE && p[3] == 0xFF ) { 26546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = ENCODING_UTF32LE; 26646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 26746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 26846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p += 4; 26946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --n; 27046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 27146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( n == 0 ) { 27246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* We can't tell, default to host order */ 27346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->src_fmt = ENCODING_UTF32NATIVE; 27446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 27546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 27646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 27746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 27846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 27946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch ( cd->dst_fmt ) { 28046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF16: 28146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Default to host order, need to add byte order marker */ 28246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 2 ) { 28346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 28446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 28546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *(Uint16 *)dst = UNICODE_BOM; 28646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 2; 28746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 2; 28846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->dst_fmt = ENCODING_UTF16NATIVE; 28946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 29046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF32: 29146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Default to host order, need to add byte order marker */ 29246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 29346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 29446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 29546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *(Uint32 *)dst = UNICODE_BOM; 29646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 29746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 29846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd->dst_fmt = ENCODING_UTF32NATIVE; 29946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 30046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 30146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 30246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner total = 0; 30346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while ( srclen > 0 ) { 30446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Decode a character */ 30546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch ( cd->src_fmt ) { 30646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_ASCII: 30746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 30846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 30946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)(p[0] & 0x7F); 31046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++src; 31146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --srclen; 31246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 31346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 31446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_LATIN1: 31546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 31646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 31746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)p[0]; 31846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++src; 31946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --srclen; 32046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 32146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 32246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF8: /* RFC 3629 */ 32346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 32446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 32546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t left = 0; 32646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_bool overlong = SDL_FALSE; 32746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] >= 0xFC ) { 32846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xFE) != 0xFC ) { 32946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 33046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 33146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 33246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 33346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 33446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] == 0xFC ) { 33546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner overlong = SDL_TRUE; 33646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 33746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)(p[0] & 0x01); 33846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner left = 5; 33946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 34046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( p[0] >= 0xF8 ) { 34146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xFC) != 0xF8 ) { 34246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 34346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 34446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 34546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 34646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 34746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] == 0xF8 ) { 34846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner overlong = SDL_TRUE; 34946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 35046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)(p[0] & 0x03); 35146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner left = 4; 35246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 35346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( p[0] >= 0xF0 ) { 35446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xF8) != 0xF0 ) { 35546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 35646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 35746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 35846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 35946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 36046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] == 0xF0 ) { 36146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner overlong = SDL_TRUE; 36246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 36346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)(p[0] & 0x07); 36446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner left = 3; 36546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 36646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( p[0] >= 0xE0 ) { 36746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xF0) != 0xE0 ) { 36846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 36946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 37046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 37146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 37246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 37346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( p[0] == 0xE0 ) { 37446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner overlong = SDL_TRUE; 37546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 37646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)(p[0] & 0x0F); 37746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner left = 2; 37846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 37946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( p[0] >= 0xC0 ) { 38046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xE0) != 0xC0 ) { 38146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 38246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 38346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 38446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 38546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 38646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xCE) == 0xC0 ) { 38746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner overlong = SDL_TRUE; 38846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 38946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)(p[0] & 0x1F); 39046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner left = 1; 39146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 39246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 39346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0x80) != 0x00 ) { 39446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 39546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 39646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 39746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 39846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 39946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)p[0]; 40046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 40146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 40246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++src; 40346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --srclen; 40446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < left ) { 40546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 40646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 40746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while ( left-- ) { 40846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++p; 40946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (p[0] & 0xC0) != 0x80 ) { 41046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 41146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 41246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 41346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 41446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 41546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 41646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch <<= 6; 41746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch |= (p[0] & 0x3F); 41846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++src; 41946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --srclen; 42046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 42146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( overlong ) { 42246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Potential security risk 42346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 42446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 42546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 42646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 42746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( (ch >= 0xD800 && ch <= 0xDFFF) || 42846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (ch == 0xFFFE || ch == 0xFFFF) || 42946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch > 0x10FFFF ) { 43046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 43146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 43246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 43346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 43446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 43546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 43646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 43746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF16BE: /* RFC 2781 */ 43846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 43946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 44046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint16 W1, W2; 44146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 2 ) { 44246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 44346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 44446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W1 = ((Uint16)p[0] << 8) | 44546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint16)p[1]; 44646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 2; 44746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 2; 44846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( W1 < 0xD800 || W1 > 0xDFFF ) { 44946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)W1; 45046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 45146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 45246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( W1 > 0xDBFF ) { 45346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 45446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 45546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 45646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 45746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 45846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 45946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 2 ) { 46046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 46146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 46246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p = (Uint8 *)src; 46346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W2 = ((Uint16)p[0] << 8) | 46446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint16)p[1]; 46546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 2; 46646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 2; 46746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( W2 < 0xDC00 || W2 > 0xDFFF ) { 46846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 46946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 47046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 47146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 47246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 47346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 47446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (((Uint32)(W1 & 0x3FF) << 10) | 47546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint32)(W2 & 0x3FF)) + 0x10000; 47646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 47746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 47846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF16LE: /* RFC 2781 */ 47946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 48046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 48146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint16 W1, W2; 48246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 2 ) { 48346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 48446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 48546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W1 = ((Uint16)p[1] << 8) | 48646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint16)p[0]; 48746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 2; 48846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 2; 48946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( W1 < 0xD800 || W1 > 0xDFFF ) { 49046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (Uint32)W1; 49146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 49246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 49346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( W1 > 0xDBFF ) { 49446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 49546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 49646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 49746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 49846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 49946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 50046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 2 ) { 50146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 50246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 50346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p = (Uint8 *)src; 50446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W2 = ((Uint16)p[1] << 8) | 50546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint16)p[0]; 50646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 2; 50746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 2; 50846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( W2 < 0xDC00 || W2 > 0xDFFF ) { 50946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Skip illegal sequences 51046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EILSEQ; 51146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner */ 51246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 51346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 51446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 51546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = (((Uint32)(W1 & 0x3FF) << 10) | 51646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint32)(W2 & 0x3FF)) + 0x10000; 51746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 51846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 51946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF32BE: 52046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 52146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 52246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 4 ) { 52346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 52446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 52546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = ((Uint32)p[0] << 24) | 52646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ((Uint32)p[1] << 16) | 52746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ((Uint32)p[2] << 8) | 52846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint32)p[3]; 52946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 4; 53046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 4; 53146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 53246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 53346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF32LE: 53446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 53546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)src; 53646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 4 ) { 53746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 53846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 53946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = ((Uint32)p[3] << 24) | 54046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ((Uint32)p[2] << 16) | 54146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ((Uint32)p[1] << 8) | 54246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner (Uint32)p[0]; 54346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 4; 54446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 4; 54546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 54646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 54746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UCS2: 54846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 54946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint16 *p = (Uint16 *)src; 55046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 2 ) { 55146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 55246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 55346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = *p; 55446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 2; 55546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 2; 55646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 55746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 55846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UCS4: 55946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 56046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint32 *p = (Uint32 *)src; 56146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( srclen < 4 ) { 56246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_EINVAL; 56346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 56446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = *p; 56546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner src += 4; 56646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner srclen -= 4; 56746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 56846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 56946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 57046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 57146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Encode a character */ 57246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch ( cd->dst_fmt ) { 57346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_ASCII: 57446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 57546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 57646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 1 ) { 57746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 57846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 57946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x7F ) { 58046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = UNKNOWN_ASCII; 58146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 58246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = (Uint8)ch; 58346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 58446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++dst; 58546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --dstlen; 58646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 58746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 58846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_LATIN1: 58946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 59046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 59146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 1 ) { 59246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 59346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 59446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0xFF ) { 59546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = UNKNOWN_ASCII; 59646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 59746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = (Uint8)ch; 59846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 59946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++dst; 60046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --dstlen; 60146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 60246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 60346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF8: /* RFC 3629 */ 60446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 60546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 60646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x10FFFF ) { 60746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 60846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 60946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch <= 0x7F ) { 61046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 1 ) { 61146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 61246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 61346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = (Uint8)ch; 61446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++dst; 61546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --dstlen; 61646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( ch <= 0x7FF ) { 61746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 2 ) { 61846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 61946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 62046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = 0xC0 | (Uint8)((ch >> 6) & 0x1F); 62146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = 0x80 | (Uint8)(ch & 0x3F); 62246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 2; 62346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 2; 62446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( ch <= 0xFFFF ) { 62546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 3 ) { 62646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 62746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 62846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = 0xE0 | (Uint8)((ch >> 12) & 0x0F); 62946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = 0x80 | (Uint8)((ch >> 6) & 0x3F); 63046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = 0x80 | (Uint8)(ch & 0x3F); 63146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 3; 63246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 3; 63346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( ch <= 0x1FFFFF ) { 63446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 63546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 63646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 63746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = 0xF0 | (Uint8)((ch >> 18) & 0x07); 63846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = 0x80 | (Uint8)((ch >> 12) & 0x3F); 63946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = 0x80 | (Uint8)((ch >> 6) & 0x3F); 64046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = 0x80 | (Uint8)(ch & 0x3F); 64146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 64246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 64346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else if ( ch <= 0x3FFFFFF ) { 64446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 5 ) { 64546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 64646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 64746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = 0xF8 | (Uint8)((ch >> 24) & 0x03); 64846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = 0x80 | (Uint8)((ch >> 18) & 0x3F); 64946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = 0x80 | (Uint8)((ch >> 12) & 0x3F); 65046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = 0x80 | (Uint8)((ch >> 6) & 0x3F); 65146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[4] = 0x80 | (Uint8)(ch & 0x3F); 65246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 5; 65346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 5; 65446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 65546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 6 ) { 65646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 65746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 65846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = 0xFC | (Uint8)((ch >> 30) & 0x01); 65946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = 0x80 | (Uint8)((ch >> 24) & 0x3F); 66046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = 0x80 | (Uint8)((ch >> 18) & 0x3F); 66146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = 0x80 | (Uint8)((ch >> 12) & 0x3F); 66246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[4] = 0x80 | (Uint8)((ch >> 6) & 0x3F); 66346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[5] = 0x80 | (Uint8)(ch & 0x3F); 66446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 6; 66546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 6; 66646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 66746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 66846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 66946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF16BE: /* RFC 2781 */ 67046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 67146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 67246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x10FFFF ) { 67346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 67446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 67546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch < 0x10000 ) { 67646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 2 ) { 67746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 67846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 67946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = (Uint8)(ch >> 8); 68046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = (Uint8)ch; 68146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 2; 68246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 2; 68346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 68446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint16 W1, W2; 68546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 68646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 68746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 68846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = ch - 0x10000; 68946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W1 = 0xD800 | (Uint16)((ch >> 10) & 0x3FF); 69046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W2 = 0xDC00 | (Uint16)(ch & 0x3FF); 69146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = (Uint8)(W1 >> 8); 69246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = (Uint8)W1; 69346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = (Uint8)(W2 >> 8); 69446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = (Uint8)W2; 69546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 69646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 69746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 69846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 69946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 70046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF16LE: /* RFC 2781 */ 70146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 70246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 70346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x10FFFF ) { 70446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 70546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 70646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch < 0x10000 ) { 70746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 2 ) { 70846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 70946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 71046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = (Uint8)(ch >> 8); 71146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = (Uint8)ch; 71246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 2; 71346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 2; 71446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } else { 71546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint16 W1, W2; 71646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 71746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 71846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 71946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = ch - 0x10000; 72046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W1 = 0xD800 | (Uint16)((ch >> 10) & 0x3FF); 72146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner W2 = 0xDC00 | (Uint16)(ch & 0x3FF); 72246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = (Uint8)(W1 >> 8); 72346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = (Uint8)W1; 72446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = (Uint8)(W2 >> 8); 72546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = (Uint8)W2; 72646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 72746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 72846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 72946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 73046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 73146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF32BE: 73246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 73346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 73446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x10FFFF ) { 73546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 73646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 73746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 73846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 73946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 74046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = (Uint8)(ch >> 24); 74146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = (Uint8)(ch >> 16); 74246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = (Uint8)(ch >> 8); 74346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = (Uint8)ch; 74446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 74546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 74646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 74746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 74846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UTF32LE: 74946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 75046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint8 *p = (Uint8 *)dst; 75146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x10FFFF ) { 75246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 75346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 75446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 75546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 75646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 75746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[3] = (Uint8)(ch >> 24); 75846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[2] = (Uint8)(ch >> 16); 75946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[1] = (Uint8)(ch >> 8); 76046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner p[0] = (Uint8)ch; 76146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 76246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 76346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 76446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 76546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UCS2: 76646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 76746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint16 *p = (Uint16 *)dst; 76846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0xFFFF ) { 76946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 77046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 77146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 2 ) { 77246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 77346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 77446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = (Uint16)ch; 77546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 2; 77646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 2; 77746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 77846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 77946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case ENCODING_UCS4: 78046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 78146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner Uint32 *p = (Uint32 *)dst; 78246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( ch > 0x7FFFFFFF ) { 78346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ch = UNKNOWN_UNICODE; 78446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 78546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( dstlen < 4 ) { 78646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return SDL_ICONV_E2BIG; 78746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 78846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *p = ch; 78946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dst += 4; 79046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner dstlen -= 4; 79146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 79246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 79346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 79446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 79546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Update state */ 79646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *inbuf = src; 79746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *inbytesleft = srclen; 79846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *outbuf = dst; 79946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner *outbytesleft = dstlen; 80046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++total; 80146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 80246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return total; 80346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 80446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 80546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerint SDL_iconv_close(SDL_iconv_t cd) 80646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 80746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( cd && cd != (SDL_iconv_t)-1 ) { 80846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_free(cd); 80946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 81046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return 0; 81146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 81246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 81346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner#endif /* !HAVE_ICONV */ 81446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 81546be48730333120a7b939116cef075e61c12c703David 'Digit' Turnerchar *SDL_iconv_string(const char *tocode, const char *fromcode, const char *inbuf, size_t inbytesleft) 81646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner{ 81746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_iconv_t cd; 81846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char *string; 81946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t stringsize; 82046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char *outbuf; 82146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t outbytesleft; 82246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner size_t retCode = 0; 82346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 82446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd = SDL_iconv_open(tocode, fromcode); 82546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( cd == (SDL_iconv_t)-1 ) { 82646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* See if we can recover here (fixes iconv on Solaris 11) */ 82746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !tocode || !*tocode ) { 82846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner tocode = "UTF-8"; 82946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 83046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !fromcode || !*fromcode ) { 83146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner tocode = "UTF-8"; 83246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 83346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner cd = SDL_iconv_open(tocode, fromcode); 83446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 83546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( cd == (SDL_iconv_t)-1 ) { 83646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return NULL; 83746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 83846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 83946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner stringsize = inbytesleft > 4 ? inbytesleft : 4; 84046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner string = SDL_malloc(stringsize); 84146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !string ) { 84246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_iconv_close(cd); 84346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return NULL; 84446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 84546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner outbuf = string; 84646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner outbytesleft = stringsize; 84746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_memset(outbuf, 0, 4); 84846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 84946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner while ( inbytesleft > 0 ) { 85046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner retCode = SDL_iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 85146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner switch (retCode) { 85246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case SDL_ICONV_E2BIG: 85346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner { 85446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner char *oldstring = string; 85546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner stringsize *= 2; 85646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner string = SDL_realloc(string, stringsize); 85746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner if ( !string ) { 85846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_iconv_close(cd); 85946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return NULL; 86046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 86146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner outbuf = string + (outbuf - oldstring); 86246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner outbytesleft = stringsize - (outbuf - string); 86346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_memset(outbuf, 0, 4); 86446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 86546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 86646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case SDL_ICONV_EILSEQ: 86746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* Try skipping some input data - not perfect, but... */ 86846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner ++inbuf; 86946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner --inbytesleft; 87046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 87146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case SDL_ICONV_EINVAL: 87246be48730333120a7b939116cef075e61c12c703David 'Digit' Turner case SDL_ICONV_ERROR: 87346be48730333120a7b939116cef075e61c12c703David 'Digit' Turner /* We can't continue... */ 87446be48730333120a7b939116cef075e61c12c703David 'Digit' Turner inbytesleft = 0; 87546be48730333120a7b939116cef075e61c12c703David 'Digit' Turner break; 87646be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 87746be48730333120a7b939116cef075e61c12c703David 'Digit' Turner } 87846be48730333120a7b939116cef075e61c12c703David 'Digit' Turner SDL_iconv_close(cd); 87946be48730333120a7b939116cef075e61c12c703David 'Digit' Turner 88046be48730333120a7b939116cef075e61c12c703David 'Digit' Turner return string; 88146be48730333120a7b939116cef075e61c12c703David 'Digit' Turner} 882