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