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