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