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