Commit | Line | Data |
---|---|---|
252b5132 | 1 | /* winduni.c -- unicode support for the windres program. |
3db64b00 AM |
2 | Copyright 1997, 1998, 2000, 2001, 2003, 2007 |
3 | Free Software Foundation, Inc. | |
252b5132 | 4 | Written by Ian Lance Taylor, Cygnus Support. |
4a594fce | 5 | Rewritten by Kai Tietz, Onevision. |
252b5132 RH |
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 | |
b43b5d5f NC |
21 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA |
22 | 02110-1301, USA. */ | |
252b5132 RH |
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 | ||
3db64b00 | 32 | #include "sysdep.h" |
252b5132 | 33 | #include "bfd.h" |
4a594fce | 34 | #include "bucomm.h" |
252b5132 | 35 | #include "winduni.h" |
3882b010 | 36 | #include "safe-ctype.h" |
252b5132 RH |
37 | |
38 | #ifdef _WIN32 | |
39 | #include <windows.h> | |
40 | #endif | |
41 | ||
4a594fce NC |
42 | /* Prototypes. */ |
43 | static int unichar_isascii (const unichar *, rc_uint_type); | |
44 | ||
252b5132 RH |
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 | |
4a594fce | 49 | unicode_from_ascii (rc_uint_type *length, unichar **unicode, const char *ascii) |
252b5132 | 50 | { |
4a594fce | 51 | rc_uint_type len; |
bcfb5d77 | 52 | #ifndef _WIN32 |
252b5132 RH |
53 | const char *s; |
54 | unsigned short *w; | |
55 | ||
56 | len = strlen (ascii); | |
252b5132 | 57 | *unicode = ((unichar *) res_alloc ((len + 1) * sizeof (unichar))); |
252b5132 RH |
58 | for (s = ascii, w = *unicode; *s != '\0'; s++, w++) |
59 | *w = *s & 0xff; | |
60 | *w = 0; | |
bcfb5d77 DS |
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'. */ | |
4a594fce | 65 | len = (rc_uint_type) MultiByteToWideChar (CP_ACP, 0, ascii, -1, NULL, 0); |
bcfb5d77 DS |
66 | if (len) |
67 | { | |
68 | *unicode = ((unichar *) res_alloc (len * sizeof (unichar))); | |
4a594fce NC |
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); | |
bcfb5d77 DS |
116 | } |
117 | /* Discount the trailing '/0'. If MultiByteToWideChar failed, | |
118 | this will set *length to -1. */ | |
119 | len--; | |
252b5132 | 120 | #endif |
bcfb5d77 DS |
121 | |
122 | if (length != NULL) | |
123 | *length = len; | |
252b5132 RH |
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 | |
4a594fce | 132 | unicode_print (FILE *e, const unichar *unicode, rc_uint_type length) |
252b5132 RH |
133 | { |
134 | while (1) | |
135 | { | |
136 | unichar ch; | |
137 | ||
138 | if (length == 0) | |
139 | return; | |
4a594fce | 140 | if ((bfd_signed_vma) length > 0) |
252b5132 RH |
141 | --length; |
142 | ||
143 | ch = *unicode; | |
144 | ||
4a594fce | 145 | if (ch == 0 && (bfd_signed_vma) length < 0) |
252b5132 RH |
146 | return; |
147 | ||
148 | ++unicode; | |
149 | ||
150 | if ((ch & 0x7f) == ch) | |
151 | { | |
152 | if (ch == '\\') | |
4a594fce NC |
153 | fputs ("\\\\", e); |
154 | else if (ch == '"') | |
155 | fputs ("\"\"", e); | |
3882b010 | 156 | else if (ISPRINT (ch)) |
252b5132 RH |
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 | } | |
4a594fce NC |
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 | } |