Updated windres tool
[external/binutils.git] / binutils / winduni.c
1 /* winduni.c -- unicode support for the windres program.
2    Copyright 1997, 1998, 2000, 2001, 2003, 2007
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 2 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 /* This file contains unicode support routines for the windres
25    program.  Ideally, we would have generic unicode support which
26    would work on all systems.  However, we don't.  Instead, on a
27    Windows host, we are prepared to call some Windows routines.  This
28    means that we will generate different output on Windows and Unix
29    hosts, but that seems better than not really supporting unicode at
30    all.  */
31
32 #include "sysdep.h"
33 #include "bfd.h"
34 #include "bucomm.h"
35 #include "winduni.h"
36 #include "safe-ctype.h"
37
38 #ifdef _WIN32
39 #include <windows.h>
40 #endif
41
42 /* Prototypes.  */
43 static int unichar_isascii (const unichar *, rc_uint_type);
44
45 /* Convert an ASCII string to a unicode string.  We just copy it,
46    expanding chars to shorts, rather than doing something intelligent.  */
47
48 void
49 unicode_from_ascii (rc_uint_type *length, unichar **unicode, const char *ascii)
50 {
51   rc_uint_type len;
52 #ifndef _WIN32
53   const char *s;
54   unsigned short *w;
55
56   len = strlen (ascii);
57   *unicode = ((unichar *) res_alloc ((len + 1) * sizeof (unichar)));
58   for (s = ascii, w = *unicode; *s != '\0'; s++, w++)
59     *w = *s & 0xff;
60   *w = 0;
61 #else
62   /* We use  MultiByteToWideChar rather than strlen to get the unicode
63      string length to allow multibyte "ascii" chars. The value returned
64      by this function includes the trailing '\0'.  */
65   len = (rc_uint_type) MultiByteToWideChar (CP_ACP, 0, ascii, -1, NULL, 0);
66   if (len)
67     {
68       *unicode = ((unichar *) res_alloc (len * sizeof (unichar)));
69       MultiByteToWideChar (CP_ACP, 0, ascii, -1, *unicode, (int) len);
70     }
71   /* Discount the trailing '/0'.  If MultiByteToWideChar failed,
72      this will set *length to -1.  */
73   len--;
74 #endif
75
76   if (length != NULL)
77     *length = len;
78 }
79
80 /* Convert an unicode string to an ASCII string.  We just copy it,
81    shrink shorts to chars, rather than doing something intelligent.
82    Shorts with not within the char range are replaced by '_'.  */
83
84 void
85 ascii_from_unicode (rc_uint_type *length, const unichar *unicode, char **ascii)
86 {
87   rc_uint_type len;
88 #ifndef _WIN32
89   char *s;
90   const unsigned short *w;
91
92   len = 0;
93   while (unicode[len] != 0)
94     ++len;
95   *ascii = ((char *) res_alloc (len + 1));
96   for (s = *ascii, w = unicode; *w != '\0'; w++, s++)
97     {
98       if(w[0]==(w[0]&0xff))
99         *s = (char) w[0];
100       else
101         *s = '_';
102     }
103   *s = 0;
104 #else
105   WINBOOL used_def = FALSE;
106   /* We use  MultiByteToWideChar rather than strlen to get the unicode
107      string length to allow multibyte "ascii" chars. The value returned
108      by this function includes the trailing '\0'.  */
109   len = (rc_uint_type) WideCharToMultiByte (CP_ACP, WC_DEFAULTCHAR, unicode, -1, NULL,
110                                        0, "_", &used_def);
111   if (len)
112     {
113       *ascii = (char *) res_alloc (len * sizeof (char));
114       WideCharToMultiByte (CP_ACP, WC_DEFAULTCHAR, unicode, -1, *ascii, (int) len,
115                            "_", &used_def);
116     }
117   /* Discount the trailing '/0'.  If MultiByteToWideChar failed,
118      this will set *length to -1.  */
119   len--;
120 #endif
121
122   if (length != NULL)
123     *length = len;
124 }
125
126 /* Print the unicode string UNICODE to the file E.  LENGTH is the
127    number of characters to print, or -1 if we should print until the
128    end of the string.  FIXME: On a Windows host, we should be calling
129    some Windows function, probably WideCharToMultiByte.  */
130
131 void
132 unicode_print (FILE *e, const unichar *unicode, rc_uint_type length)
133 {
134   while (1)
135     {
136       unichar ch;
137
138       if (length == 0)
139         return;
140       if ((bfd_signed_vma) length > 0)
141         --length;
142
143       ch = *unicode;
144
145       if (ch == 0 && (bfd_signed_vma) length < 0)
146         return;
147
148       ++unicode;
149
150       if ((ch & 0x7f) == ch)
151         {
152           if (ch == '\\')
153             fputs ("\\\\", e);
154           else if (ch == '"')
155             fputs ("\"\"", e);
156           else if (ISPRINT (ch))
157             putc (ch, e);
158           else
159             {
160               switch (ch)
161                 {
162                 case ESCAPE_A:
163                   fputs ("\\a", e);
164                   break;
165
166                 case ESCAPE_B:
167                   fputs ("\\b", e);
168                   break;
169
170                 case ESCAPE_F:
171                   fputs ("\\f", e);
172                   break;
173
174                 case ESCAPE_N:
175                   fputs ("\\n", e);
176                   break;
177
178                 case ESCAPE_R:
179                   fputs ("\\r", e);
180                   break;
181
182                 case ESCAPE_T:
183                   fputs ("\\t", e);
184                   break;
185
186                 case ESCAPE_V:
187                   fputs ("\\v", e);
188                   break;
189
190                 default:
191                   fprintf (e, "\\%03o", (unsigned int) ch);
192                   break;
193                 }
194             }
195         }
196       else if ((ch & 0xff) == ch)
197         fprintf (e, "\\%03o", (unsigned int) ch);
198       else
199         fprintf (e, "\\x%x", (unsigned int) ch);
200     }
201 }
202
203 /* Print a unicode string to a file.  */
204 void
205 ascii_print (FILE *e, const char *s, rc_uint_type length)
206 {
207   while (1)
208     {
209       char ch;
210
211       if (length == 0)
212         return;
213       if ((bfd_signed_vma) length > 0)
214         --length;
215
216       ch = *s;
217
218       if (ch == 0 && (bfd_signed_vma) length < 0)
219         return;
220
221       ++s;
222
223       if ((ch & 0x7f) == ch)
224         {
225           if (ch == '\\')
226             fputs ("\\\\", e);
227           else if (ch == '"')
228             fputs ("\"\"", e);
229           else if (ISPRINT (ch))
230             putc (ch, e);
231           else
232             {
233               switch (ch)
234                 {
235                 case ESCAPE_A:
236                   fputs ("\\a", e);
237                   break;
238
239                 case ESCAPE_B:
240                   fputs ("\\b", e);
241                   break;
242
243                 case ESCAPE_F:
244                   fputs ("\\f", e);
245                   break;
246
247                 case ESCAPE_N:
248                   fputs ("\\n", e);
249                   break;
250
251                 case ESCAPE_R:
252                   fputs ("\\r", e);
253                   break;
254
255                 case ESCAPE_T:
256                   fputs ("\\t", e);
257                   break;
258
259                 case ESCAPE_V:
260                   fputs ("\\v", e);
261                   break;
262
263                 default:
264                   fprintf (e, "\\%03o", (unsigned int) ch);
265                   break;
266                 }
267             }
268         }
269       else
270         fprintf (e, "\\%03o", (unsigned int) ch & 0xff);
271     }
272 }
273
274 rc_uint_type
275 unichar_len (const unichar *unicode)
276 {
277   rc_uint_type r = 0;
278   if (unicode)
279     while (unicode[r] != 0)
280       r++;
281   else
282     --r;
283   return r;
284 }
285
286 unichar *
287 unichar_dup (const unichar *unicode)
288 {
289   unichar *r;
290   int len;
291
292   if (! unicode)
293     return NULL;
294   for (len = 0; unicode[len] != 0; ++len)
295     ;
296   ++len;
297   r = ((unichar *) res_alloc (len * sizeof (unichar)));
298   memcpy (r, unicode, len * sizeof (unichar));
299   return r;
300 }
301
302 unichar *
303 unichar_dup_uppercase (const unichar *u)
304 {
305   unichar *r = unichar_dup (u);
306   int i;
307
308   if (! r)
309     return NULL;
310
311   for (i = 0; r[i] != 0; ++i)
312     {
313       if (r[i] >= 'a' && r[i] <= 'z')
314         r[i] &= 0xdf;
315     }
316   return r;
317 }
318
319 static int
320 unichar_isascii (const unichar *u, rc_uint_type len)
321 {
322   rc_uint_type i;
323   if ((bfd_signed_vma) len < 0)
324     {
325       if (u)
326         len = (rc_uint_type) unichar_len (u);
327       else
328         len = 0;
329     }
330
331   for (i = 0; i < len; i++)
332     if ((u[i] & 0xff80) != 0)
333       return 0;
334   return 1;
335 }
336
337 void
338 unicode_print_quoted (FILE *e, const unichar *u, rc_uint_type len)
339 {
340   if (! unichar_isascii (u, len))
341     fputc ('L', e);
342   fputc ('"', e);
343   unicode_print (e, u, len);
344   fputc ('"', e);
345 }