2 * iconv library implemented with Win32 API.
\r
4 * This file is placed in the public domain.
\r
6 * Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
\r
8 * If $WINICONV_LIBICONV_DLL environment variable was defined, win_iconv
\r
9 * loads the specified DLL dynamically and uses it. If loading the DLL
\r
10 * or iconv_open() failed, falls back to internal conversion.
\r
11 * $WINICONV_LIBICONV_DLL is a comma separated list. The first loadable
\r
12 * DLL is used. The specified DLL should have iconv_open(),
\r
13 * iconv_close() and iconv() functions. Or these functions can be
\r
14 * libiconv_open(), libiconv_close() and libiconv().
\r
16 * Win32 API does not support strict encoding conversion for some
\r
17 * codepage. And MLang function drop or replace invalid bytes and does
\r
18 * not return useful error status as iconv. This implementation cannot
\r
19 * be used for encoding validation purpose.
\r
22 #include <windows.h>
\r
30 # define USE_LIBICONV_DLL
\r
33 #if !defined(DEFAULT_LIBICONV_DLL)
\r
34 # define DEFAULT_LIBICONV_DLL ""
\r
37 #define MB_CHAR_MAX 16
\r
39 #define UNICODE_MODE_BOM_DONE 1
\r
40 #define UNICODE_MODE_SWAPPED 2
\r
42 #define UNICODE_FLAG_USE_BOM_ENDIAN 1
\r
44 #define return_error(code) \
\r
50 #define xstrlcpy(dst, src, size) \
\r
52 strncpy(dst, src, size); \
\r
53 dst[size - 1] = 0; \
\r
56 #define xstrlcpyn(dst, src, srclen, size) \
\r
57 xstrlcpy(dst, src, xmin((srclen) + 1, size))
\r
59 #define xmin(a, b) ((a) < (b) ? (a) : (b))
\r
60 #define xmax(a, b) ((a) > (b) ? (a) : (b))
\r
62 #define STATIC_STRLEN(arr) (sizeof(arr) - 1)
\r
64 typedef unsigned char uchar;
\r
65 typedef unsigned short ushort;
\r
66 typedef unsigned int uint;
\r
68 typedef void* iconv_t;
\r
70 iconv_t iconv_open(const char *tocode, const char *fromcode);
\r
71 int iconv_close(iconv_t cd);
\r
72 size_t iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
\r
74 /* libiconv interface for vim */
\r
75 #if defined(MAKE_DLL)
\r
77 iconvctl (iconv_t cd, int request, void* argument)
\r
84 typedef struct compat_t compat_t;
\r
85 typedef struct csconv_t csconv_t;
\r
86 typedef struct rec_iconv_t rec_iconv_t;
\r
88 typedef iconv_t (*f_iconv_open)(const char *tocode, const char *fromcode);
\r
89 typedef int (*f_iconv_close)(iconv_t cd);
\r
90 typedef size_t (*f_iconv)(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
\r
91 typedef int* (*f_errno)(void);
\r
92 typedef int (*f_mbtowc)(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
\r
93 typedef int (*f_wctomb)(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
\r
94 typedef int (*f_mblen)(csconv_t *cv, const uchar *buf, int bufsize);
\r
95 typedef int (*f_flush)(csconv_t *cv, uchar *buf, int bufsize);
\r
98 #define COMPAT_OUT 2
\r
100 /* unicode mapping for compatibility with other conversion table. */
\r
118 struct rec_iconv_t {
\r
120 f_iconv_close iconv_close;
\r
125 #if defined(USE_LIBICONV_DLL)
\r
130 static int win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
\r
131 static int win_iconv_close(iconv_t cd);
\r
132 static size_t win_iconv(iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
\r
134 static int load_mlang();
\r
135 static csconv_t make_csconv(const char *name);
\r
136 static int name_to_codepage(const char *name);
\r
137 static uint utf16_to_ucs4(const ushort *wbuf);
\r
138 static void ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize);
\r
139 static int is_unicode(int codepage);
\r
140 static int must_use_null_useddefaultchar(int codepage);
\r
141 static void check_utf_bom(rec_iconv_t *cd, ushort *wbuf, int *wbufsize);
\r
142 static char *strrstr(const char *str, const char *token);
\r
144 #if defined(USE_LIBICONV_DLL)
\r
145 static int libiconv_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode);
\r
146 static PVOID MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size);
\r
147 static HMODULE find_imported_module_by_funcname(HMODULE hModule, const char *funcname);
\r
149 static HMODULE hwiniconv;
\r
150 static HMODULE hlastdll; /* keep dll loaded for efficiency (unnecessary?) */
\r
153 static int sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
\r
154 static int dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize);
\r
155 static int utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize);
\r
156 static int eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize);
\r
158 static int kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
\r
159 static int kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
\r
160 static int mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
\r
161 static int mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
\r
162 static int utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
\r
163 static int utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
\r
164 static int utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
\r
165 static int utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
\r
166 static int iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize);
\r
167 static int iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize);
\r
168 static int iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize);
\r
173 } codepage_alias[] = {
\r
174 {65001, "CP65001"},
\r
180 {1200, "UTF-16LE"},
\r
184 {1201, "UTF-16BE"},
\r
185 {1201, "unicodeFFFE"},
\r
187 {12000, "CP12000"},
\r
188 {12000, "UTF32LE"},
\r
189 {12000, "UTF-32LE"},
\r
191 {12001, "CP12001"},
\r
192 {12001, "UTF32BE"},
\r
193 {12001, "UTF-32BE"},
\r
195 #ifndef GLIB_COMPILATION
\r
197 * Default is big endian.
\r
198 * See rfc2781 4.3 Interpreting text labelled as UTF-16.
\r
205 /* Default is little endian, because the platform is */
\r
212 /* copy from libiconv `iconv -l` */
\r
213 /* !IsValidCodePage(367) */
\r
214 {20127, "ANSI_X3.4-1968"},
\r
215 {20127, "ANSI_X3.4-1986"},
\r
219 {20127, "ISO-IR-6"},
\r
220 {20127, "ISO646-US"},
\r
221 {20127, "ISO_646.IRV:1991"},
\r
223 {20127, "US-ASCII"},
\r
224 {20127, "CSASCII"},
\r
226 /* !IsValidCodePage(819) */
\r
229 {28591, "ISO-8859-1"},
\r
230 {28591, "ISO-IR-100"},
\r
231 {28591, "ISO8859-1"},
\r
232 {28591, "ISO_8859-1"},
\r
233 {28591, "ISO_8859-1:1987"},
\r
236 {28591, "CSISOLATIN1"},
\r
240 {1250, "WINDOWS-1250"},
\r
244 {1251, "WINDOWS-1251"},
\r
248 {1252, "WINDOWS-1252"},
\r
251 {1253, "MS-GREEK"},
\r
252 {1253, "WINDOWS-1253"},
\r
256 {1254, "WINDOWS-1254"},
\r
260 {1255, "WINDOWS-1255"},
\r
264 {1256, "WINDOWS-1256"},
\r
267 {1257, "WINBALTRIM"},
\r
268 {1257, "WINDOWS-1257"},
\r
271 {1258, "WINDOWS-1258"},
\r
276 {850, "CSPC850MULTILINGUAL"},
\r
278 /* !IsValidCodePage(862) */
\r
282 {862, "CSPC862LATINHEBREW"},
\r
289 /* !IsValidCodePage(154) */
\r
291 {154, "CYRILLIC-ASIAN"},
\r
294 {154, "CSPTCP154"},
\r
296 /* !IsValidCodePage(1133) */
\r
298 {1133, "IBM-CP1133"},
\r
301 {874, "WINDOWS-874"},
\r
303 /* !IsValidCodePage(51932) */
\r
304 {51932, "CP51932"},
\r
305 {51932, "MS51932"},
\r
306 {51932, "WINDOWS-51932"},
\r
311 {932, "SHIFFT_JIS"},
\r
312 {932, "SHIFFT_JIS-MS"},
\r
315 {932, "SJIS-OPEN"},
\r
317 {932, "WINDOWS-31J"},
\r
318 {932, "WINDOWS-932"},
\r
319 {932, "CSWINDOWS31J"},
\r
321 {50221, "CP50221"},
\r
322 {50221, "ISO-2022-JP"},
\r
323 {50221, "ISO-2022-JP-MS"},
\r
324 {50221, "ISO2022-JP"},
\r
325 {50221, "ISO2022-JP-MS"},
\r
326 {50221, "MS50221"},
\r
327 {50221, "WINDOWS-50221"},
\r
332 {936, "WINDOWS-936"},
\r
347 {437, "CSPC8CODEPAGE437"},
\r
353 {775, "CSPC775BALTIC"},
\r
360 /* !IsValidCodePage(853) */
\r
373 /* !IsValidCodePage(858) */
\r
407 /* !IsValidCodePage(1152) */
\r
411 * Code Page Identifiers
\r
412 * http://msdn2.microsoft.com/en-us/library/ms776446.aspx
\r
414 {37, "IBM037"}, /* IBM EBCDIC US-Canada */
\r
415 {437, "IBM437"}, /* OEM United States */
\r
416 {500, "IBM500"}, /* IBM EBCDIC International */
\r
417 {708, "ASMO-708"}, /* Arabic (ASMO 708) */
\r
418 /* 709 Arabic (ASMO-449+, BCON V4) */
\r
419 /* 710 Arabic - Transparent Arabic */
\r
420 {720, "DOS-720"}, /* Arabic (Transparent ASMO); Arabic (DOS) */
\r
421 {737, "ibm737"}, /* OEM Greek (formerly 437G); Greek (DOS) */
\r
422 {775, "ibm775"}, /* OEM Baltic; Baltic (DOS) */
\r
423 {850, "ibm850"}, /* OEM Multilingual Latin 1; Western European (DOS) */
\r
424 {852, "ibm852"}, /* OEM Latin 2; Central European (DOS) */
\r
425 {855, "IBM855"}, /* OEM Cyrillic (primarily Russian) */
\r
426 {857, "ibm857"}, /* OEM Turkish; Turkish (DOS) */
\r
427 {858, "IBM00858"}, /* OEM Multilingual Latin 1 + Euro symbol */
\r
428 {860, "IBM860"}, /* OEM Portuguese; Portuguese (DOS) */
\r
429 {861, "ibm861"}, /* OEM Icelandic; Icelandic (DOS) */
\r
430 {862, "DOS-862"}, /* OEM Hebrew; Hebrew (DOS) */
\r
431 {863, "IBM863"}, /* OEM French Canadian; French Canadian (DOS) */
\r
432 {864, "IBM864"}, /* OEM Arabic; Arabic (864) */
\r
433 {865, "IBM865"}, /* OEM Nordic; Nordic (DOS) */
\r
434 {866, "cp866"}, /* OEM Russian; Cyrillic (DOS) */
\r
435 {869, "ibm869"}, /* OEM Modern Greek; Greek, Modern (DOS) */
\r
436 {870, "IBM870"}, /* IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2 */
\r
437 {874, "windows-874"}, /* ANSI/OEM Thai (same as 28605, ISO 8859-15); Thai (Windows) */
\r
438 {875, "cp875"}, /* IBM EBCDIC Greek Modern */
\r
439 {932, "shift_jis"}, /* ANSI/OEM Japanese; Japanese (Shift-JIS) */
\r
440 {932, "shift-jis"}, /* alternative name for it */
\r
441 {936, "gb2312"}, /* ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312) */
\r
442 {949, "ks_c_5601-1987"}, /* ANSI/OEM Korean (Unified Hangul Code) */
\r
443 {950, "big5"}, /* ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5) */
\r
444 {1026, "IBM1026"}, /* IBM EBCDIC Turkish (Latin 5) */
\r
445 {1047, "IBM01047"}, /* IBM EBCDIC Latin 1/Open System */
\r
446 {1140, "IBM01140"}, /* IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro) */
\r
447 {1141, "IBM01141"}, /* IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro) */
\r
448 {1142, "IBM01142"}, /* IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro) */
\r
449 {1143, "IBM01143"}, /* IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro) */
\r
450 {1144, "IBM01144"}, /* IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro) */
\r
451 {1145, "IBM01145"}, /* IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro) */
\r
452 {1146, "IBM01146"}, /* IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro) */
\r
453 {1147, "IBM01147"}, /* IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro) */
\r
454 {1148, "IBM01148"}, /* IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro) */
\r
455 {1149, "IBM01149"}, /* IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro) */
\r
456 {1250, "windows-1250"}, /* ANSI Central European; Central European (Windows) */
\r
457 {1251, "windows-1251"}, /* ANSI Cyrillic; Cyrillic (Windows) */
\r
458 {1252, "windows-1252"}, /* ANSI Latin 1; Western European (Windows) */
\r
459 {1253, "windows-1253"}, /* ANSI Greek; Greek (Windows) */
\r
460 {1254, "windows-1254"}, /* ANSI Turkish; Turkish (Windows) */
\r
461 {1255, "windows-1255"}, /* ANSI Hebrew; Hebrew (Windows) */
\r
462 {1256, "windows-1256"}, /* ANSI Arabic; Arabic (Windows) */
\r
463 {1257, "windows-1257"}, /* ANSI Baltic; Baltic (Windows) */
\r
464 {1258, "windows-1258"}, /* ANSI/OEM Vietnamese; Vietnamese (Windows) */
\r
465 {1361, "Johab"}, /* Korean (Johab) */
\r
466 {10000, "macintosh"}, /* MAC Roman; Western European (Mac) */
\r
467 {10001, "x-mac-japanese"}, /* Japanese (Mac) */
\r
468 {10002, "x-mac-chinesetrad"}, /* MAC Traditional Chinese (Big5); Chinese Traditional (Mac) */
\r
469 {10003, "x-mac-korean"}, /* Korean (Mac) */
\r
470 {10004, "x-mac-arabic"}, /* Arabic (Mac) */
\r
471 {10005, "x-mac-hebrew"}, /* Hebrew (Mac) */
\r
472 {10006, "x-mac-greek"}, /* Greek (Mac) */
\r
473 {10007, "x-mac-cyrillic"}, /* Cyrillic (Mac) */
\r
474 {10008, "x-mac-chinesesimp"}, /* MAC Simplified Chinese (GB 2312); Chinese Simplified (Mac) */
\r
475 {10010, "x-mac-romanian"}, /* Romanian (Mac) */
\r
476 {10017, "x-mac-ukrainian"}, /* Ukrainian (Mac) */
\r
477 {10021, "x-mac-thai"}, /* Thai (Mac) */
\r
478 {10029, "x-mac-ce"}, /* MAC Latin 2; Central European (Mac) */
\r
479 {10079, "x-mac-icelandic"}, /* Icelandic (Mac) */
\r
480 {10081, "x-mac-turkish"}, /* Turkish (Mac) */
\r
481 {10082, "x-mac-croatian"}, /* Croatian (Mac) */
\r
482 {20000, "x-Chinese_CNS"}, /* CNS Taiwan; Chinese Traditional (CNS) */
\r
483 {20001, "x-cp20001"}, /* TCA Taiwan */
\r
484 {20002, "x_Chinese-Eten"}, /* Eten Taiwan; Chinese Traditional (Eten) */
\r
485 {20003, "x-cp20003"}, /* IBM5550 Taiwan */
\r
486 {20004, "x-cp20004"}, /* TeleText Taiwan */
\r
487 {20005, "x-cp20005"}, /* Wang Taiwan */
\r
488 {20105, "x-IA5"}, /* IA5 (IRV International Alphabet No. 5, 7-bit); Western European (IA5) */
\r
489 {20106, "x-IA5-German"}, /* IA5 German (7-bit) */
\r
490 {20107, "x-IA5-Swedish"}, /* IA5 Swedish (7-bit) */
\r
491 {20108, "x-IA5-Norwegian"}, /* IA5 Norwegian (7-bit) */
\r
492 {20127, "us-ascii"}, /* US-ASCII (7-bit) */
\r
493 {20261, "x-cp20261"}, /* T.61 */
\r
494 {20269, "x-cp20269"}, /* ISO 6937 Non-Spacing Accent */
\r
495 {20273, "IBM273"}, /* IBM EBCDIC Germany */
\r
496 {20277, "IBM277"}, /* IBM EBCDIC Denmark-Norway */
\r
497 {20278, "IBM278"}, /* IBM EBCDIC Finland-Sweden */
\r
498 {20280, "IBM280"}, /* IBM EBCDIC Italy */
\r
499 {20284, "IBM284"}, /* IBM EBCDIC Latin America-Spain */
\r
500 {20285, "IBM285"}, /* IBM EBCDIC United Kingdom */
\r
501 {20290, "IBM290"}, /* IBM EBCDIC Japanese Katakana Extended */
\r
502 {20297, "IBM297"}, /* IBM EBCDIC France */
\r
503 {20420, "IBM420"}, /* IBM EBCDIC Arabic */
\r
504 {20423, "IBM423"}, /* IBM EBCDIC Greek */
\r
505 {20424, "IBM424"}, /* IBM EBCDIC Hebrew */
\r
506 {20833, "x-EBCDIC-KoreanExtended"}, /* IBM EBCDIC Korean Extended */
\r
507 {20838, "IBM-Thai"}, /* IBM EBCDIC Thai */
\r
508 {20866, "koi8-r"}, /* Russian (KOI8-R); Cyrillic (KOI8-R) */
\r
509 {20871, "IBM871"}, /* IBM EBCDIC Icelandic */
\r
510 {20880, "IBM880"}, /* IBM EBCDIC Cyrillic Russian */
\r
511 {20905, "IBM905"}, /* IBM EBCDIC Turkish */
\r
512 {20924, "IBM00924"}, /* IBM EBCDIC Latin 1/Open System (1047 + Euro symbol) */
\r
513 {20932, "EUC-JP"}, /* Japanese (JIS 0208-1990 and 0121-1990) */
\r
514 {20936, "x-cp20936"}, /* Simplified Chinese (GB2312); Chinese Simplified (GB2312-80) */
\r
515 {20949, "x-cp20949"}, /* Korean Wansung */
\r
516 {21025, "cp1025"}, /* IBM EBCDIC Cyrillic Serbian-Bulgarian */
\r
517 /* 21027 (deprecated) */
\r
518 {21866, "koi8-u"}, /* Ukrainian (KOI8-U); Cyrillic (KOI8-U) */
\r
519 {28591, "iso-8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
\r
520 {28591, "iso8859-1"}, /* ISO 8859-1 Latin 1; Western European (ISO) */
\r
521 {28592, "iso-8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
\r
522 {28592, "iso8859-2"}, /* ISO 8859-2 Central European; Central European (ISO) */
\r
523 {28593, "iso-8859-3"}, /* ISO 8859-3 Latin 3 */
\r
524 {28593, "iso8859-3"}, /* ISO 8859-3 Latin 3 */
\r
525 {28594, "iso-8859-4"}, /* ISO 8859-4 Baltic */
\r
526 {28594, "iso8859-4"}, /* ISO 8859-4 Baltic */
\r
527 {28595, "iso-8859-5"}, /* ISO 8859-5 Cyrillic */
\r
528 {28595, "iso8859-5"}, /* ISO 8859-5 Cyrillic */
\r
529 {28596, "iso-8859-6"}, /* ISO 8859-6 Arabic */
\r
530 {28596, "iso8859-6"}, /* ISO 8859-6 Arabic */
\r
531 {28597, "iso-8859-7"}, /* ISO 8859-7 Greek */
\r
532 {28597, "iso8859-7"}, /* ISO 8859-7 Greek */
\r
533 {28598, "iso-8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
\r
534 {28598, "iso8859-8"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Visual) */
\r
535 {28599, "iso-8859-9"}, /* ISO 8859-9 Turkish */
\r
536 {28599, "iso8859-9"}, /* ISO 8859-9 Turkish */
\r
537 {28603, "iso-8859-13"}, /* ISO 8859-13 Estonian */
\r
538 {28603, "iso8859-13"}, /* ISO 8859-13 Estonian */
\r
539 {28605, "iso-8859-15"}, /* ISO 8859-15 Latin 9 */
\r
540 {28605, "iso8859-15"}, /* ISO 8859-15 Latin 9 */
\r
541 {29001, "x-Europa"}, /* Europa 3 */
\r
542 {38598, "iso-8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
\r
543 {38598, "iso8859-8-i"}, /* ISO 8859-8 Hebrew; Hebrew (ISO-Logical) */
\r
544 {50220, "iso-2022-jp"}, /* ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS) */
\r
545 {50221, "csISO2022JP"}, /* ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana) */
\r
546 {50222, "iso-2022-jp"}, /* ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI) */
\r
547 {50225, "iso-2022-kr"}, /* ISO 2022 Korean */
\r
548 {50225, "iso2022-kr"}, /* ISO 2022 Korean */
\r
549 {50227, "x-cp50227"}, /* ISO 2022 Simplified Chinese; Chinese Simplified (ISO 2022) */
\r
550 /* 50229 ISO 2022 Traditional Chinese */
\r
551 /* 50930 EBCDIC Japanese (Katakana) Extended */
\r
552 /* 50931 EBCDIC US-Canada and Japanese */
\r
553 /* 50933 EBCDIC Korean Extended and Korean */
\r
554 /* 50935 EBCDIC Simplified Chinese Extended and Simplified Chinese */
\r
555 /* 50936 EBCDIC Simplified Chinese */
\r
556 /* 50937 EBCDIC US-Canada and Traditional Chinese */
\r
557 /* 50939 EBCDIC Japanese (Latin) Extended and Japanese */
\r
558 {51932, "euc-jp"}, /* EUC Japanese */
\r
559 {51936, "EUC-CN"}, /* EUC Simplified Chinese; Chinese Simplified (EUC) */
\r
560 {51949, "euc-kr"}, /* EUC Korean */
\r
561 /* 51950 EUC Traditional Chinese */
\r
562 {52936, "hz-gb-2312"}, /* HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ) */
\r
563 {54936, "GB18030"}, /* Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030) */
\r
564 {57002, "x-iscii-de"}, /* ISCII Devanagari */
\r
565 {57003, "x-iscii-be"}, /* ISCII Bengali */
\r
566 {57004, "x-iscii-ta"}, /* ISCII Tamil */
\r
567 {57005, "x-iscii-te"}, /* ISCII Telugu */
\r
568 {57006, "x-iscii-as"}, /* ISCII Assamese */
\r
569 {57007, "x-iscii-or"}, /* ISCII Oriya */
\r
570 {57008, "x-iscii-ka"}, /* ISCII Kannada */
\r
571 {57009, "x-iscii-ma"}, /* ISCII Malayalam */
\r
572 {57010, "x-iscii-gu"}, /* ISCII Gujarati */
\r
573 {57011, "x-iscii-pa"}, /* ISCII Punjabi */
\r
579 * SJIS SHIFTJIS table CP932 table
\r
580 * ---- --------------------------- --------------------------------
\r
581 * 5C U+00A5 YEN SIGN U+005C REVERSE SOLIDUS
\r
582 * 7E U+203E OVERLINE U+007E TILDE
\r
583 * 815C U+2014 EM DASH U+2015 HORIZONTAL BAR
\r
584 * 815F U+005C REVERSE SOLIDUS U+FF3C FULLWIDTH REVERSE SOLIDUS
\r
585 * 8160 U+301C WAVE DASH U+FF5E FULLWIDTH TILDE
\r
586 * 8161 U+2016 DOUBLE VERTICAL LINE U+2225 PARALLEL TO
\r
587 * 817C U+2212 MINUS SIGN U+FF0D FULLWIDTH HYPHEN-MINUS
\r
588 * 8191 U+00A2 CENT SIGN U+FFE0 FULLWIDTH CENT SIGN
\r
589 * 8192 U+00A3 POUND SIGN U+FFE1 FULLWIDTH POUND SIGN
\r
590 * 81CA U+00AC NOT SIGN U+FFE2 FULLWIDTH NOT SIGN
\r
592 * EUC-JP and ISO-2022-JP should be compatible with CP932.
\r
594 * Kernel and MLang have different Unicode mapping table. Make sure
\r
595 * which API is used.
\r
597 static compat_t cp932_compat[] = {
\r
598 {0x00A5, 0x005C, COMPAT_OUT},
\r
599 {0x203E, 0x007E, COMPAT_OUT},
\r
600 {0x2014, 0x2015, COMPAT_OUT},
\r
601 {0x301C, 0xFF5E, COMPAT_OUT},
\r
602 {0x2016, 0x2225, COMPAT_OUT},
\r
603 {0x2212, 0xFF0D, COMPAT_OUT},
\r
604 {0x00A2, 0xFFE0, COMPAT_OUT},
\r
605 {0x00A3, 0xFFE1, COMPAT_OUT},
\r
606 {0x00AC, 0xFFE2, COMPAT_OUT},
\r
610 static compat_t cp20932_compat[] = {
\r
611 {0x00A5, 0x005C, COMPAT_OUT},
\r
612 {0x203E, 0x007E, COMPAT_OUT},
\r
613 {0x2014, 0x2015, COMPAT_OUT},
\r
614 {0xFF5E, 0x301C, COMPAT_OUT|COMPAT_IN},
\r
615 {0x2225, 0x2016, COMPAT_OUT|COMPAT_IN},
\r
616 {0xFF0D, 0x2212, COMPAT_OUT|COMPAT_IN},
\r
617 {0xFFE0, 0x00A2, COMPAT_OUT|COMPAT_IN},
\r
618 {0xFFE1, 0x00A3, COMPAT_OUT|COMPAT_IN},
\r
619 {0xFFE2, 0x00AC, COMPAT_OUT|COMPAT_IN},
\r
623 static compat_t *cp51932_compat = cp932_compat;
\r
625 /* cp20932_compat for kernel. cp932_compat for mlang. */
\r
626 static compat_t *cp5022x_compat = cp932_compat;
\r
628 typedef HRESULT (WINAPI *CONVERTINETSTRING)(
\r
630 DWORD dwSrcEncoding,
\r
631 DWORD dwDstEncoding,
\r
637 typedef HRESULT (WINAPI *CONVERTINETMULTIBYTETOUNICODE)(
\r
639 DWORD dwSrcEncoding,
\r
641 LPINT lpnMultiCharCount,
\r
643 LPINT lpnWideCharCount
\r
645 typedef HRESULT (WINAPI *CONVERTINETUNICODETOMULTIBYTE)(
\r
649 LPINT lpnWideCharCount,
\r
651 LPINT lpnMultiCharCount
\r
653 typedef HRESULT (WINAPI *ISCONVERTINETSTRINGAVAILABLE)(
\r
654 DWORD dwSrcEncoding,
\r
655 DWORD dwDstEncoding
\r
657 typedef HRESULT (WINAPI *LCIDTORFC1766A)(
\r
662 typedef HRESULT (WINAPI *LCIDTORFC1766W)(
\r
667 typedef HRESULT (WINAPI *RFC1766TOLCIDA)(
\r
671 typedef HRESULT (WINAPI *RFC1766TOLCIDW)(
\r
675 static CONVERTINETSTRING ConvertINetString;
\r
676 static CONVERTINETMULTIBYTETOUNICODE ConvertINetMultiByteToUnicode;
\r
677 static CONVERTINETUNICODETOMULTIBYTE ConvertINetUnicodeToMultiByte;
\r
678 static ISCONVERTINETSTRINGAVAILABLE IsConvertINetStringAvailable;
\r
679 static LCIDTORFC1766A LcidToRfc1766A;
\r
680 static RFC1766TOLCIDA Rfc1766ToLcidA;
\r
686 if (ConvertINetString != NULL)
\r
688 h = LoadLibrary("mlang.dll");
\r
691 ConvertINetString = (CONVERTINETSTRING)GetProcAddress(h, "ConvertINetString");
\r
692 ConvertINetMultiByteToUnicode = (CONVERTINETMULTIBYTETOUNICODE)GetProcAddress(h, "ConvertINetMultiByteToUnicode");
\r
693 ConvertINetUnicodeToMultiByte = (CONVERTINETUNICODETOMULTIBYTE)GetProcAddress(h, "ConvertINetUnicodeToMultiByte");
\r
694 IsConvertINetStringAvailable = (ISCONVERTINETSTRINGAVAILABLE)GetProcAddress(h, "IsConvertINetStringAvailable");
\r
695 LcidToRfc1766A = (LCIDTORFC1766A)GetProcAddress(h, "LcidToRfc1766A");
\r
696 Rfc1766ToLcidA = (RFC1766TOLCIDA)GetProcAddress(h, "Rfc1766ToLcidA");
\r
701 iconv_open(const char *tocode, const char *fromcode)
\r
705 cd = (rec_iconv_t *)calloc(1, sizeof(rec_iconv_t));
\r
709 return (iconv_t)(-1);
\r
712 #if defined(USE_LIBICONV_DLL)
\r
713 if (libiconv_iconv_open(cd, tocode, fromcode))
\r
714 return (iconv_t)cd;
\r
717 if (win_iconv_open(cd, tocode, fromcode))
\r
718 return (iconv_t)cd;
\r
722 return (iconv_t)(-1);
\r
726 iconv_close(iconv_t _cd)
\r
728 rec_iconv_t *cd = (rec_iconv_t *)_cd;
\r
729 int r = cd->iconv_close(cd->cd);
\r
730 int e = *(cd->_errno());
\r
731 #if defined(USE_LIBICONV_DLL)
\r
732 if (cd->hlibiconv != NULL)
\r
733 FreeLibrary(cd->hlibiconv);
\r
741 iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
\r
743 rec_iconv_t *cd = (rec_iconv_t *)_cd;
\r
744 size_t r = cd->iconv(cd->cd, inbuf, inbytesleft, outbuf, outbytesleft);
\r
745 errno = *(cd->_errno());
\r
750 win_iconv_open(rec_iconv_t *cd, const char *tocode, const char *fromcode)
\r
752 cd->from = make_csconv(fromcode);
\r
753 cd->to = make_csconv(tocode);
\r
754 if (cd->from.codepage == -1 || cd->to.codepage == -1)
\r
756 cd->iconv_close = win_iconv_close;
\r
757 cd->iconv = win_iconv;
\r
758 cd->_errno = _errno;
\r
759 cd->cd = (iconv_t)cd;
\r
764 win_iconv_close(iconv_t cd)
\r
770 win_iconv(iconv_t _cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
\r
772 rec_iconv_t *cd = (rec_iconv_t *)_cd;
\r
773 ushort wbuf[MB_CHAR_MAX]; /* enough room for one character */
\r
782 if (inbuf == NULL || *inbuf == NULL)
\r
784 if (outbuf != NULL && *outbuf != NULL && cd->to.flush != NULL)
\r
786 outsize = cd->to.flush(&cd->to, (uchar *)*outbuf, *outbytesleft);
\r
788 return (size_t)(-1);
\r
789 *outbuf += outsize;
\r
790 *outbytesleft -= outsize;
\r
792 if (is_unicode(cd->from.codepage) && (cd->from.mode & UNICODE_MODE_SWAPPED))
\r
793 cd->from.codepage ^= 1;
\r
799 while (*inbytesleft != 0)
\r
801 mode = cd->from.mode;
\r
802 wsize = MB_CHAR_MAX;
\r
804 insize = cd->from.mbtowc(&cd->from, (const uchar *)*inbuf, *inbytesleft, wbuf, &wsize);
\r
806 return (size_t)(-1);
\r
808 if (is_unicode(cd->from.codepage) && !(cd->from.mode & UNICODE_MODE_BOM_DONE))
\r
810 check_utf_bom(cd, wbuf, &wsize);
\r
811 cd->from.mode |= UNICODE_MODE_BOM_DONE;
\r
817 *inbytesleft -= insize;
\r
821 if (cd->from.compat != NULL)
\r
823 wc = utf16_to_ucs4(wbuf);
\r
824 cp = cd->from.compat;
\r
825 for (i = 0; cp[i].in != 0; ++i)
\r
827 if ((cp[i].flag & COMPAT_IN) && cp[i].out == wc)
\r
829 ucs4_to_utf16(cp[i].in, wbuf, &wsize);
\r
835 if (cd->to.compat != NULL)
\r
837 wc = utf16_to_ucs4(wbuf);
\r
838 cp = cd->to.compat;
\r
839 for (i = 0; cp[i].in != 0; ++i)
\r
841 if ((cp[i].flag & COMPAT_OUT) && cp[i].in == wc)
\r
843 ucs4_to_utf16(cp[i].out, wbuf, &wsize);
\r
849 outsize = cd->to.wctomb(&cd->to, wbuf, wsize, (uchar *)*outbuf, *outbytesleft);
\r
852 cd->from.mode = mode;
\r
853 return (size_t)(-1);
\r
857 *outbuf += outsize;
\r
858 *inbytesleft -= insize;
\r
859 *outbytesleft -= outsize;
\r
866 make_csconv(const char *_name)
\r
870 int use_compat = TRUE;
\r
874 xstrlcpy(name, _name, sizeof(name));
\r
876 /* check for option "enc_name//opt1//opt2" */
\r
877 while ((p = strrstr(name, "//")) != NULL)
\r
879 if (_stricmp(p + 2, "nocompat") == 0)
\r
880 use_compat = FALSE;
\r
889 cv.codepage = name_to_codepage(name);
\r
890 if (cv.codepage == 1200 || cv.codepage == 1201)
\r
892 cv.mbtowc = utf16_mbtowc;
\r
893 cv.wctomb = utf16_wctomb;
\r
894 if (_stricmp(name, "UTF-16") == 0 || _stricmp(name, "UTF16") == 0)
\r
895 cv.flags |= UNICODE_FLAG_USE_BOM_ENDIAN;
\r
897 else if (cv.codepage == 12000 || cv.codepage == 12001)
\r
899 cv.mbtowc = utf32_mbtowc;
\r
900 cv.wctomb = utf32_wctomb;
\r
901 if (_stricmp(name, "UTF-32") == 0 || _stricmp(name, "UTF32") == 0)
\r
902 cv.flags |= UNICODE_FLAG_USE_BOM_ENDIAN;
\r
904 else if (cv.codepage == 65001)
\r
906 cv.mbtowc = kernel_mbtowc;
\r
907 cv.wctomb = kernel_wctomb;
\r
908 cv.mblen = utf8_mblen;
\r
910 else if ((cv.codepage == 50220 || cv.codepage == 50221 || cv.codepage == 50222) && load_mlang())
\r
912 cv.mbtowc = iso2022jp_mbtowc;
\r
913 cv.wctomb = iso2022jp_wctomb;
\r
914 cv.flush = iso2022jp_flush;
\r
916 else if (cv.codepage == 51932 && load_mlang())
\r
918 cv.mbtowc = mlang_mbtowc;
\r
919 cv.wctomb = mlang_wctomb;
\r
920 cv.mblen = eucjp_mblen;
\r
922 else if (IsValidCodePage(cv.codepage)
\r
923 && GetCPInfoEx(cv.codepage, 0, &cpinfoex) != 0
\r
924 && (cpinfoex.MaxCharSize == 1 || cpinfoex.MaxCharSize == 2))
\r
926 cv.mbtowc = kernel_mbtowc;
\r
927 cv.wctomb = kernel_wctomb;
\r
928 if (cpinfoex.MaxCharSize == 1)
\r
929 cv.mblen = sbcs_mblen;
\r
931 cv.mblen = dbcs_mblen;
\r
935 /* not supported */
\r
940 switch (cv.codepage)
\r
942 case 932: cv.compat = cp932_compat; break;
\r
943 case 20932: cv.compat = cp20932_compat; break;
\r
944 case 51932: cv.compat = cp51932_compat; break;
\r
945 case 50220: case 50221: case 50222: cv.compat = cp5022x_compat; break;
\r
952 name_to_codepage(const char *name)
\r
956 if (_strnicmp(name, "cp", 2) == 0)
\r
957 return atoi(name + 2); /* CP123 */
\r
958 else if ('0' <= name[0] && name[0] <= '9')
\r
959 return atoi(name); /* 123 */
\r
960 else if (_strnicmp(name, "xx", 2) == 0)
\r
961 return atoi(name + 2); /* XX123 for debug */
\r
963 for (i = 0; codepage_alias[i].name != NULL; ++i)
\r
964 if (_stricmp(name, codepage_alias[i].name) == 0)
\r
965 return codepage_alias[i].codepage;
\r
970 * http://www.faqs.org/rfcs/rfc2781.html
\r
973 utf16_to_ucs4(const ushort *wbuf)
\r
976 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
\r
977 wc = ((wbuf[0] & 0x3FF) << 10) + (wbuf[1] & 0x3FF) + 0x10000;
\r
982 ucs4_to_utf16(uint wc, ushort *wbuf, int *wbufsize)
\r
992 wbuf[0] = 0xD800 | ((wc >> 10) & 0x3FF);
\r
993 wbuf[1] = 0xDC00 | (wc & 0x3FF);
\r
999 is_unicode(int codepage)
\r
1001 return (codepage == 1200 || codepage == 1201 ||
\r
1002 codepage == 12000 || codepage == 12001 ||
\r
1003 codepage == 65000 || codepage == 65001);
\r
1007 must_use_null_useddefaultchar(int codepage)
\r
1009 return (codepage == 65000 || codepage == 65001 ||
\r
1010 codepage == 50220 || codepage == 50221 ||
\r
1011 codepage == 50222 || codepage == 50225 ||
\r
1012 codepage == 50227 || codepage == 50229 ||
\r
1013 codepage == 52936 || codepage == 54936 ||
\r
1014 (codepage >= 57002 && codepage <= 57011) ||
\r
1019 check_utf_bom(rec_iconv_t *cd, ushort *wbuf, int *wbufsize)
\r
1021 /* If we have a BOM, trust it, despite what the caller said */
\r
1022 if (wbuf[0] == 0xFFFE && (cd->from.flags & UNICODE_FLAG_USE_BOM_ENDIAN))
\r
1024 /* swap endian: 1200 <-> 1201 or 12000 <-> 12001 */
\r
1025 cd->from.codepage ^= 1;
\r
1026 cd->from.mode |= UNICODE_MODE_SWAPPED;
\r
1032 * Don't do this if "to" is Unicode,
\r
1033 * except if "to" is UTF-8.
\r
1035 if (wbuf[0] == 0xFEFF && (!is_unicode(cd->to.codepage) || cd->to.codepage == 65001))
\r
1040 strrstr(const char *str, const char *token)
\r
1042 int len = strlen(token);
\r
1043 const char *p = str + strlen(str);
\r
1045 while (str <= --p)
\r
1046 if (p[0] == token[0] && strncmp(p, token, len) == 0)
\r
1051 #if defined(USE_LIBICONV_DLL)
\r
1053 libiconv_iconv_open(rec_iconv_t *cd, const char *fromcode, const char *tocode)
\r
1055 HMODULE hlibiconv = NULL;
\r
1056 HMODULE hmsvcrt = NULL;
\r
1057 char dllname[_MAX_PATH];
\r
1060 f_iconv_open _iconv_open;
\r
1063 * always try to load dll, so that we can switch dll in runtime.
\r
1066 /* XXX: getenv() can't get variable set by SetEnvironmentVariable() */
\r
1067 p = getenv("WINICONV_LIBICONV_DLL");
\r
1069 p = DEFAULT_LIBICONV_DLL;
\r
1070 /* parse comma separated value */
\r
1071 for ( ; *p != 0; p = (*e == ',') ? e + 1 : e)
\r
1073 e = strchr(p, ',');
\r
1076 else if (e == NULL)
\r
1077 e = p + strlen(p);
\r
1078 xstrlcpyn(dllname, p, e - p, sizeof(dllname));
\r
1079 hlibiconv = LoadLibrary(dllname);
\r
1080 if (hlibiconv != NULL)
\r
1082 if (hlibiconv == hwiniconv)
\r
1084 FreeLibrary(hlibiconv);
\r
1092 if (hlastdll != NULL)
\r
1094 /* decrement reference count */
\r
1095 FreeLibrary(hlastdll);
\r
1099 if (hlibiconv == NULL)
\r
1102 hmsvcrt = find_imported_module_by_funcname(hlibiconv, "_errno");
\r
1103 if (hmsvcrt == NULL)
\r
1106 _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "libiconv_open");
\r
1107 if (_iconv_open == NULL)
\r
1108 _iconv_open = (f_iconv_open)GetProcAddress(hlibiconv, "iconv_open");
\r
1109 cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "libiconv_close");
\r
1110 if (cd->iconv_close == NULL)
\r
1111 cd->iconv_close = (f_iconv_close)GetProcAddress(hlibiconv, "iconv_close");
\r
1112 cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "libiconv");
\r
1113 if (cd->iconv == NULL)
\r
1114 cd->iconv = (f_iconv)GetProcAddress(hlibiconv, "iconv");
\r
1115 cd->_errno = (f_errno)GetProcAddress(hmsvcrt, "_errno");
\r
1116 if (_iconv_open == NULL || cd->iconv_close == NULL
\r
1117 || cd->iconv == NULL || cd->_errno == NULL)
\r
1120 /* increment reference count */
\r
1121 hlastdll = LoadLibrary(dllname);
\r
1123 cd->cd = _iconv_open(tocode, fromcode);
\r
1124 if (cd->cd == (iconv_t)(-1))
\r
1127 cd->hlibiconv = hlibiconv;
\r
1131 if (hlibiconv != NULL)
\r
1132 FreeLibrary(hlibiconv);
\r
1133 /* do not free hmsvcrt which is obtained by GetModuleHandle() */
\r
1139 * http://forums.belution.com/ja/vc/000/234/78s.shtml
\r
1140 * http://nienie.com/~masapico/api_ImageDirectoryEntryToData.html
\r
1142 * The formal way is
\r
1143 * imagehlp.h or dbghelp.h
\r
1144 * imagehlp.lib or dbghelp.lib
\r
1145 * ImageDirectoryEntryToData()
\r
1147 #define TO_DOS_HEADER(base) ((PIMAGE_DOS_HEADER)(base))
\r
1148 #define TO_NT_HEADERS(base) ((PIMAGE_NT_HEADERS)((LPBYTE)(base) + TO_DOS_HEADER(base)->e_lfanew))
\r
1150 MyImageDirectoryEntryToData(LPVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size)
\r
1152 /* TODO: MappedAsImage? */
\r
1153 PIMAGE_DATA_DIRECTORY p;
\r
1154 p = TO_NT_HEADERS(Base)->OptionalHeader.DataDirectory + DirectoryEntry;
\r
1155 if (p->VirtualAddress == 0) {
\r
1160 return (PVOID)((LPBYTE)Base + p->VirtualAddress);
\r
1164 find_imported_module_by_funcname(HMODULE hModule, const char *funcname)
\r
1168 PIMAGE_IMPORT_DESCRIPTOR Imp;
\r
1169 PIMAGE_THUNK_DATA Name; /* Import Name Table */
\r
1170 PIMAGE_IMPORT_BY_NAME ImpName;
\r
1172 Base = (DWORD)hModule;
\r
1173 Imp = MyImageDirectoryEntryToData(
\r
1176 IMAGE_DIRECTORY_ENTRY_IMPORT,
\r
1180 for ( ; Imp->OriginalFirstThunk != 0; ++Imp)
\r
1182 Name = (PIMAGE_THUNK_DATA)(Base + Imp->OriginalFirstThunk);
\r
1183 for ( ; Name->u1.Ordinal != 0; ++Name)
\r
1185 if (!IMAGE_SNAP_BY_ORDINAL(Name->u1.Ordinal))
\r
1187 ImpName = (PIMAGE_IMPORT_BY_NAME)
\r
1188 (Base + (DWORD)Name->u1.AddressOfData);
\r
1189 if (strcmp((char *)ImpName->Name, funcname) == 0)
\r
1190 return GetModuleHandle((char *)(Base + Imp->Name));
\r
1199 sbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
\r
1205 dbcs_mblen(csconv_t *cv, const uchar *buf, int bufsize)
\r
1207 int len = IsDBCSLeadByteEx(cv->codepage, buf[0]) ? 2 : 1;
\r
1208 if (bufsize < len)
\r
1209 return_error(EINVAL);
\r
1214 utf8_mblen(csconv_t *cv, const uchar *buf, int bufsize)
\r
1218 if (buf[0] < 0x80) len = 1;
\r
1219 else if ((buf[0] & 0xE0) == 0xC0) len = 2;
\r
1220 else if ((buf[0] & 0xF0) == 0xE0) len = 3;
\r
1221 else if ((buf[0] & 0xF8) == 0xF0) len = 4;
\r
1222 else if ((buf[0] & 0xFC) == 0xF8) len = 5;
\r
1223 else if ((buf[0] & 0xFE) == 0xFC) len = 6;
\r
1226 return_error(EILSEQ);
\r
1227 else if (bufsize < len)
\r
1228 return_error(EINVAL);
\r
1233 eucjp_mblen(csconv_t *cv, const uchar *buf, int bufsize)
\r
1235 if (buf[0] < 0x80) /* ASCII */
\r
1237 else if (buf[0] == 0x8E) /* JIS X 0201 */
\r
1240 return_error(EINVAL);
\r
1241 else if (!(0xA1 <= buf[1] && buf[1] <= 0xDF))
\r
1242 return_error(EILSEQ);
\r
1245 else if (buf[0] == 0x8F) /* JIS X 0212 */
\r
1248 return_error(EINVAL);
\r
1249 else if (!(0xA1 <= buf[1] && buf[1] <= 0xFE)
\r
1250 || !(0xA1 <= buf[2] && buf[2] <= 0xFE))
\r
1251 return_error(EILSEQ);
\r
1254 else /* JIS X 0208 */
\r
1257 return_error(EINVAL);
\r
1258 else if (!(0xA1 <= buf[0] && buf[0] <= 0xFE)
\r
1259 || !(0xA1 <= buf[1] && buf[1] <= 0xFE))
\r
1260 return_error(EILSEQ);
\r
1266 kernel_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
\r
1270 len = cv->mblen(cv, buf, bufsize);
\r
1273 *wbufsize = MultiByteToWideChar(cv->codepage, MB_ERR_INVALID_CHARS,
\r
1274 (const char *)buf, len, (wchar_t *)wbuf, *wbufsize);
\r
1275 if (*wbufsize == 0)
\r
1276 return_error(EILSEQ);
\r
1281 kernel_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
\r
1283 BOOL usedDefaultChar = 0;
\r
1287 return_error(E2BIG);
\r
1288 len = WideCharToMultiByte(cv->codepage, 0,
\r
1289 (const wchar_t *)wbuf, wbufsize, (char *)buf, bufsize, NULL,
\r
1290 must_use_null_useddefaultchar(cv->codepage) ? NULL : &usedDefaultChar);
\r
1293 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
\r
1294 return_error(E2BIG);
\r
1295 return_error(EILSEQ);
\r
1297 else if (usedDefaultChar)
\r
1298 return_error(EILSEQ);
\r
1299 else if (cv->mblen(cv, buf, len) != len) /* validate result */
\r
1300 return_error(EILSEQ);
\r
1305 * It seems that the mode (cv->mode) is fixnum.
\r
1306 * For example, when converting iso-2022-jp(cp50221) to unicode:
\r
1307 * in ascii sequence: mode=0xC42C0000
\r
1308 * in jisx0208 sequence: mode=0xC42C0001
\r
1309 * "C42C" is same for each convert session.
\r
1310 * It should be: ((codepage-1)<<16)|state
\r
1313 mlang_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
\r
1319 len = cv->mblen(cv, buf, bufsize);
\r
1323 hr = ConvertINetMultiByteToUnicode(&cv->mode, cv->codepage,
\r
1324 (const char *)buf, &insize, (wchar_t *)wbuf, wbufsize);
\r
1325 if (hr != S_OK || insize != len)
\r
1326 return_error(EILSEQ);
\r
1331 mlang_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
\r
1333 char tmpbuf[MB_CHAR_MAX]; /* enough room for one character */
\r
1334 int tmpsize = MB_CHAR_MAX;
\r
1335 int insize = wbufsize;
\r
1338 hr = ConvertINetUnicodeToMultiByte(&cv->mode, cv->codepage,
\r
1339 (const wchar_t *)wbuf, &wbufsize, tmpbuf, &tmpsize);
\r
1340 if (hr != S_OK || insize != wbufsize)
\r
1341 return_error(EILSEQ);
\r
1342 else if (bufsize < tmpsize)
\r
1343 return_error(E2BIG);
\r
1344 else if (cv->mblen(cv, (uchar *)tmpbuf, tmpsize) != tmpsize)
\r
1345 return_error(EILSEQ);
\r
1346 memcpy(buf, tmpbuf, tmpsize);
\r
1351 utf16_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
\r
1354 return_error(EINVAL);
\r
1355 if (cv->codepage == 1200) /* little endian */
\r
1356 wbuf[0] = (buf[1] << 8) | buf[0];
\r
1357 else if (cv->codepage == 1201) /* big endian */
\r
1358 wbuf[0] = (buf[0] << 8) | buf[1];
\r
1359 if (0xDC00 <= wbuf[0] && wbuf[0] <= 0xDFFF)
\r
1360 return_error(EILSEQ);
\r
1361 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
\r
1364 return_error(EINVAL);
\r
1365 if (cv->codepage == 1200) /* little endian */
\r
1366 wbuf[1] = (buf[3] << 8) | buf[2];
\r
1367 else if (cv->codepage == 1201) /* big endian */
\r
1368 wbuf[1] = (buf[2] << 8) | buf[3];
\r
1369 if (!(0xDC00 <= wbuf[1] && wbuf[1] <= 0xDFFF))
\r
1370 return_error(EILSEQ);
\r
1379 utf16_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
\r
1382 return_error(E2BIG);
\r
1383 if (cv->codepage == 1200) /* little endian */
\r
1385 buf[0] = (wbuf[0] & 0x00FF);
\r
1386 buf[1] = (wbuf[0] & 0xFF00) >> 8;
\r
1388 else if (cv->codepage == 1201) /* big endian */
\r
1390 buf[0] = (wbuf[0] & 0xFF00) >> 8;
\r
1391 buf[1] = (wbuf[0] & 0x00FF);
\r
1393 if (0xD800 <= wbuf[0] && wbuf[0] <= 0xDBFF)
\r
1396 return_error(E2BIG);
\r
1397 if (cv->codepage == 1200) /* little endian */
\r
1399 buf[2] = (wbuf[1] & 0x00FF);
\r
1400 buf[3] = (wbuf[1] & 0xFF00) >> 8;
\r
1402 else if (cv->codepage == 1201) /* big endian */
\r
1404 buf[2] = (wbuf[1] & 0xFF00) >> 8;
\r
1405 buf[3] = (wbuf[1] & 0x00FF);
\r
1413 utf32_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
\r
1418 return_error(EINVAL);
\r
1419 if (cv->codepage == 12000) /* little endian */
\r
1420 wc = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
\r
1421 else if (cv->codepage == 12001) /* big endian */
\r
1422 wc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
\r
1423 if ((0xD800 <= wc && wc <= 0xDFFF) || 0x10FFFF < wc)
\r
1424 return_error(EILSEQ);
\r
1425 ucs4_to_utf16(wc, wbuf, wbufsize);
\r
1430 utf32_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
\r
1435 return_error(E2BIG);
\r
1436 wc = utf16_to_ucs4(wbuf);
\r
1437 if (cv->codepage == 12000) /* little endian */
\r
1439 buf[0] = wc & 0x000000FF;
\r
1440 buf[1] = (wc & 0x0000FF00) >> 8;
\r
1441 buf[2] = (wc & 0x00FF0000) >> 16;
\r
1442 buf[3] = (wc & 0xFF000000) >> 24;
\r
1444 else if (cv->codepage == 12001) /* big endian */
\r
1446 buf[0] = (wc & 0xFF000000) >> 24;
\r
1447 buf[1] = (wc & 0x00FF0000) >> 16;
\r
1448 buf[2] = (wc & 0x0000FF00) >> 8;
\r
1449 buf[3] = wc & 0x000000FF;
\r
1455 * 50220: ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
\r
1456 * 50221: ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow
\r
1458 * 50222: ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte
\r
1461 * MultiByteToWideChar() and WideCharToMultiByte() behave differently
\r
1462 * depending on Windows version. On XP, WideCharToMultiByte() doesn't
\r
1463 * terminate result sequence with ascii escape. But Vista does.
\r
1464 * Use MLang instead.
\r
1467 #define ISO2022_MODE(cs, shift) (((cs) << 8) | (shift))
\r
1468 #define ISO2022_MODE_CS(mode) (((mode) >> 8) & 0xFF)
\r
1469 #define ISO2022_MODE_SHIFT(mode) ((mode) & 0xFF)
\r
1471 #define ISO2022_SI 0
\r
1472 #define ISO2022_SO 1
\r
1475 static const char iso2022_SI_seq[] = "\x0F";
\r
1477 static const char iso2022_SO_seq[] = "\x0E";
\r
1479 typedef struct iso2022_esc_t iso2022_esc_t;
\r
1480 struct iso2022_esc_t {
\r
1487 #define ISO2022JP_CS_ASCII 0
\r
1488 #define ISO2022JP_CS_JISX0201_ROMAN 1
\r
1489 #define ISO2022JP_CS_JISX0201_KANA 2
\r
1490 #define ISO2022JP_CS_JISX0208_1978 3
\r
1491 #define ISO2022JP_CS_JISX0208_1983 4
\r
1492 #define ISO2022JP_CS_JISX0212 5
\r
1494 static iso2022_esc_t iso2022jp_esc[] = {
\r
1495 {"\x1B\x28\x42", 3, 1, ISO2022JP_CS_ASCII},
\r
1496 {"\x1B\x28\x4A", 3, 1, ISO2022JP_CS_JISX0201_ROMAN},
\r
1497 {"\x1B\x28\x49", 3, 1, ISO2022JP_CS_JISX0201_KANA},
\r
1498 {"\x1B\x24\x40", 3, 2, ISO2022JP_CS_JISX0208_1983}, /* unify 1978 with 1983 */
\r
1499 {"\x1B\x24\x42", 3, 2, ISO2022JP_CS_JISX0208_1983},
\r
1500 {"\x1B\x24\x28\x44", 4, 2, ISO2022JP_CS_JISX0212},
\r
1505 iso2022jp_mbtowc(csconv_t *cv, const uchar *buf, int bufsize, ushort *wbuf, int *wbufsize)
\r
1507 iso2022_esc_t *iesc = iso2022jp_esc;
\r
1508 char tmp[MB_CHAR_MAX];
\r
1518 if (buf[0] == 0x1B)
\r
1520 for (i = 0; iesc[i].esc != NULL; ++i)
\r
1522 esc_len = iesc[i].esc_len;
\r
1523 if (bufsize < esc_len)
\r
1525 if (strncmp((char *)buf, iesc[i].esc, bufsize) == 0)
\r
1526 return_error(EINVAL);
\r
1530 if (strncmp((char *)buf, iesc[i].esc, esc_len) == 0)
\r
1532 cv->mode = ISO2022_MODE(iesc[i].cs, ISO2022_SI);
\r
1538 /* not supported escape sequence */
\r
1539 return_error(EILSEQ);
\r
1541 else if (buf[0] == iso2022_SO_seq[0])
\r
1543 cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SO);
\r
1547 else if (buf[0] == iso2022_SI_seq[0])
\r
1549 cv->mode = ISO2022_MODE(ISO2022_MODE_CS(cv->mode), ISO2022_SI);
\r
1554 cs = ISO2022_MODE_CS(cv->mode);
\r
1555 shift = ISO2022_MODE_SHIFT(cv->mode);
\r
1557 /* reset the mode for informal sequence */
\r
1558 if (buf[0] < 0x20)
\r
1560 cs = ISO2022JP_CS_ASCII;
\r
1561 shift = ISO2022_SI;
\r
1564 len = iesc[cs].len;
\r
1565 if (bufsize < len)
\r
1566 return_error(EINVAL);
\r
1567 for (i = 0; i < len; ++i)
\r
1568 if (!(buf[i] < 0x80))
\r
1569 return_error(EILSEQ);
\r
1570 esc_len = iesc[cs].esc_len;
\r
1571 memcpy(tmp, iesc[cs].esc, esc_len);
\r
1572 if (shift == ISO2022_SO)
\r
1574 memcpy(tmp + esc_len, iso2022_SO_seq, 1);
\r
1577 memcpy(tmp + esc_len, buf, len);
\r
1579 if ((cv->codepage == 50220 || cv->codepage == 50221
\r
1580 || cv->codepage == 50222) && shift == ISO2022_SO)
\r
1582 /* XXX: shift-out cannot be used for mbtowc (both kernel and
\r
1584 esc_len = iesc[ISO2022JP_CS_JISX0201_KANA].esc_len;
\r
1585 memcpy(tmp, iesc[ISO2022JP_CS_JISX0201_KANA].esc, esc_len);
\r
1586 memcpy(tmp + esc_len, buf, len);
\r
1589 insize = len + esc_len;
\r
1590 hr = ConvertINetMultiByteToUnicode(&dummy, cv->codepage,
\r
1591 (const char *)tmp, &insize, (wchar_t *)wbuf, wbufsize);
\r
1592 if (hr != S_OK || insize != len + esc_len)
\r
1593 return_error(EILSEQ);
\r
1595 /* Check for conversion error. Assuming defaultChar is 0x3F. */
\r
1596 /* ascii should be converted from ascii */
\r
1597 if (wbuf[0] == buf[0]
\r
1598 && cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
\r
1599 return_error(EILSEQ);
\r
1601 /* reset the mode for informal sequence */
\r
1602 if (cv->mode != ISO2022_MODE(cs, shift))
\r
1603 cv->mode = ISO2022_MODE(cs, shift);
\r
1609 iso2022jp_wctomb(csconv_t *cv, ushort *wbuf, int wbufsize, uchar *buf, int bufsize)
\r
1611 iso2022_esc_t *iesc = iso2022jp_esc;
\r
1612 char tmp[MB_CHAR_MAX];
\r
1613 int tmpsize = MB_CHAR_MAX;
\r
1614 int insize = wbufsize;
\r
1624 * MultiByte = [escape sequence] + character + [escape sequence]
\r
1626 * Whether trailing escape sequence is added depends on which API is
\r
1627 * used (kernel or MLang, and its version).
\r
1629 hr = ConvertINetUnicodeToMultiByte(&dummy, cv->codepage,
\r
1630 (const wchar_t *)wbuf, &wbufsize, tmp, &tmpsize);
\r
1631 if (hr != S_OK || insize != wbufsize)
\r
1632 return_error(EILSEQ);
\r
1633 else if (bufsize < tmpsize)
\r
1634 return_error(E2BIG);
\r
1638 cs = ISO2022JP_CS_ASCII;
\r
1643 for (i = 1; iesc[i].esc != NULL; ++i)
\r
1645 esc_len = iesc[i].esc_len;
\r
1646 if (strncmp(tmp, iesc[i].esc, esc_len) == 0)
\r
1652 if (iesc[i].esc == NULL)
\r
1653 /* not supported escape sequence */
\r
1654 return_error(EILSEQ);
\r
1657 shift = ISO2022_SI;
\r
1658 if (tmp[esc_len] == iso2022_SO_seq[0])
\r
1660 shift = ISO2022_SO;
\r
1664 len = iesc[cs].len;
\r
1666 /* Check for converting error. Assuming defaultChar is 0x3F. */
\r
1667 /* ascii should be converted from ascii */
\r
1668 if (cs == ISO2022JP_CS_ASCII && !(wbuf[0] < 0x80))
\r
1669 return_error(EILSEQ);
\r
1670 else if (tmpsize < esc_len + len)
\r
1671 return_error(EILSEQ);
\r
1673 if (cv->mode == ISO2022_MODE(cs, shift))
\r
1675 /* remove escape sequence */
\r
1677 memmove(tmp, tmp + esc_len, len);
\r
1682 if (cs == ISO2022JP_CS_ASCII)
\r
1684 esc_len = iesc[ISO2022JP_CS_ASCII].esc_len;
\r
1685 memmove(tmp + esc_len, tmp, len);
\r
1686 memcpy(tmp, iesc[ISO2022JP_CS_ASCII].esc, esc_len);
\r
1688 if (ISO2022_MODE_SHIFT(cv->mode) == ISO2022_SO)
\r
1690 /* shift-in before changing to other mode */
\r
1691 memmove(tmp + 1, tmp, len + esc_len);
\r
1692 memcpy(tmp, iso2022_SI_seq, 1);
\r
1697 if (bufsize < len + esc_len)
\r
1698 return_error(E2BIG);
\r
1699 memcpy(buf, tmp, len + esc_len);
\r
1700 cv->mode = ISO2022_MODE(cs, shift);
\r
1701 return len + esc_len;
\r
1705 iso2022jp_flush(csconv_t *cv, uchar *buf, int bufsize)
\r
1707 iso2022_esc_t *iesc = iso2022jp_esc;
\r
1710 if (cv->mode != ISO2022_MODE(ISO2022JP_CS_ASCII, ISO2022_SI))
\r
1713 if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
\r
1715 if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
\r
1716 esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
\r
1717 if (bufsize < esc_len)
\r
1718 return_error(E2BIG);
\r
1721 if (ISO2022_MODE_SHIFT(cv->mode) != ISO2022_SI)
\r
1723 memcpy(buf, iso2022_SI_seq, 1);
\r
1726 if (ISO2022_MODE_CS(cv->mode) != ISO2022JP_CS_ASCII)
\r
1728 memcpy(buf + esc_len, iesc[ISO2022JP_CS_ASCII].esc,
\r
1729 iesc[ISO2022JP_CS_ASCII].esc_len);
\r
1730 esc_len += iesc[ISO2022JP_CS_ASCII].esc_len;
\r
1737 #if defined(MAKE_DLL) && defined(USE_LIBICONV_DLL)
\r
1739 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
\r
1741 switch( fdwReason )
\r
1743 case DLL_PROCESS_ATTACH:
\r
1744 hwiniconv = (HMODULE)hinstDLL;
\r
1746 case DLL_THREAD_ATTACH:
\r
1747 case DLL_THREAD_DETACH:
\r
1748 case DLL_PROCESS_DETACH:
\r
1755 #if defined(MAKE_EXE)
\r
1756 #include <stdio.h>
\r
1757 #include <fcntl.h>
\r
1760 main(int argc, char **argv)
\r
1762 char *fromcode = NULL;
\r
1763 char *tocode = NULL;
\r
1765 char inbuf[BUFSIZ];
\r
1766 char outbuf[BUFSIZ];
\r
1769 size_t inbytesleft;
\r
1770 size_t outbytesleft;
\r
1776 _setmode(_fileno(stdin), _O_BINARY);
\r
1777 _setmode(_fileno(stdout), _O_BINARY);
\r
1779 for (i = 1; i < argc; ++i)
\r
1781 if (strcmp(argv[i], "-l") == 0)
\r
1783 for (i = 0; codepage_alias[i].name != NULL; ++i)
\r
1784 printf("%s\n", codepage_alias[i].name);
\r
1788 if (strcmp(argv[i], "-f") == 0)
\r
1789 fromcode = argv[++i];
\r
1790 else if (strcmp(argv[i], "-t") == 0)
\r
1791 tocode = argv[++i];
\r
1794 in = fopen(argv[i], "rb");
\r
1797 fprintf(stderr, "cannot open %s\n", argv[i]);
\r
1804 if (fromcode == NULL || tocode == NULL)
\r
1806 printf("usage: %s -f from-enc -t to-enc [file]\n", argv[0]);
\r
1810 cd = iconv_open(tocode, fromcode);
\r
1811 if (cd == (iconv_t)(-1))
\r
1813 perror("iconv_open error");
\r
1817 while ((inbytesleft = fread(inbuf + rest, 1, sizeof(inbuf) - rest, in)) != 0
\r
1820 inbytesleft += rest;
\r
1823 outbytesleft = sizeof(outbuf);
\r
1824 r = iconv(cd, &pin, &inbytesleft, &pout, &outbytesleft);
\r
1825 fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
\r
1826 if (r == (size_t)(-1) && errno != EINVAL && errno != E2BIG)
\r
1828 perror("conversion error");
\r
1831 memmove(inbuf, pin, inbytesleft);
\r
1832 rest = inbytesleft;
\r
1835 outbytesleft = sizeof(outbuf);
\r
1836 r = iconv(cd, NULL, NULL, &pout, &outbytesleft);
\r
1837 fwrite(outbuf, 1, sizeof(outbuf) - outbytesleft, stdout);
\r
1838 if (r == (size_t)(-1))
\r
1840 perror("conversion error");
\r