175fd0b74Schristos /* winduni.c -- unicode support for the windres program.
2*e992f068Schristos Copyright (C) 1997-2022 Free Software Foundation, Inc.
375fd0b74Schristos Written by Ian Lance Taylor, Cygnus Support.
475fd0b74Schristos Rewritten by Kai Tietz, Onevision.
575fd0b74Schristos
675fd0b74Schristos This file is part of GNU Binutils.
775fd0b74Schristos
875fd0b74Schristos This program is free software; you can redistribute it and/or modify
975fd0b74Schristos it under the terms of the GNU General Public License as published by
1075fd0b74Schristos the Free Software Foundation; either version 3 of the License, or
1175fd0b74Schristos (at your option) any later version.
1275fd0b74Schristos
1375fd0b74Schristos This program is distributed in the hope that it will be useful,
1475fd0b74Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1575fd0b74Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1675fd0b74Schristos GNU General Public License for more details.
1775fd0b74Schristos
1875fd0b74Schristos You should have received a copy of the GNU General Public License
1975fd0b74Schristos along with this program; if not, write to the Free Software
2075fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
2175fd0b74Schristos 02110-1301, USA. */
2275fd0b74Schristos
2375fd0b74Schristos
2475fd0b74Schristos /* This file contains unicode support routines for the windres
2575fd0b74Schristos program. Ideally, we would have generic unicode support which
2675fd0b74Schristos would work on all systems. However, we don't. Instead, on a
2775fd0b74Schristos Windows host, we are prepared to call some Windows routines. This
2875fd0b74Schristos means that we will generate different output on Windows and Unix
2975fd0b74Schristos hosts, but that seems better than not really supporting unicode at
3075fd0b74Schristos all. */
3175fd0b74Schristos
3275fd0b74Schristos #include "sysdep.h"
3375fd0b74Schristos #include "bfd.h"
3475fd0b74Schristos #include "libiberty.h" /* for xstrdup */
3575fd0b74Schristos #include "bucomm.h"
3675fd0b74Schristos /* Must be include before windows.h and winnls.h. */
3775fd0b74Schristos #if defined (_WIN32) || defined (__CYGWIN__)
3875fd0b74Schristos #include <windows.h>
3975fd0b74Schristos #include <winnls.h>
4075fd0b74Schristos #endif
4175fd0b74Schristos #include "winduni.h"
4275fd0b74Schristos #include "safe-ctype.h"
4375fd0b74Schristos
4475fd0b74Schristos #if HAVE_ICONV
4575fd0b74Schristos #include <iconv.h>
4675fd0b74Schristos #endif
4775fd0b74Schristos
4875fd0b74Schristos static rc_uint_type wind_WideCharToMultiByte (rc_uint_type, const unichar *, char *, rc_uint_type);
4975fd0b74Schristos static rc_uint_type wind_MultiByteToWideChar (rc_uint_type, const char *, unichar *, rc_uint_type);
5075fd0b74Schristos static int unichar_isascii (const unichar *, rc_uint_type);
5175fd0b74Schristos
5275fd0b74Schristos /* Convert an ASCII string to a unicode string. We just copy it,
5375fd0b74Schristos expanding chars to shorts, rather than doing something intelligent. */
5475fd0b74Schristos
5575fd0b74Schristos #if !defined (_WIN32) && !defined (__CYGWIN__)
5675fd0b74Schristos
5775fd0b74Schristos /* Codepages mapped. */
5875fd0b74Schristos static local_iconv_map codepages[] =
5975fd0b74Schristos {
60ede78133Schristos { 0, "cp1252" },
6175fd0b74Schristos { 1, "WINDOWS-1252" },
6275fd0b74Schristos { 437, "MS-ANSI" },
6375fd0b74Schristos { 737, "MS-GREEK" },
6475fd0b74Schristos { 775, "WINBALTRIM" },
6575fd0b74Schristos { 850, "MS-ANSI" },
6675fd0b74Schristos { 852, "MS-EE" },
6775fd0b74Schristos { 857, "MS-TURK" },
6875fd0b74Schristos { 862, "CP862" },
6975fd0b74Schristos { 864, "CP864" },
7075fd0b74Schristos { 866, "MS-CYRL" },
7175fd0b74Schristos { 874, "WINDOWS-874" },
7275fd0b74Schristos { 932, "CP932" },
7375fd0b74Schristos { 936, "CP936" },
7475fd0b74Schristos { 949, "CP949" },
7575fd0b74Schristos { 950, "CP950" },
7675fd0b74Schristos { 1250, "WINDOWS-1250" },
7775fd0b74Schristos { 1251, "WINDOWS-1251" },
7875fd0b74Schristos { 1252, "WINDOWS-1252" },
7975fd0b74Schristos { 1253, "WINDOWS-1253" },
8075fd0b74Schristos { 1254, "WINDOWS-1254" },
8175fd0b74Schristos { 1255, "WINDOWS-1255" },
8275fd0b74Schristos { 1256, "WINDOWS-1256" },
8375fd0b74Schristos { 1257, "WINDOWS-1257" },
8475fd0b74Schristos { 1258, "WINDOWS-1258" },
8575fd0b74Schristos { CP_UTF7, "UTF-7" },
8675fd0b74Schristos { CP_UTF8, "UTF-8" },
8775fd0b74Schristos { CP_UTF16, "UTF-16LE" },
8875fd0b74Schristos { (rc_uint_type) -1, NULL }
8975fd0b74Schristos };
9075fd0b74Schristos
9175fd0b74Schristos /* Languages supported. */
9275fd0b74Schristos static const wind_language_t languages[] =
9375fd0b74Schristos {
9475fd0b74Schristos { 0x0000, 437, 1252, "Neutral", "Neutral" },
9575fd0b74Schristos { 0x0401, 864, 1256, "Arabic", "Saudi Arabia" }, { 0x0402, 866, 1251, "Bulgarian", "Bulgaria" },
9675fd0b74Schristos { 0x0403, 850, 1252, "Catalan", "Spain" }, { 0x0404, 950, 950, "Chinese", "Taiwan" },
9775fd0b74Schristos { 0x0405, 852, 1250, "Czech", "Czech Republic" }, { 0x0406, 850, 1252, "Danish", "Denmark" },
9875fd0b74Schristos { 0x0407, 850, 1252, "German", "Germany" }, { 0x0408, 737, 1253, "Greek", "Greece" },
9975fd0b74Schristos { 0x0409, 437, 1252, "English", "United States" }, { 0x040A, 850, 1252, "Spanish - Traditional Sort", "Spain" },
10075fd0b74Schristos { 0x040B, 850, 1252, "Finnish", "Finland" }, { 0x040C, 850, 1252, "French", "France" },
10175fd0b74Schristos { 0x040D, 862, 1255, "Hebrew", "Israel" }, { 0x040E, 852, 1250, "Hungarian", "Hungary" },
10275fd0b74Schristos { 0x040F, 850, 1252, "Icelandic", "Iceland" }, { 0x0410, 850, 1252, "Italian", "Italy" },
10375fd0b74Schristos { 0x0411, 932, 932, "Japanese", "Japan" }, { 0x0412, 949, 949, "Korean", "Korea (south)" },
10475fd0b74Schristos { 0x0413, 850, 1252, "Dutch", "Netherlands" }, { 0x0414, 850, 1252, "Norwegian (Bokm\345l)", "Norway" },
10575fd0b74Schristos { 0x0415, 852, 1250, "Polish", "Poland" }, { 0x0416, 850, 1252, "Portuguese", "Brazil" },
10675fd0b74Schristos { 0x0418, 852, 1250, "Romanian", "Romania" }, { 0x0419, 866, 1251, "Russian", "Russia" },
10775fd0b74Schristos { 0x041A, 852, 1250, "Croatian", "Croatia" }, { 0x041B, 852, 1250, "Slovak", "Slovakia" },
10875fd0b74Schristos { 0x041C, 852, 1250, "Albanian", "Albania" }, { 0x041D, 850, 1252, "Swedish", "Sweden" },
10975fd0b74Schristos { 0x041E, 874, 874, "Thai", "Thailand" }, { 0x041F, 857, 1254, "Turkish", "Turkey" },
11075fd0b74Schristos { 0x0421, 850, 1252, "Indonesian", "Indonesia" }, { 0x0422, 866, 1251, "Ukrainian", "Ukraine" },
11175fd0b74Schristos { 0x0423, 866, 1251, "Belarusian", "Belarus" }, { 0x0424, 852, 1250, "Slovene", "Slovenia" },
11275fd0b74Schristos { 0x0425, 775, 1257, "Estonian", "Estonia" }, { 0x0426, 775, 1257, "Latvian", "Latvia" },
11375fd0b74Schristos { 0x0427, 775, 1257, "Lithuanian", "Lithuania" },
11475fd0b74Schristos { 0x0429, 864, 1256, "Arabic", "Farsi" }, { 0x042A,1258, 1258, "Vietnamese", "Vietnam" },
11575fd0b74Schristos { 0x042D, 850, 1252, "Basque", "Spain" },
11675fd0b74Schristos { 0x042F, 866, 1251, "Macedonian", "Former Yugoslav Republic of Macedonia" },
11775fd0b74Schristos { 0x0436, 850, 1252, "Afrikaans", "South Africa" },
11875fd0b74Schristos { 0x0438, 850, 1252, "Faroese", "Faroe Islands" },
11975fd0b74Schristos { 0x043C, 437, 1252, "Irish", "Ireland" },
12075fd0b74Schristos { 0x043E, 850, 1252, "Malay", "Malaysia" },
12175fd0b74Schristos { 0x0801, 864, 1256, "Arabic", "Iraq" },
12275fd0b74Schristos { 0x0804, 936, 936, "Chinese (People's republic of China)", "People's republic of China" },
12375fd0b74Schristos { 0x0807, 850, 1252, "German", "Switzerland" },
12475fd0b74Schristos { 0x0809, 850, 1252, "English", "United Kingdom" }, { 0x080A, 850, 1252, "Spanish", "Mexico" },
12575fd0b74Schristos { 0x080C, 850, 1252, "French", "Belgium" },
12675fd0b74Schristos { 0x0810, 850, 1252, "Italian", "Switzerland" },
12775fd0b74Schristos { 0x0813, 850, 1252, "Dutch", "Belgium" }, { 0x0814, 850, 1252, "Norwegian (Nynorsk)", "Norway" },
12875fd0b74Schristos { 0x0816, 850, 1252, "Portuguese", "Portugal" },
12975fd0b74Schristos { 0x081A, 852, 1252, "Serbian (latin)", "Yugoslavia" },
13075fd0b74Schristos { 0x081D, 850, 1252, "Swedish (Finland)", "Finland" },
13175fd0b74Schristos { 0x0C01, 864, 1256, "Arabic", "Egypt" },
13275fd0b74Schristos { 0x0C04, 950, 950, "Chinese", "Hong Kong" },
13375fd0b74Schristos { 0x0C07, 850, 1252, "German", "Austria" },
13475fd0b74Schristos { 0x0C09, 850, 1252, "English", "Australia" }, { 0x0C0A, 850, 1252, "Spanish - International Sort", "Spain" },
13575fd0b74Schristos { 0x0C0C, 850, 1252, "French", "Canada"},
13675fd0b74Schristos { 0x0C1A, 855, 1251, "Serbian (Cyrillic)", "Serbia" },
13775fd0b74Schristos { 0x1001, 864, 1256, "Arabic", "Libya" },
13875fd0b74Schristos { 0x1004, 936, 936, "Chinese", "Singapore" },
13975fd0b74Schristos { 0x1007, 850, 1252, "German", "Luxembourg" },
14075fd0b74Schristos { 0x1009, 850, 1252, "English", "Canada" },
14175fd0b74Schristos { 0x100A, 850, 1252, "Spanish", "Guatemala" },
14275fd0b74Schristos { 0x100C, 850, 1252, "French", "Switzerland" },
14375fd0b74Schristos { 0x1401, 864, 1256, "Arabic", "Algeria" },
14475fd0b74Schristos { 0x1407, 850, 1252, "German", "Liechtenstein" },
14575fd0b74Schristos { 0x1409, 850, 1252, "English", "New Zealand" }, { 0x140A, 850, 1252, "Spanish", "Costa Rica" },
14675fd0b74Schristos { 0x140C, 850, 1252, "French", "Luxembourg" },
14775fd0b74Schristos { 0x1801, 864, 1256, "Arabic", "Morocco" },
14875fd0b74Schristos { 0x1809, 850, 1252, "English", "Ireland" }, { 0x180A, 850, 1252, "Spanish", "Panama" },
14975fd0b74Schristos { 0x180C, 850, 1252, "French", "Monaco" },
15075fd0b74Schristos { 0x1C01, 864, 1256, "Arabic", "Tunisia" },
15175fd0b74Schristos { 0x1C09, 437, 1252, "English", "South Africa" }, { 0x1C0A, 850, 1252, "Spanish", "Dominican Republic" },
15275fd0b74Schristos { 0x2001, 864, 1256, "Arabic", "Oman" },
15375fd0b74Schristos { 0x2009, 850, 1252, "English", "Jamaica" }, { 0x200A, 850, 1252, "Spanish", "Venezuela" },
15475fd0b74Schristos { 0x2401, 864, 1256, "Arabic", "Yemen" },
15575fd0b74Schristos { 0x2409, 850, 1252, "English", "Caribbean" }, { 0x240A, 850, 1252, "Spanish", "Colombia" },
15675fd0b74Schristos { 0x2801, 864, 1256, "Arabic", "Syria" },
15775fd0b74Schristos { 0x2809, 850, 1252, "English", "Belize" }, { 0x280A, 850, 1252, "Spanish", "Peru" },
15875fd0b74Schristos { 0x2C01, 864, 1256, "Arabic", "Jordan" },
15975fd0b74Schristos { 0x2C09, 437, 1252, "English", "Trinidad & Tobago" },{ 0x2C0A, 850, 1252, "Spanish", "Argentina" },
16075fd0b74Schristos { 0x3001, 864, 1256, "Arabic", "Lebanon" },
16175fd0b74Schristos { 0x3009, 437, 1252, "English", "Zimbabwe" }, { 0x300A, 850, 1252, "Spanish", "Ecuador" },
16275fd0b74Schristos { 0x3401, 864, 1256, "Arabic", "Kuwait" },
16375fd0b74Schristos { 0x3409, 437, 1252, "English", "Philippines" }, { 0x340A, 850, 1252, "Spanish", "Chile" },
16475fd0b74Schristos { 0x3801, 864, 1256, "Arabic", "United Arab Emirates" },
16575fd0b74Schristos { 0x380A, 850, 1252, "Spanish", "Uruguay" },
16675fd0b74Schristos { 0x3C01, 864, 1256, "Arabic", "Bahrain" },
16775fd0b74Schristos { 0x3C0A, 850, 1252, "Spanish", "Paraguay" },
16875fd0b74Schristos { 0x4001, 864, 1256, "Arabic", "Qatar" },
16975fd0b74Schristos { 0x400A, 850, 1252, "Spanish", "Bolivia" },
17075fd0b74Schristos { 0x440A, 850, 1252, "Spanish", "El Salvador" },
17175fd0b74Schristos { 0x480A, 850, 1252, "Spanish", "Honduras" },
17275fd0b74Schristos { 0x4C0A, 850, 1252, "Spanish", "Nicaragua" },
17375fd0b74Schristos { 0x500A, 850, 1252, "Spanish", "Puerto Rico" },
17475fd0b74Schristos { (unsigned) -1, 0, 0, NULL, NULL }
17575fd0b74Schristos };
17675fd0b74Schristos
17775fd0b74Schristos #endif
17875fd0b74Schristos
17975fd0b74Schristos /* Specifies the default codepage to be used for unicode
18075fd0b74Schristos transformations. By default this is CP_ACP. */
18175fd0b74Schristos rc_uint_type wind_default_codepage = CP_ACP;
18275fd0b74Schristos
18375fd0b74Schristos /* Specifies the currently used codepage for unicode
18475fd0b74Schristos transformations. By default this is CP_ACP. */
18575fd0b74Schristos rc_uint_type wind_current_codepage = CP_ACP;
18675fd0b74Schristos
18775fd0b74Schristos /* Convert an ASCII string to a unicode string. We just copy it,
18875fd0b74Schristos expanding chars to shorts, rather than doing something intelligent. */
18975fd0b74Schristos
19075fd0b74Schristos void
unicode_from_ascii(rc_uint_type * length,unichar ** unicode,const char * ascii)19175fd0b74Schristos unicode_from_ascii (rc_uint_type *length, unichar **unicode, const char *ascii)
19275fd0b74Schristos {
19375fd0b74Schristos unicode_from_codepage (length, unicode, ascii, wind_current_codepage);
19475fd0b74Schristos }
19575fd0b74Schristos
19675fd0b74Schristos /* Convert an ASCII string with length A_LENGTH to a unicode string. We just
19775fd0b74Schristos copy it, expanding chars to shorts, rather than doing something intelligent.
19875fd0b74Schristos This routine converts also \0 within a string. */
19975fd0b74Schristos
20075fd0b74Schristos void
unicode_from_ascii_len(rc_uint_type * length,unichar ** unicode,const char * ascii,rc_uint_type a_length)20175fd0b74Schristos unicode_from_ascii_len (rc_uint_type *length, unichar **unicode, const char *ascii, rc_uint_type a_length)
20275fd0b74Schristos {
20375fd0b74Schristos char *tmp, *p;
20475fd0b74Schristos rc_uint_type tlen, elen, idx = 0;
20575fd0b74Schristos
20675fd0b74Schristos *unicode = NULL;
20775fd0b74Schristos
20875fd0b74Schristos if (!a_length)
20975fd0b74Schristos {
21075fd0b74Schristos if (length)
21175fd0b74Schristos *length = 0;
21275fd0b74Schristos return;
21375fd0b74Schristos }
21475fd0b74Schristos
21575fd0b74Schristos /* Make sure we have zero terminated string. */
21675fd0b74Schristos p = tmp = (char *) xmalloc (a_length + 1);
21775fd0b74Schristos memcpy (tmp, ascii, a_length);
21875fd0b74Schristos tmp[a_length] = 0;
21975fd0b74Schristos
22075fd0b74Schristos while (a_length > 0)
22175fd0b74Schristos {
22275fd0b74Schristos unichar *utmp, *up;
22375fd0b74Schristos
22475fd0b74Schristos tlen = strlen (p);
22575fd0b74Schristos
22675fd0b74Schristos if (tlen > a_length)
22775fd0b74Schristos tlen = a_length;
22875fd0b74Schristos if (*p == 0)
22975fd0b74Schristos {
23075fd0b74Schristos /* Make room for one more character. */
23175fd0b74Schristos utmp = (unichar *) res_alloc (sizeof (unichar) * (idx + 1));
23275fd0b74Schristos if (idx > 0)
23375fd0b74Schristos {
23475fd0b74Schristos memcpy (utmp, *unicode, idx * sizeof (unichar));
23575fd0b74Schristos }
23675fd0b74Schristos *unicode = utmp;
23775fd0b74Schristos utmp[idx++] = 0;
23875fd0b74Schristos --a_length;
23975fd0b74Schristos p++;
24075fd0b74Schristos continue;
24175fd0b74Schristos }
24275fd0b74Schristos utmp = NULL;
24375fd0b74Schristos elen = 0;
24475fd0b74Schristos elen = wind_MultiByteToWideChar (wind_current_codepage, p, NULL, 0);
24575fd0b74Schristos if (elen)
24675fd0b74Schristos {
24775fd0b74Schristos utmp = ((unichar *) res_alloc (elen + sizeof (unichar) * 2));
24875fd0b74Schristos wind_MultiByteToWideChar (wind_current_codepage, p, utmp, elen);
24975fd0b74Schristos elen /= sizeof (unichar);
25075fd0b74Schristos elen --;
25175fd0b74Schristos }
25275fd0b74Schristos else
25375fd0b74Schristos {
25475fd0b74Schristos /* Make room for one more character. */
25575fd0b74Schristos utmp = (unichar *) res_alloc (sizeof (unichar) * (idx + 1));
25675fd0b74Schristos if (idx > 0)
25775fd0b74Schristos {
25875fd0b74Schristos memcpy (utmp, *unicode, idx * sizeof (unichar));
25975fd0b74Schristos }
26075fd0b74Schristos *unicode = utmp;
26175fd0b74Schristos utmp[idx++] = ((unichar) *p) & 0xff;
26275fd0b74Schristos --a_length;
26375fd0b74Schristos p++;
26475fd0b74Schristos continue;
26575fd0b74Schristos }
26675fd0b74Schristos p += tlen;
26775fd0b74Schristos a_length -= tlen;
26875fd0b74Schristos
26975fd0b74Schristos up = (unichar *) res_alloc (sizeof (unichar) * (idx + elen));
27075fd0b74Schristos if (idx > 0)
27175fd0b74Schristos memcpy (up, *unicode, idx * sizeof (unichar));
27275fd0b74Schristos
27375fd0b74Schristos *unicode = up;
27475fd0b74Schristos if (elen)
27575fd0b74Schristos memcpy (&up[idx], utmp, sizeof (unichar) * elen);
27675fd0b74Schristos
27775fd0b74Schristos idx += elen;
27875fd0b74Schristos }
27975fd0b74Schristos
28075fd0b74Schristos if (length)
28175fd0b74Schristos *length = idx;
28275fd0b74Schristos
28375fd0b74Schristos free (tmp);
28475fd0b74Schristos }
28575fd0b74Schristos
28675fd0b74Schristos /* Convert an unicode string to an ASCII string. We just copy it,
28775fd0b74Schristos shrink shorts to chars, rather than doing something intelligent.
28875fd0b74Schristos Shorts with not within the char range are replaced by '_'. */
28975fd0b74Schristos
29075fd0b74Schristos void
ascii_from_unicode(rc_uint_type * length,const unichar * unicode,char ** ascii)29175fd0b74Schristos ascii_from_unicode (rc_uint_type *length, const unichar *unicode, char **ascii)
29275fd0b74Schristos {
29375fd0b74Schristos codepage_from_unicode (length, unicode, ascii, wind_current_codepage);
29475fd0b74Schristos }
29575fd0b74Schristos
29675fd0b74Schristos /* Print the unicode string UNICODE to the file E. LENGTH is the
29775fd0b74Schristos number of characters to print, or -1 if we should print until the
29875fd0b74Schristos end of the string. FIXME: On a Windows host, we should be calling
29975fd0b74Schristos some Windows function, probably WideCharToMultiByte. */
30075fd0b74Schristos
30175fd0b74Schristos void
unicode_print(FILE * e,const unichar * unicode,rc_uint_type length)30275fd0b74Schristos unicode_print (FILE *e, const unichar *unicode, rc_uint_type length)
30375fd0b74Schristos {
30475fd0b74Schristos while (1)
30575fd0b74Schristos {
30675fd0b74Schristos unichar ch;
30775fd0b74Schristos
30875fd0b74Schristos if (length == 0)
30975fd0b74Schristos return;
31075fd0b74Schristos if ((bfd_signed_vma) length > 0)
31175fd0b74Schristos --length;
31275fd0b74Schristos
31375fd0b74Schristos ch = *unicode;
31475fd0b74Schristos
31575fd0b74Schristos if (ch == 0 && (bfd_signed_vma) length < 0)
31675fd0b74Schristos return;
31775fd0b74Schristos
31875fd0b74Schristos ++unicode;
31975fd0b74Schristos
32075fd0b74Schristos if ((ch & 0x7f) == ch)
32175fd0b74Schristos {
32275fd0b74Schristos if (ch == '\\')
32375fd0b74Schristos fputs ("\\\\", e);
32475fd0b74Schristos else if (ch == '"')
32575fd0b74Schristos fputs ("\"\"", e);
32675fd0b74Schristos else if (ISPRINT (ch))
32775fd0b74Schristos putc (ch, e);
32875fd0b74Schristos else
32975fd0b74Schristos {
33075fd0b74Schristos switch (ch)
33175fd0b74Schristos {
33275fd0b74Schristos case ESCAPE_A:
33375fd0b74Schristos fputs ("\\a", e);
33475fd0b74Schristos break;
33575fd0b74Schristos
33675fd0b74Schristos case ESCAPE_B:
33775fd0b74Schristos fputs ("\\b", e);
33875fd0b74Schristos break;
33975fd0b74Schristos
34075fd0b74Schristos case ESCAPE_F:
34175fd0b74Schristos fputs ("\\f", e);
34275fd0b74Schristos break;
34375fd0b74Schristos
34475fd0b74Schristos case ESCAPE_N:
34575fd0b74Schristos fputs ("\\n", e);
34675fd0b74Schristos break;
34775fd0b74Schristos
34875fd0b74Schristos case ESCAPE_R:
34975fd0b74Schristos fputs ("\\r", e);
35075fd0b74Schristos break;
35175fd0b74Schristos
35275fd0b74Schristos case ESCAPE_T:
35375fd0b74Schristos fputs ("\\t", e);
35475fd0b74Schristos break;
35575fd0b74Schristos
35675fd0b74Schristos case ESCAPE_V:
35775fd0b74Schristos fputs ("\\v", e);
35875fd0b74Schristos break;
35975fd0b74Schristos
36075fd0b74Schristos default:
36175fd0b74Schristos fprintf (e, "\\%03o", (unsigned int) ch);
36275fd0b74Schristos break;
36375fd0b74Schristos }
36475fd0b74Schristos }
36575fd0b74Schristos }
36675fd0b74Schristos else if ((ch & 0xff) == ch)
36775fd0b74Schristos fprintf (e, "\\%03o", (unsigned int) ch);
36875fd0b74Schristos else
36975fd0b74Schristos fprintf (e, "\\x%04x", (unsigned int) ch);
37075fd0b74Schristos }
37175fd0b74Schristos }
37275fd0b74Schristos
37375fd0b74Schristos /* Print a unicode string to a file. */
37475fd0b74Schristos
37575fd0b74Schristos void
ascii_print(FILE * e,const char * s,rc_uint_type length)37675fd0b74Schristos ascii_print (FILE *e, const char *s, rc_uint_type length)
37775fd0b74Schristos {
37875fd0b74Schristos while (1)
37975fd0b74Schristos {
38075fd0b74Schristos char ch;
38175fd0b74Schristos
38275fd0b74Schristos if (length == 0)
38375fd0b74Schristos return;
38475fd0b74Schristos if ((bfd_signed_vma) length > 0)
38575fd0b74Schristos --length;
38675fd0b74Schristos
38775fd0b74Schristos ch = *s;
38875fd0b74Schristos
38975fd0b74Schristos if (ch == 0 && (bfd_signed_vma) length < 0)
39075fd0b74Schristos return;
39175fd0b74Schristos
39275fd0b74Schristos ++s;
39375fd0b74Schristos
39475fd0b74Schristos if ((ch & 0x7f) == ch)
39575fd0b74Schristos {
39675fd0b74Schristos if (ch == '\\')
39775fd0b74Schristos fputs ("\\\\", e);
39875fd0b74Schristos else if (ch == '"')
39975fd0b74Schristos fputs ("\"\"", e);
40075fd0b74Schristos else if (ISPRINT (ch))
40175fd0b74Schristos putc (ch, e);
40275fd0b74Schristos else
40375fd0b74Schristos {
40475fd0b74Schristos switch (ch)
40575fd0b74Schristos {
40675fd0b74Schristos case ESCAPE_A:
40775fd0b74Schristos fputs ("\\a", e);
40875fd0b74Schristos break;
40975fd0b74Schristos
41075fd0b74Schristos case ESCAPE_B:
41175fd0b74Schristos fputs ("\\b", e);
41275fd0b74Schristos break;
41375fd0b74Schristos
41475fd0b74Schristos case ESCAPE_F:
41575fd0b74Schristos fputs ("\\f", e);
41675fd0b74Schristos break;
41775fd0b74Schristos
41875fd0b74Schristos case ESCAPE_N:
41975fd0b74Schristos fputs ("\\n", e);
42075fd0b74Schristos break;
42175fd0b74Schristos
42275fd0b74Schristos case ESCAPE_R:
42375fd0b74Schristos fputs ("\\r", e);
42475fd0b74Schristos break;
42575fd0b74Schristos
42675fd0b74Schristos case ESCAPE_T:
42775fd0b74Schristos fputs ("\\t", e);
42875fd0b74Schristos break;
42975fd0b74Schristos
43075fd0b74Schristos case ESCAPE_V:
43175fd0b74Schristos fputs ("\\v", e);
43275fd0b74Schristos break;
43375fd0b74Schristos
43475fd0b74Schristos default:
43575fd0b74Schristos fprintf (e, "\\%03o", (unsigned int) ch);
43675fd0b74Schristos break;
43775fd0b74Schristos }
43875fd0b74Schristos }
43975fd0b74Schristos }
44075fd0b74Schristos else
44175fd0b74Schristos fprintf (e, "\\%03o", (unsigned int) ch & 0xff);
44275fd0b74Schristos }
44375fd0b74Schristos }
44475fd0b74Schristos
44575fd0b74Schristos rc_uint_type
unichar_len(const unichar * unicode)44675fd0b74Schristos unichar_len (const unichar *unicode)
44775fd0b74Schristos {
44875fd0b74Schristos rc_uint_type r = 0;
44975fd0b74Schristos
45075fd0b74Schristos if (unicode)
45175fd0b74Schristos while (unicode[r] != 0)
45275fd0b74Schristos r++;
45375fd0b74Schristos else
45475fd0b74Schristos --r;
45575fd0b74Schristos return r;
45675fd0b74Schristos }
45775fd0b74Schristos
45875fd0b74Schristos unichar *
unichar_dup(const unichar * unicode)45975fd0b74Schristos unichar_dup (const unichar *unicode)
46075fd0b74Schristos {
46175fd0b74Schristos unichar *r;
46275fd0b74Schristos int len;
46375fd0b74Schristos
46475fd0b74Schristos if (! unicode)
46575fd0b74Schristos return NULL;
46675fd0b74Schristos for (len = 0; unicode[len] != 0; ++len)
46775fd0b74Schristos ;
46875fd0b74Schristos ++len;
46975fd0b74Schristos r = ((unichar *) res_alloc (len * sizeof (unichar)));
47075fd0b74Schristos memcpy (r, unicode, len * sizeof (unichar));
47175fd0b74Schristos return r;
47275fd0b74Schristos }
47375fd0b74Schristos
47475fd0b74Schristos unichar *
unichar_dup_uppercase(const unichar * u)47575fd0b74Schristos unichar_dup_uppercase (const unichar *u)
47675fd0b74Schristos {
47775fd0b74Schristos unichar *r = unichar_dup (u);
47875fd0b74Schristos int i;
47975fd0b74Schristos
48075fd0b74Schristos if (! r)
48175fd0b74Schristos return NULL;
48275fd0b74Schristos
48375fd0b74Schristos for (i = 0; r[i] != 0; ++i)
48475fd0b74Schristos {
48575fd0b74Schristos if (r[i] >= 'a' && r[i] <= 'z')
48675fd0b74Schristos r[i] &= 0xdf;
48775fd0b74Schristos }
48875fd0b74Schristos return r;
48975fd0b74Schristos }
49075fd0b74Schristos
49175fd0b74Schristos static int
unichar_isascii(const unichar * u,rc_uint_type len)49275fd0b74Schristos unichar_isascii (const unichar *u, rc_uint_type len)
49375fd0b74Schristos {
49475fd0b74Schristos rc_uint_type i;
49575fd0b74Schristos
49675fd0b74Schristos if ((bfd_signed_vma) len < 0)
49775fd0b74Schristos {
49875fd0b74Schristos if (u)
49975fd0b74Schristos len = (rc_uint_type) unichar_len (u);
50075fd0b74Schristos else
50175fd0b74Schristos len = 0;
50275fd0b74Schristos }
50375fd0b74Schristos
50475fd0b74Schristos for (i = 0; i < len; i++)
50575fd0b74Schristos if ((u[i] & 0xff80) != 0)
50675fd0b74Schristos return 0;
50775fd0b74Schristos return 1;
50875fd0b74Schristos }
50975fd0b74Schristos
51075fd0b74Schristos void
unicode_print_quoted(FILE * e,const unichar * u,rc_uint_type len)51175fd0b74Schristos unicode_print_quoted (FILE *e, const unichar *u, rc_uint_type len)
51275fd0b74Schristos {
51375fd0b74Schristos if (! unichar_isascii (u, len))
51475fd0b74Schristos fputc ('L', e);
51575fd0b74Schristos fputc ('"', e);
51675fd0b74Schristos unicode_print (e, u, len);
51775fd0b74Schristos fputc ('"', e);
51875fd0b74Schristos }
51975fd0b74Schristos
52075fd0b74Schristos int
unicode_is_valid_codepage(rc_uint_type cp)52175fd0b74Schristos unicode_is_valid_codepage (rc_uint_type cp)
52275fd0b74Schristos {
52375fd0b74Schristos if ((cp & 0xffff) != cp)
52475fd0b74Schristos return 0;
52575fd0b74Schristos if (cp == CP_UTF16 || cp == CP_ACP)
52675fd0b74Schristos return 1;
52775fd0b74Schristos
52875fd0b74Schristos #if !defined (_WIN32) && !defined (__CYGWIN__)
52975fd0b74Schristos if (! wind_find_codepage_info (cp))
53075fd0b74Schristos return 0;
53175fd0b74Schristos return 1;
53275fd0b74Schristos #else
53375fd0b74Schristos return !! IsValidCodePage ((UINT) cp);
53475fd0b74Schristos #endif
53575fd0b74Schristos }
53675fd0b74Schristos
53775fd0b74Schristos #if defined (_WIN32) || defined (__CYGWIN__)
53875fd0b74Schristos
53975fd0b74Schristos #define max_cp_string_len 6
54075fd0b74Schristos
54175fd0b74Schristos static unsigned int
codepage_from_langid(unsigned short langid)54275fd0b74Schristos codepage_from_langid (unsigned short langid)
54375fd0b74Schristos {
54475fd0b74Schristos char cp_string [max_cp_string_len];
54575fd0b74Schristos int c;
54675fd0b74Schristos
54775fd0b74Schristos memset (cp_string, 0, max_cp_string_len);
54875fd0b74Schristos /* LOCALE_RETURN_NUMBER flag would avoid strtoul conversion,
54975fd0b74Schristos but is unavailable on Win95. */
55075fd0b74Schristos c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
55175fd0b74Schristos LOCALE_IDEFAULTANSICODEPAGE,
55275fd0b74Schristos cp_string, max_cp_string_len);
55375fd0b74Schristos /* If codepage data for an LCID is not installed on users's system,
55475fd0b74Schristos GetLocaleInfo returns an empty string. Fall back to system ANSI
55575fd0b74Schristos default. */
55675fd0b74Schristos if (c == 0)
55775fd0b74Schristos return CP_ACP;
55875fd0b74Schristos return strtoul (cp_string, 0, 10);
55975fd0b74Schristos }
56075fd0b74Schristos
56175fd0b74Schristos static unsigned int
wincodepage_from_langid(unsigned short langid)56275fd0b74Schristos wincodepage_from_langid (unsigned short langid)
56375fd0b74Schristos {
56475fd0b74Schristos char cp_string [max_cp_string_len];
56575fd0b74Schristos int c;
56675fd0b74Schristos
56775fd0b74Schristos memset (cp_string, 0, max_cp_string_len);
56875fd0b74Schristos /* LOCALE_RETURN_NUMBER flag would avoid strtoul conversion,
56975fd0b74Schristos but is unavailable on Win95. */
57075fd0b74Schristos c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
57175fd0b74Schristos LOCALE_IDEFAULTCODEPAGE,
57275fd0b74Schristos cp_string, max_cp_string_len);
57375fd0b74Schristos /* If codepage data for an LCID is not installed on users's system,
57475fd0b74Schristos GetLocaleInfo returns an empty string. Fall back to system ANSI
57575fd0b74Schristos default. */
57675fd0b74Schristos if (c == 0)
57775fd0b74Schristos return CP_OEM;
57875fd0b74Schristos return strtoul (cp_string, 0, 10);
57975fd0b74Schristos }
58075fd0b74Schristos
58175fd0b74Schristos static char *
lang_from_langid(unsigned short langid)58275fd0b74Schristos lang_from_langid (unsigned short langid)
58375fd0b74Schristos {
58475fd0b74Schristos char cp_string[261];
58575fd0b74Schristos int c;
58675fd0b74Schristos
58775fd0b74Schristos memset (cp_string, 0, 261);
58875fd0b74Schristos c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
58975fd0b74Schristos LOCALE_SENGLANGUAGE,
59075fd0b74Schristos cp_string, 260);
59175fd0b74Schristos /* If codepage data for an LCID is not installed on users's system,
59275fd0b74Schristos GetLocaleInfo returns an empty string. Fall back to system ANSI
59375fd0b74Schristos default. */
59475fd0b74Schristos if (c == 0)
59575fd0b74Schristos strcpy (cp_string, "Neutral");
59675fd0b74Schristos return xstrdup (cp_string);
59775fd0b74Schristos }
59875fd0b74Schristos
59975fd0b74Schristos static char *
country_from_langid(unsigned short langid)60075fd0b74Schristos country_from_langid (unsigned short langid)
60175fd0b74Schristos {
60275fd0b74Schristos char cp_string[261];
60375fd0b74Schristos int c;
60475fd0b74Schristos
60575fd0b74Schristos memset (cp_string, 0, 261);
60675fd0b74Schristos c = GetLocaleInfoA (MAKELCID (langid, SORT_DEFAULT),
60775fd0b74Schristos LOCALE_SENGCOUNTRY,
60875fd0b74Schristos cp_string, 260);
60975fd0b74Schristos /* If codepage data for an LCID is not installed on users's system,
61075fd0b74Schristos GetLocaleInfo returns an empty string. Fall back to system ANSI
61175fd0b74Schristos default. */
61275fd0b74Schristos if (c == 0)
61375fd0b74Schristos strcpy (cp_string, "Neutral");
61475fd0b74Schristos return xstrdup (cp_string);
61575fd0b74Schristos }
61675fd0b74Schristos
61775fd0b74Schristos #endif
61875fd0b74Schristos
61975fd0b74Schristos const wind_language_t *
wind_find_language_by_id(unsigned id)62075fd0b74Schristos wind_find_language_by_id (unsigned id)
62175fd0b74Schristos {
62275fd0b74Schristos #if !defined (_WIN32) && !defined (__CYGWIN__)
62375fd0b74Schristos int i;
62475fd0b74Schristos
62575fd0b74Schristos if (! id)
62675fd0b74Schristos return NULL;
62775fd0b74Schristos for (i = 0; languages[i].id != (unsigned) -1 && languages[i].id != id; i++)
62875fd0b74Schristos ;
62975fd0b74Schristos if (languages[i].id == id)
63075fd0b74Schristos return &languages[i];
63175fd0b74Schristos return NULL;
63275fd0b74Schristos #else
63375fd0b74Schristos static wind_language_t wl;
63475fd0b74Schristos
63575fd0b74Schristos wl.id = id;
63675fd0b74Schristos wl.doscp = codepage_from_langid ((unsigned short) id);
63775fd0b74Schristos wl.wincp = wincodepage_from_langid ((unsigned short) id);
63875fd0b74Schristos wl.name = lang_from_langid ((unsigned short) id);
63975fd0b74Schristos wl.country = country_from_langid ((unsigned short) id);
64075fd0b74Schristos
64175fd0b74Schristos return & wl;
64275fd0b74Schristos #endif
64375fd0b74Schristos }
64475fd0b74Schristos
64575fd0b74Schristos const local_iconv_map *
wind_find_codepage_info(unsigned cp)64675fd0b74Schristos wind_find_codepage_info (unsigned cp)
64775fd0b74Schristos {
64875fd0b74Schristos #if !defined (_WIN32) && !defined (__CYGWIN__)
64975fd0b74Schristos int i;
65075fd0b74Schristos
65175fd0b74Schristos for (i = 0; codepages[i].codepage != (rc_uint_type) -1 && codepages[i].codepage != cp; i++)
65275fd0b74Schristos ;
65375fd0b74Schristos if (codepages[i].codepage == (rc_uint_type) -1)
65475fd0b74Schristos return NULL;
65575fd0b74Schristos return &codepages[i];
65675fd0b74Schristos #else
65775fd0b74Schristos static local_iconv_map lim;
65875fd0b74Schristos if (!unicode_is_valid_codepage (cp))
65975fd0b74Schristos return NULL;
66075fd0b74Schristos lim.codepage = cp;
66175fd0b74Schristos lim.iconv_name = "";
66275fd0b74Schristos return & lim;
66375fd0b74Schristos #endif
66475fd0b74Schristos }
66575fd0b74Schristos
66675fd0b74Schristos /* Convert an Codepage string to a unicode string. */
66775fd0b74Schristos
66875fd0b74Schristos void
unicode_from_codepage(rc_uint_type * length,unichar ** u,const char * src,rc_uint_type cp)66975fd0b74Schristos unicode_from_codepage (rc_uint_type *length, unichar **u, const char *src, rc_uint_type cp)
67075fd0b74Schristos {
67175fd0b74Schristos rc_uint_type len;
67275fd0b74Schristos
67375fd0b74Schristos len = wind_MultiByteToWideChar (cp, src, NULL, 0);
67475fd0b74Schristos if (len)
67575fd0b74Schristos {
67675fd0b74Schristos *u = ((unichar *) res_alloc (len));
67775fd0b74Schristos wind_MultiByteToWideChar (cp, src, *u, len);
67875fd0b74Schristos }
67975fd0b74Schristos /* Discount the trailing '/0'. If MultiByteToWideChar failed,
68075fd0b74Schristos this will set *length to -1. */
68175fd0b74Schristos len -= sizeof (unichar);
68275fd0b74Schristos
68375fd0b74Schristos if (length != NULL)
68475fd0b74Schristos *length = len / sizeof (unichar);
68575fd0b74Schristos }
68675fd0b74Schristos
68775fd0b74Schristos /* Convert an unicode string to an codepage string. */
68875fd0b74Schristos
68975fd0b74Schristos void
codepage_from_unicode(rc_uint_type * length,const unichar * unicode,char ** ascii,rc_uint_type cp)69075fd0b74Schristos codepage_from_unicode (rc_uint_type *length, const unichar *unicode, char **ascii, rc_uint_type cp)
69175fd0b74Schristos {
69275fd0b74Schristos rc_uint_type len;
69375fd0b74Schristos
69475fd0b74Schristos len = wind_WideCharToMultiByte (cp, unicode, NULL, 0);
69575fd0b74Schristos if (len)
69675fd0b74Schristos {
69775fd0b74Schristos *ascii = (char *) res_alloc (len * sizeof (char));
69875fd0b74Schristos wind_WideCharToMultiByte (cp, unicode, *ascii, len);
69975fd0b74Schristos }
70075fd0b74Schristos /* Discount the trailing '/0'. If MultiByteToWideChar failed,
70175fd0b74Schristos this will set *length to -1. */
70275fd0b74Schristos len--;
70375fd0b74Schristos
70475fd0b74Schristos if (length != NULL)
70575fd0b74Schristos *length = len;
70675fd0b74Schristos }
70775fd0b74Schristos
70875fd0b74Schristos #if defined (HAVE_ICONV) && !defined (_WIN32) && !defined (__CYGWIN__)
70975fd0b74Schristos static int
iconv_onechar(iconv_t cd,ICONV_CONST char * s,char * d,int d_len,const char ** n_s,char ** n_d)71075fd0b74Schristos iconv_onechar (iconv_t cd, ICONV_CONST char *s, char *d, int d_len, const char **n_s, char **n_d)
71175fd0b74Schristos {
71275fd0b74Schristos int i;
71375fd0b74Schristos
71475fd0b74Schristos for (i = 1; i <= 32; i++)
71575fd0b74Schristos {
71675fd0b74Schristos char *tmp_d = d;
71775fd0b74Schristos ICONV_CONST char *tmp_s = s;
71875fd0b74Schristos size_t ret;
71975fd0b74Schristos size_t s_left = (size_t) i;
72075fd0b74Schristos size_t d_left = (size_t) d_len;
72175fd0b74Schristos
72275fd0b74Schristos ret = iconv (cd, & tmp_s, & s_left, & tmp_d, & d_left);
72375fd0b74Schristos
72475fd0b74Schristos if (ret != (size_t) -1)
72575fd0b74Schristos {
72675fd0b74Schristos *n_s = tmp_s;
72775fd0b74Schristos *n_d = tmp_d;
72875fd0b74Schristos return 0;
72975fd0b74Schristos }
73075fd0b74Schristos }
73175fd0b74Schristos
73275fd0b74Schristos return 1;
73375fd0b74Schristos }
73475fd0b74Schristos
73575fd0b74Schristos static const char *
wind_iconv_cp(rc_uint_type cp)73675fd0b74Schristos wind_iconv_cp (rc_uint_type cp)
73775fd0b74Schristos {
73875fd0b74Schristos const local_iconv_map *lim = wind_find_codepage_info (cp);
73975fd0b74Schristos
74075fd0b74Schristos if (!lim)
74175fd0b74Schristos return NULL;
74275fd0b74Schristos return lim->iconv_name;
74375fd0b74Schristos }
74475fd0b74Schristos #endif /* HAVE_ICONV */
74575fd0b74Schristos
74675fd0b74Schristos static rc_uint_type
wind_MultiByteToWideChar(rc_uint_type cp,const char * mb,unichar * u,rc_uint_type u_len)74775fd0b74Schristos wind_MultiByteToWideChar (rc_uint_type cp, const char *mb,
74875fd0b74Schristos unichar *u, rc_uint_type u_len)
74975fd0b74Schristos {
75075fd0b74Schristos rc_uint_type ret = 0;
75175fd0b74Schristos
75275fd0b74Schristos #if defined (_WIN32) || defined (__CYGWIN__)
75375fd0b74Schristos rc_uint_type conv_flags = MB_PRECOMPOSED;
75475fd0b74Schristos
75575fd0b74Schristos /* MB_PRECOMPOSED is not allowed for UTF-7 or UTF-8.
75675fd0b74Schristos MultiByteToWideChar will set the last error to
75775fd0b74Schristos ERROR_INVALID_FLAGS if we do. */
75875fd0b74Schristos if (cp == CP_UTF8 || cp == CP_UTF7)
75975fd0b74Schristos conv_flags = 0;
76075fd0b74Schristos
76175fd0b74Schristos ret = (rc_uint_type) MultiByteToWideChar (cp, conv_flags,
76275fd0b74Schristos mb, -1, u, u_len);
76375fd0b74Schristos /* Convert to bytes. */
76475fd0b74Schristos ret *= sizeof (unichar);
76575fd0b74Schristos
76675fd0b74Schristos #elif defined (HAVE_ICONV)
76775fd0b74Schristos int first = 1;
76875fd0b74Schristos char tmp[32];
76975fd0b74Schristos char *p_tmp;
77075fd0b74Schristos const char *iconv_name = wind_iconv_cp (cp);
77175fd0b74Schristos
77275fd0b74Schristos if (!mb || !iconv_name)
77375fd0b74Schristos return 0;
77475fd0b74Schristos iconv_t cd = iconv_open ("UTF-16LE", iconv_name);
77575fd0b74Schristos
77675fd0b74Schristos while (1)
77775fd0b74Schristos {
77875fd0b74Schristos int iret;
77975fd0b74Schristos const char *n_mb = "";
78075fd0b74Schristos char *n_tmp = "";
78175fd0b74Schristos
78275fd0b74Schristos p_tmp = tmp;
78375fd0b74Schristos iret = iconv_onechar (cd, (ICONV_CONST char *) mb, p_tmp, 32, & n_mb, & n_tmp);
78475fd0b74Schristos if (first)
78575fd0b74Schristos {
78675fd0b74Schristos first = 0;
78775fd0b74Schristos continue;
78875fd0b74Schristos }
78975fd0b74Schristos if (!iret)
79075fd0b74Schristos {
79175fd0b74Schristos size_t l_tmp = (size_t) (n_tmp - p_tmp);
79275fd0b74Schristos
79375fd0b74Schristos if (u)
79475fd0b74Schristos {
79575fd0b74Schristos if ((size_t) u_len < l_tmp)
79675fd0b74Schristos break;
79775fd0b74Schristos memcpy (u, tmp, l_tmp);
79875fd0b74Schristos u += l_tmp/2;
79975fd0b74Schristos u_len -= l_tmp;
80075fd0b74Schristos }
80175fd0b74Schristos ret += l_tmp;
80275fd0b74Schristos }
80375fd0b74Schristos else
80475fd0b74Schristos break;
80575fd0b74Schristos if (tmp[0] == 0 && tmp[1] == 0)
80675fd0b74Schristos break;
80775fd0b74Schristos mb = n_mb;
80875fd0b74Schristos }
80975fd0b74Schristos iconv_close (cd);
81075fd0b74Schristos #else
81175fd0b74Schristos if (cp)
81275fd0b74Schristos ret = 0;
81375fd0b74Schristos ret = strlen (mb) + 1;
81475fd0b74Schristos ret *= sizeof (unichar);
81575fd0b74Schristos if (u != NULL && u_len != 0)
81675fd0b74Schristos {
81775fd0b74Schristos do
81875fd0b74Schristos {
81975fd0b74Schristos *u++ = ((unichar) *mb) & 0xff;
82075fd0b74Schristos --u_len; mb++;
82175fd0b74Schristos }
82275fd0b74Schristos while (u_len != 0 && mb[-1] != 0);
82375fd0b74Schristos }
82475fd0b74Schristos if (u != NULL && u_len != 0)
82575fd0b74Schristos *u = 0;
82675fd0b74Schristos #endif
82775fd0b74Schristos return ret;
82875fd0b74Schristos }
82975fd0b74Schristos
83075fd0b74Schristos static rc_uint_type
wind_WideCharToMultiByte(rc_uint_type cp,const unichar * u,char * mb,rc_uint_type mb_len)83175fd0b74Schristos wind_WideCharToMultiByte (rc_uint_type cp, const unichar *u, char *mb, rc_uint_type mb_len)
83275fd0b74Schristos {
83375fd0b74Schristos rc_uint_type ret = 0;
83475fd0b74Schristos #if defined (_WIN32) || defined (__CYGWIN__)
835*e992f068Schristos WINBOOL used_def = false;
83675fd0b74Schristos
83775fd0b74Schristos ret = (rc_uint_type) WideCharToMultiByte (cp, 0, u, -1, mb, mb_len,
83875fd0b74Schristos NULL, & used_def);
83975fd0b74Schristos #elif defined (HAVE_ICONV)
84075fd0b74Schristos int first = 1;
84175fd0b74Schristos char tmp[32];
84275fd0b74Schristos char *p_tmp;
84375fd0b74Schristos const char *iconv_name = wind_iconv_cp (cp);
84475fd0b74Schristos
84575fd0b74Schristos if (!u || !iconv_name)
84675fd0b74Schristos return 0;
84775fd0b74Schristos iconv_t cd = iconv_open (iconv_name, "UTF-16LE");
84875fd0b74Schristos
84975fd0b74Schristos while (1)
85075fd0b74Schristos {
85175fd0b74Schristos int iret;
85275fd0b74Schristos const char *n_u = "";
85375fd0b74Schristos char *n_tmp = "";
85475fd0b74Schristos
85575fd0b74Schristos p_tmp = tmp;
85675fd0b74Schristos iret = iconv_onechar (cd, (ICONV_CONST char *) u, p_tmp, 32, &n_u, & n_tmp);
85775fd0b74Schristos if (first)
85875fd0b74Schristos {
85975fd0b74Schristos first = 0;
86075fd0b74Schristos continue;
86175fd0b74Schristos }
86275fd0b74Schristos if (!iret)
86375fd0b74Schristos {
86475fd0b74Schristos size_t l_tmp = (size_t) (n_tmp - p_tmp);
86575fd0b74Schristos
86675fd0b74Schristos if (mb)
86775fd0b74Schristos {
86875fd0b74Schristos if ((size_t) mb_len < l_tmp)
86975fd0b74Schristos break;
87075fd0b74Schristos memcpy (mb, tmp, l_tmp);
87175fd0b74Schristos mb += l_tmp;
87275fd0b74Schristos mb_len -= l_tmp;
87375fd0b74Schristos }
87475fd0b74Schristos ret += l_tmp;
87575fd0b74Schristos }
87675fd0b74Schristos else
87775fd0b74Schristos break;
87875fd0b74Schristos if (u[0] == 0)
87975fd0b74Schristos break;
88075fd0b74Schristos u = (const unichar *) n_u;
88175fd0b74Schristos }
88275fd0b74Schristos iconv_close (cd);
88375fd0b74Schristos #else
88475fd0b74Schristos if (cp)
88575fd0b74Schristos ret = 0;
88675fd0b74Schristos
88775fd0b74Schristos while (u[ret] != 0)
88875fd0b74Schristos ++ret;
88975fd0b74Schristos
89075fd0b74Schristos ++ret;
89175fd0b74Schristos
89275fd0b74Schristos if (mb)
89375fd0b74Schristos {
89475fd0b74Schristos while (*u != 0 && mb_len != 0)
89575fd0b74Schristos {
89675fd0b74Schristos if (u[0] == (u[0] & 0x7f))
89775fd0b74Schristos *mb++ = (char) u[0];
89875fd0b74Schristos else
89975fd0b74Schristos *mb++ = '_';
90075fd0b74Schristos ++u; --mb_len;
90175fd0b74Schristos }
90275fd0b74Schristos if (mb_len != 0)
90375fd0b74Schristos *mb = 0;
90475fd0b74Schristos }
90575fd0b74Schristos #endif
90675fd0b74Schristos return ret;
90775fd0b74Schristos }
908