]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
gsmopen: compile on windows, with iconv for windows. Substituted actual file to symlink
authorGiovanni Maruzzelli <gmaruzz@gmail.com>
Wed, 18 Apr 2012 14:33:09 +0000 (16:33 +0200)
committerGiovanni Maruzzelli <gmaruzz@gmail.com>
Wed, 18 Apr 2012 14:33:09 +0000 (16:33 +0200)
src/mod/endpoints/mod_gsmopen/win_iconv.c [new file with mode: 0644]

diff --git a/src/mod/endpoints/mod_gsmopen/win_iconv.c b/src/mod/endpoints/mod_gsmopen/win_iconv.c
new file mode 100644 (file)
index 0000000..94c8d4a
--- /dev/null
@@ -0,0 +1,1986 @@
+/*\r
+ * iconv library using Win32 API to conversion.\r
+ *\r
+ * This file is placed in the public domain.\r
+ *\r
+ * Last Change: 2009-07-06\r
+ *\r
+ * ENVIRONMENT VARIABLE:\r
+ *     WINICONV_LIBICONV_DLL\r
+ *         If $WINICONV_LIBICONV_DLL is set, win_iconv uses the DLL.  If\r
+ *         loading the DLL or iconv_open() failed, falls back to internal\r
+ *         conversion.  If a few DLL are specified as comma separated list,\r
+ *         the first loadable DLL is used.  The DLL should have iconv_open(),\r
+ *         iconv_close() and iconv().  Or libiconv_open(), libiconv_close()\r
+ *         and libiconv().\r
+ *         (only available when USE_LIBICONV_DLL is defined at compile time)\r
+ *\r
+ * Win32 API does not support strict encoding conversion for some\r
+ * codepage.  And MLang function drop or replace invalid bytes and does\r
+ * not return useful error status as iconv.  This implementation cannot\r
+ * be used for encoding validation purpose.\r
+ */\r
+\r
+/* for WC_NO_BEST_FIT_CHARS */\r
+#ifndef WINVER\r
+# define WINVER 0x0500\r
+#endif\r
+\r
+#include <windows.h>\r
+#include <errno.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+\r
+#if 0\r
+# define MAKE_EXE\r
+# define MAKE_DLL\r
+# define USE_LIBICONV_DLL\r
+#endif\r
+\r
+#if !defined(DEFAULT_LIBICONV_DLL)\r
+# define DEFAULT_LIBICONV_DLL ""\r
+#endif\r
+\r
+#define MB_CHAR_MAX 16\r
+\r
+#define UNICODE_MODE_BOM_DONE   1\r
+#define UNICODE_MODE_SWAPPED    2\r
+\r
+#define FLAG_USE_BOM            1\r
+#define FLAG_TRANSLIT           2 /* //TRANSLIT */\r
+#define FLAG_IGNORE             4 /* //IGNORE (not implemented) */\r
+\r
+typedef unsigned char uchar;\r
+typedef unsigned short ushort;\r
+typedef unsigned int uint;\r
+\r
+typedef void* iconv_t;\r
+\r
+iconv_t iconv_open(const char *tocode, const char *fromcode);\r
+int iconv_close(iconv_t cd);\r
+size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
+\r
+/* libiconv interface for vim */\r
+#if defined(MAKE_DLL)\r
+int\r
+iconvctl (iconv_t cd, int request, void* argument)\r
+{\r
+    /* not supported */\r
+    return 0;\r
+}\r
+#endif\r
+\r
+typedef struct compat_t compat_t;\r
+typedef struct csconv_t csconv_t;\r
+typedef struct rec_iconv_t rec_iconv_t;\r
+\r
+typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);\r
+typedef int (*f_iconv_close)(iconv_t cd);\r
+typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
+typedef int* (*f_errno)(void);\r
+typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
+typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
+typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);\r
+typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);\r
+\r
+#define COMPAT_IN   1\r
+#define COMPAT_OUT  2\r
+\r
+/* unicode mapping for compatibility with other conversion table. */\r
+struct compat_t {\r
+    uint in;\r
+    uint out;\r
+    uint flag;\r
+};\r
+\r
+struct csconv_t {\r
+    int codepage;\r
+    int flags;\r
+    f_mbtowc mbtowc;\r
+    f_wctomb wctomb;\r
+    f_mblen mblen;\r
+    f_flush flush;\r
+    DWORD mode;\r
+    compat_t *compat;\r
+};\r
+\r
+struct rec_iconv_t {\r
+    iconv_t cd;\r
+    f_iconv_close iconv_close;\r
+    f_iconv iconv;\r
+    f_errno _errno;\r
+    csconv_t from;\r
+    csconv_t to;\r
+#if defined(USE_LIBICONV_DLL)\r
+    HMODULE hlibiconv;\r
+#endif\r
+};\r
+\r
+static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);\r
+static int win_iconv_close(iconv_t cd);\r
+static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);\r
+\r
+static int load_mlang();\r
+static int make_csconv(const char *name, csconv_t *cv);\r
+static int name_to_codepage(const char *name);\r
+static uint utf16_to_ucs4(const ushort *wbuf);\r
+static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);\r
+static int mbtowc_flags(int codepage);\r
+static int must_use_null_useddefaultchar(int codepage);\r
+static char *strrstr(const char *str, const char *token);\r
+static char *xstrndup(const char *s, size_t n);\r
+static int seterror(int err);\r
+\r
+#if defined(USE_LIBICONV_DLL)\r
+static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);\r
+static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);\r
+static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);\r
+\r
+static HMODULE hwiniconv;\r
+#endif\r
+\r
+static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
+static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
+static int mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
+static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
+static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);\r
+\r
+static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
+static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
+static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
+static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
+static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
+static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
+static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
+static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
+static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);\r
+static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);\r
+static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);\r
+\r
+static struct {\r
+    int codepage;\r
+    const char *name;\r
+} codepage_alias[] = {\r
+    {65001, "CP65001"},\r
+    {65001, "UTF8"},\r
+    {65001, "UTF-8"},\r
+\r
+    {1200, "CP1200"},\r
+    {1200, "UTF16LE"},\r
+    {1200, "UTF-16LE"},\r
+    {1200, "UCS-2LE"},\r
+\r
+    {1201, "CP1201"},\r
+    {1201, "UTF16BE"},\r
+    {1201, "UTF-16BE"},\r
+    {1201, "UCS-2BE"},\r
+    {1201, "unicodeFFFE"},\r
+\r
+    {12000, "CP12000"},\r
+    {12000, "UTF32LE"},\r
+    {12000, "UTF-32LE"},\r
+\r
+    {12001, "CP12001"},\r
+    {12001, "UTF32BE"},\r
+    {12001, "UTF-32BE"},\r
+\r
+#ifndef GLIB_COMPILATION\r
+    /*\r
+     * Default is big endian.\r
+     * See rfc2781 4.3 Interpreting text labelled as UTF-16.\r
+     */\r
+    {1201, "UTF16"},\r
+    {1201, "UTF-16"},\r
+    {12001, "UTF32"},\r
+    {12001, "UTF-32"},\r
+#else\r
+    /* Default is little endian, because the platform is */\r
+    {1200, "UTF16"},\r
+    {1200, "UTF-16"},\r
+    {1200, "UCS-2"},\r
+    {12000, "UTF32"},\r
+    {12000, "UTF-32"},\r
+#endif\r
+\r
+    /* copy from libiconv `iconv -l` */\r
+    /* !IsValidCodePage(367) */\r
+    {20127, "ANSI_X3.4-1968"},\r
+    {20127, "ANSI_X3.4-1986"},\r
+    {20127, "ASCII"},\r
+    {20127, "CP367"},\r
+    {20127, "IBM367"},\r
+    {20127, "ISO-IR-6"},\r
+    {20127, "ISO646-US"},\r
+    {20127, "ISO_646.IRV:1991"},\r
+    {20127, "US"},\r
+    {20127, "US-ASCII"},\r
+    {20127, "CSASCII"},\r
+\r
+    /* !IsValidCodePage(819) */\r
+    {1252, "CP819"},\r
+    {1252, "IBM819"},\r
+    {28591, "ISO-8859-1"},\r
+    {28591, "ISO-IR-100"},\r
+    {28591, "ISO8859-1"},\r
+    {28591, "ISO_8859-1"},\r
+    {28591, "ISO_8859-1:1987"},\r
+    {28591, "L1"},\r
+    {28591, "LATIN1"},\r
+    {28591, "CSISOLATIN1"},\r
+\r
+    {1250, "CP1250"},\r
+    {1250, "MS-EE"},\r
+    {1250, "WINDOWS-1250"},\r
+\r
+    {1251, "CP1251"},\r
+    {1251, "MS-CYRL"},\r
+    {1251, "WINDOWS-1251"},\r
+\r
+    {1252, "CP1252"},\r
+    {1252, "MS-ANSI"},\r
+    {1252, "WINDOWS-1252"},\r
+\r
+    {1253, "CP1253"},\r
+    {1253, "MS-GREEK"},\r
+    {1253, "WINDOWS-1253"},\r
+\r
+    {1254, "CP1254"},\r
+    {1254, "MS-TURK"},\r
+    {1254, "WINDOWS-1254"},\r
+\r
+    {1255, "CP1255"},\r
+    {1255, "MS-HEBR"},\r
+    {1255, "WINDOWS-1255"},\r
+\r
+    {1256, "CP1256"},\r
+    {1256, "MS-ARAB"},\r
+    {1256, "WINDOWS-1256"},\r
+\r
+    {1257, "CP1257"},\r
+    {1257, "WINBALTRIM"},\r
+    {1257, "WINDOWS-1257"},\r
+\r
+    {1258, "CP1258"},\r
+    {1258, "WINDOWS-1258"},\r
+\r
+    {850, "850"},\r
+    {850, "CP850"},\r
+    {850, "IBM850"},\r
+    {850, "CSPC850MULTILINGUAL"},\r
+\r
+    /* !IsValidCodePage(862) */\r
+    {862, "862"},\r
+    {862, "CP862"},\r
+    {862, "IBM862"},\r
+    {862, "CSPC862LATINHEBREW"},\r
+\r
+    {866, "866"},\r
+    {866, "CP866"},\r
+    {866, "IBM866"},\r
+    {866, "CSIBM866"},\r
+\r
+    /* !IsValidCodePage(154) */\r
+    {154, "CP154"},\r
+    {154, "CYRILLIC-ASIAN"},\r
+    {154, "PT154"},\r
+    {154, "PTCP154"},\r
+    {154, "CSPTCP154"},\r
+\r
+    /* !IsValidCodePage(1133) */\r
+    {1133, "CP1133"},\r
+    {1133, "IBM-CP1133"},\r
+\r
+    {874, "CP874"},\r
+    {874, "WINDOWS-874"},\r
+\r
+    /* !IsValidCodePage(51932) */\r
+    {51932, "CP51932"},\r
+    {51932, "MS51932"},\r
+    {51932, "WINDOWS-51932"},\r
+    {51932, "EUC-JP"},\r
+\r
+    {932, "CP932"},\r
+    {932, "MS932"},\r
+    {932, "SHIFFT_JIS"},\r
+    {932, "SHIFFT_JIS-MS"},\r
+    {932, "SJIS"},\r
+    {932, "SJIS-MS"},\r
+    {932, "SJIS-OPEN"},\r
+    {932, "SJIS-WIN"},\r
+    {932, "WINDOWS-31J"},\r
+    {932, "WINDOWS-932"},\r
+    {932, "CSWINDOWS31J"},\r
+\r
+    {50221, "CP50221"},\r
+    {50221, "ISO-2022-JP"},\r
+    {50221, "ISO-2022-JP-MS"},\r
+    {50221, "ISO2022-JP"},\r
+    {50221, "ISO2022-JP-MS"},\r
+    {50221, "MS50221"},\r
+    {50221, "WINDOWS-50221"},\r
+\r
+    {936, "CP936"},\r
+    {936, "GBK"},\r
+    {936, "MS936"},\r
+    {936, "WINDOWS-936"},\r
+\r
+    {950, "CP950"},\r
+    {950, "BIG5"},\r
+\r
+    {949, "CP949"},\r
+    {949, "UHC"},\r
+    {949, "EUC-KR"},\r
+\r
+    {1361, "CP1361"},\r
+    {1361, "JOHAB"},\r
+\r
+    {437, "437"},\r
+    {437, "CP437"},\r
+    {437, "IBM437"},\r
+    {437, "CSPC8CODEPAGE437"},\r
+\r
+    {737, "CP737"},\r
+\r
+    {775, "CP775"},\r
+    {775, "IBM775"},\r
+    {775, "CSPC775BALTIC"},\r
+\r
+    {852, "852"},\r
+    {852, "CP852"},\r
+    {852, "IBM852"},\r
+    {852, "CSPCP852"},\r
+\r
+    /* !IsValidCodePage(853) */\r
+    {853, "CP853"},\r
+\r
+    {855, "855"},\r
+    {855, "CP855"},\r
+    {855, "IBM855"},\r
+    {855, "CSIBM855"},\r
+\r
+    {857, "857"},\r
+    {857, "CP857"},\r
+    {857, "IBM857"},\r
+    {857, "CSIBM857"},\r
+\r
+    /* !IsValidCodePage(858) */\r
+    {858, "CP858"},\r
+\r
+    {860, "860"},\r
+    {860, "CP860"},\r
+    {860, "IBM860"},\r
+    {860, "CSIBM860"},\r
+\r
+    {861, "861"},\r
+    {861, "CP-IS"},\r
+    {861, "CP861"},\r
+    {861, "IBM861"},\r
+    {861, "CSIBM861"},\r
+\r
+    {863, "863"},\r
+    {863, "CP863"},\r
+    {863, "IBM863"},\r
+    {863, "CSIBM863"},\r
+\r
+    {864, "CP864"},\r
+    {864, "IBM864"},\r
+    {864, "CSIBM864"},\r
+\r
+    {865, "865"},\r
+    {865, "CP865"},\r
+    {865, "IBM865"},\r
+    {865, "CSIBM865"},\r
+\r
+    {869, "869"},\r
+    {869, "CP-GR"},\r
+    {869, "CP869"},\r
+    {869, "IBM869"},\r
+    {869, "CSIBM869"},\r
+\r
+    /* !IsValidCodePage(1152) */\r
+    {1125, "CP1125"},\r
+\r
+    /*\r
+     * Code Page Identifiers\r
+     * http://msdn2.microsoft.com/en-us/library/ms776446.aspx\r
+     */\r
+    {37, "IBM037"}, /* IBM EBCDIC US-Canada */\r
+    {437, "IBM437"}, /* OEM United States */\r
+    {500, "IBM500"}, /* IBM EBCDIC International */\r
+    {708, "ASMO-708"}, /* Arabic (ASMO 708) */\r
+    /* 709             Arabic (ASMO-449+, BCON V4) */\r
+    /* 710             Arabic - Transparent Arabic */\r
+    {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */\r
+    {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */\r
+    {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */\r
+    {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */\r
+    {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */\r
+    {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */\r
+    {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */\r
+    {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */\r
+    {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */\r
+    {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */\r
+    {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */\r
+    {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */\r
+    {864, "IBM864"}, /* OEM Arabic; Arabic (864) */\r
+    {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */\r
+    {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */\r
+    {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */\r
+    {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */\r
+    {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */\r
+    {875, "cp875"}, /* IBM EBCDIC Greek Modern */\r
+    {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */\r
+    {932, "shift-jis"}, /* alternative name for it */\r
+    {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */\r
+    {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */\r
+    {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */\r
+    {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */\r
+    {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */\r
+    {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */\r
+    {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */\r
+    {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */\r
+    {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */\r
+    {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */\r
+    {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */\r
+    {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */\r
+    {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */\r
+    {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */\r
+    {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */\r
+    {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */\r
+    {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */\r
+    {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */\r
+    {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */\r
+    {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */\r
+    {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */\r
+    {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */\r
+    {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */\r
+    {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */\r
+    {1361, "Johab"}, /* Korean (Johab) */\r
+    {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */\r
+    {10001, "x-mac-japanese"}, /* Japanese (Mac) */\r
+    {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */\r
+    {10003, "x-mac-korean"}, /* Korean (Mac) */\r
+    {10004, "x-mac-arabic"}, /* Arabic (Mac) */\r
+    {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */\r
+    {10006, "x-mac-greek"}, /* Greek (Mac) */\r
+    {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */\r
+    {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */\r
+    {10010, "x-mac-romanian"}, /* Romanian (Mac) */\r
+    {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */\r
+    {10021, "x-mac-thai"}, /* Thai (Mac) */\r
+    {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */\r
+    {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */\r
+    {10081, "x-mac-turkish"}, /* Turkish (Mac) */\r
+    {10082, "x-mac-croatian"}, /* Croatian (Mac) */\r
+    {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */\r
+    {20001, "x-cp20001"}, /* TCA Taiwan */\r
+    {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */\r
+    {20003, "x-cp20003"}, /* IBM5550 Taiwan */\r
+    {20004, "x-cp20004"}, /* TeleText Taiwan */\r
+    {20005, "x-cp20005"}, /* Wang Taiwan */\r
+    {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */\r
+    {20106, "x-IA5-German"}, /* IA5 German (7-bit) */\r
+    {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */\r
+    {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */\r
+    {20127, "us-ascii"}, /* US-ASCII (7-bit) */\r
+    {20261, "x-cp20261"}, /* T.61 */\r
+    {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */\r
+    {20273, "IBM273"}, /* IBM EBCDIC Germany */\r
+    {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */\r
+    {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */\r
+    {20280, "IBM280"}, /* IBM EBCDIC Italy */\r
+    {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */\r
+    {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */\r
+    {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */\r
+    {20297, "IBM297"}, /* IBM EBCDIC France */\r
+    {20420, "IBM420"}, /* IBM EBCDIC Arabic */\r
+    {20423, "IBM423"}, /* IBM EBCDIC Greek */\r
+    {20424, "IBM424"}, /* IBM EBCDIC Hebrew */\r
+    {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */\r
+    {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */\r
+    {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */\r
+    {20871, "IBM871"}, /* IBM EBCDIC Icelandic */\r
+    {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */\r
+    {20905, "IBM905"}, /* IBM EBCDIC Turkish */\r
+    {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */\r
+    {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */\r
+    {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */\r
+    {20949, "x-cp20949"}, /* Korean Wansung */\r
+    {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */\r
+    /* 21027           (deprecated) */\r
+    {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */\r
+    {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */\r
+    {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */\r
+    {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */\r
+    {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */\r
+    {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */\r
+    {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */\r
+    {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */\r
+    {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */\r
+    {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */\r
+    {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */\r
+    {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */\r
+    {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */\r
+    {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */\r
+    {28597, "iso8859-7"}, /* ISO 8859-7 Greek */\r
+    {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */\r
+    {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */\r
+    {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */\r
+    {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */\r
+    {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */\r
+    {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */\r
+    {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */\r
+    {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */\r
+    {29001, "x-Europa"}, /* Europa 3 */\r
+    {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */\r
+    {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */\r
+    {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */\r
+    {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */\r
+    {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */\r
+    {50225, "iso-2022-kr"}, /* ISO 2022 Korean */\r
+    {50225, "iso2022-kr"}, /* ISO 2022 Korean */\r
+    {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */\r
+    /* 50229           ISO 2022 Traditional Chinese */\r
+    /* 50930           EBCDIC Japanese (Katakana) Extended */\r
+    /* 50931           EBCDIC US-Canada and Japanese */\r
+    /* 50933           EBCDIC Korean Extended and Korean */\r
+    /* 50935           EBCDIC Simplified Chinese Extended and Simplified Chinese */\r
+    /* 50936           EBCDIC Simplified Chinese */\r
+    /* 50937           EBCDIC US-Canada and Traditional Chinese */\r
+    /* 50939           EBCDIC Japanese (Latin) Extended and Japanese */\r
+    {51932, "euc-jp"}, /* EUC Japanese */\r
+    {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */\r
+    {51949, "euc-kr"}, /* EUC Korean */\r
+    /* 51950           EUC Traditional Chinese */\r
+    {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */\r
+    {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */\r
+    {57002, "x-iscii-de"}, /* ISCII Devanagari */\r
+    {57003, "x-iscii-be"}, /* ISCII Bengali */\r
+    {57004, "x-iscii-ta"}, /* ISCII Tamil */\r
+    {57005, "x-iscii-te"}, /* ISCII Telugu */\r
+    {57006, "x-iscii-as"}, /* ISCII Assamese */\r
+    {57007, "x-iscii-or"}, /* ISCII Oriya */\r
+    {57008, "x-iscii-ka"}, /* ISCII Kannada */\r
+    {57009, "x-iscii-ma"}, /* ISCII Malayalam */\r
+    {57010, "x-iscii-gu"}, /* ISCII Gujarati */\r
+    {57011, "x-iscii-pa"}, /* ISCII Punjabi */\r
+\r
+    {0, NULL}\r
+};\r
+\r
+/*\r
+ * SJIS SHIFTJIS table              CP932 table\r
+ * ---- --------------------------- --------------------------------\r
+ *   5C U+00A5 YEN SIGN             U+005C REVERSE SOLIDUS\r
+ *   7E U+203E OVERLINE             U+007E TILDE\r
+ * 815C U+2014 EM DASH              U+2015 HORIZONTAL BAR\r
+ * 815F U+005C REVERSE SOLIDUS      U+FF3C FULLWIDTH REVERSE SOLIDUS\r
+ * 8160 U+301C WAVE DASH            U+FF5E FULLWIDTH TILDE\r
+ * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO\r
+ * 817C U+2212 MINUS SIGN           U+FF0D FULLWIDTH HYPHEN-MINUS\r
+ * 8191 U+00A2 CENT SIGN            U+FFE0 FULLWIDTH CENT SIGN\r
+ * 8192 U+00A3 POUND SIGN           U+FFE1 FULLWIDTH POUND SIGN\r
+ * 81CA U+00AC NOT SIGN             U+FFE2 FULLWIDTH NOT SIGN\r
+ *\r
+ * EUC-JP and ISO-2022-JP should be compatible with CP932.\r
+ *\r
+ * Kernel and MLang have different Unicode mapping table.  Make sure\r
+ * which API is used.\r
+ */\r
+static compat_t cp932_compat[] = {\r
+    {0x00A5, 0x005C, COMPAT_OUT},\r
+    {0x203E, 0x007E, COMPAT_OUT},\r
+    {0x2014, 0x2015, COMPAT_OUT},\r
+    {0x301C, 0xFF5E, COMPAT_OUT},\r
+    {0x2016, 0x2225, COMPAT_OUT},\r
+    {0x2212, 0xFF0D, COMPAT_OUT},\r
+    {0x00A2, 0xFFE0, COMPAT_OUT},\r
+    {0x00A3, 0xFFE1, COMPAT_OUT},\r
+    {0x00AC, 0xFFE2, COMPAT_OUT},\r
+    {0, 0, 0}\r
+};\r
+\r
+static compat_t cp20932_compat[] = {\r
+    {0x00A5, 0x005C, COMPAT_OUT},\r
+    {0x203E, 0x007E, COMPAT_OUT},\r
+    {0x2014, 0x2015, COMPAT_OUT},\r
+    {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},\r
+    {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},\r
+    {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},\r
+    {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},\r
+    {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},\r
+    {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},\r
+    {0, 0, 0}\r
+};\r
+\r
+static compat_t *cp51932_compat = cp932_compat;\r
+\r
+/* cp20932_compat for kernel.  cp932_compat for mlang. */\r
+static compat_t *cp5022x_compat = cp932_compat;\r
+\r
+typedef HRESULT (WINAPI *CONVERTINETSTRING)(\r
+    LPDWORD lpdwMode,\r
+    DWORD dwSrcEncoding,\r
+    DWORD dwDstEncoding,\r
+    LPCSTR lpSrcStr,\r
+    LPINT lpnSrcSize,\r
+    LPBYTE lpDstStr,\r
+    LPINT lpnDstSize\r
+);\r
+typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(\r
+    LPDWORD lpdwMode,\r
+    DWORD dwSrcEncoding,\r
+    LPCSTR lpSrcStr,\r
+    LPINT lpnMultiCharCount,\r
+    LPWSTR lpDstStr,\r
+    LPINT lpnWideCharCount\r
+);\r
+typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(\r
+    LPDWORD lpdwMode,\r
+    DWORD dwEncoding,\r
+    LPCWSTR lpSrcStr,\r
+    LPINT lpnWideCharCount,\r
+    LPSTR lpDstStr,\r
+    LPINT lpnMultiCharCount\r
+);\r
+typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(\r
+    DWORD dwSrcEncoding,\r
+    DWORD dwDstEncoding\r
+);\r
+typedef HRESULT (WINAPI *LCIDTORFC1766A)(\r
+    LCID Locale,\r
+    LPSTR pszRfc1766,\r
+    int nChar\r
+);\r
+typedef HRESULT (WINAPI *LCIDTORFC1766W)(\r
+    LCID Locale,\r
+    LPWSTR pszRfc1766,\r
+    int nChar\r
+);\r
+typedef HRESULT (WINAPI *RFC1766TOLCIDA)(\r
+    LCID *pLocale,\r
+    LPSTR pszRfc1766\r
+);\r
+typedef HRESULT (WINAPI *RFC1766TOLCIDW)(\r
+    LCID *pLocale,\r
+    LPWSTR pszRfc1766\r
+);\r
+static CONVERTINETSTRING ConvertINetString;\r
+static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;\r
+static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;\r
+static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;\r
+static LCIDTORFC1766A LcidToRfc1766A;\r
+static RFC1766TOLCIDA Rfc1766ToLcidA;\r
+\r
+static int\r
+load_mlang()\r
+{\r
+    HMODULE h;\r
+    if (ConvertINetString != NULL)\r
+        return TRUE;\r
+    h = LoadLibrary("mlang.dll");\r
+    if (!h)\r
+        return FALSE;\r
+    ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");\r
+    ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");\r
+    ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");\r
+    IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");\r
+    LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");\r
+    Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");\r
+    return TRUE;\r
+}\r
+\r
+iconv_t\r
+iconv_open(const char *tocode, const char *fromcode)\r
+{\r
+    rec_iconv_t *cd;\r
+\r
+    cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));\r
+    if (cd == NULL)\r
+        return (iconv_t)(-1);\r
+\r
+#if defined(USE_LIBICONV_DLL)\r
+    errno = 0;\r
+    if (libiconv_iconv_open(cd, tocode, fromcode))\r
+        return (iconv_t)cd;\r
+#endif\r
+\r
+    /* reset the errno to prevent reporting wrong error code.\r
+     * 0 for unsorted error. */\r
+    errno = 0;\r
+    if (win_iconv_open(cd, tocode, fromcode))\r
+        return (iconv_t)cd;\r
+\r
+    free(cd);\r
+\r
+    return (iconv_t)(-1);\r
+}\r
+\r
+int\r
+iconv_close(iconv_t _cd)\r
+{\r
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
+    int r = cd->iconv_close(cd->cd);\r
+    int e = *(cd->_errno());\r
+#if defined(USE_LIBICONV_DLL)\r
+    if (cd->hlibiconv != NULL)\r
+        FreeLibrary(cd->hlibiconv);\r
+#endif\r
+    free(cd);\r
+    errno = e;\r
+    return r;\r
+}\r
+\r
+size_t\r
+iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)\r
+{\r
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
+    size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);\r
+    errno = *(cd->_errno());\r
+    return r;\r
+}\r
+\r
+static int\r
+win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)\r
+{\r
+    if (!make_csconv(fromcode, &cd->from) || !make_csconv(tocode, &cd->to))\r
+        return FALSE;\r
+    cd->iconv_close = win_iconv_close;\r
+    cd->iconv = win_iconv;\r
+    cd->_errno = _errno;\r
+    cd->cd = (iconv_t)cd;\r
+    return TRUE;\r
+}\r
+\r
+static int\r
+win_iconv_close(iconv_t cd)\r
+{\r
+    return 0;\r
+}\r
+\r
+static size_t\r
+win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)\r
+{\r
+    rec_iconv_t *cd = (rec_iconv_t *)_cd;\r
+    ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */\r
+    int insize;\r
+    int outsize;\r
+    int wsize;\r
+    DWORD frommode;\r
+    DWORD tomode;\r
+    uint wc;\r
+    compat_t *cp;\r
+    int i;\r
+\r
+    if (inbuf == NULL || *inbuf == NULL)\r
+    {\r
+        if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)\r
+        {\r
+            tomode = cd->to.mode;\r
+            outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);\r
+            if (outsize == -1)\r
+            {\r
+                cd->to.mode = tomode;\r
+                return (size_t)(-1);\r
+            }\r
+            *outbuf += outsize;\r
+            *outbytesleft -= outsize;\r
+        }\r
+        cd->from.mode = 0;\r
+        cd->to.mode = 0;\r
+        return 0;\r
+    }\r
+\r
+    while (*inbytesleft != 0)\r
+    {\r
+        frommode = cd->from.mode;\r
+        tomode = cd->to.mode;\r
+        wsize = MB_CHAR_MAX;\r
+\r
+        insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);\r
+        if (insize == -1)\r
+        {\r
+            cd->from.mode = frommode;\r
+            return (size_t)(-1);\r
+        }\r
+\r
+        if (wsize == 0)\r
+        {\r
+            *inbuf += insize;\r
+            *inbytesleft -= insize;\r
+            continue;\r
+        }\r
+\r
+        if (cd->from.compat != NULL)\r
+        {\r
+            wc = utf16_to_ucs4(wbuf);\r
+            cp = cd->from.compat;\r
+            for (i = 0; cp[i].in != 0; ++i)\r
+            {\r
+                if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)\r
+                {\r
+                    ucs4_to_utf16(cp[i].in, wbuf, &wsize);\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+\r
+        if (cd->to.compat != NULL)\r
+        {\r
+            wc = utf16_to_ucs4(wbuf);\r
+            cp = cd->to.compat;\r
+            for (i = 0; cp[i].in != 0; ++i)\r
+            {\r
+                if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)\r
+                {\r
+                    ucs4_to_utf16(cp[i].out, wbuf, &wsize);\r
+                    break;\r
+                }\r
+            }\r
+        }\r
+\r
+        outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);\r
+        if (outsize == -1)\r
+        {\r
+            cd->from.mode = frommode;\r
+            cd->to.mode = tomode;\r
+            return (size_t)(-1);\r
+        }\r
+\r
+        *inbuf += insize;\r
+        *outbuf += outsize;\r
+        *inbytesleft -= insize;\r
+        *outbytesleft -= outsize;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+static int\r
+make_csconv(const char *_name, csconv_t *cv)\r
+{\r
+    CPINFOEX cpinfoex;\r
+    int use_compat = TRUE;\r
+    int flag = 0;\r
+    char *name;\r
+    char *p;\r
+\r
+    name = xstrndup(_name, strlen(_name));\r
+    if (name == NULL)\r
+        return FALSE;\r
+\r
+    /* check for option "enc_name//opt1//opt2" */\r
+    while ((p = strrstr(name, "//")) != NULL)\r
+    {\r
+        if (_stricmp(p + 2, "nocompat") == 0)\r
+            use_compat = FALSE;\r
+        else if (_stricmp(p + 2, "translit") == 0)\r
+            flag |= FLAG_TRANSLIT;\r
+        else if (_stricmp(p + 2, "ignore") == 0)\r
+            flag |= FLAG_IGNORE;\r
+        *p = 0;\r
+    }\r
+\r
+    cv->mode = 0;\r
+    cv->flags = flag;\r
+    cv->mblen = NULL;\r
+    cv->flush = NULL;\r
+    cv->compat = NULL;\r
+    cv->codepage = name_to_codepage(name);\r
+    if (cv->codepage == 1200 || cv->codepage == 1201)\r
+    {\r
+        cv->mbtowc = utf16_mbtowc;\r
+        cv->wctomb = utf16_wctomb;\r
+        if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0)\r
+            cv->flags |= FLAG_USE_BOM;\r
+    }\r
+    else if (cv->codepage == 12000 || cv->codepage == 12001)\r
+    {\r
+        cv->mbtowc = utf32_mbtowc;\r
+        cv->wctomb = utf32_wctomb;\r
+        if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0)\r
+            cv->flags |= FLAG_USE_BOM;\r
+    }\r
+    else if (cv->codepage == 65001)\r
+    {\r
+        cv->mbtowc = kernel_mbtowc;\r
+        cv->wctomb = kernel_wctomb;\r
+        cv->mblen = utf8_mblen;\r
+    }\r
+    else if ((cv->codepage == 50220 || cv->codepage == 50221 || cv->codepage == 50222) && load_mlang())\r
+    {\r
+        cv->mbtowc = iso2022jp_mbtowc;\r
+        cv->wctomb = iso2022jp_wctomb;\r
+        cv->flush = iso2022jp_flush;\r
+    }\r
+    else if (cv->codepage == 51932 && load_mlang())\r
+    {\r
+        cv->mbtowc = mlang_mbtowc;\r
+        cv->wctomb = mlang_wctomb;\r
+        cv->mblen = eucjp_mblen;\r
+    }\r
+    else if (IsValidCodePage(cv->codepage)\r
+            && GetCPInfoEx(cv->codepage, 0, &cpinfoex) != 0)\r
+    {\r
+        cv->mbtowc = kernel_mbtowc;\r
+        cv->wctomb = kernel_wctomb;\r
+        if (cpinfoex.MaxCharSize == 1)\r
+            cv->mblen = sbcs_mblen;\r
+        else if (cpinfoex.MaxCharSize == 2)\r
+            cv->mblen = dbcs_mblen;\r
+       else\r
+           cv->mblen = mbcs_mblen;\r
+    }\r
+    else\r
+    {\r
+        /* not supported */\r
+        free(name);\r
+        errno = EINVAL;\r
+        return FALSE;\r
+    }\r
+\r
+    if (use_compat)\r
+    {\r
+        switch (cv->codepage)\r
+        {\r
+        case 932: cv->compat = cp932_compat; break;\r
+        case 20932: cv->compat = cp20932_compat; break;\r
+        case 51932: cv->compat = cp51932_compat; break;\r
+        case 50220: case 50221: case 50222: cv->compat = cp5022x_compat; break;\r
+        }\r
+    }\r
+\r
+    free(name);\r
+\r
+    return TRUE;\r
+}\r
+\r
+static int\r
+name_to_codepage(const char *name)\r
+{\r
+    int i;\r
+\r
+    if (*name == '\0' ||\r
+       strcmp(name, "char") == 0)\r
+        return GetACP();\r
+    else if (strcmp(name, "wchar_t") == 0)\r
+        return 1200;\r
+    else if (_strnicmp(name, "cp", 2) == 0)\r
+        return atoi(name + 2); /* CP123 */\r
+    else if ('0' <= name[0] && name[0] <= '9')\r
+        return atoi(name);     /* 123 */\r
+    else if (_strnicmp(name, "xx", 2) == 0)\r
+        return atoi(name + 2); /* XX123 for debug */\r
+\r
+    for (i = 0; codepage_alias[i].name != NULL; ++i)\r
+        if (_stricmp(name, codepage_alias[i].name) == 0)\r
+            return codepage_alias[i].codepage;\r
+    return -1;\r
+}\r
+\r
+/*\r
+ * http://www.faqs.org/rfcs/rfc2781.html\r
+ */\r
+static uint\r
+utf16_to_ucs4(const ushort *wbuf)\r
+{\r
+    uint wc = wbuf[0];\r
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
+        wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;\r
+    return wc;\r
+}\r
+\r
+static void\r
+ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)\r
+{\r
+    if (wc < 0x10000)\r
+    {\r
+        wbuf[0] = wc;\r
+        *wbufsize = 1;\r
+    }\r
+    else\r
+    {\r
+        wc -= 0x10000;\r
+        wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);\r
+        wbuf[1] = 0xDC00 | (wc & 0x3FF);\r
+        *wbufsize = 2;\r
+    }\r
+}\r
+\r
+/*\r
+ * Check if codepage is one of those for which the dwFlags parameter\r
+ * to MultiByteToWideChar() must be zero. Return zero or\r
+ * MB_ERR_INVALID_CHARS.  The docs in Platform SDK for for Windows\r
+ * Server 2003 R2 claims that also codepage 65001 is one of these, but\r
+ * that doesn't seem to be the case. The MSDN docs for MSVS2008 leave\r
+ * out 65001 (UTF-8), and that indeed seems to be the case on XP, it\r
+ * works fine to pass MB_ERR_INVALID_CHARS in dwFlags when converting\r
+ * from UTF-8.\r
+ */\r
+static int\r
+mbtowc_flags(int codepage)\r
+{\r
+    return (codepage == 50220 || codepage == 50221 ||\r
+           codepage == 50222 || codepage == 50225 ||\r
+           codepage == 50227 || codepage == 50229 ||\r
+           codepage == 52936 || codepage == 54936 ||\r
+           (codepage >= 57002 && codepage <= 57011) ||\r
+           codepage == 65000 || codepage == 42) ? 0 : MB_ERR_INVALID_CHARS;\r
+}\r
+\r
+/*\r
+ * Check if codepage is one those for which the lpUsedDefaultChar\r
+ * parameter to WideCharToMultiByte() must be NULL.  The docs in\r
+ * Platform SDK for for Windows Server 2003 R2 claims that this is the\r
+ * list below, while the MSDN docs for MSVS2008 claim that it is only\r
+ * for 65000 (UTF-7) and 65001 (UTF-8). This time the earlier Platform\r
+ * SDK seems to be correct, at least for XP.\r
+ */\r
+static int\r
+must_use_null_useddefaultchar(int codepage)\r
+{\r
+    return (codepage == 65000 || codepage == 65001 ||\r
+            codepage == 50220 || codepage == 50221 ||\r
+            codepage == 50222 || codepage == 50225 ||\r
+            codepage == 50227 || codepage == 50229 ||\r
+            codepage == 52936 || codepage == 54936 ||\r
+            (codepage >= 57002 && codepage <= 57011) ||\r
+            codepage == 42);\r
+}\r
+\r
+static char *\r
+strrstr(const char *str, const char *token)\r
+{\r
+    int len = strlen(token);\r
+    const char *p = str + strlen(str);\r
+\r
+    while (str <= --p)\r
+        if (p[0] == token[0] && strncmp(p, token, len) == 0)\r
+            return (char *)p;\r
+    return NULL;\r
+}\r
+\r
+static char *\r
+xstrndup(const char *s, size_t n)\r
+{\r
+    char *p;\r
+\r
+    p = (char *)malloc(n + 1);\r
+    if (p == NULL)\r
+        return NULL;\r
+    memcpy(p, s, n);\r
+    p[n] = '\0';\r
+    return p;\r
+}\r
+\r
+static int\r
+seterror(int err)\r
+{\r
+    errno = err;\r
+    return -1;\r
+}\r
+\r
+#if defined(USE_LIBICONV_DLL)\r
+static int\r
+libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)\r
+{\r
+    HMODULE hlibiconv = NULL;\r
+    HMODULE hmsvcrt = NULL;\r
+    char *dllname;\r
+    const char *p;\r
+    const char *e;\r
+    f_iconv_open _iconv_open;\r
+\r
+    /*\r
+     * always try to load dll, so that we can switch dll in runtime.\r
+     */\r
+\r
+    /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */\r
+    p = getenv("WINICONV_LIBICONV_DLL");\r
+    if (p == NULL)\r
+        p = DEFAULT_LIBICONV_DLL;\r
+    /* parse comma separated value */\r
+    for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)\r
+    {\r
+        e = strchr(p, ',');\r
+        if (p == e)\r
+            continue;\r
+        else if (e == NULL)\r
+            e = p + strlen(p);\r
+        dllname = xstrndup(p, e - p);\r
+        if (dllname == NULL)\r
+            return FALSE;\r
+        hlibiconv = LoadLibrary(dllname);\r
+        free(dllname);\r
+        if (hlibiconv != NULL)\r
+        {\r
+            if (hlibiconv == hwiniconv)\r
+            {\r
+                FreeLibrary(hlibiconv);\r
+                hlibiconv = NULL;\r
+                continue;\r
+            }\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (hlibiconv == NULL)\r
+        goto failed;\r
+\r
+    hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");\r
+    if (hmsvcrt == NULL)\r
+        goto failed;\r
+\r
+    _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");\r
+    if (_iconv_open == NULL)\r
+        _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");\r
+    cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");\r
+    if (cd->iconv_close == NULL)\r
+        cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");\r
+    cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");\r
+    if (cd->iconv == NULL)\r
+        cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");\r
+    cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");\r
+    if (_iconv_open == NULL || cd->iconv_close == NULL\r
+            || cd->iconv == NULL || cd->_errno == NULL)\r
+        goto failed;\r
+\r
+    cd->cd = _iconv_open(tocode, fromcode);\r
+    if (cd->cd == (iconv_t)(-1))\r
+        goto failed;\r
+\r
+    cd->hlibiconv = hlibiconv;\r
+    return TRUE;\r
+\r
+failed:\r
+    if (hlibiconv != NULL)\r
+        FreeLibrary(hlibiconv);\r
+    /* do not free hmsvcrt which is obtained by GetModuleHandle() */\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ * Reference:\r
+ * http://forums.belution.com/ja/vc/000/234/78s.shtml\r
+ * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html\r
+ *\r
+ * The formal way is\r
+ *   imagehlp.h or dbghelp.h\r
+ *   imagehlp.lib or dbghelp.lib\r
+ *   ImageDirectoryEntryToData()\r
+ */\r
+#define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))\r
+#define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))\r
+static PVOID\r
+MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)\r
+{\r
+    /* TODO: MappedAsImage? */\r
+    PIMAGE_DATA_DIRECTORY p;\r
+    p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;\r
+    if (p->VirtualAddress == 0) {\r
+      *Size = 0;\r
+      return NULL;\r
+    }\r
+    *Size = p->Size;\r
+    return (PVOID)((LPBYTE)Base + p->VirtualAddress);\r
+}\r
+\r
+static HMODULE\r
+find_imported_module_by_funcname(HMODULE hModule, const char *funcname)\r
+{\r
+    DWORD Base;\r
+    ULONG Size;\r
+    PIMAGE_IMPORT_DESCRIPTOR Imp;\r
+    PIMAGE_THUNK_DATA Name;         /* Import Name Table */\r
+    PIMAGE_IMPORT_BY_NAME ImpName;\r
+\r
+    Base = (DWORD)hModule;\r
+    Imp = MyImageDirectoryEntryToData(\r
+            (LPVOID)Base,\r
+            TRUE,\r
+            IMAGE_DIRECTORY_ENTRY_IMPORT,\r
+            &Size);\r
+    if (Imp == NULL)\r
+        return NULL;\r
+    for ( ; Imp->OriginalFirstThunk != 0; ++Imp)\r
+    {\r
+        Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);\r
+        for ( ; Name->u1.Ordinal != 0; ++Name)\r
+        {\r
+            if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))\r
+            {\r
+                ImpName = (PIMAGE_IMPORT_BY_NAME)\r
+                    (Base + (DWORD)Name->u1.AddressOfData);\r
+                if (strcmp((char *)ImpName->Name, funcname) == 0)\r
+                    return GetModuleHandle((char *)(Base + Imp->Name));\r
+            }\r
+        }\r
+    }\r
+    return NULL;\r
+}\r
+#endif\r
+\r
+static int\r
+sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
+{\r
+    return 1;\r
+}\r
+\r
+static int\r
+dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
+{\r
+    int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;\r
+    if (bufsize < len)\r
+        return seterror(EINVAL);\r
+    return len;\r
+}\r
+\r
+static int\r
+mbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
+{\r
+    int len = 0;\r
+\r
+    if (cv->codepage == 54936) {\r
+       if (buf[0] <= 0x7F) len = 1;\r
+       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&\r
+                bufsize >= 2 &&\r
+                ((buf[1] >= 0x40 && buf[1] <= 0x7E) ||\r
+                 (buf[1] >= 0x80 && buf[1] <= 0xFE))) len = 2;\r
+       else if (buf[0] >= 0x81 && buf[0] <= 0xFE &&\r
+                bufsize >= 4 &&\r
+                buf[1] >= 0x30 && buf[1] <= 0x39) len = 4;\r
+       else\r
+           return seterror(EINVAL);\r
+       return len;\r
+    }\r
+    else\r
+       return seterror(EINVAL);\r
+}\r
+\r
+static int\r
+utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
+{\r
+    int len = 0;\r
+\r
+    if (buf[0] < 0x80) len = 1;\r
+    else if ((buf[0] & 0xE0) == 0xC0) len = 2;\r
+    else if ((buf[0] & 0xF0) == 0xE0) len = 3;\r
+    else if ((buf[0] & 0xF8) == 0xF0) len = 4;\r
+    else if ((buf[0] & 0xFC) == 0xF8) len = 5;\r
+    else if ((buf[0] & 0xFE) == 0xFC) len = 6;\r
+\r
+    if (len == 0)\r
+        return seterror(EILSEQ);\r
+    else if (bufsize < len)\r
+        return seterror(EINVAL);\r
+    return len;\r
+}\r
+\r
+static int\r
+eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)\r
+{\r
+    if (buf[0] < 0x80) /* ASCII */\r
+        return 1;\r
+    else if (buf[0] == 0x8E) /* JIS X 0201 */\r
+    {\r
+        if (bufsize < 2)\r
+            return seterror(EINVAL);\r
+        else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))\r
+            return seterror(EILSEQ);\r
+        return 2;\r
+    }\r
+    else if (buf[0] == 0x8F) /* JIS X 0212 */\r
+    {\r
+        if (bufsize < 3)\r
+            return seterror(EINVAL);\r
+        else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)\r
+                || !(0xA1 <= buf[2] && buf[2] <= 0xFE))\r
+            return seterror(EILSEQ);\r
+        return 3;\r
+    }\r
+    else /* JIS X 0208 */\r
+    {\r
+        if (bufsize < 2)\r
+            return seterror(EINVAL);\r
+        else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)\r
+                || !(0xA1 <= buf[1] && buf[1] <= 0xFE))\r
+            return seterror(EILSEQ);\r
+        return 2;\r
+    }\r
+}\r
+\r
+static int\r
+kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
+{\r
+    int len;\r
+\r
+    len = cv->mblen(cv, buf, bufsize);\r
+    if (len == -1)\r
+        return -1;\r
+    *wbufsize = MultiByteToWideChar(cv->codepage, mbtowc_flags (cv->codepage),\r
+            (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);\r
+    if (*wbufsize == 0)\r
+        return seterror(EILSEQ);\r
+    return len;\r
+}\r
+\r
+static int\r
+kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
+{\r
+    BOOL usedDefaultChar = 0;\r
+    BOOL *p = NULL;\r
+    int flags = 0;\r
+    int len;\r
+\r
+    if (bufsize == 0)\r
+        return seterror(E2BIG);\r
+    if (!must_use_null_useddefaultchar(cv->codepage))\r
+    {\r
+        p = &usedDefaultChar;\r
+#ifdef WC_NO_BEST_FIT_CHARS\r
+        if (!(cv->flags & FLAG_TRANSLIT))\r
+            flags |= WC_NO_BEST_FIT_CHARS;\r
+#endif\r
+    }\r
+    len = WideCharToMultiByte(cv->codepage, flags,\r
+            (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL, p);\r
+    if (len == 0)\r
+    {\r
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)\r
+            return seterror(E2BIG);\r
+        return seterror(EILSEQ);\r
+    }\r
+    else if (usedDefaultChar)\r
+        return seterror(EILSEQ);\r
+    else if (cv->mblen(cv, buf, len) != len) /* validate result */\r
+        return seterror(EILSEQ);\r
+    return len;\r
+}\r
+\r
+/*\r
+ * It seems that the mode (cv->mode) is fixnum.\r
+ * For example, when converting iso-2022-jp(cp50221) to unicode:\r
+ *      in ascii sequence: mode=0xC42C0000\r
+ *   in jisx0208 sequence: mode=0xC42C0001\r
+ * "C42C" is same for each convert session.\r
+ * It should be: ((codepage-1)<<16)|state\r
+ */\r
+static int\r
+mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
+{\r
+    int len;\r
+    int insize;\r
+    HRESULT hr;\r
+\r
+    len = cv->mblen(cv, buf, bufsize);\r
+    if (len == -1)\r
+        return -1;\r
+    insize = len;\r
+    hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,\r
+            (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);\r
+    if (hr != S_OK || insize != len)\r
+        return seterror(EILSEQ);\r
+    return len;\r
+}\r
+\r
+static int\r
+mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
+{\r
+    char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */\r
+    int tmpsize = MB_CHAR_MAX;\r
+    int insize = wbufsize;\r
+    HRESULT hr;\r
+\r
+    hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,\r
+            (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);\r
+    if (hr != S_OK || insize != wbufsize)\r
+        return seterror(EILSEQ);\r
+    else if (bufsize < tmpsize)\r
+        return seterror(E2BIG);\r
+    else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)\r
+        return seterror(EILSEQ);\r
+    memcpy(buf, tmpbuf, tmpsize);\r
+    return tmpsize;\r
+}\r
+\r
+static int\r
+utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
+{\r
+    int codepage = cv->codepage;\r
+\r
+    /* swap endian: 1200 <-> 1201 */\r
+    if (cv->mode & UNICODE_MODE_SWAPPED)\r
+        codepage ^= 1;\r
+\r
+    if (bufsize < 2)\r
+        return seterror(EINVAL);\r
+    if (codepage == 1200) /* little endian */\r
+        wbuf[0] = (buf[1] << 8) | buf[0];\r
+    else if (codepage == 1201) /* big endian */\r
+        wbuf[0] = (buf[0] << 8) | buf[1];\r
+\r
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
+    {\r
+        cv->mode |= UNICODE_MODE_BOM_DONE;\r
+        if (wbuf[0] == 0xFFFE)\r
+        {\r
+            cv->mode |= UNICODE_MODE_SWAPPED;\r
+            *wbufsize = 0;\r
+            return 2;\r
+        }\r
+        else if (wbuf[0] == 0xFEFF)\r
+        {\r
+            *wbufsize = 0;\r
+            return 2;\r
+        }\r
+    }\r
+\r
+    if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)\r
+        return seterror(EILSEQ);\r
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
+    {\r
+        if (bufsize < 4)\r
+            return seterror(EINVAL);\r
+        if (codepage == 1200) /* little endian */\r
+            wbuf[1] = (buf[3] << 8) | buf[2];\r
+        else if (codepage == 1201) /* big endian */\r
+            wbuf[1] = (buf[2] << 8) | buf[3];\r
+        if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))\r
+            return seterror(EILSEQ);\r
+        *wbufsize = 2;\r
+        return 4;\r
+    }\r
+    *wbufsize = 1;\r
+    return 2;\r
+}\r
+\r
+static int\r
+utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
+{\r
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
+    {\r
+        int r;\r
+\r
+        cv->mode |= UNICODE_MODE_BOM_DONE;\r
+        if (bufsize < 2)\r
+            return seterror(E2BIG);\r
+        if (cv->codepage == 1200) /* little endian */\r
+            memcpy(buf, "\xFF\xFE", 2);\r
+        else if (cv->codepage == 1201) /* big endian */\r
+            memcpy(buf, "\xFE\xFF", 2);\r
+\r
+        r = utf16_wctomb(cv, wbuf, wbufsize, buf + 2, bufsize - 2);\r
+        if (r == -1)\r
+            return -1;\r
+        return r + 2;\r
+    }\r
+\r
+    if (bufsize < 2)\r
+        return seterror(E2BIG);\r
+    if (cv->codepage == 1200) /* little endian */\r
+    {\r
+        buf[0] = (wbuf[0] & 0x00FF);\r
+        buf[1] = (wbuf[0] & 0xFF00) >> 8;\r
+    }\r
+    else if (cv->codepage == 1201) /* big endian */\r
+    {\r
+        buf[0] = (wbuf[0] & 0xFF00) >> 8;\r
+        buf[1] = (wbuf[0] & 0x00FF);\r
+    }\r
+    if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)\r
+    {\r
+        if (bufsize < 4)\r
+            return seterror(E2BIG);\r
+        if (cv->codepage == 1200) /* little endian */\r
+        {\r
+            buf[2] = (wbuf[1] & 0x00FF);\r
+            buf[3] = (wbuf[1] & 0xFF00) >> 8;\r
+        }\r
+        else if (cv->codepage == 1201) /* big endian */\r
+        {\r
+            buf[2] = (wbuf[1] & 0xFF00) >> 8;\r
+            buf[3] = (wbuf[1] & 0x00FF);\r
+        }\r
+        return 4;\r
+    }\r
+    return 2;\r
+}\r
+\r
+static int\r
+utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
+{\r
+    int codepage = cv->codepage;\r
+    uint wc;\r
+\r
+    /* swap endian: 12000 <-> 12001 */\r
+    if (cv->mode & UNICODE_MODE_SWAPPED)\r
+        codepage ^= 1;\r
+\r
+    if (bufsize < 4)\r
+        return seterror(EINVAL);\r
+    if (codepage == 12000) /* little endian */\r
+        wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];\r
+    else if (codepage == 12001) /* big endian */\r
+        wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];\r
+\r
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
+    {\r
+        cv->mode |= UNICODE_MODE_BOM_DONE;\r
+        if (wc == 0xFFFE0000)\r
+        {\r
+            cv->mode |= UNICODE_MODE_SWAPPED;\r
+            *wbufsize = 0;\r
+            return 4;\r
+        }\r
+        else if (wc == 0x0000FEFF)\r
+        {\r
+            *wbufsize = 0;\r
+            return 4;\r
+        }\r
+    }\r
+\r
+    if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)\r
+        return seterror(EILSEQ);\r
+    ucs4_to_utf16(wc, wbuf, wbufsize);\r
+    return 4;\r
+}\r
+\r
+static int\r
+utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
+{\r
+    uint wc;\r
+\r
+    if ((cv->flags & FLAG_USE_BOM) && !(cv->mode & UNICODE_MODE_BOM_DONE))\r
+    {\r
+        int r;\r
+\r
+        cv->mode |= UNICODE_MODE_BOM_DONE;\r
+        if (bufsize < 4)\r
+            return seterror(E2BIG);\r
+        if (cv->codepage == 12000) /* little endian */\r
+            memcpy(buf, "\xFF\xFE\x00\x00", 4);\r
+        else if (cv->codepage == 12001) /* big endian */\r
+            memcpy(buf, "\x00\x00\xFE\xFF", 4);\r
+\r
+        r = utf32_wctomb(cv, wbuf, wbufsize, buf + 4, bufsize - 4);\r
+        if (r == -1)\r
+            return -1;\r
+        return r + 4;\r
+    }\r
+\r
+    if (bufsize < 4)\r
+        return seterror(E2BIG);\r
+    wc = utf16_to_ucs4(wbuf);\r
+    if (cv->codepage == 12000) /* little endian */\r
+    {\r
+        buf[0] = wc & 0x000000FF;\r
+        buf[1] = (wc & 0x0000FF00) >> 8;\r
+        buf[2] = (wc & 0x00FF0000) >> 16;\r
+        buf[3] = (wc & 0xFF000000) >> 24;\r
+    }\r
+    else if (cv->codepage == 12001) /* big endian */\r
+    {\r
+        buf[0] = (wc & 0xFF000000) >> 24;\r
+        buf[1] = (wc & 0x00FF0000) >> 16;\r
+        buf[2] = (wc & 0x0000FF00) >> 8;\r
+        buf[3] = wc & 0x000000FF;\r
+    }\r
+    return 4;\r
+}\r
+\r
+/*\r
+ * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)\r
+ * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow\r
+ *        1 byte Kana)\r
+ * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte\r
+ *        Kana - SO/SI)\r
+ *\r
+ * MultiByteToWideChar() and WideCharToMultiByte() behave differently\r
+ * depending on Windows version.  On XP, WideCharToMultiByte() doesn't\r
+ * terminate result sequence with ascii escape.  But Vista does.\r
+ * Use MLang instead.\r
+ */\r
+\r
+#define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))\r
+#define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)\r
+#define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)\r
+\r
+#define ISO2022_SI  0\r
+#define ISO2022_SO  1\r
+\r
+/* shift in */\r
+static const char iso2022_SI_seq[] = "\x0F";\r
+/* shift out */\r
+static const char iso2022_SO_seq[] = "\x0E";\r
+\r
+typedef struct iso2022_esc_t iso2022_esc_t;\r
+struct iso2022_esc_t {\r
+    const char *esc;\r
+    int esc_len;\r
+    int len;\r
+    int cs;\r
+};\r
+\r
+#define ISO2022JP_CS_ASCII            0\r
+#define ISO2022JP_CS_JISX0201_ROMAN   1\r
+#define ISO2022JP_CS_JISX0201_KANA    2\r
+#define ISO2022JP_CS_JISX0208_1978    3\r
+#define ISO2022JP_CS_JISX0208_1983    4\r
+#define ISO2022JP_CS_JISX0212         5\r
+\r
+static iso2022_esc_t iso2022jp_esc[] = {\r
+    {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},\r
+    {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},\r
+    {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},\r
+    {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */\r
+    {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},\r
+    {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},\r
+    {NULL, 0, 0, 0}\r
+};\r
+\r
+static int\r
+iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)\r
+{\r
+    iso2022_esc_t *iesc = iso2022jp_esc;\r
+    char tmp[MB_CHAR_MAX];\r
+    int insize;\r
+    HRESULT hr;\r
+    DWORD dummy = 0;\r
+    int len;\r
+    int esc_len;\r
+    int cs;\r
+    int shift;\r
+    int i;\r
+\r
+    if (buf[0] == 0x1B)\r
+    {\r
+        for (i = 0; iesc[i].esc != NULL; ++i)\r
+        {\r
+            esc_len = iesc[i].esc_len;\r
+            if (bufsize < esc_len)\r
+            {\r
+                if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)\r
+                    return seterror(EINVAL);\r
+            }\r
+            else\r
+            {\r
+                if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)\r
+                {\r
+                    cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);\r
+                    *wbufsize = 0;\r
+                    return esc_len;\r
+                }\r
+            }\r
+        }\r
+        /* not supported escape sequence */\r
+        return seterror(EILSEQ);\r
+    }\r
+    else if (buf[0] == iso2022_SO_seq[0])\r
+    {\r
+        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);\r
+        *wbufsize = 0;\r
+        return 1;\r
+    }\r
+    else if (buf[0] == iso2022_SI_seq[0])\r
+    {\r
+        cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);\r
+        *wbufsize = 0;\r
+        return 1;\r
+    }\r
+\r
+    cs = ISO2022_MODE_CS(cv->mode);\r
+    shift = ISO2022_MODE_SHIFT(cv->mode);\r
+\r
+    /* reset the mode for informal sequence */\r
+    if (buf[0] < 0x20)\r
+    {\r
+        cs = ISO2022JP_CS_ASCII;\r
+        shift = ISO2022_SI;\r
+    }\r
+\r
+    len = iesc[cs].len;\r
+    if (bufsize < len)\r
+        return seterror(EINVAL);\r
+    for (i = 0; i < len; ++i)\r
+        if (!(buf[i] < 0x80))\r
+            return seterror(EILSEQ);\r
+    esc_len = iesc[cs].esc_len;\r
+    memcpy(tmp, iesc[cs].esc, esc_len);\r
+    if (shift == ISO2022_SO)\r
+    {\r
+        memcpy(tmp + esc_len, iso2022_SO_seq, 1);\r
+        esc_len += 1;\r
+    }\r
+    memcpy(tmp + esc_len, buf, len);\r
+\r
+    if ((cv->codepage == 50220 || cv->codepage == 50221\r
+                || cv->codepage == 50222) && shift == ISO2022_SO)\r
+    {\r
+        /* XXX: shift-out cannot be used for mbtowc (both kernel and\r
+         * mlang) */\r
+        esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;\r
+        memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);\r
+        memcpy(tmp + esc_len, buf, len);\r
+    }\r
+\r
+    insize = len + esc_len;\r
+    hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,\r
+            (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);\r
+    if (hr != S_OK || insize != len + esc_len)\r
+        return seterror(EILSEQ);\r
+\r
+    /* Check for conversion error.  Assuming defaultChar is 0x3F. */\r
+    /* ascii should be converted from ascii */\r
+    if (wbuf[0] == buf[0]\r
+            && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))\r
+        return seterror(EILSEQ);\r
+\r
+    /* reset the mode for informal sequence */\r
+    if (cv->mode != ISO2022_MODE(cs, shift))\r
+        cv->mode = ISO2022_MODE(cs, shift);\r
+\r
+    return len;\r
+}\r
+\r
+static int\r
+iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)\r
+{\r
+    iso2022_esc_t *iesc = iso2022jp_esc;\r
+    char tmp[MB_CHAR_MAX];\r
+    int tmpsize = MB_CHAR_MAX;\r
+    int insize = wbufsize;\r
+    HRESULT hr;\r
+    DWORD dummy = 0;\r
+    int len;\r
+    int esc_len;\r
+    int cs;\r
+    int shift;\r
+    int i;\r
+\r
+    /*\r
+     * MultiByte = [escape sequence] + character + [escape sequence]\r
+     *\r
+     * Whether trailing escape sequence is added depends on which API is\r
+     * used (kernel or MLang, and its version).\r
+     */\r
+    hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,\r
+            (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);\r
+    if (hr != S_OK || insize != wbufsize)\r
+        return seterror(EILSEQ);\r
+    else if (bufsize < tmpsize)\r
+        return seterror(E2BIG);\r
+\r
+    if (tmpsize == 1)\r
+    {\r
+        cs = ISO2022JP_CS_ASCII;\r
+        esc_len = 0;\r
+    }\r
+    else\r
+    {\r
+        for (i = 1; iesc[i].esc != NULL; ++i)\r
+        {\r
+            esc_len = iesc[i].esc_len;\r
+            if (strncmp(tmp, iesc[i].esc, esc_len) == 0)\r
+            {\r
+                cs = iesc[i].cs;\r
+                break;\r
+            }\r
+        }\r
+        if (iesc[i].esc == NULL)\r
+            /* not supported escape sequence */\r
+            return seterror(EILSEQ);\r
+    }\r
+\r
+    shift = ISO2022_SI;\r
+    if (tmp[esc_len] == iso2022_SO_seq[0])\r
+    {\r
+        shift = ISO2022_SO;\r
+        esc_len += 1;\r
+    }\r
+\r
+    len = iesc[cs].len;\r
+\r
+    /* Check for converting error.  Assuming defaultChar is 0x3F. */\r
+    /* ascii should be converted from ascii */\r
+    if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))\r
+        return seterror(EILSEQ);\r
+    else if (tmpsize < esc_len + len)\r
+        return seterror(EILSEQ);\r
+\r
+    if (cv->mode == ISO2022_MODE(cs, shift))\r
+    {\r
+        /* remove escape sequence */\r
+        if (esc_len != 0)\r
+            memmove(tmp, tmp + esc_len, len);\r
+        esc_len = 0;\r
+    }\r
+    else\r
+    {\r
+        if (cs == ISO2022JP_CS_ASCII)\r
+        {\r
+            esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;\r
+            memmove(tmp + esc_len, tmp, len);\r
+            memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);\r
+        }\r
+        if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)\r
+        {\r
+            /* shift-in before changing to other mode */\r
+            memmove(tmp + 1, tmp, len + esc_len);\r
+            memcpy(tmp, iso2022_SI_seq, 1);\r
+            esc_len += 1;\r
+        }\r
+    }\r
+\r
+    if (bufsize < len + esc_len)\r
+        return seterror(E2BIG);\r
+    memcpy(buf, tmp, len + esc_len);\r
+    cv->mode = ISO2022_MODE(cs, shift);\r
+    return len + esc_len;\r
+}\r
+\r
+static int\r
+iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)\r
+{\r
+    iso2022_esc_t *iesc = iso2022jp_esc;\r
+    int esc_len;\r
+\r
+    if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))\r
+    {\r
+        esc_len = 0;\r
+        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)\r
+            esc_len += 1;\r
+        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)\r
+            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;\r
+        if (bufsize < esc_len)\r
+            return seterror(E2BIG);\r
+\r
+        esc_len = 0;\r
+        if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)\r
+        {\r
+            memcpy(buf, iso2022_SI_seq, 1);\r
+            esc_len += 1;\r
+        }\r
+        if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)\r
+        {\r
+            memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,\r
+                    iesc[ISO2022JP_CS_ASCII].esc_len);\r
+            esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;\r
+        }\r
+        return esc_len;\r
+    }\r
+    return 0;\r
+}\r
+\r
+#if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)\r
+BOOL WINAPI\r
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)\r
+{\r
+    switch( fdwReason )\r
+    {\r
+    case DLL_PROCESS_ATTACH:\r
+        hwiniconv = (HMODULE)hinstDLL;\r
+        break;\r
+    case DLL_THREAD_ATTACH:\r
+    case DLL_THREAD_DETACH:\r
+    case DLL_PROCESS_DETACH:\r
+        break;\r
+    }\r
+    return TRUE;\r
+}\r
+#endif\r
+\r
+#if defined(MAKE_EXE)\r
+#include <stdio.h>\r
+#include <fcntl.h>\r
+#include <io.h>\r
+int\r
+main(int argc, char **argv)\r
+{\r
+    char *fromcode = NULL;\r
+    char *tocode = NULL;\r
+    int i;\r
+    char inbuf[BUFSIZ];\r
+    char outbuf[BUFSIZ];\r
+    const char *pin;\r
+    char *pout;\r
+    size_t inbytesleft;\r
+    size_t outbytesleft;\r
+    size_t rest = 0;\r
+    iconv_t cd;\r
+    size_t r;\r
+    FILE *in = stdin;\r
+\r
+    _setmode(_fileno(stdin), _O_BINARY);\r
+    _setmode(_fileno(stdout), _O_BINARY);\r
+\r
+    for (i = 1; i < argc; ++i)\r
+    {\r
+        if (strcmp(argv[i], "-l") == 0)\r
+        {\r
+            for (i = 0; codepage_alias[i].name != NULL; ++i)\r
+                printf("%s\n", codepage_alias[i].name);\r
+            return 0;\r
+        }\r
+\r
+        if (strcmp(argv[i], "-f") == 0)\r
+            fromcode = argv[++i];\r
+        else if (strcmp(argv[i], "-t") == 0)\r
+            tocode = argv[++i];\r
+        else\r
+        {\r
+            in = fopen(argv[i], "rb");\r
+            if (in == NULL)\r
+            {\r
+                fprintf(stderr, "cannot open %s\n", argv[i]);\r
+                return 1;\r
+            }\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (fromcode == NULL || tocode == NULL)\r
+    {\r
+        printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);\r
+        return 0;\r
+    }\r
+\r
+    cd = iconv_open(tocode, fromcode);\r
+    if (cd == (iconv_t)(-1))\r
+    {\r
+        perror("iconv_open error");\r
+        return 1;\r
+    }\r
+\r
+    while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0\r
+            || rest != 0)\r
+    {\r
+        inbytesleft += rest;\r
+        pin = inbuf;\r
+        pout = outbuf;\r
+        outbytesleft = sizeof(outbuf);\r
+        r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);\r
+        fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);\r
+        if (r == (size_t)(-1) && errno != E2BIG && (errno != EINVAL || feof(in)))\r
+        {\r
+            perror("conversion error");\r
+            return 1;\r
+        }\r
+        memmove(inbuf, pin, inbytesleft);\r
+        rest = inbytesleft;\r
+    }\r
+    pout = outbuf;\r
+    outbytesleft = sizeof(outbuf);\r
+    r = iconv(cd, NULL, NULL, &pout, &outbytesleft);\r
+    fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);\r
+    if (r == (size_t)(-1))\r
+    {\r
+        perror("conversion error");\r
+        return 1;\r
+    }\r
+\r
+    iconv_close(cd);\r
+\r
+    return 0;\r
+}\r
+#endif\r
+\r