update copyright dates
[deliverable/binutils-gdb.git] / binutils / winduni.c
1 /* winduni.c -- unicode support for the windres program.
2 Copyright 1997, 1998, 2000, 2001, 2003, 2005, 2007, 2009
3 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support.
5 Rewritten by Kai Tietz, Onevision.
6
7 This file is part of GNU Binutils.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
23
24
25 /* This file contains unicode support routines for the windres
26 program. Ideally, we would have generic unicode support which
27 would work on all systems. However, we don't. Instead, on a
28 Windows host, we are prepared to call some Windows routines. This
29 means that we will generate different output on Windows and Unix
30 hosts, but that seems better than not really supporting unicode at
31 all. */
32
33 #include "sysdep.h"
34 #include "bfd.h"
35 #include "libiberty.h" /* for xstrdup */
36 #include "bucomm.h"
37 /* Must be include before windows.h and winnls.h. */
38 #if defined (_WIN32) || defined (__CYGWIN__)
39 #include <windows.h>
40 #include <winnls.h>
41 #endif
42 #include "winduni.h"
43 #include "safe-ctype.h"
44
45 #if HAVE_ICONV
46 #include <iconv.h>
47 #endif
48
49 static rc_uint_type wind_WideCharToMultiByte (rc_uint_type, const unichar *, char *, rc_uint_type);
50 static rc_uint_type wind_MultiByteToWideChar (rc_uint_type, const char *, unichar *, rc_uint_type);
51 static int unichar_isascii (const unichar *, rc_uint_type);
52
53 /* Convert an ASCII string to a unicode string. We just copy it,
54 expanding chars to shorts, rather than doing something intelligent. */
55
56 #if !defined (_WIN32) && !defined (__CYGWIN__)
57
58 /* Codepages mapped. */
59 static local_iconv_map codepages[] =
60 {
61 { 0, "MS-ANSI" },
62 { 1, "WINDOWS-1252" },
63 { 437, "MS-ANSI" },
64 { 737, "MS-GREEK" },
65 { 775, "WINBALTRIM" },
66 { 850, "MS-ANSI" },
67 { 852, "MS-EE" },
68 { 857, "MS-TURK" },
69 { 862, "CP862" },
70 { 864, "CP864" },
71 { 866, "MS-CYRL" },
72 { 874, "WINDOWS-874" },
73 { 932, "CP932" },
74 { 936, "CP936" },
75 { 949, "CP949" },
76 { 950, "CP950" },
77 { 1250, "WINDOWS-1250" },
78 { 1251, "WINDOWS-1251" },
79 { 1252, "WINDOWS-1252" },
80 { 1253, "WINDOWS-1253" },
81 { 1254, "WINDOWS-1254" },
82 { 1255, "WINDOWS-1255" },
83 { 1256, "WINDOWS-1256" },
84 { 1257, "WINDOWS-1257" },
85 { 1258, "WINDOWS-1258" },
86 { CP_UTF7, "UTF-7" },
87 { CP_UTF8, "UTF-8" },
88 { CP_UTF16, "UTF-16" },
89 { (rc_uint_type) -1, NULL }
90 };
91
92 /* Languages supported. */
93 static const wind_language_t languages[] =
94 {
95 { 0x0000, 437, 1252, "Neutral", "Neutral" },
96 { 0x0401, 864, 1256, "Arabic", "Saudi Arabia" }, { 0x0402, 866, 1251, "Bulgarian", "Bulgaria" },
97 { 0x0403, 850, 1252, "Catalan", "Spain" }, { 0x0404, 950, 950, "Chinese", "Taiwan" },
98 { 0x0405, 852, 1250, "Czech", "Czech Republic" }, { 0x0406, 850, 1252, "Danish", "Denmark" },
99 { 0x0407, 850, 1252, "German", "Germany" }, { 0x0408, 737, 1253, "Greek", "Greece" },
100 { 0x0409, 437, 1252, "English", "United States" }, { 0x040A, 850, 1252, "Spanish - Traditional Sort", "Spain" },
101 { 0x040B, 850, 1252, "Finnish", "Finland" }, { 0x040C, 850, 1252, "French", "France" },
102 { 0x040D, 862, 1255, "Hebrew", "Israel" }, { 0x040E, 852, 1250, "Hungarian", "Hungary" },
103 { 0x040F, 850, 1252, "Icelandic", "Iceland" }, { 0x0410, 850, 1252, "Italian", "Italy" },
104 { 0x0411, 932, 932, "Japanese", "Japan" }, { 0x0412, 949, 949, "Korean", "Korea (south)" },
105 { 0x0413, 850, 1252, "Dutch", "Netherlands" }, { 0x0414, 850, 1252, "Norwegian (Bokmål)", "Norway" },
106 { 0x0415, 852, 1250, "Polish", "Poland" }, { 0x0416, 850, 1252, "Portuguese", "Brazil" },
107 { 0x0418, 852, 1250, "Romanian", "Romania" }, { 0x0419, 866, 1251, "Russian", "Russia" },
108 { 0x041A, 852, 1250, "Croatian", "Croatia" }, { 0x041B, 852, 1250, "Slovak", "Slovakia" },
109 { 0x041C, 852, 1250, "Albanian", "Albania" }, { 0x041D, 850, 1252, "Swedish", "Sweden" },
110 { 0x041E, 874, 874, "Thai", "Thailand" }, { 0x041F, 857, 1254, "Turkish", "Turkey" },
111 { 0x0421, 850, 1252, "Indonesian", "Indonesia" }, { 0x0422, 866, 1251, "Ukrainian", "Ukraine" },
112 { 0x0423, 866, 1251, "Belarusian", "Belarus" }, { 0x0424, 852, 1250, "Slovene", "Slovenia" },
113 { 0x0425, 775, 1257, "Estonian", "Estonia" }, { 0x0426, 775, 1257, "Latvian", "Latvia" },
114 { 0x0427, 775, 1257, "Lithuanian", "Lithuania" },
115 { 0x0429, 864, 1256, "Arabic", "Farsi" }, { 0x042A,1258, 1258, "Vietnamese", "Vietnam" },
116 { 0x042D, 850, 1252, "Basque", "Spain" },
117 { 0x042F, 866, 1251, "Macedonian", "Former Yugoslav Republic of Macedonia" },
118 { 0x0436, 850, 1252, "Afrikaans", "South Africa" },
119 { 0x0438, 850, 1252, "Faroese", "Faroe Islands" },
120 { 0x043C, 437, 1252, "Irish", "Ireland" },
121 { 0x043E, 850, 1252, "Malay", "Malaysia" },
122 { 0x0801, 864, 1256, "Arabic", "Iraq" },
123 { 0x0804, 936, 936, "Chinese (People's republic of China)", "People's republic of China" },
124 { 0x0807, 850, 1252, "German", "Switzerland" },
125 { 0x0809, 850, 1252, "English", "United Kingdom" }, { 0x080A, 850, 1252, "Spanish", "Mexico" },
126 { 0x080C, 850, 1252, "French", "Belgium" },
127 { 0x0810, 850, 1252, "Italian", "Switzerland" },
128 { 0x0813, 850, 1252, "Dutch", "Belgium" }, { 0x0814, 850, 1252, "Norwegian (Nynorsk)", "Norway" },
129 { 0x0816, 850, 1252, "Portuguese", "Portugal" },
130 { 0x081A, 852, 1252, "Serbian (latin)", "Yugoslavia" },
131 { 0x081D, 850, 1252, "Swedish (Finland)", "Finland" },
132 { 0x0C01, 864, 1256, "Arabic", "Egypt" },
133 { 0x0C04, 950, 950, "Chinese", "Hong Kong" },
134 { 0x0C07, 850, 1252, "German", "Austria" },
135 { 0x0C09, 850, 1252, "English", "Australia" }, { 0x0C0A, 850, 1252, "Spanish - International Sort", "Spain" },
136 { 0x0C0C, 850, 1252, "French", "Canada"},
137 { 0x0C1A, 855, 1251, "Serbian (Cyrillic)", "Serbia" },
138 { 0x1001, 864, 1256, "Arabic", "Libya" },
139 { 0x1004, 936, 936, "Chinese", "Singapore" },
140 { 0x1007, 850, 1252, "German", "Luxembourg" },
141 { 0x1009, 850, 1252, "English", "Canada" },
142 { 0x100A, 850, 1252, "Spanish", "Guatemala" },
143 { 0x100C, 850, 1252, "French", "Switzerland" },
144 { 0x1401, 864, 1256, "Arabic", "Algeria" },
145 { 0x1407, 850, 1252, "German", "Liechtenstein" },
146 { 0x1409, 850, 1252, "English", "New Zealand" }, { 0x140A, 850, 1252, "Spanish", "Costa Rica" },
147 { 0x140C, 850, 1252, "French", "Luxembourg" },
148 { 0x1801, 864, 1256, "Arabic", "Morocco" },
149 { 0x1809, 850, 1252, "English", "Ireland" }, { 0x180A, 850, 1252, "Spanish", "Panama" },
150 { 0x180C, 850, 1252, "French", "Monaco" },
151 { 0x1C01, 864, 1256, "Arabic", "Tunisia" },
152 { 0x1C09, 437, 1252, "English", "South Africa" }, { 0x1C0A, 850, 1252, "Spanish", "Dominican Republic" },
153 { 0x2001, 864, 1256, "Arabic", "Oman" },
154 { 0x2009, 850, 1252, "English", "Jamaica" }, { 0x200A, 850, 1252, "Spanish", "Venezuela" },
155 { 0x2401, 864, 1256, "Arabic", "Yemen" },
156 { 0x2409, 850, 1252, "English", "Caribbean" }, { 0x240A, 850, 1252, "Spanish", "Colombia" },
157 { 0x2801, 864, 1256, "Arabic", "Syria" },
158 { 0x2809, 850, 1252, "English", "Belize" }, { 0x280A, 850, 1252, "Spanish", "Peru" },
159 { 0x2C01, 864, 1256, "Arabic", "Jordan" },
160 { 0x2C09, 437, 1252, "English", "Trinidad & Tobago" },{ 0x2C0A, 850, 1252, "Spanish", "Argentina" },
161 { 0x3001, 864, 1256, "Arabic", "Lebanon" },
162 { 0x3009, 437, 1252, "English", "Zimbabwe" }, { 0x300A, 850, 1252, "Spanish", "Ecuador" },
163 { 0x3401, 864, 1256, "Arabic", "Kuwait" },
164 { 0x3409, 437, 1252, "English", "Philippines" }, { 0x340A, 850, 1252, "Spanish", "Chile" },
165 { 0x3801, 864, 1256, "Arabic", "United Arab Emirates" },
166 { 0x380A, 850, 1252, "Spanish", "Uruguay" },
167 { 0x3C01, 864, 1256, "Arabic", "Bahrain" },
168 { 0x3C0A, 850, 1252, "Spanish", "Paraguay" },
169 { 0x4001, 864, 1256, "Arabic", "Qatar" },
170 { 0x400A, 850, 1252, "Spanish", "Bolivia" },
171 { 0x440A, 850, 1252, "Spanish", "El Salvador" },
172 { 0x480A, 850, 1252, "Spanish", "Honduras" },
173 { 0x4C0A, 850, 1252, "Spanish", "Nicaragua" },
174 { 0x500A, 850, 1252, "Spanish", "Puerto Rico" },
175 { (unsigned) -1, 0, 0, NULL, NULL }
176 };
177
178 #endif
179
180 /* Specifies the default codepage to be used for unicode
181 transformations. By default this is CP_ACP. */
182 rc_uint_type wind_default_codepage = CP_ACP;
183
184 /* Specifies the currently used codepage for unicode
185 transformations. By default this is CP_ACP. */
186 rc_uint_type wind_current_codepage = CP_ACP;
187
188 /* Convert an ASCII string to a unicode string. We just copy it,
189 expanding chars to shorts, rather than doing something intelligent. */
190
191 void
192 unicode_from_ascii (rc_uint_type *length, unichar **unicode, const char *ascii)
193 {
194 unicode_from_codepage (length, unicode, ascii, wind_current_codepage);
195 }
196
197 /* Convert an unicode string to an ASCII string. We just copy it,
198 shrink shorts to chars, rather than doing something intelligent.
199 Shorts with not within the char range are replaced by '_'. */
200
201 void
202 ascii_from_unicode (rc_uint_type *length, const unichar *unicode, char **ascii)
203 {
204 codepage_from_unicode (length, unicode, ascii, wind_current_codepage);
205 }
206
207 /* Print the unicode string UNICODE to the file E. LENGTH is the
208 number of characters to print, or -1 if we should print until the
209 end of the string. FIXME: On a Windows host, we should be calling
210 some Windows function, probably WideCharToMultiByte. */
211
212 void
213 unicode_print (FILE *e, const unichar *unicode, rc_uint_type length)
214 {
215 while (1)
216 {
217 unichar ch;
218
219 if (length == 0)
220 return;
221 if ((bfd_signed_vma) length > 0)
222 --length;
223
224 ch = *unicode;
225
226 if (ch == 0 && (bfd_signed_vma) length < 0)
227 return;
228
229 ++unicode;
230
231 if ((ch & 0x7f) == ch)
232 {
233 if (ch == '\\')
234 fputs ("\\\\", e);
235 else if (ch == '"')
236 fputs ("\"\"", e);
237 else if (ISPRINT (ch))
238 putc (ch, e);
239 else
240 {
241 switch (ch)
242 {
243 case ESCAPE_A:
244 fputs ("\\a", e);
245 break;
246
247 case ESCAPE_B:
248 fputs ("\\b", e);
249 break;
250
251 case ESCAPE_F:
252 fputs ("\\f", e);
253 break;
254
255 case ESCAPE_N:
256 fputs ("\\n", e);
257 break;
258
259 case ESCAPE_R:
260 fputs ("\\r", e);
261 break;
262
263 case ESCAPE_T:
264 fputs ("\\t", e);
265 break;
266
267 case ESCAPE_V:
268 fputs ("\\v", e);
269 break;
270
271 default:
272 fprintf (e, "\\%03o", (unsigned int) ch);
273 break;
274 }
275 }
276 }
277 else if ((ch & 0xff) == ch)
278 fprintf (e, "\\%03o", (unsigned int) ch);
279 else
280 fprintf (e, "\\x%04x", (unsigned int) ch);
281 }
282 }
283
284 /* Print a unicode string to a file. */
285
286 void
287 ascii_print (FILE *e, const char *s, rc_uint_type length)
288 {
289 while (1)
290 {
291 char ch;
292
293 if (length == 0)
294 return;
295 if ((bfd_signed_vma) length > 0)
296 --length;
297
298 ch = *s;
299
300 if (ch == 0 && (bfd_signed_vma) length < 0)
301 return;
302
303 ++s;
304
305 if ((ch & 0x7f) == ch)
306 {
307 if (ch == '\\')
308 fputs ("\\\\", e);
309 else if (ch == '"')
310 fputs ("\"\"", e);
311 else if (ISPRINT (ch))
312 putc (ch, e);
313 else
314 {
315 switch (ch)
316 {
317 case ESCAPE_A:
318 fputs ("\\a", e);
319 break;
320
321 case ESCAPE_B:
322 fputs ("\\b", e);
323 break;
324
325 case ESCAPE_F:
326 fputs ("\\f", e);
327 break;
328
329 case ESCAPE_N:
330 fputs ("\\n", e);
331 break;
332
333 case ESCAPE_R:
334 fputs ("\\r", e);
335 break;
336
337 case ESCAPE_T:
338 fputs ("\\t", e);
339 break;
340
341 case ESCAPE_V:
342 fputs ("\\v", e);
343 break;
344
345 default:
346 fprintf (e, "\\%03o", (unsigned int) ch);
347 break;
348 }
349 }
350 }
351 else
352 fprintf (e, "\\%03o", (unsigned int) ch & 0xff);
353 }
354 }
355
356 rc_uint_type
357 unichar_len (const unichar *unicode)
358 {
359 rc_uint_type r = 0;
360
361 if (unicode)
362 while (unicode[r] != 0)
363 r++;
364 else
365 --r;
366 return r;
367 }
368
369 unichar *
370 unichar_dup (const unichar *unicode)
371 {
372 unichar *r;
373 int len;
374
375 if (! unicode)
376 return NULL;
377 for (len = 0; unicode[len] != 0; ++len)
378 ;
379 ++len;
380 r = ((unichar *) res_alloc (len * sizeof (unichar)));
381 memcpy (r, unicode, len * sizeof (unichar));
382 return r;
383 }
384
385 unichar *
386 unichar_dup_uppercase (const unichar *u)
387 {
388 unichar *r = unichar_dup (u);
389 int i;
390
391 if (! r)
392 return NULL;
393
394 for (i = 0; r[i] != 0; ++i)
395 {
396 if (r[i] >= 'a' && r[i] <= 'z')
397 r[i] &= 0xdf;
398 }
399 return r;
400 }
401
402 static int
403 unichar_isascii (const unichar *u, rc_uint_type len)
404 {
405 rc_uint_type i;
406
407 if ((bfd_signed_vma) len < 0)
408 {
409 if (u)
410 len = (rc_uint_type) unichar_len (u);
411 else
412 len = 0;
413 }
414
415 for (i = 0; i < len; i++)
416 if ((u[i] & 0xff80) != 0)
417 return 0;
418 return 1;
419 }
420
421 void
422 unicode_print_quoted (FILE *e, const unichar *u, rc_uint_type len)
423 {
424 if (! unichar_isascii (u, len))
425 fputc ('L', e);
426 fputc ('"', e);
427 unicode_print (e, u, len);
428 fputc ('"', e);
429 }
430
431 int
432 unicode_is_valid_codepage (rc_uint_type cp)
433 {
434 if ((cp & 0xffff) != cp)
435 return 0;
436 if (cp == CP_UTF16 || cp == CP_ACP)
437 return 1;
438
439 #if !defined (_WIN32) && !defined (__CYGWIN__)
440 if (! wind_find_codepage_info (cp))
441 return 0;
442 return 1;
443 #else
444 return !! IsValidCodePage ((UINT) cp);
445 #endif
446 }
447
448 #if defined (_WIN32) || defined (__CYGWIN__)
449
450 #define max_cp_string_len 6
451
452 static unsigned int
453 codepage_from_langid (unsigned short langid)
454 {
455 char cp_string [max_cp_string_len];
456 int c;
457
458 memset (cp_string, 0, max_cp_string_len);
459 /* LOCALE_RETURN_NUMBER flag would avoid strtoul conversion,
460 but is unavailable on Win95. */
461 c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
462 LOCALE_IDEFAULTANSICODEPAGE,
463 cp_string, max_cp_string_len);
464 /* If codepage data for an LCID is not installed on users's system,
465 GetLocaleInfo returns an empty string. Fall back to system ANSI
466 default. */
467 if (c == 0)
468 return CP_ACP;
469 return strtoul (cp_string, 0, 10);
470 }
471
472 static unsigned int
473 wincodepage_from_langid (unsigned short langid)
474 {
475 char cp_string [max_cp_string_len];
476 int c;
477
478 memset (cp_string, 0, max_cp_string_len);
479 /* LOCALE_RETURN_NUMBER flag would avoid strtoul conversion,
480 but is unavailable on Win95. */
481 c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
482 LOCALE_IDEFAULTCODEPAGE,
483 cp_string, max_cp_string_len);
484 /* If codepage data for an LCID is not installed on users's system,
485 GetLocaleInfo returns an empty string. Fall back to system ANSI
486 default. */
487 if (c == 0)
488 return CP_OEM;
489 return strtoul (cp_string, 0, 10);
490 }
491
492 static char *
493 lang_from_langid (unsigned short langid)
494 {
495 char cp_string[261];
496 int c;
497
498 memset (cp_string, 0, 261);
499 c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
500 LOCALE_SENGLANGUAGE,
501 cp_string, 260);
502 /* If codepage data for an LCID is not installed on users's system,
503 GetLocaleInfo returns an empty string. Fall back to system ANSI
504 default. */
505 if (c == 0)
506 strcpy (cp_string, "Neutral");
507 return xstrdup (cp_string);
508 }
509
510 static char *
511 country_from_langid (unsigned short langid)
512 {
513 char cp_string[261];
514 int c;
515
516 memset (cp_string, 0, 261);
517 c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
518 LOCALE_SENGCOUNTRY,
519 cp_string, 260);
520 /* If codepage data for an LCID is not installed on users's system,
521 GetLocaleInfo returns an empty string. Fall back to system ANSI
522 default. */
523 if (c == 0)
524 strcpy (cp_string, "Neutral");
525 return xstrdup (cp_string);
526 }
527
528 #endif
529
530 const wind_language_t *
531 wind_find_language_by_id (unsigned id)
532 {
533 #if !defined (_WIN32) && !defined (__CYGWIN__)
534 int i;
535
536 if (! id)
537 return NULL;
538 for (i = 0; languages[i].id != (unsigned) -1 && languages[i].id != id; i++)
539 ;
540 if (languages[i].id == id)
541 return &languages[i];
542 return NULL;
543 #else
544 static wind_language_t wl;
545
546 wl.id = id;
547 wl.doscp = codepage_from_langid ((unsigned short) id);
548 wl.wincp = wincodepage_from_langid ((unsigned short) id);
549 wl.name = lang_from_langid ((unsigned short) id);
550 wl.country = country_from_langid ((unsigned short) id);
551
552 return & wl;
553 #endif
554 }
555
556 const local_iconv_map *
557 wind_find_codepage_info (unsigned cp)
558 {
559 #if !defined (_WIN32) && !defined (__CYGWIN__)
560 int i;
561
562 for (i = 0; codepages[i].codepage != (rc_uint_type) -1 && codepages[i].codepage != cp; i++)
563 ;
564 if (codepages[i].codepage == (rc_uint_type) -1)
565 return NULL;
566 return &codepages[i];
567 #else
568 static local_iconv_map lim;
569 if (!unicode_is_valid_codepage (cp))
570 return NULL;
571 lim.codepage = cp;
572 lim.iconv_name = "";
573 return & lim;
574 #endif
575 }
576
577 /* Convert an Codepage string to a unicode string. */
578
579 void
580 unicode_from_codepage (rc_uint_type *length, unichar **u, const char *src, rc_uint_type cp)
581 {
582 rc_uint_type len;
583
584 len = wind_MultiByteToWideChar (cp, src, NULL, 0);
585 if (len)
586 {
587 *u = ((unichar *) res_alloc (len));
588 wind_MultiByteToWideChar (cp, src, *u, len);
589 }
590 /* Discount the trailing '/0'. If MultiByteToWideChar failed,
591 this will set *length to -1. */
592 len -= sizeof (unichar);
593
594 if (length != NULL)
595 *length = len / sizeof (unichar);
596 }
597
598 /* Convert an unicode string to an codepage string. */
599
600 void
601 codepage_from_unicode (rc_uint_type *length, const unichar *unicode, char **ascii, rc_uint_type cp)
602 {
603 rc_uint_type len;
604
605 len = wind_WideCharToMultiByte (cp, unicode, NULL, 0);
606 if (len)
607 {
608 *ascii = (char *) res_alloc (len * sizeof (char));
609 wind_WideCharToMultiByte (cp, unicode, *ascii, len);
610 }
611 /* Discount the trailing '/0'. If MultiByteToWideChar failed,
612 this will set *length to -1. */
613 len--;
614
615 if (length != NULL)
616 *length = len;
617 }
618
619 #if defined (HAVE_ICONV) && !defined (_WIN32) && !defined (__CYGWIN__)
620 static int
621 iconv_onechar (iconv_t cd, ICONV_CONST char *s, char *d, int d_len, const char **n_s, char **n_d)
622 {
623 int i;
624
625 for (i = 1; i <= 32; i++)
626 {
627 char *tmp_d = d;
628 ICONV_CONST char *tmp_s = s;
629 size_t ret;
630 size_t s_left = (size_t) i;
631 size_t d_left = (size_t) d_len;
632
633 ret = iconv (cd, & tmp_s, & s_left, & tmp_d, & d_left);
634
635 if (ret != (size_t) -1)
636 {
637 *n_s = tmp_s;
638 *n_d = tmp_d;
639 return 0;
640 }
641 }
642
643 return 1;
644 }
645
646 static const char *
647 wind_iconv_cp (rc_uint_type cp)
648 {
649 const local_iconv_map *lim = wind_find_codepage_info (cp);
650
651 if (!lim)
652 return NULL;
653 return lim->iconv_name;
654 }
655 #endif /* HAVE_ICONV */
656
657 static rc_uint_type
658 wind_MultiByteToWideChar (rc_uint_type cp, const char *mb,
659 unichar *u, rc_uint_type u_len)
660 {
661 rc_uint_type ret = 0;
662
663 #if defined (_WIN32) || defined (__CYGWIN__)
664 rc_uint_type conv_flags = MB_PRECOMPOSED;
665
666 /* MB_PRECOMPOSED is not allowed for UTF-7 or UTF-8.
667 MultiByteToWideChar will set the last error to
668 ERROR_INVALID_FLAGS if we do. */
669 if (cp == CP_UTF8 || cp == CP_UTF7)
670 conv_flags = 0;
671
672 ret = (rc_uint_type) MultiByteToWideChar (cp, conv_flags,
673 mb, -1, u, u_len);
674 /* Convert to bytes. */
675 ret *= sizeof (unichar);
676
677 #elif defined (HAVE_ICONV)
678 int first = 1;
679 char tmp[32];
680 char *p_tmp;
681 const char *iconv_name = wind_iconv_cp (cp);
682
683 if (!mb || !iconv_name)
684 return 0;
685 iconv_t cd = iconv_open ("UTF-16", iconv_name);
686
687 while (1)
688 {
689 int iret;
690 const char *n_mb = "";
691 char *n_tmp = "";
692
693 p_tmp = tmp;
694 iret = iconv_onechar (cd, (ICONV_CONST char *) mb, p_tmp, 32, & n_mb, & n_tmp);
695 if (first)
696 {
697 first = 0;
698 continue;
699 }
700 if (!iret)
701 {
702 size_t l_tmp = (size_t) (n_tmp - p_tmp);
703
704 if (u)
705 {
706 if ((size_t) u_len < l_tmp)
707 break;
708 memcpy (u, tmp, l_tmp);
709 u += l_tmp/2;
710 u_len -= l_tmp;
711 }
712 ret += l_tmp;
713 }
714 else
715 break;
716 if (tmp[0] == 0 && tmp[1] == 0)
717 break;
718 mb = n_mb;
719 }
720 iconv_close (cd);
721 #else
722 if (cp)
723 ret = 0;
724 ret = strlen (mb) + 1;
725 ret *= sizeof (unichar);
726 if (u != NULL && u_len != 0)
727 {
728 do
729 {
730 *u++ = ((unichar) *mb) & 0xff;
731 --u_len; mb++;
732 }
733 while (u_len != 0 && mb[-1] != 0);
734 }
735 if (u != NULL && u_len != 0)
736 *u = 0;
737 #endif
738 return ret;
739 }
740
741 static rc_uint_type
742 wind_WideCharToMultiByte (rc_uint_type cp, const unichar *u, char *mb, rc_uint_type mb_len)
743 {
744 rc_uint_type ret = 0;
745 #if defined (_WIN32) || defined (__CYGWIN__)
746 WINBOOL used_def = FALSE;
747
748 ret = (rc_uint_type) WideCharToMultiByte (cp, 0, u, -1, mb, mb_len,
749 NULL, & used_def);
750 #elif defined (HAVE_ICONV)
751 int first = 1;
752 char tmp[32];
753 char *p_tmp;
754 const char *iconv_name = wind_iconv_cp (cp);
755
756 if (!u || !iconv_name)
757 return 0;
758 iconv_t cd = iconv_open (iconv_name, "UTF-16");
759
760 while (1)
761 {
762 int iret;
763 const char *n_u = "";
764 char *n_tmp = "";
765
766 p_tmp = tmp;
767 iret = iconv_onechar (cd, (ICONV_CONST char *) u, p_tmp, 32, &n_u, & n_tmp);
768 if (first)
769 {
770 first = 0;
771 continue;
772 }
773 if (!iret)
774 {
775 size_t l_tmp = (size_t) (n_tmp - p_tmp);
776
777 if (mb)
778 {
779 if ((size_t) mb_len < l_tmp)
780 break;
781 memcpy (mb, tmp, l_tmp);
782 mb += l_tmp;
783 mb_len -= l_tmp;
784 }
785 ret += l_tmp;
786 }
787 else
788 break;
789 if (u[0] == 0)
790 break;
791 u = (const unichar *) n_u;
792 }
793 iconv_close (cd);
794 #else
795 if (cp)
796 ret = 0;
797
798 while (u[ret] != 0)
799 ++ret;
800
801 ++ret;
802
803 if (mb)
804 {
805 while (*u != 0 && mb_len != 0)
806 {
807 if (u[0] == (u[0] & 0x7f))
808 *mb++ = (char) u[0];
809 else
810 *mb++ = '_';
811 ++u; --mb_len;
812 }
813 if (mb_len != 0)
814 *mb = 0;
815 }
816 #endif
817 return ret;
818 }
This page took 0.065825 seconds and 4 git commands to generate.