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