xref: /netbsd-src/external/gpl3/binutils.old/dist/binutils/winduni.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
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