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