LCOV - code coverage report
Current view: top level - glib - win_iconv.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 43.7 % 643 281
Test Date: 2026-08-11 05:12:37 Functions: 71.9 % 32 23
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * iconv library implemented with Win32 API.
       3                 :             :  *
       4                 :             :  * This file is placed in the public domain.
       5                 :             :  *
       6                 :             :  * Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
       7                 :             :  *
       8                 :             :  * If $WINICONV_LIBICONV_DLL environment variable was defined, win_iconv
       9                 :             :  * loads the specified DLL dynamically and uses it.  If loading the DLL
      10                 :             :  * or iconv_open() failed, falls back to internal conversion.
      11                 :             :  * $WINICONV_LIBICONV_DLL is a comma separated list.  The first loadable
      12                 :             :  * DLL is used.  The specified DLL should have iconv_open(),
      13                 :             :  * iconv_close() and iconv() functions.  Or these functions can be
      14                 :             :  * libiconv_open(), libiconv_close() and libiconv().
      15                 :             :  *
      16                 :             :  * Win32 API does not support strict encoding conversion for some
      17                 :             :  * codepage.  And MLang function drop or replace invalid bytes and does
      18                 :             :  * not return useful error status as iconv.  This implementation cannot
      19                 :             :  * be used for encoding validation purpose.
      20                 :             :  */
      21                 :             : 
      22                 :             : /* for WC_NO_BEST_FIT_CHARS */
      23                 :             : #ifndef WINVER
      24                 :             : # define WINVER 0x0500
      25                 :             : #endif
      26                 :             : 
      27                 :             : #ifndef STRICT
      28                 :             : # define STRICT
      29                 :             : #endif
      30                 :             : 
      31                 :             : #include <windows.h>
      32                 :             : #include <errno.h>
      33                 :             : #include <string.h>
      34                 :             : #include <stdlib.h>
      35                 :             : 
      36                 :             : #ifdef __GNUC__
      37                 :             : #define UNUSED __attribute__((unused))
      38                 :             : #else
      39                 :             : #define UNUSED
      40                 :             : #endif
      41                 :             : 
      42                 :             : /* WORKAROUND: */
      43                 :             : #ifndef UNDER_CE
      44                 :             : #define GetProcAddressA GetProcAddress
      45                 :             : #endif
      46                 :             : 
      47                 :             : #if 0
      48                 :             : # define MAKE_EXE
      49                 :             : # define MAKE_DLL
      50                 :             : # define USE_LIBICONV_DLL
      51                 :             : #endif
      52                 :             : 
      53                 :             : #if !defined(DEFAULT_LIBICONV_DLL)
      54                 :             : # define DEFAULT_LIBICONV_DLL ""
      55                 :             : #endif
      56                 :             : 
      57                 :             : #define MB_CHAR_MAX 16
      58                 :             : 
      59                 :             : #define UNICODE_MODE_BOM_DONE   1
      60                 :             : #define UNICODE_MODE_SWAPPED    2
      61                 :             : 
      62                 :             : #define FLAG_USE_BOM            1
      63                 :             : #define FLAG_TRANSLIT           2 /* //TRANSLIT */
      64                 :             : #define FLAG_IGNORE             4 /* //IGNORE */
      65                 :             : 
      66                 :             : typedef unsigned char uchar;
      67                 :             : typedef unsigned short ushort;
      68                 :             : typedef unsigned int uint;
      69                 :             : 
      70                 :             : typedef void* iconv_t;
      71                 :             : 
      72                 :             : iconv_t iconv_open(const char *tocode, const char *fromcode);
      73                 :             : int iconv_close(iconv_t cd);
      74                 :             : size_t iconv(iconv_t cd, /* const */ char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
      75                 :             : 
      76                 :             : /* libiconv interface for vim */
      77                 :             : #if defined(MAKE_DLL)
      78                 :             : int
      79                 :             : iconvctl (iconv_t cd, int request, void* argument)
      80                 :             : {
      81                 :             :     /* not supported */
      82                 :             :     return 0;
      83                 :             : }
      84                 :             : #endif
      85                 :             : 
      86                 :             : typedef struct compat_t compat_t;
      87                 :             : typedef struct csconv_t csconv_t;
      88                 :             : typedef struct rec_iconv_t rec_iconv_t;
      89                 :             : 
      90                 :             : typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);
      91                 :             : typedef int (*f_iconv_close)(iconv_t cd);
      92                 :             : typedef size_t (*f_iconv)(iconv_t cd, /* const */ char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
      93                 :             : typedef int* (*f_errno)(void);
      94                 :             : typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
      95                 :             : typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
      96                 :             : typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
      97                 :             : typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
      98                 :             : 
      99                 :             : #define COMPAT_IN   1
     100                 :             : #define COMPAT_OUT  2
     101                 :             : 
     102                 :             : /* unicode mapping for compatibility with other conversion table. */
     103                 :             : struct compat_t {
     104                 :             :     uint in;
     105                 :             :     uint out;
     106                 :             :     uint flag;
     107                 :             : };
     108                 :             : 
     109                 :             : struct csconv_t {
     110                 :             :     int codepage;
     111                 :             :     int flags;
     112                 :             :     f_mbtowc mbtowc;
     113                 :             :     f_wctomb wctomb;
     114                 :             :     f_mblen mblen;
     115                 :             :     f_flush flush;
     116                 :             :     DWORD mode;
     117                 :             :     compat_t *compat;
     118                 :             : };
     119                 :             : 
     120                 :             : struct rec_iconv_t {
     121                 :             :     iconv_t cd;
     122                 :             :     f_iconv_close iconv_close;
     123                 :             :     f_iconv iconv;
     124                 :             :     f_errno _errno;
     125                 :             :     csconv_t from;
     126                 :             :     csconv_t to;
     127                 :             : #if defined(USE_LIBICONV_DLL)
     128                 :             :     HMODULE hlibiconv;
     129                 :             : #endif
     130                 :             : };
     131                 :             : 
     132                 :             : static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
     133                 :             : static int win_iconv_close(iconv_t cd);
     134                 :             : static size_t win_iconv(iconv_t cd, /* const */ char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
     135                 :             : 
     136                 :             : static int load_mlang(void);
     137                 :             : static int make_csconv(const char *name, csconv_t *cv);
     138                 :             : static int name_to_codepage(const char *name);
     139                 :             : static uint utf16_to_ucs4(const ushort *wbuf);
     140                 :             : static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
     141                 :             : static int mbtowc_flags(int codepage);
     142                 :             : static int must_use_null_useddefaultchar(int codepage);
     143                 :             : static char *strrstr(const char *str, const char *token);
     144                 :             : static char *xstrndup(const char *s, size_t n);
     145                 :             : static int seterror(int err);
     146                 :             : 
     147                 :             : #if defined(USE_LIBICONV_DLL)
     148                 :             : static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
     149                 :             : static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
     150                 :             : static FARPROC find_imported_function(HMODULE hModule, const char *funcname);
     151                 :             : 
     152                 :             : static HMODULE hwiniconv;
     153                 :             : #endif
     154                 :             : 
     155                 :             : static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
     156                 :             : static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
     157                 :             : static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
     158                 :             : static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
     159                 :             : static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
     160                 :             : 
     161                 :             : static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
     162                 :             : static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
     163                 :             : static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
     164                 :             : static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
     165                 :             : static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
     166                 :             : static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
     167                 :             : static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
     168                 :             : static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
     169                 :             : static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
     170                 :             : static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
     171                 :             : static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
     172                 :             : 
     173                 :             : static struct {
     174                 :             :     int codepage;
     175                 :             :     const char *name;
     176                 :             : } codepage_alias[] = {
     177                 :             :     {65001, "CP65001"},
     178                 :             :     {65001, "UTF8"},
     179                 :             :     {65001, "UTF-8"},
     180                 :             : 
     181                 :             :     {1200, "CP1200"},
     182                 :             :     {1200, "UTF16LE"},
     183                 :             :     {1200, "UTF-16LE"},
     184                 :             :     {1200, "UCS2LE"},
     185                 :             :     {1200, "UCS-2LE"},
     186                 :             : 
     187                 :             :     {1201, "CP1201"},
     188                 :             :     {1201, "UTF16BE"},
     189                 :             :     {1201, "UTF-16BE"},
     190                 :             :     {1201, "UCS2BE"},
     191                 :             :     {1201, "UCS-2BE"},
     192                 :             :     {1201, "unicodeFFFE"},
     193                 :             : 
     194                 :             :     {12000, "CP12000"},
     195                 :             :     {12000, "UTF32LE"},
     196                 :             :     {12000, "UTF-32LE"},
     197                 :             :     {12000, "UCS4LE"},
     198                 :             :     {12000, "UCS-4LE"},
     199                 :             : 
     200                 :             :     {12001, "CP12001"},
     201                 :             :     {12001, "UTF32BE"},
     202                 :             :     {12001, "UTF-32BE"},
     203                 :             :     {12001, "UCS4BE"},
     204                 :             :     {12001, "UCS-4BE"},
     205                 :             : 
     206                 :             : #ifndef GLIB_COMPILATION
     207                 :             :     /*
     208                 :             :      * Default is big endian.
     209                 :             :      * See rfc2781 4.3 Interpreting text labelled as UTF-16.
     210                 :             :      */
     211                 :             :     {1201, "UTF16"},
     212                 :             :     {1201, "UTF-16"},
     213                 :             :     {1201, "UCS2"},
     214                 :             :     {1201, "UCS-2"},
     215                 :             :     {12001, "UTF32"},
     216                 :             :     {12001, "UTF-32"},
     217                 :             :     {12001, "UCS-4"},
     218                 :             :     {12001, "UCS4"},
     219                 :             : #else
     220                 :             :     /* Default is little endian, because the platform is */
     221                 :             :     {1200, "UTF16"},
     222                 :             :     {1200, "UTF-16"},
     223                 :             :     {1200, "UCS2"},
     224                 :             :     {1200, "UCS-2"},
     225                 :             :     {12000, "UTF32"},
     226                 :             :     {12000, "UTF-32"},
     227                 :             :     {12000, "UCS4"},
     228                 :             :     {12000, "UCS-4"},
     229                 :             : #endif
     230                 :             : 
     231                 :             :     /* copy from libiconv `iconv -l` */
     232                 :             :     /* !IsValidCodePage(367) */
     233                 :             :     {20127, "ANSI_X3.4-1968"},
     234                 :             :     {20127, "ANSI_X3.4-1986"},
     235                 :             :     {20127, "ASCII"},
     236                 :             :     {20127, "CP367"},
     237                 :             :     {20127, "IBM367"},
     238                 :             :     {20127, "ISO-IR-6"},
     239                 :             :     {20127, "ISO646-US"},
     240                 :             :     {20127, "ISO_646.IRV:1991"},
     241                 :             :     {20127, "US"},
     242                 :             :     {20127, "US-ASCII"},
     243                 :             :     {20127, "CSASCII"},
     244                 :             : 
     245                 :             :     /* !IsValidCodePage(819) */
     246                 :             :     {1252, "CP819"},
     247                 :             :     {1252, "IBM819"},
     248                 :             :     {28591, "ISO-8859-1"},
     249                 :             :     {28591, "ISO-IR-100"},
     250                 :             :     {28591, "ISO8859-1"},
     251                 :             :     {28591, "ISO_8859-1"},
     252                 :             :     {28591, "ISO_8859-1:1987"},
     253                 :             :     {28591, "L1"},
     254                 :             :     {28591, "LATIN1"},
     255                 :             :     {28591, "CSISOLATIN1"},
     256                 :             : 
     257                 :             :     {1250, "CP1250"},
     258                 :             :     {1250, "MS-EE"},
     259                 :             :     {1250, "WINDOWS-1250"},
     260                 :             : 
     261                 :             :     {1251, "CP1251"},
     262                 :             :     {1251, "MS-CYRL"},
     263                 :             :     {1251, "WINDOWS-1251"},
     264                 :             : 
     265                 :             :     {1252, "CP1252"},
     266                 :             :     {1252, "MS-ANSI"},
     267                 :             :     {1252, "WINDOWS-1252"},
     268                 :             : 
     269                 :             :     {1253, "CP1253"},
     270                 :             :     {1253, "MS-GREEK"},
     271                 :             :     {1253, "WINDOWS-1253"},
     272                 :             : 
     273                 :             :     {1254, "CP1254"},
     274                 :             :     {1254, "MS-TURK"},
     275                 :             :     {1254, "WINDOWS-1254"},
     276                 :             : 
     277                 :             :     {1255, "CP1255"},
     278                 :             :     {1255, "MS-HEBR"},
     279                 :             :     {1255, "WINDOWS-1255"},
     280                 :             : 
     281                 :             :     {1256, "CP1256"},
     282                 :             :     {1256, "MS-ARAB"},
     283                 :             :     {1256, "WINDOWS-1256"},
     284                 :             : 
     285                 :             :     {1257, "CP1257"},
     286                 :             :     {1257, "WINBALTRIM"},
     287                 :             :     {1257, "WINDOWS-1257"},
     288                 :             : 
     289                 :             :     {1258, "CP1258"},
     290                 :             :     {1258, "WINDOWS-1258"},
     291                 :             : 
     292                 :             :     {850, "850"},
     293                 :             :     {850, "CP850"},
     294                 :             :     {850, "IBM850"},
     295                 :             :     {850, "CSPC850MULTILINGUAL"},
     296                 :             : 
     297                 :             :     /* !IsValidCodePage(862) */
     298                 :             :     {862, "862"},
     299                 :             :     {862, "CP862"},
     300                 :             :     {862, "IBM862"},
     301                 :             :     {862, "CSPC862LATINHEBREW"},
     302                 :             : 
     303                 :             :     {866, "866"},
     304                 :             :     {866, "CP866"},
     305                 :             :     {866, "IBM866"},
     306                 :             :     {866, "CSIBM866"},
     307                 :             : 
     308                 :             :     /* !IsValidCodePage(154) */
     309                 :             :     {154, "CP154"},
     310                 :             :     {154, "CYRILLIC-ASIAN"},
     311                 :             :     {154, "PT154"},
     312                 :             :     {154, "PTCP154"},
     313                 :             :     {154, "CSPTCP154"},
     314                 :             : 
     315                 :             :     /* !IsValidCodePage(1133) */
     316                 :             :     {1133, "CP1133"},
     317                 :             :     {1133, "IBM-CP1133"},
     318                 :             : 
     319                 :             :     {874, "CP874"},
     320                 :             :     {874, "WINDOWS-874"},
     321                 :             : 
     322                 :             :     /* !IsValidCodePage(51932) */
     323                 :             :     {51932, "CP51932"},
     324                 :             :     {51932, "MS51932"},
     325                 :             :     {51932, "WINDOWS-51932"},
     326                 :             :     {51932, "EUC-JP"},
     327                 :             : 
     328                 :             :     {932, "CP932"},
     329                 :             :     {932, "MS932"},
     330                 :             :     {932, "SHIFFT_JIS"},
     331                 :             :     {932, "SHIFFT_JIS-MS"},
     332                 :             :     {932, "SJIS"},
     333                 :             :     {932, "SJIS-MS"},
     334                 :             :     {932, "SJIS-OPEN"},
     335                 :             :     {932, "SJIS-WIN"},
     336                 :             :     {932, "WINDOWS-31J"},
     337                 :             :     {932, "WINDOWS-932"},
     338                 :             :     {932, "CSWINDOWS31J"},
     339                 :             : 
     340                 :             :     {50221, "CP50221"},
     341                 :             :     {50221, "ISO-2022-JP"},
     342                 :             :     {50221, "ISO-2022-JP-MS"},
     343                 :             :     {50221, "ISO2022-JP"},
     344                 :             :     {50221, "ISO2022-JP-MS"},
     345                 :             :     {50221, "MS50221"},
     346                 :             :     {50221, "WINDOWS-50221"},
     347                 :             : 
     348                 :             :     {936, "CP936"},
     349                 :             :     {936, "GBK"},
     350                 :             :     {936, "MS936"},
     351                 :             :     {936, "WINDOWS-936"},
     352                 :             : 
     353                 :             :     {950, "CP950"},
     354                 :             :     {950, "BIG5"},
     355                 :             :     {950, "BIG5HKSCS"},
     356                 :             :     {950, "BIG5-HKSCS"},
     357                 :             : 
     358                 :             :     {949, "CP949"},
     359                 :             :     {949, "UHC"},
     360                 :             :     {949, "EUC-KR"},
     361                 :             : 
     362                 :             :     {1361, "CP1361"},
     363                 :             :     {1361, "JOHAB"},
     364                 :             : 
     365                 :             :     {437, "437"},
     366                 :             :     {437, "CP437"},
     367                 :             :     {437, "IBM437"},
     368                 :             :     {437, "CSPC8CODEPAGE437"},
     369                 :             : 
     370                 :             :     {737, "CP737"},
     371                 :             : 
     372                 :             :     {775, "CP775"},
     373                 :             :     {775, "IBM775"},
     374                 :             :     {775, "CSPC775BALTIC"},
     375                 :             : 
     376                 :             :     {852, "852"},
     377                 :             :     {852, "CP852"},
     378                 :             :     {852, "IBM852"},
     379                 :             :     {852, "CSPCP852"},
     380                 :             : 
     381                 :             :     /* !IsValidCodePage(853) */
     382                 :             :     {853, "CP853"},
     383                 :             : 
     384                 :             :     {855, "855"},
     385                 :             :     {855, "CP855"},
     386                 :             :     {855, "IBM855"},
     387                 :             :     {855, "CSIBM855"},
     388                 :             : 
     389                 :             :     {857, "857"},
     390                 :             :     {857, "CP857"},
     391                 :             :     {857, "IBM857"},
     392                 :             :     {857, "CSIBM857"},
     393                 :             : 
     394                 :             :     /* !IsValidCodePage(858) */
     395                 :             :     {858, "CP858"},
     396                 :             : 
     397                 :             :     {860, "860"},
     398                 :             :     {860, "CP860"},
     399                 :             :     {860, "IBM860"},
     400                 :             :     {860, "CSIBM860"},
     401                 :             : 
     402                 :             :     {861, "861"},
     403                 :             :     {861, "CP-IS"},
     404                 :             :     {861, "CP861"},
     405                 :             :     {861, "IBM861"},
     406                 :             :     {861, "CSIBM861"},
     407                 :             : 
     408                 :             :     {863, "863"},
     409                 :             :     {863, "CP863"},
     410                 :             :     {863, "IBM863"},
     411                 :             :     {863, "CSIBM863"},
     412                 :             : 
     413                 :             :     {864, "CP864"},
     414                 :             :     {864, "IBM864"},
     415                 :             :     {864, "CSIBM864"},
     416                 :             : 
     417                 :             :     {865, "865"},
     418                 :             :     {865, "CP865"},
     419                 :             :     {865, "IBM865"},
     420                 :             :     {865, "CSIBM865"},
     421                 :             : 
     422                 :             :     {869, "869"},
     423                 :             :     {869, "CP-GR"},
     424                 :             :     {869, "CP869"},
     425                 :             :     {869, "IBM869"},
     426                 :             :     {869, "CSIBM869"},
     427                 :             : 
     428                 :             :     /* !IsValidCodePage(1152) */
     429                 :             :     {1125, "CP1125"},
     430                 :             : 
     431                 :             :     /*
     432                 :             :      * Code Page Identifiers
     433                 :             :      * http://msdn2.microsoft.com/en-us/library/ms776446.aspx
     434                 :             :      */
     435                 :             :     {37, "IBM037"}, /* IBM EBCDIC US-Canada */
     436                 :             :     {437, "IBM437"}, /* OEM United States */
     437                 :             :     {500, "IBM500"}, /* IBM EBCDIC International */
     438                 :             :     {708, "ASMO-708"}, /* Arabic (ASMO 708) */
     439                 :             :     /* 709              Arabic (ASMO-449+, BCON V4) */
     440                 :             :     /* 710              Arabic - Transparent Arabic */
     441                 :             :     {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */
     442                 :             :     {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */
     443                 :             :     {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */
     444                 :             :     {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */
     445                 :             :     {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */
     446                 :             :     {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */
     447                 :             :     {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */
     448                 :             :     {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */
     449                 :             :     {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */
     450                 :             :     {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */
     451                 :             :     {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */
     452                 :             :     {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */
     453                 :             :     {864, "IBM864"}, /* OEM Arabic; Arabic (864) */
     454                 :             :     {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */
     455                 :             :     {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */
     456                 :             :     {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */
     457                 :             :     {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */
     458                 :             :     {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */
     459                 :             :     {875, "cp875"}, /* IBM EBCDIC Greek Modern */
     460                 :             :     {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */
     461                 :             :     {932, "shift-jis"}, /* alternative name for it */
     462                 :             :     {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */
     463                 :             :     {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */
     464                 :             :     {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */
     465                 :             :     {950, "big5hkscs"}, /* ANSI/OEM Traditional Chinese (Hong Kong SAR); Chinese Traditional (Big5-HKSCS) */
     466                 :             :     {950, "big5-hkscs"}, /* alternative name for it */
     467                 :             :     {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */
     468                 :             :     {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */
     469                 :             :     {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */
     470                 :             :     {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */
     471                 :             :     {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */
     472                 :             :     {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */
     473                 :             :     {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */
     474                 :             :     {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */
     475                 :             :     {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */
     476                 :             :     {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */
     477                 :             :     {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */
     478                 :             :     {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */
     479                 :             :     {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */
     480                 :             :     {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */
     481                 :             :     {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */
     482                 :             :     {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */
     483                 :             :     {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */
     484                 :             :     {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */
     485                 :             :     {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */
     486                 :             :     {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */
     487                 :             :     {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */
     488                 :             :     {1361, "Johab"}, /* Korean (Johab) */
     489                 :             :     {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */
     490                 :             :     {10001, "x-mac-japanese"}, /* Japanese (Mac) */
     491                 :             :     {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */
     492                 :             :     {10003, "x-mac-korean"}, /* Korean (Mac) */
     493                 :             :     {10004, "x-mac-arabic"}, /* Arabic (Mac) */
     494                 :             :     {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */
     495                 :             :     {10006, "x-mac-greek"}, /* Greek (Mac) */
     496                 :             :     {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */
     497                 :             :     {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */
     498                 :             :     {10010, "x-mac-romanian"}, /* Romanian (Mac) */
     499                 :             :     {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */
     500                 :             :     {10021, "x-mac-thai"}, /* Thai (Mac) */
     501                 :             :     {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */
     502                 :             :     {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */
     503                 :             :     {10081, "x-mac-turkish"}, /* Turkish (Mac) */
     504                 :             :     {10082, "x-mac-croatian"}, /* Croatian (Mac) */
     505                 :             :     {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */
     506                 :             :     {20001, "x-cp20001"}, /* TCA Taiwan */
     507                 :             :     {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */
     508                 :             :     {20003, "x-cp20003"}, /* IBM5550 Taiwan */
     509                 :             :     {20004, "x-cp20004"}, /* TeleText Taiwan */
     510                 :             :     {20005, "x-cp20005"}, /* Wang Taiwan */
     511                 :             :     {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */
     512                 :             :     {20106, "x-IA5-German"}, /* IA5 German (7-bit) */
     513                 :             :     {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */
     514                 :             :     {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */
     515                 :             :     {20127, "us-ascii"}, /* US-ASCII (7-bit) */
     516                 :             :     {20261, "x-cp20261"}, /* T.61 */
     517                 :             :     {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */
     518                 :             :     {20273, "IBM273"}, /* IBM EBCDIC Germany */
     519                 :             :     {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */
     520                 :             :     {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */
     521                 :             :     {20280, "IBM280"}, /* IBM EBCDIC Italy */
     522                 :             :     {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */
     523                 :             :     {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */
     524                 :             :     {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */
     525                 :             :     {20297, "IBM297"}, /* IBM EBCDIC France */
     526                 :             :     {20420, "IBM420"}, /* IBM EBCDIC Arabic */
     527                 :             :     {20423, "IBM423"}, /* IBM EBCDIC Greek */
     528                 :             :     {20424, "IBM424"}, /* IBM EBCDIC Hebrew */
     529                 :             :     {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */
     530                 :             :     {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */
     531                 :             :     {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */
     532                 :             :     {20871, "IBM871"}, /* IBM EBCDIC Icelandic */
     533                 :             :     {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */
     534                 :             :     {20905, "IBM905"}, /* IBM EBCDIC Turkish */
     535                 :             :     {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */
     536                 :             :     {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */
     537                 :             :     {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */
     538                 :             :     {20949, "x-cp20949"}, /* Korean Wansung */
     539                 :             :     {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */
     540                 :             :     /* 21027            (deprecated) */
     541                 :             :     {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */
     542                 :             :     {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
     543                 :             :     {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
     544                 :             :     {28591, "iso_8859-1"},
     545                 :             :     {28591, "iso_8859_1"},
     546                 :             :     {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
     547                 :             :     {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
     548                 :             :     {28592, "iso_8859-2"},
     549                 :             :     {28592, "iso_8859_2"},
     550                 :             :     {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */
     551                 :             :     {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */
     552                 :             :     {28593, "iso_8859-3"},
     553                 :             :     {28593, "iso_8859_3"},
     554                 :             :     {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */
     555                 :             :     {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */
     556                 :             :     {28594, "iso_8859-4"},
     557                 :             :     {28594, "iso_8859_4"},
     558                 :             :     {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */
     559                 :             :     {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */
     560                 :             :     {28595, "iso_8859-5"},
     561                 :             :     {28595, "iso_8859_5"},
     562                 :             :     {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */
     563                 :             :     {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */
     564                 :             :     {28596, "iso_8859-6"},
     565                 :             :     {28596, "iso_8859_6"},
     566                 :             :     {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */
     567                 :             :     {28597, "iso8859-7"}, /* ISO 8859-7 Greek */
     568                 :             :     {28597, "iso_8859-7"},
     569                 :             :     {28597, "iso_8859_7"},
     570                 :             :     {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
     571                 :             :     {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
     572                 :             :     {28598, "iso_8859-8"},
     573                 :             :     {28598, "iso_8859_8"},
     574                 :             :     {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */
     575                 :             :     {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */
     576                 :             :     {28599, "iso_8859-9"},
     577                 :             :     {28599, "iso_8859_9"},
     578                 :             :     {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */
     579                 :             :     {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */
     580                 :             :     {28603, "iso_8859-13"},
     581                 :             :     {28603, "iso_8859_13"},
     582                 :             :     {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */
     583                 :             :     {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */
     584                 :             :     {28605, "iso_8859-15"},
     585                 :             :     {28605, "iso_8859_15"},
     586                 :             :     {29001, "x-Europa"}, /* Europa 3 */
     587                 :             :     {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
     588                 :             :     {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
     589                 :             :     {38598, "iso_8859-8-i"},
     590                 :             :     {38598, "iso_8859_8-i"},
     591                 :             :     {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */
     592                 :             :     {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */
     593                 :             :     {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */
     594                 :             :     {50225, "iso-2022-kr"}, /* ISO 2022 Korean */
     595                 :             :     {50225, "iso2022-kr"}, /* ISO 2022 Korean */
     596                 :             :     {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */
     597                 :             :     /* 50229            ISO 2022 Traditional Chinese */
     598                 :             :     /* 50930            EBCDIC Japanese (Katakana) Extended */
     599                 :             :     /* 50931            EBCDIC US-Canada and Japanese */
     600                 :             :     /* 50933            EBCDIC Korean Extended and Korean */
     601                 :             :     /* 50935            EBCDIC Simplified Chinese Extended and Simplified Chinese */
     602                 :             :     /* 50936            EBCDIC Simplified Chinese */
     603                 :             :     /* 50937            EBCDIC US-Canada and Traditional Chinese */
     604                 :             :     /* 50939            EBCDIC Japanese (Latin) Extended and Japanese */
     605                 :             :     {51932, "euc-jp"}, /* EUC Japanese */
     606                 :             :     {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */
     607                 :             :     {51949, "euc-kr"}, /* EUC Korean */
     608                 :             :     /* 51950            EUC Traditional Chinese */
     609                 :             :     {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */
     610                 :             :     {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */
     611                 :             :     {57002, "x-iscii-de"}, /* ISCII Devanagari */
     612                 :             :     {57003, "x-iscii-be"}, /* ISCII Bengali */
     613                 :             :     {57004, "x-iscii-ta"}, /* ISCII Tamil */
     614                 :             :     {57005, "x-iscii-te"}, /* ISCII Telugu */
     615                 :             :     {57006, "x-iscii-as"}, /* ISCII Assamese */
     616                 :             :     {57007, "x-iscii-or"}, /* ISCII Oriya */
     617                 :             :     {57008, "x-iscii-ka"}, /* ISCII Kannada */
     618                 :             :     {57009, "x-iscii-ma"}, /* ISCII Malayalam */
     619                 :             :     {57010, "x-iscii-gu"}, /* ISCII Gujarati */
     620                 :             :     {57011, "x-iscii-pa"}, /* ISCII Punjabi */
     621                 :             : 
     622                 :             :     {0, NULL}
     623                 :             : };
     624                 :             : 
     625                 :             : /*
     626                 :             :  * SJIS SHIFTJIS table              CP932 table
     627                 :             :  * ---- --------------------------- --------------------------------
     628                 :             :  *   5C U+00A5 YEN SIGN             U+005C REVERSE SOLIDUS
     629                 :             :  *   7E U+203E OVERLINE             U+007E TILDE
     630                 :             :  * 815C U+2014 EM DASH              U+2015 HORIZONTAL BAR
     631                 :             :  * 815F U+005C REVERSE SOLIDUS      U+FF3C FULLWIDTH REVERSE SOLIDUS
     632                 :             :  * 8160 U+301C WAVE DASH            U+FF5E FULLWIDTH TILDE
     633                 :             :  * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
     634                 :             :  * 817C U+2212 MINUS SIGN           U+FF0D FULLWIDTH HYPHEN-MINUS
     635                 :             :  * 8191 U+00A2 CENT SIGN            U+FFE0 FULLWIDTH CENT SIGN
     636                 :             :  * 8192 U+00A3 POUND SIGN           U+FFE1 FULLWIDTH POUND SIGN
     637                 :             :  * 81CA U+00AC NOT SIGN             U+FFE2 FULLWIDTH NOT SIGN
     638                 :             :  *
     639                 :             :  * EUC-JP and ISO-2022-JP should be compatible with CP932.
     640                 :             :  *
     641                 :             :  * Kernel and MLang have different Unicode mapping table.  Make sure
     642                 :             :  * which API is used.
     643                 :             :  */
     644                 :             : static compat_t cp932_compat[] = {
     645                 :             :     {0x00A5, 0x005C, COMPAT_OUT},
     646                 :             :     {0x203E, 0x007E, COMPAT_OUT},
     647                 :             :     {0x2014, 0x2015, COMPAT_OUT},
     648                 :             :     {0x301C, 0xFF5E, COMPAT_OUT},
     649                 :             :     {0x2016, 0x2225, COMPAT_OUT},
     650                 :             :     {0x2212, 0xFF0D, COMPAT_OUT},
     651                 :             :     {0x00A2, 0xFFE0, COMPAT_OUT},
     652                 :             :     {0x00A3, 0xFFE1, COMPAT_OUT},
     653                 :             :     {0x00AC, 0xFFE2, COMPAT_OUT},
     654                 :             :     {0, 0, 0}
     655                 :             : };
     656                 :             : 
     657                 :             : static compat_t cp20932_compat[] = {
     658                 :             :     {0x00A5, 0x005C, COMPAT_OUT},
     659                 :             :     {0x203E, 0x007E, COMPAT_OUT},
     660                 :             :     {0x2014, 0x2015, COMPAT_OUT},
     661                 :             :     {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
     662                 :             :     {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
     663                 :             :     {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
     664                 :             :     {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
     665                 :             :     {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
     666                 :             :     {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
     667                 :             :     {0, 0, 0}
     668                 :             : };
     669                 :             : 
     670                 :             : static compat_t *cp51932_compat = cp932_compat;
     671                 :             : 
     672                 :             : /* cp20932_compat for kernel.  cp932_compat for mlang. */
     673                 :             : static compat_t *cp5022x_compat = cp932_compat;
     674                 :             : 
     675                 :             : typedef HRESULT (WINAPI *CONVERTINETSTRING)(
     676                 :             :     LPDWORD lpdwMode,
     677                 :             :     DWORD dwSrcEncoding,
     678                 :             :     DWORD dwDstEncoding,
     679                 :             :     LPCSTR lpSrcStr,
     680                 :             :     LPINT lpnSrcSize,
     681                 :             :     LPBYTE lpDstStr,
     682                 :             :     LPINT lpnDstSize
     683                 :             : );
     684                 :             : typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
     685                 :             :     LPDWORD lpdwMode,
     686                 :             :     DWORD dwSrcEncoding,
     687                 :             :     LPCSTR lpSrcStr,
     688                 :             :     LPINT lpnMultiCharCount,
     689                 :             :     LPWSTR lpDstStr,
     690                 :             :     LPINT lpnWideCharCount
     691                 :             : );
     692                 :             : typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
     693                 :             :     LPDWORD lpdwMode,
     694                 :             :     DWORD dwEncoding,
     695                 :             :     LPCWSTR lpSrcStr,
     696                 :             :     LPINT lpnWideCharCount,
     697                 :             :     LPSTR lpDstStr,
     698                 :             :     LPINT lpnMultiCharCount
     699                 :             : );
     700                 :             : typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(
     701                 :             :     DWORD dwSrcEncoding,
     702                 :             :     DWORD dwDstEncoding
     703                 :             : );
     704                 :             : typedef HRESULT (WINAPI *LCIDTORFC1766A)(
     705                 :             :     LCID Locale,
     706                 :             :     LPSTR pszRfc1766,
     707                 :             :     int nChar
     708                 :             : );
     709                 :             : typedef HRESULT (WINAPI *LCIDTORFC1766W)(
     710                 :             :     LCID Locale,
     711                 :             :     LPWSTR pszRfc1766,
     712                 :             :     int nChar
     713                 :             : );
     714                 :             : typedef HRESULT (WINAPI *RFC1766TOLCIDA)(
     715                 :             :     LCID *pLocale,
     716                 :             :     LPSTR pszRfc1766
     717                 :             : );
     718                 :             : typedef HRESULT (WINAPI *RFC1766TOLCIDW)(
     719                 :             :     LCID *pLocale,
     720                 :             :     LPWSTR pszRfc1766
     721                 :             : );
     722                 :             : static CONVERTINETSTRING ConvertINetString;
     723                 :             : static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
     724                 :             : static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
     725                 :             : static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;
     726                 :             : static LCIDTORFC1766A LcidToRfc1766A;
     727                 :             : static RFC1766TOLCIDA Rfc1766ToLcidA;
     728                 :             : 
     729                 :             : static int
     730                 :           1 : load_mlang(void)
     731                 :             : {
     732                 :             :     HMODULE h;
     733                 :           1 :     if (ConvertINetString != NULL)
     734                 :           0 :         return TRUE;
     735                 :           1 :     h = LoadLibrary(TEXT("mlang.dll"));
     736                 :           1 :     if (!h)
     737                 :           0 :         return FALSE;
     738                 :           1 :     ConvertINetString = (CONVERTINETSTRING)GetProcAddressA(h, "ConvertINetString");
     739                 :           1 :     ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddressA(h, "ConvertINetMultiByteToUnicode");
     740                 :           1 :     ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddressA(h, "ConvertINetUnicodeToMultiByte");
     741                 :           1 :     IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddressA(h, "IsConvertINetStringAvailable");
     742                 :           1 :     LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddressA(h, "LcidToRfc1766A");
     743                 :           1 :     Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddressA(h, "Rfc1766ToLcidA");
     744                 :           1 :     return TRUE;
     745                 :           1 : }
     746                 :             : 
     747                 :             : iconv_t
     748                 :       14678 : iconv_open(const char *tocode, const char *fromcode)
     749                 :             : {
     750                 :             :     rec_iconv_t *cd;
     751                 :             : 
     752                 :       14678 :     cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));
     753                 :       14678 :     if (cd == NULL)
     754                 :           0 :         return (iconv_t)(-1);
     755                 :             : 
     756                 :             : #if defined(USE_LIBICONV_DLL)
     757                 :             :     errno = 0;
     758                 :             :     if (libiconv_iconv_open(cd, tocode, fromcode))
     759                 :             :         return (iconv_t)cd;
     760                 :             : #endif
     761                 :             : 
     762                 :             :     /* reset the errno to prevent reporting wrong error code.
     763                 :             :      * 0 for unsorted error. */
     764                 :       14678 :     errno = 0;
     765                 :       14678 :     if (win_iconv_open(cd, tocode, fromcode))
     766                 :       14677 :         return (iconv_t)cd;
     767                 :             : 
     768                 :           1 :     free(cd);
     769                 :             : 
     770                 :           1 :     return (iconv_t)(-1);
     771                 :       14678 : }
     772                 :             : 
     773                 :             : int
     774                 :       14676 : iconv_close(iconv_t _cd)
     775                 :             : {
     776                 :       14676 :     rec_iconv_t *cd = (rec_iconv_t *)_cd;
     777                 :       14676 :     int r = cd->iconv_close(cd->cd);
     778                 :       14676 :     int e = *(cd->_errno());
     779                 :             : #if defined(USE_LIBICONV_DLL)
     780                 :             :     if (cd->hlibiconv != NULL)
     781                 :             :         FreeLibrary(cd->hlibiconv);
     782                 :             : #endif
     783                 :       14676 :     free(cd);
     784                 :       14676 :     errno = e;
     785                 :       14676 :     return r;
     786                 :             : }
     787                 :             : 
     788                 :             : size_t
     789                 :       29361 : iconv(iconv_t _cd, /* const */ char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
     790                 :             : {
     791                 :       29361 :     rec_iconv_t *cd = (rec_iconv_t *)_cd;
     792                 :       29361 :     size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
     793                 :       29361 :     errno = *(cd->_errno());
     794                 :       29361 :     return r;
     795                 :             : }
     796                 :             : 
     797                 :             : static int
     798                 :       14678 : win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
     799                 :             : {
     800                 :       14678 :     if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))
     801                 :           1 :         return FALSE;
     802                 :       14677 :     cd->iconv_close = win_iconv_close;
     803                 :       14677 :     cd->iconv = win_iconv;
     804                 :       14677 :     cd->_errno = _errno;
     805                 :       14677 :     cd->cd = (iconv_t)cd;
     806                 :       14677 :     return TRUE;
     807                 :       14678 : }
     808                 :             : 
     809                 :             : static int
     810                 :       14676 : win_iconv_close(iconv_t cd UNUSED)
     811                 :             : {
     812                 :       14676 :     return 0;
     813                 :             : }
     814                 :             : 
     815                 :             : static size_t
     816                 :       29360 : win_iconv(iconv_t _cd, /* const */ char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
     817                 :             : {
     818                 :       29360 :     rec_iconv_t *cd = (rec_iconv_t *)_cd;
     819                 :             :     ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
     820                 :             :     int insize;
     821                 :             :     int outsize;
     822                 :             :     int wsize;
     823                 :             :     DWORD frommode;
     824                 :             :     DWORD tomode;
     825                 :             :     uint wc;
     826                 :             :     compat_t *cp;
     827                 :             :     int i;
     828                 :             : 
     829                 :       29360 :     if (inbuf == NULL || *inbuf == NULL)
     830                 :             :     {
     831                 :       14673 :         if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
     832                 :             :         {
     833                 :           0 :             tomode = cd->to.mode;
     834                 :           0 :             outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
     835                 :           0 :             if (outsize == -1)
     836                 :             :             {
     837                 :           0 :                 if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
     838                 :             :                 {
     839                 :           0 :                     outsize = 0;
     840                 :           0 :                 }
     841                 :             :                 else
     842                 :             :                 {
     843                 :           0 :                     cd->to.mode = tomode;
     844                 :           0 :                     return (size_t)(-1);
     845                 :             :                 }
     846                 :           0 :             }
     847                 :           0 :             *outbuf += outsize;
     848                 :           0 :             *outbytesleft -= outsize;
     849                 :           0 :         }
     850                 :       14673 :         cd->from.mode = 0;
     851                 :       14673 :         cd->to.mode = 0;
     852                 :       14673 :         return 0;
     853                 :             :     }
     854                 :             : 
     855                 :     1031188 :     while (*inbytesleft != 0)
     856                 :             :     {
     857                 :     1016515 :         frommode = cd->from.mode;
     858                 :     1016515 :         tomode = cd->to.mode;
     859                 :     1016515 :         wsize = MB_CHAR_MAX;
     860                 :             : 
     861                 :     1016515 :         insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
     862                 :     1016515 :         if (insize == -1)
     863                 :             :         {
     864                 :           2 :             if (cd->to.flags & FLAG_IGNORE)
     865                 :             :             {
     866                 :           0 :                 cd->from.mode = frommode;
     867                 :           0 :                 insize = 1;
     868                 :           0 :                 wsize = 0;
     869                 :           0 :             }
     870                 :             :             else
     871                 :             :             {
     872                 :           2 :                 cd->from.mode = frommode;
     873                 :           2 :                 return (size_t)(-1);
     874                 :             :             }
     875                 :           0 :         }
     876                 :             : 
     877                 :     1016513 :         if (wsize == 0)
     878                 :             :         {
     879                 :           2 :             *inbuf += insize;
     880                 :           2 :             *inbytesleft -= insize;
     881                 :           2 :             continue;
     882                 :             :         }
     883                 :             : 
     884                 :     1016511 :         if (cd->from.compat != NULL)
     885                 :             :         {
     886                 :          62 :             wc = utf16_to_ucs4(wbuf);
     887                 :          62 :             cp = cd->from.compat;
     888                 :         620 :             for (i = 0; cp[i].in != 0; ++i)
     889                 :             :             {
     890                 :         558 :                 if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
     891                 :             :                 {
     892                 :           0 :                     ucs4_to_utf16(cp[i].in, wbuf, &wsize);
     893                 :           0 :                     break;
     894                 :             :                 }
     895                 :         558 :             }
     896                 :          62 :         }
     897                 :             : 
     898                 :     1016511 :         if (cd->to.compat != NULL)
     899                 :             :         {
     900                 :           0 :             wc = utf16_to_ucs4(wbuf);
     901                 :           0 :             cp = cd->to.compat;
     902                 :           0 :             for (i = 0; cp[i].in != 0; ++i)
     903                 :             :             {
     904                 :           0 :                 if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
     905                 :             :                 {
     906                 :           0 :                     ucs4_to_utf16(cp[i].out, wbuf, &wsize);
     907                 :           0 :                     break;
     908                 :             :                 }
     909                 :           0 :             }
     910                 :           0 :         }
     911                 :             : 
     912                 :     1016511 :         outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
     913                 :     1016511 :         if (outsize == -1)
     914                 :             :         {
     915                 :          12 :             if ((cd->to.flags & FLAG_IGNORE) && errno != E2BIG)
     916                 :             :             {
     917                 :           0 :                 cd->to.mode = tomode;
     918                 :           0 :                 outsize = 0;
     919                 :           0 :             }
     920                 :             :             else
     921                 :             :             {
     922                 :          12 :                 cd->from.mode = frommode;
     923                 :          12 :                 cd->to.mode = tomode;
     924                 :          12 :                 return (size_t)(-1);
     925                 :             :             }
     926                 :           0 :         }
     927                 :             : 
     928                 :     1016499 :         *inbuf += insize;
     929                 :     1016499 :         *outbuf += outsize;
     930                 :     1016499 :         *inbytesleft -= insize;
     931                 :     1016499 :         *outbytesleft -= outsize;
     932                 :             :     }
     933                 :             : 
     934                 :       14673 :     return 0;
     935                 :       29360 : }
     936                 :             : 
     937                 :             : static int
     938                 :       29355 : make_csconv(const char *_name, csconv_t *cv)
     939                 :             : {
     940                 :             :     CPINFO cpinfo;
     941                 :       29355 :     int use_compat = TRUE;
     942                 :       29355 :     int flag = 0;
     943                 :             :     char *name;
     944                 :             :     char *p;
     945                 :             : 
     946                 :       29355 :     name = xstrndup(_name, strlen(_name));
     947                 :       29355 :     if (name == NULL)
     948                 :           0 :         return FALSE;
     949                 :             : 
     950                 :             :     /* check for option "enc_name//opt1//opt2" */
     951                 :       29355 :     while ((p = strrstr(name, "//")) != NULL)
     952                 :             :     {
     953                 :           0 :         if (_stricmp(p + 2, "nocompat") == 0)
     954                 :           0 :             use_compat = FALSE;
     955                 :           0 :         else if (_stricmp(p + 2, "translit") == 0)
     956                 :           0 :             flag |= FLAG_TRANSLIT;
     957                 :           0 :         else if (_stricmp(p + 2, "ignore") == 0)
     958                 :           0 :             flag |= FLAG_IGNORE;
     959                 :           0 :         *p = 0;
     960                 :             :     }
     961                 :             : 
     962                 :       29355 :     cv->mode = 0;
     963                 :       29355 :     cv->flags = flag;
     964                 :       29355 :     cv->mblen = NULL;
     965                 :       29355 :     cv->flush = NULL;
     966                 :       29355 :     cv->compat = NULL;
     967                 :       29355 :     cv->codepage = name_to_codepage(name);
     968                 :       29355 :     if (cv->codepage == 1200 || cv->codepage == 1201)
     969                 :             :     {
     970                 :       14627 :         cv->mbtowc = utf16_mbtowc;
     971                 :       14627 :         cv->wctomb = utf16_wctomb;
     972                 :       14627 :         if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0 ||
     973                 :          13 :           _stricmp(name, "UCS-2") == 0 || _stricmp(name, "UCS2") == 0)
     974                 :       14614 :             cv->flags |= FLAG_USE_BOM;
     975                 :       14627 :     }
     976                 :       14728 :     else if (cv->codepage == 12000 || cv->codepage == 12001)
     977                 :             :     {
     978                 :           0 :         cv->mbtowc = utf32_mbtowc;
     979                 :           0 :         cv->wctomb = utf32_wctomb;
     980                 :           0 :         if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0 ||
     981                 :           0 :           _stricmp(name, "UCS-4") == 0 || _stricmp(name, "UCS4") == 0)
     982                 :           0 :             cv->flags |= FLAG_USE_BOM;
     983                 :           0 :     }
     984                 :       14728 :     else if (cv->codepage == 65001)
     985                 :             :     {
     986                 :       14678 :         cv->mbtowc = kernel_mbtowc;
     987                 :       14678 :         cv->wctomb = kernel_wctomb;
     988                 :       14678 :         cv->mblen = utf8_mblen;
     989                 :       14678 :     }
     990                 :          50 :     else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())
     991                 :             :     {
     992                 :           0 :         cv->mbtowc = iso2022jp_mbtowc;
     993                 :           0 :         cv->wctomb = iso2022jp_wctomb;
     994                 :           0 :         cv->flush = iso2022jp_flush;
     995                 :           0 :     }
     996                 :          50 :     else if (cv->codepage == 51932 && load_mlang())
     997                 :             :     {
     998                 :           1 :         cv->mbtowc = mlang_mbtowc;
     999                 :           1 :         cv->wctomb = mlang_wctomb;
    1000                 :           1 :         cv->mblen = eucjp_mblen;
    1001                 :           1 :     }
    1002                 :          49 :     else if (IsValidCodePage(cv->codepage)
    1003                 :          49 :              && GetCPInfo(cv->codepage, &cpinfo) != 0)
    1004                 :             :     {
    1005                 :          48 :         cv->mbtowc = kernel_mbtowc;
    1006                 :          48 :         cv->wctomb = kernel_wctomb;
    1007                 :          48 :         if (cpinfo.MaxCharSize == 1)
    1008                 :          48 :             cv->mblen = sbcs_mblen;
    1009                 :           0 :         else if (cpinfo.MaxCharSize == 2)
    1010                 :           0 :             cv->mblen = dbcs_mblen;
    1011                 :             :         else
    1012                 :           0 :             cv->mblen = mbcs_mblen;
    1013                 :          48 :     }
    1014                 :             :     else
    1015                 :             :     {
    1016                 :             :         /* not supported */
    1017                 :           1 :         free(name);
    1018                 :           1 :         errno = EINVAL;
    1019                 :           1 :         return FALSE;
    1020                 :             :     }
    1021                 :             : 
    1022                 :       29354 :     if (use_compat)
    1023                 :             :     {
    1024                 :       29354 :         switch (cv->codepage)
    1025                 :             :         {
    1026                 :           0 :         case 932: cv->compat = cp932_compat; break;
    1027                 :           0 :         case 20932: cv->compat = cp20932_compat; break;
    1028                 :           1 :         case 51932: cv->compat = cp51932_compat; break;
    1029                 :           0 :         case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;
    1030                 :             :         }
    1031                 :       29354 :     }
    1032                 :             : 
    1033                 :       29354 :     free(name);
    1034                 :             : 
    1035                 :       29354 :     return TRUE;
    1036                 :       29355 : }
    1037                 :             : 
    1038                 :             : static int
    1039                 :       29355 : name_to_codepage(const char *name)
    1040                 :             : {
    1041                 :             :     int i;
    1042                 :             : 
    1043                 :       29355 :     if (*name == '\0' ||
    1044                 :       29355 :         strcmp(name, "char") == 0)
    1045                 :           0 :         return GetACP();
    1046                 :       29355 :     else if (strcmp(name, "wchar_t") == 0)
    1047                 :           0 :         return 1200;
    1048                 :       29355 :     else if (_strnicmp(name, "cp", 2) == 0)
    1049                 :          38 :         return atoi(name + 2); /* CP123 */
    1050                 :       29317 :     else if ('0' <= name[0] && name[0] <= '9')
    1051                 :           0 :         return atoi(name);     /* 123 */
    1052                 :       29317 :     else if (_strnicmp(name, "xx", 2) == 0)
    1053                 :           0 :         return atoi(name + 2); /* XX123 for debug */
    1054                 :             : 
    1055                 :      396624 :     for (i = 0; codepage_alias[i].name != NULL; ++i)
    1056                 :      396623 :         if (_stricmp(name, codepage_alias[i].name) == 0)
    1057                 :       29316 :             return codepage_alias[i].codepage;
    1058                 :           1 :     return -1;
    1059                 :       29355 : }
    1060                 :             : 
    1061                 :             : /*
    1062                 :             :  * http://www.faqs.org/rfcs/rfc2781.html
    1063                 :             :  */
    1064                 :             : static uint
    1065                 :          62 : utf16_to_ucs4(const ushort *wbuf)
    1066                 :             : {
    1067                 :          62 :     uint wc = wbuf[0];
    1068                 :          62 :     if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
    1069                 :           0 :         wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
    1070                 :          62 :     return wc;
    1071                 :             : }
    1072                 :             : 
    1073                 :             : static void
    1074                 :           0 : ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
    1075                 :             : {
    1076                 :           0 :     if (wc < 0x10000)
    1077                 :             :     {
    1078                 :           0 :         wbuf[0] = wc;
    1079                 :           0 :         *wbufsize = 1;
    1080                 :           0 :     }
    1081                 :             :     else
    1082                 :             :     {
    1083                 :           0 :         wc -= 0x10000;
    1084                 :           0 :         wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
    1085                 :           0 :         wbuf[1] = 0xDC00 | (wc & 0x3FF);
    1086                 :           0 :         *wbufsize = 2;
    1087                 :             :     }
    1088                 :           0 : }
    1089                 :             : 
    1090                 :             : /*
    1091                 :             :  * Check if codepage is one of those for which the dwFlags parameter
    1092                 :             :  * to MultiByteToWideChar() must be zero. Return zero or
    1093                 :             :  * MB_ERR_INVALID_CHARS.  The docs in Platform SDK for Windows
    1094                 :             :  * Server 2003 R2 claims that also codepage 65001 is one of these, but
    1095                 :             :  * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave
    1096                 :             :  * out 65001 (UTF-8), and that indeed seems to be the case on XP, it
    1097                 :             :  * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting
    1098                 :             :  * from UTF-8.
    1099                 :             :  */
    1100                 :             : static int
    1101                 :         341 : mbtowc_flags(int codepage)
    1102                 :             : {
    1103                 :         944 :     return (codepage == 50220 || codepage == 50221 ||
    1104                 :         341 :             codepage == 50222 || codepage == 50225 ||
    1105                 :         341 :             codepage == 50227 || codepage == 50229 ||
    1106                 :         341 :             codepage == 52936 || codepage == 54936 ||
    1107                 :         341 :             (codepage >= 57002 && codepage <= 57011) ||
    1108                 :         210 :             codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;
    1109                 :             : }
    1110                 :             : 
    1111                 :             : /*
    1112                 :             :  * Check if codepage is one those for which the lpUsedDefaultChar
    1113                 :             :  * parameter to WideCharToMultiByte() must be NULL.  The docs in
    1114                 :             :  * Platform SDK for Windows Server 2003 R2 claims that this is the
    1115                 :             :  * list below, while the MSDN docs for MSVS2008 claim that it is only
    1116                 :             :  * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform
    1117                 :             :  * SDK seems to be correct, at least for XP.
    1118                 :             :  */
    1119                 :             : static int
    1120                 :     1016487 : must_use_null_useddefaultchar(int codepage)
    1121                 :             : {
    1122                 :     1016594 :     return (codepage == 65000 || codepage == 65001 ||
    1123                 :         107 :             codepage == 50220 || codepage == 50221 ||
    1124                 :         107 :             codepage == 50222 || codepage == 50225 ||
    1125                 :         107 :             codepage == 50227 || codepage == 50229 ||
    1126                 :         107 :             codepage == 52936 || codepage == 54936 ||
    1127                 :     1016487 :             (codepage >= 57002 && codepage <= 57011) ||
    1128                 :         107 :             codepage == 42);
    1129                 :             : }
    1130                 :             : 
    1131                 :             : static char *
    1132                 :       29355 : strrstr(const char *str, const char *token)
    1133                 :             : {
    1134                 :       29355 :     size_t len = strlen(token);
    1135                 :       29355 :     const char *p = str + strlen(str);
    1136                 :             : 
    1137                 :      161641 :     while (str <= --p)
    1138                 :      132286 :         if (p[0] == token[0] && strncmp(p, token, len) == 0)
    1139                 :           0 :             return (char *)p;
    1140                 :       29355 :     return NULL;
    1141                 :       29355 : }
    1142                 :             : 
    1143                 :             : static char *
    1144                 :       29355 : xstrndup(const char *s, size_t n)
    1145                 :             : {
    1146                 :             :     char *p;
    1147                 :             : 
    1148                 :       29355 :     p = (char *)malloc(n + 1);
    1149                 :       29355 :     if (p == NULL)
    1150                 :           0 :         return NULL;
    1151                 :       29355 :     memcpy(p, s, n);
    1152                 :       29355 :     p[n] = '\0';
    1153                 :       29355 :     return p;
    1154                 :       29355 : }
    1155                 :             : 
    1156                 :             : static int
    1157                 :          14 : seterror(int err)
    1158                 :             : {
    1159                 :          14 :     errno = err;
    1160                 :          14 :     return -1;
    1161                 :             : }
    1162                 :             : 
    1163                 :             : #if defined(USE_LIBICONV_DLL)
    1164                 :             : static int
    1165                 :             : libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
    1166                 :             : {
    1167                 :             :     HMODULE hlibiconv = NULL;
    1168                 :             :     char *dllname;
    1169                 :             :     const char *p;
    1170                 :             :     const char *e;
    1171                 :             :     f_iconv_open _iconv_open;
    1172                 :             : 
    1173                 :             :     /*
    1174                 :             :      * always try to load dll, so that we can switch dll in runtime.
    1175                 :             :      */
    1176                 :             : 
    1177                 :             :     /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */
    1178                 :             :     p = getenv("WINICONV_LIBICONV_DLL");
    1179                 :             :     if (p == NULL)
    1180                 :             :         p = DEFAULT_LIBICONV_DLL;
    1181                 :             :     /* parse comma separated value */
    1182                 :             :     for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)
    1183                 :             :     {
    1184                 :             :         e = strchr(p, ',');
    1185                 :             :         if (p == e)
    1186                 :             :             continue;
    1187                 :             :         else if (e == NULL)
    1188                 :             :             e = p + strlen(p);
    1189                 :             :         dllname = xstrndup(p, e - p);
    1190                 :             :         if (dllname == NULL)
    1191                 :             :             return FALSE;
    1192                 :             :         hlibiconv = LoadLibraryA(dllname);
    1193                 :             :         free(dllname);
    1194                 :             :         if (hlibiconv != NULL)
    1195                 :             :         {
    1196                 :             :             if (hlibiconv == hwiniconv)
    1197                 :             :             {
    1198                 :             :                 FreeLibrary(hlibiconv);
    1199                 :             :                 hlibiconv = NULL;
    1200                 :             :                 continue;
    1201                 :             :             }
    1202                 :             :             break;
    1203                 :             :         }
    1204                 :             :     }
    1205                 :             : 
    1206                 :             :     if (hlibiconv == NULL)
    1207                 :             :         goto failed;
    1208                 :             : 
    1209                 :             :     _iconv_open = (f_iconv_open)GetProcAddressA(hlibiconv, "libiconv_open");
    1210                 :             :     if (_iconv_open == NULL)
    1211                 :             :         _iconv_open = (f_iconv_open)GetProcAddressA(hlibiconv, "iconv_open");
    1212                 :             :     cd->iconv_close = (f_iconv_close)GetProcAddressA(hlibiconv, "libiconv_close");
    1213                 :             :     if (cd->iconv_close == NULL)
    1214                 :             :         cd->iconv_close = (f_iconv_close)GetProcAddressA(hlibiconv, "iconv_close");
    1215                 :             :     cd->iconv = (f_iconv)GetProcAddressA(hlibiconv, "libiconv");
    1216                 :             :     if (cd->iconv == NULL)
    1217                 :             :         cd->iconv = (f_iconv)GetProcAddressA(hlibiconv, "iconv");
    1218                 :             :     cd->_errno = (f_errno)find_imported_function(hlibiconv, "_errno");
    1219                 :             :     if (_iconv_open == NULL || cd->iconv_close == NULL
    1220                 :             :             || cd->iconv == NULL || cd->_errno == NULL)
    1221                 :             :         goto failed;
    1222                 :             : 
    1223                 :             :     cd->cd = _iconv_open(tocode, fromcode);
    1224                 :             :     if (cd->cd == (iconv_t)(-1))
    1225                 :             :         goto failed;
    1226                 :             : 
    1227                 :             :     cd->hlibiconv = hlibiconv;
    1228                 :             :     return TRUE;
    1229                 :             : 
    1230                 :             : failed:
    1231                 :             :     if (hlibiconv != NULL)
    1232                 :             :         FreeLibrary(hlibiconv);
    1233                 :             :     return FALSE;
    1234                 :             : }
    1235                 :             : 
    1236                 :             : /*
    1237                 :             :  * Reference:
    1238                 :             :  * http://forums.belution.com/ja/vc/000/234/78s.shtml
    1239                 :             :  * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
    1240                 :             :  *
    1241                 :             :  * The formal way is
    1242                 :             :  *   imagehlp.h or dbghelp.h
    1243                 :             :  *   imagehlp.lib or dbghelp.lib
    1244                 :             :  *   ImageDirectoryEntryToData()
    1245                 :             :  */
    1246                 :             : #define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
    1247                 :             : #define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
    1248                 :             : static PVOID
    1249                 :             : MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
    1250                 :             : {
    1251                 :             :     /* TODO: MappedAsImage? */
    1252                 :             :     PIMAGE_DATA_DIRECTORY p;
    1253                 :             :     p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
    1254                 :             :     if (p->VirtualAddress == 0) {
    1255                 :             :       *Size = 0;
    1256                 :             :       return NULL;
    1257                 :             :     }
    1258                 :             :     *Size = p->Size;
    1259                 :             :     return (PVOID)((LPBYTE)Base + p->VirtualAddress);
    1260                 :             : }
    1261                 :             : 
    1262                 :             : static FARPROC
    1263                 :             : find_imported_function(HMODULE hModule, const char *funcname)
    1264                 :             : {
    1265                 :             :     DWORD_PTR Base;
    1266                 :             :     ULONG Size;
    1267                 :             :     PIMAGE_IMPORT_DESCRIPTOR Imp;
    1268                 :             :     PIMAGE_THUNK_DATA Address;      /* Import Address Table */
    1269                 :             :     PIMAGE_THUNK_DATA Name;         /* Import Name Table */
    1270                 :             :     PIMAGE_IMPORT_BY_NAME ImpName;
    1271                 :             : 
    1272                 :             :     Base = (DWORD_PTR)hModule;
    1273                 :             :     Imp = (PIMAGE_IMPORT_DESCRIPTOR)MyImageDirectoryEntryToData(
    1274                 :             :             (LPVOID)Base,
    1275                 :             :             TRUE,
    1276                 :             :             IMAGE_DIRECTORY_ENTRY_IMPORT,
    1277                 :             :             &Size);
    1278                 :             :     if (Imp == NULL)
    1279                 :             :         return NULL;
    1280                 :             :     for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
    1281                 :             :     {
    1282                 :             :         Address = (PIMAGE_THUNK_DATA)(Base + Imp->FirstThunk);
    1283                 :             :         Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
    1284                 :             :         for ( ; Name->u1.Ordinal != 0; ++Name, ++Address)
    1285                 :             :         {
    1286                 :             :             if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))
    1287                 :             :             {
    1288                 :             :                 ImpName = (PIMAGE_IMPORT_BY_NAME)
    1289                 :             :                     (Base + (DWORD_PTR)Name->u1.AddressOfData);
    1290                 :             :                 if (strcmp((char *)ImpName->Name, funcname) == 0)
    1291                 :             :                     return (FARPROC)Address->u1.Function;
    1292                 :             :             }
    1293                 :             :         }
    1294                 :             :     }
    1295                 :             :     return NULL;
    1296                 :             : }
    1297                 :             : #endif
    1298                 :             : 
    1299                 :             : static int
    1300                 :         309 : sbcs_mblen(csconv_t *cv UNUSED, const uchar *buf UNUSED, int bufsize UNUSED)
    1301                 :             : {
    1302                 :         309 :     return 1;
    1303                 :             : }
    1304                 :             : 
    1305                 :             : static int
    1306                 :           0 : dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
    1307                 :             : {
    1308                 :           0 :     int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
    1309                 :           0 :     if (bufsize < len)
    1310                 :           0 :         return seterror(EINVAL);
    1311                 :           0 :     return len;
    1312                 :           0 : }
    1313                 :             : 
    1314                 :             : static int
    1315                 :           0 : mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
    1316                 :             : {
    1317                 :           0 :     int len = 0;
    1318                 :             : 
    1319                 :           0 :     if (cv->codepage == 54936) {
    1320                 :           0 :         if (buf[0] <= 0x7F) len = 1;
    1321                 :           0 :         else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
    1322                 :           0 :                  bufsize >= 2 &&
    1323                 :           0 :                  ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||
    1324                 :           0 :                   (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;
    1325                 :           0 :         else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&
    1326                 :           0 :                  bufsize >= 4 &&
    1327                 :           0 :                  buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;
    1328                 :             :         else
    1329                 :           0 :             return seterror(EINVAL);
    1330                 :           0 :         return len;
    1331                 :             :     }
    1332                 :             :     else
    1333                 :           0 :         return seterror(EINVAL);
    1334                 :           0 : }
    1335                 :             : 
    1336                 :             : static int
    1337                 :     1016514 : utf8_mblen(csconv_t *cv UNUSED, const uchar *buf, int bufsize)
    1338                 :             : {
    1339                 :     1016514 :     int len = 0;
    1340                 :             : 
    1341                 :     1016514 :     if (buf[0] < 0x80) len = 1;
    1342                 :          43 :     else if ((buf[0] & 0xE0) == 0xC0) len = 2;
    1343                 :          14 :     else if ((buf[0] & 0xF0) == 0xE0) len = 3;
    1344                 :           8 :     else if ((buf[0] & 0xF8) == 0xF0) len = 4;
    1345                 :           2 :     else if ((buf[0] & 0xFC) == 0xF8) len = 5;
    1346                 :           2 :     else if ((buf[0] & 0xFE) == 0xFC) len = 6;
    1347                 :             : 
    1348                 :     1016514 :     if (len == 0)
    1349                 :           2 :         return seterror(EILSEQ);
    1350                 :     1016512 :     else if (bufsize < len)
    1351                 :           0 :         return seterror(EINVAL);
    1352                 :     1016512 :     return len;
    1353                 :     1016514 : }
    1354                 :             : 
    1355                 :             : static int
    1356                 :          62 : eucjp_mblen(csconv_t *cv UNUSED, const uchar *buf, int bufsize)
    1357                 :             : {
    1358                 :          62 :     if (buf[0] < 0x80) /* ASCII */
    1359                 :          62 :         return 1;
    1360                 :           0 :     else if (buf[0] == 0x8E) /* JIS X 0201 */
    1361                 :             :     {
    1362                 :           0 :         if (bufsize < 2)
    1363                 :           0 :             return seterror(EINVAL);
    1364                 :           0 :         else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
    1365                 :           0 :             return seterror(EILSEQ);
    1366                 :           0 :         return 2;
    1367                 :             :     }
    1368                 :           0 :     else if (buf[0] == 0x8F) /* JIS X 0212 */
    1369                 :             :     {
    1370                 :           0 :         if (bufsize < 3)
    1371                 :           0 :             return seterror(EINVAL);
    1372                 :           0 :         else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
    1373                 :           0 :                 || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
    1374                 :           0 :             return seterror(EILSEQ);
    1375                 :           0 :         return 3;
    1376                 :             :     }
    1377                 :             :     else /* JIS X 0208 */
    1378                 :             :     {
    1379                 :           0 :         if (bufsize < 2)
    1380                 :           0 :             return seterror(EINVAL);
    1381                 :           0 :         else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
    1382                 :           0 :                 || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
    1383                 :           0 :             return seterror(EILSEQ);
    1384                 :           0 :         return 2;
    1385                 :             :     }
    1386                 :          62 : }
    1387                 :             : 
    1388                 :             : static int
    1389                 :         343 : kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
    1390                 :             : {
    1391                 :             :     int len;
    1392                 :             : 
    1393                 :         343 :     len = cv->mblen(cv, buf, bufsize);
    1394                 :         343 :     if (len == -1)
    1395                 :           2 :         return -1;
    1396                 :             :     /* If converting from ASCII, reject 8bit
    1397                 :             :      * chars. MultiByteToWideChar() doesn't. Note that for ASCII we
    1398                 :             :      * know that the mblen function is sbcs_mblen() so len is 1.
    1399                 :             :      */
    1400                 :         341 :     if (cv->codepage == 20127 && buf[0] >= 0x80)
    1401                 :           0 :         return seterror(EILSEQ);
    1402                 :         682 :     *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),
    1403                 :         341 :             (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
    1404                 :         341 :     if (*wbufsize == 0)
    1405                 :           0 :         return seterror(EILSEQ);
    1406                 :         341 :     return len;
    1407                 :         343 : }
    1408                 :             : 
    1409                 :             : static int
    1410                 :     1016488 : kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
    1411                 :             : {
    1412                 :     1016488 :     BOOL usedDefaultChar = 0;
    1413                 :     1016488 :     BOOL *p = NULL;
    1414                 :     1016488 :     int flags = 0;
    1415                 :             :     int len;
    1416                 :             : 
    1417                 :     1016488 :     if (bufsize == 0)
    1418                 :           0 :         return seterror(E2BIG);
    1419                 :     1016488 :     if (!must_use_null_useddefaultchar(cv->codepage))
    1420                 :             :     {
    1421                 :         107 :         p = &usedDefaultChar;
    1422                 :             : #ifdef WC_NO_BEST_FIT_CHARS
    1423                 :         107 :         if (!(cv->flags & FLAG_TRANSLIT))
    1424                 :         107 :             flags |= WC_NO_BEST_FIT_CHARS;
    1425                 :             : #endif
    1426                 :         107 :     }
    1427                 :     2032976 :     len = WideCharToMultiByte(cv->codepage, flags,
    1428                 :     1016488 :             (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);
    1429                 :     1016488 :     if (len == 0)
    1430                 :             :     {
    1431                 :           2 :         if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
    1432                 :           2 :             return seterror(E2BIG);
    1433                 :           0 :         return seterror(EILSEQ);
    1434                 :             :     }
    1435                 :     1016486 :     else if (usedDefaultChar && !(cv->flags & FLAG_TRANSLIT))
    1436                 :           8 :         return seterror(EILSEQ);
    1437                 :     1016478 :     else if (cv->mblen(cv, buf, len) != len) /* validate result */
    1438                 :           0 :         return seterror(EILSEQ);
    1439                 :     1016478 :     return len;
    1440                 :     1016488 : }
    1441                 :             : 
    1442                 :             : /*
    1443                 :             :  * It seems that the mode (cv->mode) is fixnum.
    1444                 :             :  * For example, when converting iso-2022-jp(cp50221) to unicode:
    1445                 :             :  *      in ascii sequence: mode=0xC42C0000
    1446                 :             :  *   in jisx0208 sequence: mode=0xC42C0001
    1447                 :             :  * "C42C" is same for each convert session.
    1448                 :             :  * It should be: ((codepage-1)<<16)|state
    1449                 :             :  */
    1450                 :             : static int
    1451                 :          62 : mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
    1452                 :             : {
    1453                 :             :     int len;
    1454                 :             :     int insize;
    1455                 :             :     HRESULT hr;
    1456                 :             : 
    1457                 :          62 :     len = cv->mblen(cv, buf, bufsize);
    1458                 :          62 :     if (len == -1)
    1459                 :           0 :         return -1;
    1460                 :          62 :     insize = len;
    1461                 :         124 :     hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
    1462                 :          62 :             (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
    1463                 :          62 :     if (hr != S_OK || insize != len)
    1464                 :           0 :         return seterror(EILSEQ);
    1465                 :          62 :     return len;
    1466                 :          62 : }
    1467                 :             : 
    1468                 :             : static int
    1469                 :           0 : mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
    1470                 :             : {
    1471                 :             :     char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
    1472                 :           0 :     int tmpsize = MB_CHAR_MAX;
    1473                 :           0 :     int insize = wbufsize;
    1474                 :             :     HRESULT hr;
    1475                 :             : 
    1476                 :           0 :     hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
    1477                 :           0 :             (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
    1478                 :           0 :     if (hr != S_OK || insize != wbufsize)
    1479                 :           0 :         return seterror(EILSEQ);
    1480                 :           0 :     else if (bufsize < tmpsize)
    1481                 :           0 :         return seterror(E2BIG);
    1482                 :           0 :     else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
    1483                 :           0 :         return seterror(EILSEQ);
    1484                 :           0 :     memcpy(buf, tmpbuf, tmpsize);
    1485                 :           0 :     return tmpsize;
    1486                 :           0 : }
    1487                 :             : 
    1488                 :             : static int
    1489                 :     1016112 : utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
    1490                 :             : {
    1491                 :     1016112 :     int codepage = cv->codepage;
    1492                 :             : 
    1493                 :             :     /* swap endian: 1200 <-> 1201 */
    1494                 :     1016112 :     if (cv->mode & UNICODE_MODE_SWAPPED)
    1495                 :           1 :         codepage ^= 1;
    1496                 :             : 
    1497                 :     1016112 :     if (bufsize < 2)
    1498                 :           0 :         return seterror(EINVAL);
    1499                 :     1016112 :     if (codepage == 1200) /* little endian */
    1500                 :     1016111 :         wbuf[0] = (buf[1] << 8) | buf[0];
    1501                 :           1 :     else if (codepage == 1201) /* big endian */
    1502                 :           1 :         wbuf[0] = (buf[0] << 8) | buf[1];
    1503                 :             : 
    1504                 :     1016112 :     if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
    1505                 :             :     {
    1506                 :       14614 :         cv->mode |= UNICODE_MODE_BOM_DONE;
    1507                 :       14614 :         if (wbuf[0] == 0xFFFE)
    1508                 :             :         {
    1509                 :           1 :             cv->mode |= UNICODE_MODE_SWAPPED;
    1510                 :           1 :             *wbufsize = 0;
    1511                 :           1 :             return 2;
    1512                 :             :         }
    1513                 :       14613 :         else if (wbuf[0] == 0xFEFF)
    1514                 :             :         {
    1515                 :           1 :             *wbufsize = 0;
    1516                 :           1 :             return 2;
    1517                 :             :         }
    1518                 :       14612 :     }
    1519                 :             : 
    1520                 :     1016110 :     if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
    1521                 :           0 :         return seterror(EILSEQ);
    1522                 :     1016110 :     if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
    1523                 :             :     {
    1524                 :           0 :         if (bufsize < 4)
    1525                 :           0 :             return seterror(EINVAL);
    1526                 :           0 :         if (codepage == 1200) /* little endian */
    1527                 :           0 :             wbuf[1] = (buf[3] << 8) | buf[2];
    1528                 :           0 :         else if (codepage == 1201) /* big endian */
    1529                 :           0 :             wbuf[1] = (buf[2] << 8) | buf[3];
    1530                 :           0 :         if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
    1531                 :           0 :             return seterror(EILSEQ);
    1532                 :           0 :         *wbufsize = 2;
    1533                 :           0 :         return 4;
    1534                 :             :     }
    1535                 :     1016110 :     *wbufsize = 1;
    1536                 :     1016110 :     return 2;
    1537                 :     1016112 : }
    1538                 :             : 
    1539                 :             : static int
    1540                 :          23 : utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
    1541                 :             : {
    1542                 :          23 :     if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
    1543                 :             :     {
    1544                 :             :         int r;
    1545                 :             : 
    1546                 :           0 :         cv->mode |= UNICODE_MODE_BOM_DONE;
    1547                 :           0 :         if (bufsize < 2)
    1548                 :           0 :             return seterror(E2BIG);
    1549                 :           0 :         if (cv->codepage == 1200) /* little endian */
    1550                 :           0 :             memcpy(buf, "\xFF\xFE", 2);
    1551                 :           0 :         else if (cv->codepage == 1201) /* big endian */
    1552                 :           0 :             memcpy(buf, "\xFE\xFF", 2);
    1553                 :             : 
    1554                 :           0 :         r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);
    1555                 :           0 :         if (r == -1)
    1556                 :           0 :             return -1;
    1557                 :           0 :         return r + 2;
    1558                 :             :     }
    1559                 :             : 
    1560                 :          23 :     if (bufsize < 2)
    1561                 :           1 :         return seterror(E2BIG);
    1562                 :          22 :     if (cv->codepage == 1200) /* little endian */
    1563                 :             :     {
    1564                 :          22 :         buf[0] = (wbuf[0] & 0x00FF);
    1565                 :          22 :         buf[1] = (wbuf[0] & 0xFF00) >> 8;
    1566                 :          22 :     }
    1567                 :           0 :     else if (cv->codepage == 1201) /* big endian */
    1568                 :             :     {
    1569                 :           0 :         buf[0] = (wbuf[0] & 0xFF00) >> 8;
    1570                 :           0 :         buf[1] = (wbuf[0] & 0x00FF);
    1571                 :           0 :     }
    1572                 :          22 :     if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
    1573                 :             :     {
    1574                 :           6 :         if (bufsize < 4)
    1575                 :           1 :             return seterror(E2BIG);
    1576                 :           5 :         if (cv->codepage == 1200) /* little endian */
    1577                 :             :         {
    1578                 :           5 :             buf[2] = (wbuf[1] & 0x00FF);
    1579                 :           5 :             buf[3] = (wbuf[1] & 0xFF00) >> 8;
    1580                 :           5 :         }
    1581                 :           0 :         else if (cv->codepage == 1201) /* big endian */
    1582                 :             :         {
    1583                 :           0 :             buf[2] = (wbuf[1] & 0xFF00) >> 8;
    1584                 :           0 :             buf[3] = (wbuf[1] & 0x00FF);
    1585                 :           0 :         }
    1586                 :           5 :         return 4;
    1587                 :             :     }
    1588                 :          16 :     return 2;
    1589                 :          23 : }
    1590                 :             : 
    1591                 :             : static int
    1592                 :           0 : utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
    1593                 :             : {
    1594                 :           0 :     int codepage = cv->codepage;
    1595                 :           0 :     uint wc = 0xD800;
    1596                 :             : 
    1597                 :             :     /* swap endian: 12000 <-> 12001 */
    1598                 :           0 :     if (cv->mode & UNICODE_MODE_SWAPPED)
    1599                 :           0 :         codepage ^= 1;
    1600                 :             : 
    1601                 :           0 :     if (bufsize < 4)
    1602                 :           0 :         return seterror(EINVAL);
    1603                 :           0 :     if (codepage == 12000) /* little endian */
    1604                 :           0 :         wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
    1605                 :           0 :     else if (codepage == 12001) /* big endian */
    1606                 :           0 :         wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
    1607                 :             : 
    1608                 :           0 :     if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
    1609                 :             :     {
    1610                 :           0 :         cv->mode |= UNICODE_MODE_BOM_DONE;
    1611                 :           0 :         if (wc == 0xFFFE0000)
    1612                 :             :         {
    1613                 :           0 :             cv->mode |= UNICODE_MODE_SWAPPED;
    1614                 :           0 :             *wbufsize = 0;
    1615                 :           0 :             return 4;
    1616                 :             :         }
    1617                 :           0 :         else if (wc == 0x0000FEFF)
    1618                 :             :         {
    1619                 :           0 :             *wbufsize = 0;
    1620                 :           0 :             return 4;
    1621                 :             :         }
    1622                 :           0 :     }
    1623                 :             : 
    1624                 :           0 :     if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
    1625                 :           0 :         return seterror(EILSEQ);
    1626                 :           0 :     ucs4_to_utf16(wc, wbuf, wbufsize);
    1627                 :           0 :     return 4;
    1628                 :           0 : }
    1629                 :             : 
    1630                 :             : static int
    1631                 :           0 : utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
    1632                 :             : {
    1633                 :             :     uint wc;
    1634                 :             : 
    1635                 :           0 :     if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))
    1636                 :             :     {
    1637                 :             :         int r;
    1638                 :             : 
    1639                 :           0 :         cv->mode |= UNICODE_MODE_BOM_DONE;
    1640                 :           0 :         if (bufsize < 4)
    1641                 :           0 :             return seterror(E2BIG);
    1642                 :           0 :         if (cv->codepage == 12000) /* little endian */
    1643                 :           0 :             memcpy(buf, "\xFF\xFE\x00\x00", 4);
    1644                 :           0 :         else if (cv->codepage == 12001) /* big endian */
    1645                 :           0 :             memcpy(buf, "\x00\x00\xFE\xFF", 4);
    1646                 :             : 
    1647                 :           0 :         r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);
    1648                 :           0 :         if (r == -1)
    1649                 :           0 :             return -1;
    1650                 :           0 :         return r + 4;
    1651                 :             :     }
    1652                 :             : 
    1653                 :           0 :     if (bufsize < 4)
    1654                 :           0 :         return seterror(E2BIG);
    1655                 :           0 :     wc = utf16_to_ucs4(wbuf);
    1656                 :           0 :     if (cv->codepage == 12000) /* little endian */
    1657                 :             :     {
    1658                 :           0 :         buf[0] = wc & 0x000000FF;
    1659                 :           0 :         buf[1] = (wc & 0x0000FF00) >> 8;
    1660                 :           0 :         buf[2] = (wc & 0x00FF0000) >> 16;
    1661                 :           0 :         buf[3] = (wc & 0xFF000000) >> 24;
    1662                 :           0 :     }
    1663                 :           0 :     else if (cv->codepage == 12001) /* big endian */
    1664                 :             :     {
    1665                 :           0 :         buf[0] = (wc & 0xFF000000) >> 24;
    1666                 :           0 :         buf[1] = (wc & 0x00FF0000) >> 16;
    1667                 :           0 :         buf[2] = (wc & 0x0000FF00) >> 8;
    1668                 :           0 :         buf[3] = wc & 0x000000FF;
    1669                 :           0 :     }
    1670                 :           0 :     return 4;
    1671                 :           0 : }
    1672                 :             : 
    1673                 :             : /*
    1674                 :             :  * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
    1675                 :             :  * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
    1676                 :             :  *        1 byte Kana)
    1677                 :             :  * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
    1678                 :             :  *        Kana - SO/SI)
    1679                 :             :  *
    1680                 :             :  * MultiByteToWideChar() and WideCharToMultiByte() behave differently
    1681                 :             :  * depending on Windows version.  On XP, WideCharToMultiByte() doesn't
    1682                 :             :  * terminate result sequence with ascii escape.  But Vista does.
    1683                 :             :  * Use MLang instead.
    1684                 :             :  */
    1685                 :             : 
    1686                 :             : #define ISO2022_MODE(cs, shift) ((((DWORD) cs) << 8) | (shift))
    1687                 :             : #define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
    1688                 :             : #define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
    1689                 :             : 
    1690                 :             : #define ISO2022_SI  0
    1691                 :             : #define ISO2022_SO  1
    1692                 :             : 
    1693                 :             : /* shift in */
    1694                 :             : static const char iso2022_SI_seq[] = "\x0F";
    1695                 :             : /* shift out */
    1696                 :             : static const char iso2022_SO_seq[] = "\x0E";
    1697                 :             : 
    1698                 :             : typedef struct iso2022_esc_t iso2022_esc_t;
    1699                 :             : struct iso2022_esc_t {
    1700                 :             :     const char *esc;
    1701                 :             :     int esc_len;
    1702                 :             :     int len;
    1703                 :             :     int cs;
    1704                 :             : };
    1705                 :             : 
    1706                 :             : #define ISO2022JP_CS_ASCII            0
    1707                 :             : #define ISO2022JP_CS_JISX0201_ROMAN   1
    1708                 :             : #define ISO2022JP_CS_JISX0201_KANA    2
    1709                 :             : #define ISO2022JP_CS_JISX0208_1978    3
    1710                 :             : #define ISO2022JP_CS_JISX0208_1983    4
    1711                 :             : #define ISO2022JP_CS_JISX0212         5
    1712                 :             : 
    1713                 :             : static iso2022_esc_t iso2022jp_esc[] = {
    1714                 :             :     {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
    1715                 :             :     {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
    1716                 :             :     {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
    1717                 :             :     {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
    1718                 :             :     {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
    1719                 :             :     {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
    1720                 :             :     {NULL, 0, 0, 0}
    1721                 :             : };
    1722                 :             : 
    1723                 :             : static int
    1724                 :           0 : iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
    1725                 :             : {
    1726                 :           0 :     iso2022_esc_t *iesc = iso2022jp_esc;
    1727                 :             :     char tmp[MB_CHAR_MAX];
    1728                 :             :     int insize;
    1729                 :             :     HRESULT hr;
    1730                 :           0 :     DWORD dummy = 0;
    1731                 :             :     int len;
    1732                 :             :     int esc_len;
    1733                 :             :     int cs;
    1734                 :             :     int shift;
    1735                 :             :     int i;
    1736                 :             : 
    1737                 :           0 :     if (buf[0] == 0x1B)
    1738                 :             :     {
    1739                 :           0 :         for (i = 0; iesc[i].esc != NULL; ++i)
    1740                 :             :         {
    1741                 :           0 :             esc_len = iesc[i].esc_len;
    1742                 :           0 :             if (bufsize < esc_len)
    1743                 :             :             {
    1744                 :           0 :                 if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
    1745                 :           0 :                     return seterror(EINVAL);
    1746                 :           0 :             }
    1747                 :             :             else
    1748                 :             :             {
    1749                 :           0 :                 if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
    1750                 :             :                 {
    1751                 :           0 :                     cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
    1752                 :           0 :                     *wbufsize = 0;
    1753                 :           0 :                     return esc_len;
    1754                 :             :                 }
    1755                 :             :             }
    1756                 :           0 :         }
    1757                 :             :         /* not supported escape sequence */
    1758                 :           0 :         return seterror(EILSEQ);
    1759                 :             :     }
    1760                 :           0 :     else if (buf[0] == iso2022_SO_seq[0])
    1761                 :             :     {
    1762                 :           0 :         cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
    1763                 :           0 :         *wbufsize = 0;
    1764                 :           0 :         return 1;
    1765                 :             :     }
    1766                 :           0 :     else if (buf[0] == iso2022_SI_seq[0])
    1767                 :             :     {
    1768                 :           0 :         cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
    1769                 :           0 :         *wbufsize = 0;
    1770                 :           0 :         return 1;
    1771                 :             :     }
    1772                 :             : 
    1773                 :           0 :     cs = ISO2022_MODE_CS(cv->mode);
    1774                 :           0 :     shift = ISO2022_MODE_SHIFT(cv->mode);
    1775                 :             : 
    1776                 :             :     /* reset the mode for informal sequence */
    1777                 :           0 :     if (buf[0] < 0x20)
    1778                 :             :     {
    1779                 :           0 :         cs = ISO2022JP_CS_ASCII;
    1780                 :           0 :         shift = ISO2022_SI;
    1781                 :           0 :     }
    1782                 :             : 
    1783                 :           0 :     len = iesc[cs].len;
    1784                 :           0 :     if (bufsize < len)
    1785                 :           0 :         return seterror(EINVAL);
    1786                 :           0 :     for (i = 0; i < len; ++i)
    1787                 :           0 :         if (!(buf[i] < 0x80))
    1788                 :           0 :             return seterror(EILSEQ);
    1789                 :           0 :     esc_len = iesc[cs].esc_len;
    1790                 :           0 :     memcpy(tmp, iesc[cs].esc, esc_len);
    1791                 :           0 :     if (shift == ISO2022_SO)
    1792                 :             :     {
    1793                 :           0 :         memcpy(tmp + esc_len, iso2022_SO_seq, 1);
    1794                 :           0 :         esc_len += 1;
    1795                 :           0 :     }
    1796                 :           0 :     memcpy(tmp + esc_len, buf, len);
    1797                 :             : 
    1798                 :           0 :     if ((cv->codepage == 50220 || cv->codepage == 50221
    1799                 :           0 :                 || cv->codepage == 50222) && shift == ISO2022_SO)
    1800                 :             :     {
    1801                 :             :         /* XXX: shift-out cannot be used for mbtowc (both kernel and
    1802                 :             :          * mlang) */
    1803                 :           0 :         esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
    1804                 :           0 :         memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
    1805                 :           0 :         memcpy(tmp + esc_len, buf, len);
    1806                 :           0 :     }
    1807                 :             : 
    1808                 :           0 :     insize = len + esc_len;
    1809                 :           0 :     hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
    1810                 :           0 :             (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
    1811                 :           0 :     if (hr != S_OK || insize != len + esc_len)
    1812                 :           0 :         return seterror(EILSEQ);
    1813                 :             : 
    1814                 :             :     /* Check for conversion error.  Assuming defaultChar is 0x3F. */
    1815                 :             :     /* ascii should be converted from ascii */
    1816                 :           0 :     if (wbuf[0] == buf[0]
    1817                 :           0 :             && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
    1818                 :           0 :         return seterror(EILSEQ);
    1819                 :             : 
    1820                 :             :     /* reset the mode for informal sequence */
    1821                 :           0 :     if (cv->mode != ISO2022_MODE(cs, shift))
    1822                 :           0 :         cv->mode = ISO2022_MODE(cs, shift);
    1823                 :             : 
    1824                 :           0 :     return len;
    1825                 :           0 : }
    1826                 :             : 
    1827                 :             : static int
    1828                 :           0 : iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
    1829                 :             : {
    1830                 :           0 :     iso2022_esc_t *iesc = iso2022jp_esc;
    1831                 :             :     char tmp[MB_CHAR_MAX];
    1832                 :           0 :     int tmpsize = MB_CHAR_MAX;
    1833                 :           0 :     int insize = wbufsize;
    1834                 :             :     HRESULT hr;
    1835                 :           0 :     DWORD dummy = 0;
    1836                 :             :     int len;
    1837                 :             :     int esc_len;
    1838                 :             :     int cs;
    1839                 :             :     int shift;
    1840                 :             :     int i;
    1841                 :             : 
    1842                 :             :     /*
    1843                 :             :      * MultiByte = [escape sequence] + character + [escape sequence]
    1844                 :             :      *
    1845                 :             :      * Whether trailing escape sequence is added depends on which API is
    1846                 :             :      * used (kernel or MLang, and its version).
    1847                 :             :      */
    1848                 :           0 :     hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
    1849                 :           0 :             (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
    1850                 :           0 :     if (hr != S_OK || insize != wbufsize)
    1851                 :           0 :         return seterror(EILSEQ);
    1852                 :           0 :     else if (bufsize < tmpsize)
    1853                 :           0 :         return seterror(E2BIG);
    1854                 :             : 
    1855                 :           0 :     if (tmpsize == 1)
    1856                 :             :     {
    1857                 :           0 :         cs = ISO2022JP_CS_ASCII;
    1858                 :           0 :         esc_len = 0;
    1859                 :           0 :     }
    1860                 :             :     else
    1861                 :             :     {
    1862                 :           0 :         for (i = 1; iesc[i].esc != NULL; ++i)
    1863                 :             :         {
    1864                 :           0 :             esc_len = iesc[i].esc_len;
    1865                 :           0 :             if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
    1866                 :             :             {
    1867                 :           0 :                 cs = iesc[i].cs;
    1868                 :           0 :                 break;
    1869                 :             :             }
    1870                 :           0 :         }
    1871                 :           0 :         if (iesc[i].esc == NULL)
    1872                 :             :             /* not supported escape sequence */
    1873                 :           0 :             return seterror(EILSEQ);
    1874                 :             :     }
    1875                 :             : 
    1876                 :           0 :     shift = ISO2022_SI;
    1877                 :           0 :     if (tmp[esc_len] == iso2022_SO_seq[0])
    1878                 :             :     {
    1879                 :           0 :         shift = ISO2022_SO;
    1880                 :           0 :         esc_len += 1;
    1881                 :           0 :     }
    1882                 :             : 
    1883                 :           0 :     len = iesc[cs].len;
    1884                 :             : 
    1885                 :             :     /* Check for converting error.  Assuming defaultChar is 0x3F. */
    1886                 :             :     /* ascii should be converted from ascii */
    1887                 :           0 :     if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
    1888                 :           0 :         return seterror(EILSEQ);
    1889                 :           0 :     else if (tmpsize < esc_len + len)
    1890                 :           0 :         return seterror(EILSEQ);
    1891                 :             : 
    1892                 :           0 :     if (cv->mode == ISO2022_MODE(cs, shift))
    1893                 :             :     {
    1894                 :             :         /* remove escape sequence */
    1895                 :           0 :         if (esc_len != 0)
    1896                 :           0 :             memmove(tmp, tmp + esc_len, len);
    1897                 :           0 :         esc_len = 0;
    1898                 :           0 :     }
    1899                 :             :     else
    1900                 :             :     {
    1901                 :           0 :         if (cs == ISO2022JP_CS_ASCII)
    1902                 :             :         {
    1903                 :           0 :             esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
    1904                 :           0 :             memmove(tmp + esc_len, tmp, len);
    1905                 :           0 :             memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
    1906                 :           0 :         }
    1907                 :           0 :         if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
    1908                 :             :         {
    1909                 :             :             /* shift-in before changing to other mode */
    1910                 :           0 :             memmove(tmp + 1, tmp, len + esc_len);
    1911                 :           0 :             memcpy(tmp, iso2022_SI_seq, 1);
    1912                 :           0 :             esc_len += 1;
    1913                 :           0 :         }
    1914                 :             :     }
    1915                 :             : 
    1916                 :           0 :     if (bufsize < len + esc_len)
    1917                 :           0 :         return seterror(E2BIG);
    1918                 :           0 :     memcpy(buf, tmp, len + esc_len);
    1919                 :           0 :     cv->mode = ISO2022_MODE(cs, shift);
    1920                 :           0 :     return len + esc_len;
    1921                 :           0 : }
    1922                 :             : 
    1923                 :             : static int
    1924                 :           0 : iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
    1925                 :             : {
    1926                 :           0 :     iso2022_esc_t *iesc = iso2022jp_esc;
    1927                 :             :     int esc_len;
    1928                 :             : 
    1929                 :           0 :     if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
    1930                 :             :     {
    1931                 :           0 :         esc_len = 0;
    1932                 :           0 :         if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
    1933                 :           0 :             esc_len += 1;
    1934                 :           0 :         if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
    1935                 :           0 :             esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
    1936                 :           0 :         if (bufsize < esc_len)
    1937                 :           0 :             return seterror(E2BIG);
    1938                 :             : 
    1939                 :           0 :         esc_len = 0;
    1940                 :           0 :         if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
    1941                 :             :         {
    1942                 :           0 :             memcpy(buf, iso2022_SI_seq, 1);
    1943                 :           0 :             esc_len += 1;
    1944                 :           0 :         }
    1945                 :           0 :         if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
    1946                 :             :         {
    1947                 :           0 :             memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
    1948                 :           0 :                     iesc[ISO2022JP_CS_ASCII].esc_len);
    1949                 :           0 :             esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
    1950                 :           0 :         }
    1951                 :           0 :         return esc_len;
    1952                 :             :     }
    1953                 :           0 :     return 0;
    1954                 :           0 : }
    1955                 :             : 
    1956                 :             : #if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)
    1957                 :             : BOOL WINAPI
    1958                 :             : DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
    1959                 :             : {
    1960                 :             :     switch( fdwReason )
    1961                 :             :     {
    1962                 :             :     case DLL_PROCESS_ATTACH:
    1963                 :             :         hwiniconv = (HMODULE)hinstDLL;
    1964                 :             :         break;
    1965                 :             :     case DLL_THREAD_ATTACH:
    1966                 :             :     case DLL_THREAD_DETACH:
    1967                 :             :     case DLL_PROCESS_DETACH:
    1968                 :             :         break;
    1969                 :             :     }
    1970                 :             :     return TRUE;
    1971                 :             : }
    1972                 :             : #endif
    1973                 :             : 
    1974                 :             : #if defined(MAKE_EXE)
    1975                 :             : #include <stdio.h>
    1976                 :             : #include <fcntl.h>
    1977                 :             : #include <io.h>
    1978                 :             : int
    1979                 :             : main(int argc, char **argv)
    1980                 :             : {
    1981                 :             :     char *fromcode = NULL;
    1982                 :             :     char *tocode = NULL;
    1983                 :             :     int i;
    1984                 :             :     char inbuf[BUFSIZ];
    1985                 :             :     char outbuf[BUFSIZ];
    1986                 :             :     const char *pin;
    1987                 :             :     char *pout;
    1988                 :             :     size_t inbytesleft;
    1989                 :             :     size_t outbytesleft;
    1990                 :             :     size_t rest = 0;
    1991                 :             :     iconv_t cd;
    1992                 :             :     size_t r;
    1993                 :             :     FILE *in = stdin;
    1994                 :             :     FILE *out = stdout;
    1995                 :             :     FILE *in_allocated = NULL, *out_allocated = NULL;
    1996                 :             :     int ignore = 0;
    1997                 :             :     char *p;
    1998                 :             : 
    1999                 :             :     _setmode(_fileno(stdin), _O_BINARY);
    2000                 :             :     _setmode(_fileno(stdout), _O_BINARY);
    2001                 :             : 
    2002                 :             :     for (i = 1; i < argc; ++i)
    2003                 :             :     {
    2004                 :             :         if (strcmp(argv[i], "-l") == 0)
    2005                 :             :         {
    2006                 :             :             for (i = 0; codepage_alias[i].name != NULL; ++i)
    2007                 :             :                 printf("%s\n", codepage_alias[i].name);
    2008                 :             :             return 0;
    2009                 :             :         }
    2010                 :             : 
    2011                 :             :         if (strcmp(argv[i], "-f") == 0)
    2012                 :             :             fromcode = argv[++i];
    2013                 :             :         else if (strcmp(argv[i], "-t") == 0)
    2014                 :             :             tocode = argv[++i];
    2015                 :             :         else if (strcmp(argv[i], "-c") == 0)
    2016                 :             :             ignore = 1;
    2017                 :             :         else if (strcmp(argv[i], "--output") == 0)
    2018                 :             :         {
    2019                 :             :             out_allocated = out = fopen(argv[++i], "wb");
    2020                 :             :             if(out == NULL)
    2021                 :             :             {
    2022                 :             :                 fprintf(stderr, "cannot open %s\n", argv[i]);
    2023                 :             :                 return 1;
    2024                 :             :             }
    2025                 :             :         }
    2026                 :             :         else
    2027                 :             :         {
    2028                 :             :             in_allocated = in = fopen(argv[i], "rb");
    2029                 :             :             if (in == NULL)
    2030                 :             :             {
    2031                 :             :                 fprintf(stderr, "cannot open %s\n", argv[i]);
    2032                 :             :                 return 1;
    2033                 :             :             }
    2034                 :             :             break;
    2035                 :             :         }
    2036                 :             :     }
    2037                 :             : 
    2038                 :             :     if (fromcode == NULL || tocode == NULL)
    2039                 :             :     {
    2040                 :             :         printf("usage: %s [-c] -f from-enc -t to-enc [file]\n",
    2041                 :             :                (argc > 0) ? argv[0] : "win_iconv");
    2042                 :             :         return 0;
    2043                 :             :     }
    2044                 :             : 
    2045                 :             :     if (ignore)
    2046                 :             :     {
    2047                 :             :         p = tocode;
    2048                 :             :         tocode = (char *)malloc(strlen(p) + strlen("//IGNORE") + 1);
    2049                 :             :         if (tocode == NULL)
    2050                 :             :         {
    2051                 :             :             perror("fatal error");
    2052                 :             :             return 1;
    2053                 :             :         }
    2054                 :             :         strcpy(tocode, p);
    2055                 :             :         strcat(tocode, "//IGNORE");
    2056                 :             :     }
    2057                 :             : 
    2058                 :             :     cd = iconv_open(tocode, fromcode);
    2059                 :             :     if (cd == (iconv_t)(-1))
    2060                 :             :     {
    2061                 :             :         perror("iconv_open error");
    2062                 :             :         return 1;
    2063                 :             :     }
    2064                 :             : 
    2065                 :             :     while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0
    2066                 :             :             || rest != 0)
    2067                 :             :     {
    2068                 :             :         inbytesleft += rest;
    2069                 :             :         pin = inbuf;
    2070                 :             :         pout = outbuf;
    2071                 :             :         outbytesleft = sizeof(outbuf);
    2072                 :             :         r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
    2073                 :             :         fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
    2074                 :             :         if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))
    2075                 :             :         {
    2076                 :             :             perror("conversion error");
    2077                 :             :             return 1;
    2078                 :             :         }
    2079                 :             :         memmove(inbuf, pin, inbytesleft);
    2080                 :             :         rest = inbytesleft;
    2081                 :             :     }
    2082                 :             :     pout = outbuf;
    2083                 :             :     outbytesleft = sizeof(outbuf);
    2084                 :             :     r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
    2085                 :             :     fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, out);
    2086                 :             :     if (r == (size_t)(-1))
    2087                 :             :     {
    2088                 :             :         perror("conversion error");
    2089                 :             :         return 1;
    2090                 :             :     }
    2091                 :             : 
    2092                 :             :     iconv_close(cd);
    2093                 :             : 
    2094                 :             :     if (in_allocated != NULL)
    2095                 :             :         fclose (in_allocated);
    2096                 :             :     if (out_allocated != NULL)
    2097                 :             :         fclose (out_allocated);
    2098                 :             : 
    2099                 :             :     return 0;
    2100                 :             : }
    2101                 :             : #endif
        

Generated by: LCOV version 2.0-1