src/stdlib/SDL_iconv.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 21 Apr 2016 03:16:44 -0400
changeset 11729 d1ce8396c356
parent 11491 3c9983546738
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Initial shot at a renderer target for Apple's Metal API.

This isn't complete, but is enough to run testsprite2. It's currently
Mac-only; with a little work to figure out how to properly glue in a Metal
layer to a UIView, this will likely work on iOS, too.

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