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