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