]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/resbin.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / binutils / resbin.c
CommitLineData
252b5132 1/* resbin.c -- manipulate the Windows binary resource format.
fd67aa11 2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
252b5132 3 Written by Ian Lance Taylor, Cygnus Support.
4a594fce 4 Rewritten by Kai Tietz, Onevision.
252b5132
RH
5
6 This file is part of GNU Binutils.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
32866df7 10 the Free Software Foundation; either version 3 of the License, or
252b5132
RH
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
b43b5d5f
NC
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21 02110-1301, USA. */
252b5132 22
32866df7 23
252b5132
RH
24/* This file contains functions to convert between the binary resource
25 format and the internal structures that we want to use. The same
26 binary resource format is used in both res and COFF files. */
27
3db64b00 28#include "sysdep.h"
252b5132 29#include "bfd.h"
3db64b00 30#include "bucomm.h"
4a594fce 31#include "libiberty.h"
252b5132
RH
32#include "windres.h"
33
252b5132
RH
34/* Local functions. */
35
2da42df6
AJ
36static void toosmall (const char *);
37
4a594fce
NC
38static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
39static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
40static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
41 const bfd_byte *, rc_uint_type);
42static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
43static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
44static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
45 rc_uint_type *);
46static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
47 rc_uint_type *);
48static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
49static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
50static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
51static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
52static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
53static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
54static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
55static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
56static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
b773a180 57static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *);
4a594fce
NC
58static void get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
59 unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
60 rc_uint_type *);
252b5132
RH
61
62/* Given a resource type ID, a pointer to data, a length, return a
4a594fce 63 rc_res_resource structure which represents that resource. The caller
252b5132
RH
64 is responsible for initializing the res_info and coff_info fields
65 of the returned structure. */
66
4a594fce
NC
67rc_res_resource *
68bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
69 rc_uint_type length)
252b5132
RH
70{
71 if (type.named)
4a594fce 72 return bin_to_res_userdata (wrbfd, data, length);
252b5132
RH
73 else
74 {
75 switch (type.u.id)
76 {
77 default:
4a594fce 78 return bin_to_res_userdata (wrbfd, data, length);
252b5132 79 case RT_CURSOR:
4a594fce 80 return bin_to_res_cursor (wrbfd, data, length);
252b5132 81 case RT_BITMAP:
4a594fce 82 return bin_to_res_generic (wrbfd, RES_TYPE_BITMAP, data, length);
252b5132 83 case RT_ICON:
4a594fce 84 return bin_to_res_generic (wrbfd, RES_TYPE_ICON, data, length);
252b5132 85 case RT_MENU:
4a594fce 86 return bin_to_res_menu (wrbfd, data, length);
252b5132 87 case RT_DIALOG:
4a594fce 88 return bin_to_res_dialog (wrbfd, data, length);
252b5132 89 case RT_STRING:
4a594fce 90 return bin_to_res_string (wrbfd, data, length);
252b5132 91 case RT_FONTDIR:
4a594fce 92 return bin_to_res_fontdir (wrbfd, data, length);
252b5132 93 case RT_FONT:
4a594fce 94 return bin_to_res_generic (wrbfd, RES_TYPE_FONT, data, length);
252b5132 95 case RT_ACCELERATOR:
4a594fce 96 return bin_to_res_accelerators (wrbfd, data, length);
252b5132 97 case RT_RCDATA:
4a594fce 98 return bin_to_res_rcdata (wrbfd, data, length, RES_TYPE_RCDATA);
252b5132 99 case RT_MESSAGETABLE:
4a594fce 100 return bin_to_res_generic (wrbfd, RES_TYPE_MESSAGETABLE, data, length);
252b5132 101 case RT_GROUP_CURSOR:
4a594fce 102 return bin_to_res_group_cursor (wrbfd, data, length);
252b5132 103 case RT_GROUP_ICON:
4a594fce 104 return bin_to_res_group_icon (wrbfd, data, length);
252b5132 105 case RT_VERSION:
4a594fce
NC
106 return bin_to_res_version (wrbfd, data, length);
107 case RT_TOOLBAR:
b773a180 108 return bin_to_res_toolbar (wrbfd, data);
4a594fce 109
252b5132
RH
110 }
111 }
112}
113
114/* Give an error if the binary data is too small. */
115
116static void
2da42df6 117toosmall (const char *msg)
252b5132
RH
118{
119 fatal (_("%s: not enough binary data"), msg);
120}
121
122/* Swap in a NULL terminated unicode string. */
123
124static unichar *
4a594fce
NC
125get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
126 rc_uint_type *retlen)
252b5132 127{
4a594fce 128 rc_uint_type c, i;
252b5132
RH
129 unichar *ret;
130
131 c = 0;
132 while (1)
133 {
4a594fce 134 if (length < c * 2 + 2)
252b5132 135 toosmall (_("null terminated unicode string"));
4a594fce 136 if (windres_get_16 (wrbfd, data + c * 2, 2) == 0)
252b5132
RH
137 break;
138 ++c;
139 }
140
141 ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
142
143 for (i = 0; i < c; i++)
4a594fce 144 ret[i] = windres_get_16 (wrbfd, data + i * 2, 2);
252b5132
RH
145 ret[i] = 0;
146
147 if (retlen != NULL)
148 *retlen = c;
149
150 return ret;
151}
152
153/* Get a resource identifier. This returns the number of bytes used. */
154
155static int
4a594fce
NC
156get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
157 rc_uint_type length)
252b5132 158{
4a594fce 159 rc_uint_type first;
252b5132
RH
160
161 if (length < 2)
162 toosmall (_("resource ID"));
163
4a594fce 164 first = windres_get_16 (wrbfd, data, 2);
252b5132
RH
165 if (first == 0xffff)
166 {
167 if (length < 4)
168 toosmall (_("resource ID"));
169 id->named = 0;
4a594fce 170 id->u.id = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
171 return 4;
172 }
173 else
174 {
175 id->named = 1;
4a594fce 176 id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
252b5132
RH
177 return id->u.n.length * 2 + 2;
178 }
179}
180
181/* Convert a resource which just stores uninterpreted data from
182 binary. */
183
4a594fce
NC
184rc_res_resource *
185bin_to_res_generic (windres_bfd *wrbfd ATTRIBUTE_UNUSED, enum rc_res_type type,
186 const bfd_byte *data, rc_uint_type length)
252b5132 187{
4a594fce 188 rc_res_resource *r;
252b5132 189
4a594fce 190 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
252b5132
RH
191 r->type = type;
192 r->u.data.data = data;
193 r->u.data.length = length;
194
195 return r;
196}
197
198/* Convert a cursor resource from binary. */
199
4a594fce
NC
200rc_res_resource *
201bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 202{
4a594fce
NC
203 rc_cursor *c;
204 rc_res_resource *r;
252b5132
RH
205
206 if (length < 4)
207 toosmall (_("cursor"));
208
4a594fce
NC
209 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
210 c->xhotspot = windres_get_16 (wrbfd, data, 2);
211 c->yhotspot = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
212 c->length = length - 4;
213 c->data = data + 4;
214
4a594fce 215 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
216 r->type = RES_TYPE_CURSOR;
217 r->u.cursor = c;
218
219 return r;
220}
221
222/* Convert a menu resource from binary. */
223
4a594fce
NC
224rc_res_resource *
225bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 226{
4a594fce
NC
227 rc_res_resource *r;
228 rc_menu *m;
91d6fa6a 229 rc_uint_type version, got;
252b5132 230
4a594fce 231 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
232 r->type = RES_TYPE_MENU;
233
4a594fce 234 m = (rc_menu *) res_alloc (sizeof (rc_menu));
252b5132
RH
235 r->u.menu = m;
236
237 if (length < 2)
238 toosmall (_("menu header"));
239
4a594fce 240 version = windres_get_16 (wrbfd, data, 2);
252b5132
RH
241
242 if (version == 0)
243 {
244 if (length < 4)
245 toosmall (_("menu header"));
246 m->help = 0;
91d6fa6a 247 m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &got);
252b5132
RH
248 }
249 else if (version == 1)
250 {
4a594fce 251 rc_uint_type offset;
252b5132
RH
252
253 if (length < 8)
254 toosmall (_("menuex header"));
4a594fce
NC
255 m->help = windres_get_32 (wrbfd, data + 4, 4);
256 offset = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
257 if (offset + 4 >= length)
258 toosmall (_("menuex offset"));
4a594fce 259 m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
91d6fa6a 260 length - (4 + offset), &got);
252b5132
RH
261 }
262 else
4a594fce 263 fatal (_("unsupported menu version %d"), (int) version);
252b5132
RH
264
265 return r;
266}
267
268/* Convert menu items from binary. */
269
4a594fce
NC
270static rc_menuitem *
271bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
91d6fa6a 272 rc_uint_type *got)
252b5132 273{
4a594fce 274 rc_menuitem *first, **pp;
252b5132
RH
275
276 first = NULL;
277 pp = &first;
278
91d6fa6a 279 *got = 0;
252b5132
RH
280
281 while (length > 0)
282 {
4a594fce
NC
283 rc_uint_type flags, slen, itemlen;
284 rc_uint_type stroff;
285 rc_menuitem *mi;
252b5132
RH
286
287 if (length < 4)
288 toosmall (_("menuitem header"));
289
4a594fce 290 mi = (rc_menuitem *) res_alloc (sizeof *mi);
252b5132
RH
291 mi->state = 0;
292 mi->help = 0;
293
4a594fce 294 flags = windres_get_16 (wrbfd, data, 2);
252b5132
RH
295 mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
296
297 if ((flags & MENUITEM_POPUP) == 0)
298 stroff = 4;
299 else
300 stroff = 2;
301
302 if (length < stroff + 2)
303 toosmall (_("menuitem header"));
304
4a594fce 305 if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
252b5132
RH
306 {
307 slen = 0;
308 mi->text = NULL;
309 }
310 else
4a594fce 311 mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
252b5132
RH
312
313 itemlen = stroff + slen * 2 + 2;
314
315 if ((flags & MENUITEM_POPUP) == 0)
316 {
317 mi->popup = NULL;
4a594fce 318 mi->id = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
319 }
320 else
321 {
4a594fce 322 rc_uint_type subread;
252b5132
RH
323
324 mi->id = 0;
4a594fce
NC
325 mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
326 &subread);
252b5132
RH
327 itemlen += subread;
328 }
329
330 mi->next = NULL;
331 *pp = mi;
332 pp = &mi->next;
333
334 data += itemlen;
335 length -= itemlen;
91d6fa6a 336 *got += itemlen;
252b5132
RH
337
338 if ((flags & MENUITEM_ENDMENU) != 0)
339 return first;
340 }
341
342 return first;
343}
344
345/* Convert menuex items from binary. */
346
4a594fce
NC
347static rc_menuitem *
348bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
91d6fa6a 349 rc_uint_type *got)
252b5132 350{
4a594fce 351 rc_menuitem *first, **pp;
252b5132
RH
352
353 first = NULL;
354 pp = &first;
355
91d6fa6a 356 *got = 0;
252b5132
RH
357
358 while (length > 0)
359 {
4a594fce
NC
360 rc_uint_type flags, slen;
361 rc_uint_type itemlen;
362 rc_menuitem *mi;
252b5132 363
4a594fce 364 if (length < 16)
252b5132
RH
365 toosmall (_("menuitem header"));
366
4a594fce
NC
367 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
368 mi->type = windres_get_32 (wrbfd, data, 4);
369 mi->state = windres_get_32 (wrbfd, data + 4, 4);
370 mi->id = windres_get_32 (wrbfd, data + 8, 4);
252b5132 371
4a594fce 372 flags = windres_get_16 (wrbfd, data + 12, 2);
252b5132 373
4a594fce 374 if (windres_get_16 (wrbfd, data + 14, 2) == 0)
252b5132
RH
375 {
376 slen = 0;
377 mi->text = NULL;
378 }
379 else
4a594fce 380 mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
252b5132 381
4a594fce 382 itemlen = 14 + slen * 2 + 2;
252b5132
RH
383 itemlen = (itemlen + 3) &~ 3;
384
385 if ((flags & 1) == 0)
386 {
387 mi->popup = NULL;
388 mi->help = 0;
389 }
390 else
391 {
4a594fce 392 rc_uint_type subread;
252b5132
RH
393
394 if (length < itemlen + 4)
395 toosmall (_("menuitem"));
4a594fce 396 mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
252b5132
RH
397 itemlen += 4;
398
4a594fce
NC
399 mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
400 length - itemlen, &subread);
252b5132
RH
401 itemlen += subread;
402 }
403
404 mi->next = NULL;
405 *pp = mi;
406 pp = &mi->next;
407
408 data += itemlen;
409 length -= itemlen;
91d6fa6a 410 *got += itemlen;
252b5132
RH
411
412 if ((flags & 0x80) != 0)
413 return first;
414 }
415
416 return first;
417}
418
419/* Convert a dialog resource from binary. */
420
4a594fce
NC
421static rc_res_resource *
422bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 423{
4a594fce
NC
424 rc_uint_type signature;
425 rc_dialog *d;
426 rc_uint_type c, sublen, i;
427 rc_uint_type off;
428 rc_dialog_control **pp;
429 rc_res_resource *r;
252b5132
RH
430
431 if (length < 18)
432 toosmall (_("dialog header"));
433
4a594fce 434 d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
252b5132 435
4a594fce 436 signature = windres_get_16 (wrbfd, data + 2, 2);
7e8d45b7 437 if (signature != 0xffff)
252b5132
RH
438 {
439 d->ex = NULL;
4a594fce
NC
440 d->style = windres_get_32 (wrbfd, data, 4);
441 d->exstyle = windres_get_32 (wrbfd, data + 4, 4);
252b5132
RH
442 off = 8;
443 }
444 else
445 {
7e8d45b7 446 int version;
53c7db4b 447
4a594fce 448 version = windres_get_16 (wrbfd, data, 2);
7e8d45b7
NC
449 if (version != 1)
450 fatal (_("unexpected DIALOGEX version %d"), version);
252b5132 451
4a594fce
NC
452 d->ex = (rc_dialog_ex *) res_alloc (sizeof (rc_dialog_ex));
453 d->ex->help = windres_get_32 (wrbfd, data + 4, 4);
454 d->exstyle = windres_get_32 (wrbfd, data + 8, 4);
455 d->style = windres_get_32 (wrbfd, data + 12, 4);
252b5132
RH
456 off = 16;
457 }
458
459 if (length < off + 10)
460 toosmall (_("dialog header"));
461
4a594fce
NC
462 c = windres_get_16 (wrbfd, data + off, 2);
463 d->x = windres_get_16 (wrbfd, data + off + 2, 2);
464 d->y = windres_get_16 (wrbfd, data + off + 4, 2);
465 d->width = windres_get_16 (wrbfd, data + off + 6, 2);
466 d->height = windres_get_16 (wrbfd, data + off + 8, 2);
252b5132
RH
467
468 off += 10;
469
4a594fce 470 sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
252b5132
RH
471 off += sublen;
472
4a594fce 473 sublen = get_resid (wrbfd, &d->class, data + off, length - off);
252b5132
RH
474 off += sublen;
475
4a594fce 476 d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
252b5132 477 off += sublen * 2 + 2;
53c7db4b 478 if (sublen == 0)
420380ba 479 d->caption = NULL;
252b5132
RH
480
481 if ((d->style & DS_SETFONT) == 0)
482 {
483 d->pointsize = 0;
484 d->font = NULL;
485 if (d->ex != NULL)
486 {
487 d->ex->weight = 0;
488 d->ex->italic = 0;
45b99827 489 d->ex->charset = 1; /* Default charset. */
252b5132
RH
490 }
491 }
492 else
493 {
494 if (length < off + 2)
495 toosmall (_("dialog font point size"));
496
4a594fce 497 d->pointsize = windres_get_16 (wrbfd, data + off, 2);
252b5132
RH
498 off += 2;
499
500 if (d->ex != NULL)
501 {
502 if (length < off + 4)
503 toosmall (_("dialogex font information"));
4a594fce
NC
504 d->ex->weight = windres_get_16 (wrbfd, data + off, 2);
505 d->ex->italic = windres_get_8 (wrbfd, data + off + 2, 1);
506 d->ex->charset = windres_get_8 (wrbfd, data + off + 3, 1);
252b5132
RH
507 off += 4;
508 }
509
4a594fce 510 d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
252b5132
RH
511 off += sublen * 2 + 2;
512 }
513
514 d->controls = NULL;
515 pp = &d->controls;
516
517 for (i = 0; i < c; i++)
518 {
4a594fce 519 rc_dialog_control *dc;
252b5132
RH
520 int datalen;
521
522 off = (off + 3) &~ 3;
523
4a594fce 524 dc = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
252b5132
RH
525
526 if (d->ex == NULL)
527 {
528 if (length < off + 8)
529 toosmall (_("dialog control"));
530
4a594fce
NC
531 dc->style = windres_get_32 (wrbfd, data + off, 4);
532 dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
252b5132
RH
533 dc->help = 0;
534 off += 8;
535 }
536 else
537 {
538 if (length < off + 12)
539 toosmall (_("dialogex control"));
4a594fce
NC
540 dc->help = windres_get_32 (wrbfd, data + off, 4);
541 dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
542 dc->style = windres_get_32 (wrbfd, data + off + 8, 4);
252b5132
RH
543 off += 12;
544 }
545
4a594fce 546 if (length < off + (d->ex != NULL ? 2 : 0) + 10)
252b5132
RH
547 toosmall (_("dialog control"));
548
4a594fce
NC
549 dc->x = windres_get_16 (wrbfd, data + off, 2);
550 dc->y = windres_get_16 (wrbfd, data + off + 2, 2);
551 dc->width = windres_get_16 (wrbfd, data + off + 4, 2);
552 dc->height = windres_get_16 (wrbfd, data + off + 6, 2);
252b5132
RH
553
554 if (d->ex != NULL)
4a594fce 555 dc->id = windres_get_32 (wrbfd, data + off + 8, 4);
252b5132 556 else
4a594fce 557 dc->id = windres_get_16 (wrbfd, data + off + 8, 2);
252b5132
RH
558
559 off += 10 + (d->ex != NULL ? 2 : 0);
560
4a594fce 561 sublen = get_resid (wrbfd, &dc->class, data + off, length - off);
252b5132
RH
562 off += sublen;
563
4a594fce 564 sublen = get_resid (wrbfd, &dc->text, data + off, length - off);
252b5132
RH
565 off += sublen;
566
567 if (length < off + 2)
568 toosmall (_("dialog control end"));
569
4a594fce 570 datalen = windres_get_16 (wrbfd, data + off, 2);
252b5132
RH
571 off += 2;
572
573 if (datalen == 0)
574 dc->data = NULL;
575 else
576 {
252b5132
RH
577 if (length < off + datalen)
578 toosmall (_("dialog control data"));
579
4a594fce
NC
580 dc->data = ((rc_rcdata_item *)
581 res_alloc (sizeof (rc_rcdata_item)));
252b5132
RH
582 dc->data->next = NULL;
583 dc->data->type = RCDATA_BUFFER;
584 dc->data->u.buffer.length = datalen;
585 dc->data->u.buffer.data = data + off;
586
53c7db4b 587 off += datalen;
252b5132
RH
588 }
589
590 dc->next = NULL;
591 *pp = dc;
592 pp = &dc->next;
593 }
594
4a594fce 595 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
596 r->type = RES_TYPE_DIALOG;
597 r->u.dialog = d;
598
599 return r;
600}
601
602/* Convert a stringtable resource from binary. */
603
4a594fce
NC
604static rc_res_resource *
605bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 606{
4a594fce 607 rc_stringtable *st;
252b5132 608 int i;
4a594fce 609 rc_res_resource *r;
252b5132 610
4a594fce 611 st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
252b5132
RH
612
613 for (i = 0; i < 16; i++)
614 {
615 unsigned int slen;
616
617 if (length < 2)
618 toosmall (_("stringtable string length"));
4a594fce 619 slen = windres_get_16 (wrbfd, data, 2);
252b5132
RH
620 st->strings[i].length = slen;
621
622 if (slen > 0)
623 {
624 unichar *s;
625 unsigned int j;
626
627 if (length < 2 + 2 * slen)
628 toosmall (_("stringtable string"));
629
630 s = (unichar *) res_alloc (slen * sizeof (unichar));
631 st->strings[i].string = s;
632
633 for (j = 0; j < slen; j++)
4a594fce 634 s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
252b5132
RH
635 }
636
637 data += 2 + 2 * slen;
638 length -= 2 + 2 * slen;
639 }
640
4a594fce 641 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
642 r->type = RES_TYPE_STRINGTABLE;
643 r->u.stringtable = st;
644
645 return r;
646}
647
648/* Convert a fontdir resource from binary. */
649
4a594fce
NC
650static rc_res_resource *
651bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 652{
4a594fce
NC
653 rc_uint_type c, i;
654 rc_fontdir *first, **pp;
655 rc_res_resource *r;
252b5132
RH
656
657 if (length < 2)
658 toosmall (_("fontdir header"));
659
4a594fce 660 c = windres_get_16 (wrbfd, data, 2);
252b5132
RH
661
662 first = NULL;
663 pp = &first;
664
665 for (i = 0; i < c; i++)
666 {
4a594fce
NC
667 const struct bin_fontdir_item *bfi;
668 rc_fontdir *fd;
252b5132
RH
669 unsigned int off;
670
671 if (length < 56)
672 toosmall (_("fontdir"));
673
4a594fce
NC
674 bfi = (const struct bin_fontdir_item *) data;
675 fd = (rc_fontdir *) res_alloc (sizeof *fd);
676 fd->index = windres_get_16 (wrbfd, bfi->index, 2);
252b5132
RH
677
678 /* To work out the length of the fontdir data, we must get the
679 length of the device name and face name strings, even though
4a594fce 680 we don't store them in the rc_fontdir. The
252b5132
RH
681 documentation says that these are NULL terminated char
682 strings, not Unicode strings. */
683
684 off = 56;
685
686 while (off < length && data[off] != '\0')
687 ++off;
688 if (off >= length)
689 toosmall (_("fontdir device name"));
690 ++off;
691
692 while (off < length && data[off] != '\0')
693 ++off;
694 if (off >= length)
695 toosmall (_("fontdir face name"));
696 ++off;
697
698 fd->length = off;
699 fd->data = data;
700
701 fd->next = NULL;
702 *pp = fd;
703 pp = &fd->next;
704
705 /* The documentation does not indicate that any rounding is
706 required. */
707
708 data += off;
709 length -= off;
710 }
711
4a594fce 712 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
713 r->type = RES_TYPE_FONTDIR;
714 r->u.fontdir = first;
715
716 return r;
717}
718
719/* Convert an accelerators resource from binary. */
720
4a594fce
NC
721static rc_res_resource *
722bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 723{
4a594fce
NC
724 rc_accelerator *first, **pp;
725 rc_res_resource *r;
252b5132
RH
726
727 first = NULL;
728 pp = &first;
729
730 while (1)
731 {
4a594fce 732 rc_accelerator *a;
252b5132
RH
733
734 if (length < 8)
735 toosmall (_("accelerator"));
736
4a594fce 737 a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
252b5132 738
4a594fce
NC
739 a->flags = windres_get_16 (wrbfd, data, 2);
740 a->key = windres_get_16 (wrbfd, data + 2, 2);
741 a->id = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
742
743 a->next = NULL;
744 *pp = a;
745 pp = &a->next;
746
747 if ((a->flags & ACC_LAST) != 0)
748 break;
749
750 data += 8;
751 length -= 8;
752 }
753
4a594fce 754 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
252b5132
RH
755 r->type = RES_TYPE_ACCELERATOR;
756 r->u.acc = first;
757
758 return r;
759}
760
761/* Convert an rcdata resource from binary. */
762
4a594fce
NC
763static rc_res_resource *
764bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
765 rc_uint_type length, int rctyp)
252b5132 766{
4a594fce
NC
767 rc_rcdata_item *ri;
768 rc_res_resource *r;
252b5132 769
4a594fce 770 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
771
772 ri->next = NULL;
773 ri->type = RCDATA_BUFFER;
774 ri->u.buffer.length = length;
775 ri->u.buffer.data = data;
776
4a594fce
NC
777 r = (rc_res_resource *) res_alloc (sizeof *r);
778 r->type = rctyp;
252b5132
RH
779 r->u.rcdata = ri;
780
781 return r;
782}
783
784/* Convert a group cursor resource from binary. */
785
4a594fce
NC
786static rc_res_resource *
787bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132
RH
788{
789 int type, c, i;
4a594fce
NC
790 rc_group_cursor *first, **pp;
791 rc_res_resource *r;
252b5132
RH
792
793 if (length < 6)
794 toosmall (_("group cursor header"));
795
4a594fce 796 type = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
797 if (type != 2)
798 fatal (_("unexpected group cursor type %d"), type);
799
4a594fce 800 c = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
801
802 data += 6;
803 length -= 6;
804
805 first = NULL;
806 pp = &first;
807
808 for (i = 0; i < c; i++)
809 {
4a594fce 810 rc_group_cursor *gc;
252b5132
RH
811
812 if (length < 14)
813 toosmall (_("group cursor"));
814
4a594fce 815 gc = (rc_group_cursor *) res_alloc (sizeof *gc);
252b5132 816
4a594fce
NC
817 gc->width = windres_get_16 (wrbfd, data, 2);
818 gc->height = windres_get_16 (wrbfd, data + 2, 2);
819 gc->planes = windres_get_16 (wrbfd, data + 4, 2);
820 gc->bits = windres_get_16 (wrbfd, data + 6, 2);
821 gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
822 gc->index = windres_get_16 (wrbfd, data + 12, 2);
252b5132
RH
823
824 gc->next = NULL;
825 *pp = gc;
826 pp = &gc->next;
827
828 data += 14;
829 length -= 14;
830 }
831
4a594fce 832 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
252b5132
RH
833 r->type = RES_TYPE_GROUP_CURSOR;
834 r->u.group_cursor = first;
835
836 return r;
837}
838
839/* Convert a group icon resource from binary. */
840
4a594fce
NC
841static rc_res_resource *
842bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132
RH
843{
844 int type, c, i;
4a594fce
NC
845 rc_group_icon *first, **pp;
846 rc_res_resource *r;
252b5132
RH
847
848 if (length < 6)
849 toosmall (_("group icon header"));
850
4a594fce 851 type = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
852 if (type != 1)
853 fatal (_("unexpected group icon type %d"), type);
854
4a594fce 855 c = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
856
857 data += 6;
858 length -= 6;
859
860 first = NULL;
861 pp = &first;
862
863 for (i = 0; i < c; i++)
864 {
4a594fce 865 rc_group_icon *gi;
252b5132
RH
866
867 if (length < 14)
868 toosmall (_("group icon"));
869
4a594fce 870 gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
252b5132 871
4a594fce
NC
872 gi->width = windres_get_8 (wrbfd, data, 1);
873 gi->height = windres_get_8 (wrbfd, data + 1, 1);
874 gi->colors = windres_get_8 (wrbfd, data + 2, 1);
875 gi->planes = windres_get_16 (wrbfd, data + 4, 2);
876 gi->bits = windres_get_16 (wrbfd, data + 6, 2);
877 gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
878 gi->index = windres_get_16 (wrbfd, data + 12, 2);
252b5132
RH
879
880 gi->next = NULL;
881 *pp = gi;
882 pp = &gi->next;
883
884 data += 14;
885 length -= 14;
886 }
887
4a594fce 888 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
889 r->type = RES_TYPE_GROUP_ICON;
890 r->u.group_icon = first;
891
892 return r;
893}
894
895/* Extract data from a version header. If KEY is not NULL, then the
896 key must be KEY; otherwise, the key is returned in *PKEY. This
897 sets *LEN to the total length, *VALLEN to the value length, *TYPE
898 to the type, and *OFF to the offset to the children. */
899
900static void
4a594fce
NC
901get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
902 const char *key, unichar **pkey,
903 rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
904 rc_uint_type *off)
252b5132
RH
905{
906 if (length < 8)
907 toosmall (key);
908
fb98f7b7 909 *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
4a594fce
NC
910 *vallen = windres_get_16 (wrbfd, data + 2, 2);
911 *type = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
912
913 *off = 6;
914
915 length -= 6;
916 data += 6;
917
918 if (key == NULL)
919 {
4a594fce 920 rc_uint_type sublen;
252b5132 921
4a594fce
NC
922 *pkey = get_unicode (wrbfd, data, length, &sublen);
923 *off += (sublen + 1) * sizeof (unichar);
252b5132
RH
924 }
925 else
926 {
927 while (1)
928 {
929 if (length < 2)
930 toosmall (key);
4a594fce 931 if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
252b5132
RH
932 fatal (_("unexpected version string"));
933
934 *off += 2;
935 length -= 2;
936 data += 2;
937
938 if (*key == '\0')
939 break;
940
941 ++key;
942 }
943 }
944
945 *off = (*off + 3) &~ 3;
946}
947
948/* Convert a version resource from binary. */
949
4a594fce
NC
950static rc_res_resource *
951bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 952{
4a594fce
NC
953 rc_uint_type verlen, vallen, type, off;
954 rc_fixed_versioninfo *fi;
955 rc_ver_info *first, **pp;
956 rc_versioninfo *v;
957 rc_res_resource *r;
252b5132 958
4a594fce 959 get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
7e8d45b7 960 (unichar **) NULL, &verlen, &vallen, &type, &off);
252b5132 961
4931146e
NC
962 /* PR 17512: The verlen field does not include padding length. */
963 if (verlen > length)
964 fatal (_("version length %lu greater than resource length %lu"),
2d5bddc1 965 (unsigned long) verlen, (unsigned long) length);
252b5132
RH
966
967 if (type != 0)
4a594fce 968 fatal (_("unexpected version type %d"), (int) type);
252b5132 969
6be872a4
MH
970 /* PR 27686: Ignore any padding bytes after the end of the version structure. */
971 length = verlen;
972
252b5132
RH
973 data += off;
974 length -= off;
975
976 if (vallen == 0)
977 fi = NULL;
978 else
979 {
980 unsigned long signature, fiv;
981
982 if (vallen != 52)
4a594fce 983 fatal (_("unexpected fixed version information length %ld"), (long) vallen);
252b5132
RH
984
985 if (length < 52)
986 toosmall (_("fixed version info"));
987
4a594fce 988 signature = windres_get_32 (wrbfd, data, 4);
252b5132
RH
989 if (signature != 0xfeef04bd)
990 fatal (_("unexpected fixed version signature %lu"), signature);
991
4a594fce 992 fiv = windres_get_32 (wrbfd, data + 4, 4);
252b5132
RH
993 if (fiv != 0 && fiv != 0x10000)
994 fatal (_("unexpected fixed version info version %lu"), fiv);
995
4a594fce 996 fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
252b5132 997
4a594fce
NC
998 fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
999 fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
1000 fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
1001 fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1002 fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1003 fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1004 fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1005 fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1006 fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1007 fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1008 fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
252b5132
RH
1009
1010 data += 52;
1011 length -= 52;
1012 }
1013
1014 first = NULL;
1015 pp = &first;
1016
1017 while (length > 0)
1018 {
4a594fce 1019 rc_ver_info *vi;
252b5132
RH
1020 int ch;
1021
1022 if (length < 8)
1023 toosmall (_("version var info"));
1024
4a594fce 1025 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
252b5132 1026
4a594fce 1027 ch = windres_get_16 (wrbfd, data + 6, 2);
252b5132
RH
1028
1029 if (ch == 'S')
1030 {
bfb6c1ab 1031 rc_ver_stringtable **ppvst;
252b5132
RH
1032
1033 vi->type = VERINFO_STRING;
1034
4a594fce 1035 get_version_header (wrbfd, data, length, "StringFileInfo",
7e8d45b7 1036 (unichar **) NULL, &verlen, &vallen, &type,
252b5132
RH
1037 &off);
1038
1039 if (vallen != 0)
4a594fce 1040 fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
252b5132
RH
1041
1042 data += off;
1043 length -= off;
1044
fb98f7b7 1045 verlen -= off;
252b5132 1046
bfb6c1ab
NC
1047 vi->u.string.stringtables = NULL;
1048 ppvst = &vi->u.string.stringtables;
1049
252b5132 1050 while (verlen > 0)
bfb6c1ab
NC
1051 {
1052 rc_ver_stringtable *vst;
1053 rc_uint_type stverlen;
1054 rc_ver_stringinfo **ppvs;
1055
1056 if (length < 8)
1057 toosmall (_("version stringtable"));
1058
1059 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1060
1061 get_version_header (wrbfd, data, length, (const char *) NULL,
1062 &vst->language, &stverlen, &vallen, &type, &off);
1063
1064 if (vallen != 0)
1065 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1066
1067 data += off;
1068 length -= off;
1069 verlen -= off;
1070
fb98f7b7 1071 stverlen -= off;
3aade688 1072
bfb6c1ab
NC
1073 vst->strings = NULL;
1074 ppvs = &vst->strings;
1075
1076 while (stverlen > 0)
252b5132 1077 {
4a594fce 1078 rc_ver_stringinfo *vs;
bfb6c1ab
NC
1079 rc_uint_type sverlen, vslen, valoff;
1080
1081 if (length < 8)
1082 toosmall (_("version string"));
252b5132 1083
bfb6c1ab 1084 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
252b5132 1085
bfb6c1ab
NC
1086 get_version_header (wrbfd, data, length, (const char *) NULL,
1087 &vs->key, &sverlen, &vallen, &type, &off);
252b5132 1088
252b5132
RH
1089 data += off;
1090 length -= off;
1091
4a594fce 1092 vs->value = get_unicode (wrbfd, data, length, &vslen);
252b5132 1093 valoff = vslen * 2 + 2;
fb98f7b7 1094 valoff = (valoff + 3) & ~3;
252b5132 1095
bfb6c1ab 1096 if (off + valoff != sverlen)
4a594fce 1097 fatal (_("unexpected version string length %ld != %ld + %ld"),
bfb6c1ab 1098 (long) sverlen, (long) off, (long) valoff);
252b5132
RH
1099
1100 data += valoff;
1101 length -= valoff;
1102
bfb6c1ab 1103 if (stverlen < sverlen)
4a594fce 1104 fatal (_("unexpected version string length %ld < %ld"),
bfb6c1ab
NC
1105 (long) verlen, (long) sverlen);
1106 stverlen -= sverlen;
fb98f7b7 1107 verlen -= sverlen;
bfb6c1ab
NC
1108
1109 vs->next = NULL;
1110 *ppvs = vs;
1111 ppvs = &vs->next;
1112 }
252b5132 1113
bfb6c1ab
NC
1114 vst->next = NULL;
1115 *ppvst = vst;
1116 ppvst = &vst->next;
252b5132
RH
1117 }
1118 }
1119 else if (ch == 'V')
1120 {
4a594fce 1121 rc_ver_varinfo **ppvv;
252b5132
RH
1122
1123 vi->type = VERINFO_VAR;
1124
4a594fce 1125 get_version_header (wrbfd, data, length, "VarFileInfo",
7e8d45b7 1126 (unichar **) NULL, &verlen, &vallen, &type,
252b5132
RH
1127 &off);
1128
1129 if (vallen != 0)
4a594fce 1130 fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
252b5132
RH
1131
1132 data += off;
1133 length -= off;
1134
4a594fce 1135 get_version_header (wrbfd, data, length, (const char *) NULL,
252b5132
RH
1136 &vi->u.var.key, &verlen, &vallen, &type, &off);
1137
1138 data += off;
1139 length -= off;
1140
1141 vi->u.var.var = NULL;
1142 ppvv = &vi->u.var.var;
1143
1144 while (vallen > 0)
1145 {
4a594fce 1146 rc_ver_varinfo *vv;
252b5132
RH
1147
1148 if (length < 4)
1149 toosmall (_("version varfileinfo"));
1150
4a594fce 1151 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
252b5132 1152
4a594fce
NC
1153 vv->language = windres_get_16 (wrbfd, data, 2);
1154 vv->charset = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
1155
1156 vv->next = NULL;
1157 *ppvv = vv;
1158 ppvv = &vv->next;
1159
1160 data += 4;
1161 length -= 4;
1162
1163 if (vallen < 4)
4a594fce 1164 fatal (_("unexpected version value length %ld"), (long) vallen);
252b5132
RH
1165
1166 vallen -= 4;
1167 }
1168 }
4931146e
NC
1169 else if (ch == 0)
1170 {
1171 if (length == 8)
1172 /* Padding - skip. */
1173 break;
1174 fatal (_("nul bytes found in version string"));
1175 }
252b5132 1176 else
4931146e 1177 fatal (_("unexpected version string character: %x"), ch);
252b5132
RH
1178
1179 vi->next = NULL;
1180 *pp = vi;
53c7db4b 1181 pp = &vi->next;
252b5132
RH
1182 }
1183
4a594fce 1184 v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
252b5132
RH
1185 v->fixed = fi;
1186 v->var = first;
1187
4a594fce 1188 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
1189 r->type = RES_TYPE_VERSIONINFO;
1190 r->u.versioninfo = v;
1191
53c7db4b 1192 return r;
252b5132
RH
1193}
1194
1195/* Convert an arbitrary user defined resource from binary. */
1196
4a594fce
NC
1197static rc_res_resource *
1198bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1199 rc_uint_type length)
252b5132 1200{
4a594fce
NC
1201 rc_rcdata_item *ri;
1202 rc_res_resource *r;
252b5132 1203
4a594fce 1204 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
1205
1206 ri->next = NULL;
1207 ri->type = RCDATA_BUFFER;
1208 ri->u.buffer.length = length;
1209 ri->u.buffer.data = data;
1210
4a594fce 1211 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
1212 r->type = RES_TYPE_USERDATA;
1213 r->u.rcdata = ri;
1214
1215 return r;
1216}
1217\f
4a594fce 1218static rc_res_resource *
b773a180 1219bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data)
4a594fce
NC
1220{
1221 rc_toolbar *ri;
1222 rc_res_resource *r;
1223 rc_uint_type i;
1224
1225 ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1226 ri->button_width = windres_get_32 (wrbfd, data, 4);
1227 ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1228 ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1229 ri->items = NULL;
1230
1231 data += 12;
4a594fce
NC
1232 for (i=0 ; i < ri->nitems; i++)
1233 {
1234 rc_toolbar_item *it;
1235 it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1236 it->id.named = 0;
1237 it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1238 it->prev = it->next = NULL;
1239 data += 4;
4a594fce
NC
1240 if(ri->items) {
1241 rc_toolbar_item *ii = ri->items;
1242 while (ii->next != NULL)
1243 ii = ii->next;
1244 it->prev = ii;
1245 ii->next = it;
1246 }
1247 else
1248 ri->items = it;
1249 }
1250 r = (rc_res_resource *) res_alloc (sizeof *r);
1251 r->type = RES_TYPE_TOOLBAR;
1252 r->u.toolbar = ri;
1253 return r;
1254}
252b5132 1255
252b5132
RH
1256
1257/* Local functions used to convert resources to binary format. */
1258
4a594fce
NC
1259static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1260static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1261static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1262static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1263static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1264static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1265static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1266static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1267static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1268static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1269static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1270static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1271static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1272static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1273static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1274static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1275static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1276 const bfd_byte *);
252b5132
RH
1277
1278/* Convert a resource to binary. */
1279
4a594fce
NC
1280rc_uint_type
1281res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
252b5132
RH
1282{
1283 switch (res->type)
1284 {
252b5132
RH
1285 case RES_TYPE_BITMAP:
1286 case RES_TYPE_FONT:
1287 case RES_TYPE_ICON:
1288 case RES_TYPE_MESSAGETABLE:
4a594fce 1289 return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
252b5132 1290 case RES_TYPE_ACCELERATOR:
4a594fce 1291 return res_to_bin_accelerator (wrbfd, off, res->u.acc);
252b5132 1292 case RES_TYPE_CURSOR:
4a594fce 1293 return res_to_bin_cursor (wrbfd, off, res->u.cursor);
252b5132 1294 case RES_TYPE_GROUP_CURSOR:
4a594fce 1295 return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
252b5132 1296 case RES_TYPE_DIALOG:
4a594fce 1297 return res_to_bin_dialog (wrbfd, off, res->u.dialog);
252b5132 1298 case RES_TYPE_FONTDIR:
4a594fce 1299 return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
252b5132 1300 case RES_TYPE_GROUP_ICON:
4a594fce 1301 return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
252b5132 1302 case RES_TYPE_MENU:
4a594fce 1303 return res_to_bin_menu (wrbfd, off, res->u.menu);
252b5132 1304 case RES_TYPE_STRINGTABLE:
4a594fce 1305 return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
252b5132 1306 case RES_TYPE_VERSIONINFO:
4a594fce
NC
1307 return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1308 case RES_TYPE_TOOLBAR:
1309 return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1310 case RES_TYPE_USERDATA:
1311 case RES_TYPE_RCDATA:
1312 default:
1313 return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
252b5132
RH
1314 }
1315}
1316
252b5132
RH
1317/* Convert a resource ID to binary. This always returns exactly one
1318 bindata structure. */
1319
4a594fce
NC
1320static rc_uint_type
1321resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
252b5132 1322{
252b5132
RH
1323 if (! id.named)
1324 {
4a594fce
NC
1325 if (wrbfd)
1326 {
1327 struct bin_res_id bri;
3aade688 1328
4a594fce
NC
1329 windres_put_16 (wrbfd, bri.sig, 0xffff);
1330 windres_put_16 (wrbfd, bri.id, id.u.id);
1331 set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1332 }
1333 off += BIN_RES_ID;
252b5132
RH
1334 }
1335 else
1336 {
4a594fce
NC
1337 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1338 if (wrbfd)
1339 {
1340 bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1341 rc_uint_type i;
1342 for (i = 0; i < len; i++)
1343 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1344 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1345 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
252b5132 1346 }
4a594fce
NC
1347 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1348 }
1349 return off;
252b5132
RH
1350}
1351
1352/* Convert a null terminated unicode string to binary. This always
1353 returns exactly one bindata structure. */
1354
4a594fce
NC
1355static rc_uint_type
1356unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
252b5132 1357{
4a594fce 1358 rc_uint_type len = 0;
252b5132 1359
252b5132 1360 if (str != NULL)
4a594fce 1361 len = unichar_len (str);
252b5132 1362
4a594fce 1363 if (wrbfd)
252b5132 1364 {
4a594fce
NC
1365 bfd_byte *d;
1366 rc_uint_type i;
1367 d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1368 for (i = 0; i < len; i++)
1369 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1370 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1371 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
252b5132 1372 }
4a594fce 1373 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
252b5132 1374
4a594fce 1375 return off;
252b5132
RH
1376}
1377
1378/* Convert an accelerator resource to binary. */
1379
4a594fce
NC
1380static rc_uint_type
1381res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1382 const rc_accelerator *accelerators)
252b5132 1383{
4a594fce 1384 const rc_accelerator *a;
252b5132 1385
252b5132
RH
1386 for (a = accelerators; a != NULL; a = a->next)
1387 {
4a594fce
NC
1388 if (wrbfd)
1389 {
1390 struct bin_accelerator ba;
252b5132 1391
4a594fce
NC
1392 windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1393 windres_put_16 (wrbfd, ba.key, a->key);
1394 windres_put_16 (wrbfd, ba.id, a->id);
1395 windres_put_16 (wrbfd, ba.pad, 0);
1396 set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1397 }
1398 off += BIN_ACCELERATOR_SIZE;
1399 }
1400 return off;
252b5132
RH
1401}
1402
1403/* Convert a cursor resource to binary. */
1404
4a594fce
NC
1405static rc_uint_type
1406res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
252b5132 1407{
4a594fce
NC
1408 if (wrbfd)
1409 {
1410 struct bin_cursor bc;
252b5132 1411
4a594fce
NC
1412 windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1413 windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1414 set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1415 if (c->length)
1416 set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1417 }
1418 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1419 return off;
252b5132
RH
1420}
1421
1422/* Convert a group cursor resource to binary. */
1423
4a594fce
NC
1424static rc_uint_type
1425res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1426 const rc_group_cursor *group_cursors)
252b5132 1427{
4a594fce
NC
1428 int c = 0;
1429 const rc_group_cursor *gc;
1430 struct bin_group_cursor bgc;
1431 struct bin_group_cursor_item bgci;
1432 rc_uint_type start = off;
252b5132 1433
4a594fce 1434 off += BIN_GROUP_CURSOR_SIZE;
252b5132 1435
4a594fce 1436 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
252b5132 1437 {
4a594fce
NC
1438 if (wrbfd)
1439 {
1440 windres_put_16 (wrbfd, bgci.width, gc->width);
1441 windres_put_16 (wrbfd, bgci.height, gc->height);
1442 windres_put_16 (wrbfd, bgci.planes, gc->planes);
1443 windres_put_16 (wrbfd, bgci.bits, gc->bits);
1444 windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1445 windres_put_16 (wrbfd, bgci.index, gc->index);
1446 set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
252b5132
RH
1447 }
1448
4a594fce
NC
1449 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1450 }
1451 if (wrbfd)
1452 {
1453 windres_put_16 (wrbfd, bgc.sig1, 0);
1454 windres_put_16 (wrbfd, bgc.sig2, 2);
1455 windres_put_16 (wrbfd, bgc.nitems, c);
1456 set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1457 }
1458 return off;
252b5132
RH
1459}
1460
1461/* Convert a dialog resource to binary. */
1462
4a594fce
NC
1463static rc_uint_type
1464res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
252b5132 1465{
4a594fce
NC
1466 rc_uint_type off_delta;
1467 rc_uint_type start, marker;
252b5132 1468 int dialogex;
4a594fce
NC
1469 int c;
1470 rc_dialog_control *dc;
1471 struct bin_dialogex bdx;
1472 struct bin_dialog bd;
252b5132 1473
4a594fce
NC
1474 off_delta = off;
1475 start = off;
252b5132
RH
1476 dialogex = extended_dialog (dialog);
1477
4a594fce
NC
1478 if (wrbfd)
1479 {
252b5132
RH
1480 if (! dialogex)
1481 {
4a594fce
NC
1482 windres_put_32 (wrbfd, bd.style, dialog->style);
1483 windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1484 windres_put_16 (wrbfd, bd.x, dialog->x);
1485 windres_put_16 (wrbfd, bd.y, dialog->y);
1486 windres_put_16 (wrbfd, bd.width, dialog->width);
1487 windres_put_16 (wrbfd, bd.height, dialog->height);
252b5132
RH
1488 }
1489 else
1490 {
4a594fce
NC
1491 windres_put_16 (wrbfd, bdx.sig1, 1);
1492 windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1493 windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1494 windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1495 windres_put_32 (wrbfd, bdx.style, dialog->style);
1496 windres_put_16 (wrbfd, bdx.x, dialog->x);
1497 windres_put_16 (wrbfd, bdx.y, dialog->y);
1498 windres_put_16 (wrbfd, bdx.width, dialog->width);
1499 windres_put_16 (wrbfd, bdx.height, dialog->height);
1500 }
252b5132
RH
1501 }
1502
4a594fce 1503 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
252b5132 1504
4a594fce
NC
1505 off = resid_to_bin (wrbfd, off, dialog->menu);
1506 off = resid_to_bin (wrbfd, off, dialog->class);
1507 off = unicode_to_bin (wrbfd, off, dialog->caption);
252b5132
RH
1508
1509 if ((dialog->style & DS_SETFONT) != 0)
1510 {
4a594fce 1511 if (wrbfd)
252b5132 1512 {
4a594fce 1513 if (! dialogex)
252b5132 1514 {
4a594fce
NC
1515 struct bin_dialogfont bdf;
1516 windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1517 set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
252b5132
RH
1518 }
1519 else
1520 {
4a594fce
NC
1521 struct bin_dialogexfont bdxf;
1522 windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1523 windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1524 windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1525 windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1526 set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
252b5132
RH
1527 }
1528 }
4a594fce
NC
1529 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1530 off = unicode_to_bin (wrbfd, off, dialog->font);
252b5132 1531 }
4a594fce 1532 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
252b5132 1533 {
4a594fce 1534 bfd_byte dc_rclen[2];
252b5132 1535
4a594fce
NC
1536 off += (4 - ((off - off_delta) & 3)) & 3;
1537 if (wrbfd)
1538 {
252b5132
RH
1539 if (! dialogex)
1540 {
4a594fce
NC
1541 struct bin_dialog_control bdc;
1542
1543 windres_put_32 (wrbfd, bdc.style, dc->style);
1544 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1545 windres_put_16 (wrbfd, bdc.x, dc->x);
1546 windres_put_16 (wrbfd, bdc.y, dc->y);
1547 windres_put_16 (wrbfd, bdc.width, dc->width);
1548 windres_put_16 (wrbfd, bdc.height, dc->height);
1549 windres_put_16 (wrbfd, bdc.id, dc->id);
1550 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
252b5132
RH
1551 }
1552 else
1553 {
4a594fce
NC
1554 struct bin_dialogex_control bdc;
1555
1556 windres_put_32 (wrbfd, bdc.help, dc->help);
1557 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1558 windres_put_32 (wrbfd, bdc.style, dc->style);
1559 windres_put_16 (wrbfd, bdc.x, dc->x);
1560 windres_put_16 (wrbfd, bdc.y, dc->y);
1561 windres_put_16 (wrbfd, bdc.width, dc->width);
1562 windres_put_16 (wrbfd, bdc.height, dc->height);
1563 windres_put_32 (wrbfd, bdc.id, dc->id);
1564 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1565 }
3aade688 1566 }
4a594fce 1567 off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
252b5132 1568
4a594fce
NC
1569 off = resid_to_bin (wrbfd, off, dc->class);
1570 off = resid_to_bin (wrbfd, off, dc->text);
252b5132 1571
4a594fce
NC
1572 marker = off; /* Save two bytes for size of optional data. */
1573 off += 2;
252b5132
RH
1574
1575 if (dc->data == NULL)
4a594fce
NC
1576 {
1577 if (wrbfd)
1578 windres_put_16 (wrbfd, dc_rclen, 0);
1579 }
252b5132
RH
1580 else
1581 {
4a594fce
NC
1582 rc_uint_type saved_off = off;
1583 rc_uint_type old_off;
4a594fce
NC
1584
1585 old_off = off;
1586 off = res_to_bin_rcdata (wrbfd, off, dc->data);
1587 if ((off - old_off) == 0)
1588 old_off = off = saved_off;
1589 if (wrbfd)
1590 windres_put_16 (wrbfd, dc_rclen, off - old_off);
6bb21700 1591 }
4a594fce
NC
1592 if (wrbfd)
1593 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
6bb21700 1594 }
4a594fce
NC
1595
1596 if (wrbfd)
1597 {
1598 windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1599 if (! dialogex)
1600 set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1601 else
1602 set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
252b5132 1603 }
252b5132 1604
4a594fce 1605 return off;
252b5132
RH
1606}
1607
1608/* Convert a fontdir resource to binary. */
4a594fce
NC
1609static rc_uint_type
1610res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
252b5132 1611{
4a594fce 1612 rc_uint_type start;
252b5132 1613 int c;
4a594fce 1614 const rc_fontdir *fd;
252b5132 1615
4a594fce
NC
1616 start = off;
1617 off += 2;
252b5132 1618
4a594fce 1619 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
252b5132 1620 {
4a594fce
NC
1621 if (wrbfd)
1622 {
1623 bfd_byte d[2];
1624 windres_put_16 (wrbfd, d, fd->index);
1625 set_windres_bfd_content (wrbfd, d, off, 2);
1626 if (fd->length)
1627 set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1628 }
1629 off += (rc_uint_type) fd->length + 2;
252b5132
RH
1630 }
1631
4a594fce
NC
1632 if (wrbfd)
1633 {
1634 bfd_byte d[2];
1635 windres_put_16 (wrbfd, d, c);
1636 set_windres_bfd_content (wrbfd, d, start, 2);
1637 }
1638 return off;
252b5132
RH
1639}
1640
1641/* Convert a group icon resource to binary. */
1642
4a594fce
NC
1643static rc_uint_type
1644res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
252b5132 1645{
4a594fce
NC
1646 rc_uint_type start;
1647 struct bin_group_icon bgi;
252b5132 1648 int c;
4a594fce 1649 const rc_group_icon *gi;
252b5132 1650
4a594fce
NC
1651 start = off;
1652 off += BIN_GROUP_ICON_SIZE;
252b5132 1653
4a594fce 1654 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
252b5132 1655 {
4a594fce 1656 struct bin_group_icon_item bgii;
252b5132 1657
4a594fce
NC
1658 if (wrbfd)
1659 {
1660 windres_put_8 (wrbfd, bgii.width, gi->width);
1661 windres_put_8 (wrbfd, bgii.height, gi->height);
1662 windres_put_8 (wrbfd, bgii.colors, gi->colors);
1663 windres_put_8 (wrbfd, bgii.pad, 0);
1664 windres_put_16 (wrbfd, bgii.planes, gi->planes);
1665 windres_put_16 (wrbfd, bgii.bits, gi->bits);
1666 windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1667 windres_put_16 (wrbfd, bgii.index, gi->index);
1668 set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1669 }
1670 off += BIN_GROUP_ICON_ITEM_SIZE;
252b5132
RH
1671 }
1672
4a594fce
NC
1673 if (wrbfd)
1674 {
1675 windres_put_16 (wrbfd, bgi.sig1, 0);
1676 windres_put_16 (wrbfd, bgi.sig2, 1);
1677 windres_put_16 (wrbfd, bgi.count, c);
1678 set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1679 }
1680 return off;
252b5132
RH
1681}
1682
1683/* Convert a menu resource to binary. */
1684
4a594fce
NC
1685static rc_uint_type
1686res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
252b5132
RH
1687{
1688 int menuex;
252b5132
RH
1689
1690 menuex = extended_menu (menu);
1691
4a594fce
NC
1692 if (wrbfd)
1693 {
252b5132
RH
1694 if (! menuex)
1695 {
4a594fce
NC
1696 struct bin_menu bm;
1697 windres_put_16 (wrbfd, bm.sig1, 0);
1698 windres_put_16 (wrbfd, bm.sig2, 0);
1699 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
252b5132
RH
1700 }
1701 else
1702 {
4a594fce
NC
1703 struct bin_menuex bm;
1704 windres_put_16 (wrbfd, bm.sig1, 1);
1705 windres_put_16 (wrbfd, bm.sig2, 4);
1706 windres_put_32 (wrbfd, bm.help, menu->help);
1707 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
252b5132 1708 }
4a594fce
NC
1709 }
1710 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1711 if (! menuex)
1712 {
1713 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1714 }
1715 else
1716 {
1717 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1718 }
1719 return off;
252b5132
RH
1720}
1721
1722/* Convert menu items to binary. */
1723
4a594fce
NC
1724static rc_uint_type
1725res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
252b5132 1726{
4a594fce 1727 const rc_menuitem *mi;
252b5132
RH
1728
1729 for (mi = items; mi != NULL; mi = mi->next)
1730 {
4a594fce 1731 struct bin_menuitem bmi;
252b5132
RH
1732 int flags;
1733
252b5132
RH
1734 flags = mi->type;
1735 if (mi->next == NULL)
1736 flags |= MENUITEM_ENDMENU;
1737 if (mi->popup != NULL)
1738 flags |= MENUITEM_POPUP;
1739
4a594fce
NC
1740 if (wrbfd)
1741 {
1742 windres_put_16 (wrbfd, bmi.flags, flags);
252b5132 1743 if (mi->popup == NULL)
4a594fce
NC
1744 windres_put_16 (wrbfd, bmi.id, mi->id);
1745 set_windres_bfd_content (wrbfd, &bmi, off,
1746 mi->popup == NULL ? BIN_MENUITEM_SIZE
1747 : BIN_MENUITEM_POPUP_SIZE);
1748 }
1749 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
252b5132 1750
4a594fce 1751 off = unicode_to_bin (wrbfd, off, mi->text);
252b5132
RH
1752
1753 if (mi->popup != NULL)
1754 {
4a594fce 1755 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
252b5132
RH
1756 }
1757 }
4a594fce 1758 return off;
252b5132
RH
1759}
1760
1761/* Convert menuex items to binary. */
1762
4a594fce
NC
1763static rc_uint_type
1764res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
252b5132 1765{
4a594fce
NC
1766 rc_uint_type off_delta = off;
1767 const rc_menuitem *mi;
252b5132
RH
1768
1769 for (mi = items; mi != NULL; mi = mi->next)
1770 {
4a594fce 1771 struct bin_menuitemex bmi;
252b5132
RH
1772 int flags;
1773
4a594fce 1774 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132
RH
1775
1776 flags = 0;
1777 if (mi->next == NULL)
1778 flags |= 0x80;
1779 if (mi->popup != NULL)
1780 flags |= 1;
252b5132 1781
4a594fce
NC
1782 if (wrbfd)
1783 {
1784 windres_put_32 (wrbfd, bmi.type, mi->type);
1785 windres_put_32 (wrbfd, bmi.state, mi->state);
1786 windres_put_32 (wrbfd, bmi.id, mi->id);
1787 windres_put_16 (wrbfd, bmi.flags, flags);
1788 set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1789 }
1790 off += BIN_MENUITEMEX_SIZE;
252b5132 1791
4a594fce 1792 off = unicode_to_bin (wrbfd, off, mi->text);
252b5132
RH
1793
1794 if (mi->popup != NULL)
1795 {
4a594fce 1796 bfd_byte help[4];
252b5132 1797
4a594fce 1798 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 1799
4a594fce 1800 if (wrbfd)
252b5132 1801 {
4a594fce
NC
1802 windres_put_32 (wrbfd, help, mi->help);
1803 set_windres_bfd_content (wrbfd, help, off, 4);
252b5132 1804 }
4a594fce
NC
1805 off += 4;
1806 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
252b5132
RH
1807 }
1808 }
4a594fce 1809 return off;
252b5132
RH
1810}
1811
1812/* Convert an rcdata resource to binary. This is also used to convert
4a594fce 1813 other information which happens to be stored in rc_rcdata_item lists
252b5132
RH
1814 to binary. */
1815
4a594fce
NC
1816static rc_uint_type
1817res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
252b5132 1818{
4a594fce 1819 const rc_rcdata_item *ri;
252b5132
RH
1820
1821 for (ri = items; ri != NULL; ri = ri->next)
1822 {
4a594fce 1823 rc_uint_type len;
252b5132
RH
1824 switch (ri->type)
1825 {
1826 default:
1827 abort ();
252b5132 1828 case RCDATA_WORD:
4a594fce 1829 len = 2;
252b5132 1830 break;
252b5132 1831 case RCDATA_DWORD:
4a594fce 1832 len = 4;
252b5132 1833 break;
252b5132 1834 case RCDATA_STRING:
4a594fce
NC
1835 len = ri->u.string.length;
1836 break;
1837 case RCDATA_WSTRING:
1838 len = ri->u.wstring.length * sizeof (unichar);
1839 break;
1840 case RCDATA_BUFFER:
1841 len = ri->u.buffer.length;
1842 break;
1843 }
1844 if (wrbfd)
1845 {
1846 bfd_byte h[4];
1847 bfd_byte *hp = &h[0];
1848 switch (ri->type)
1849 {
1850 case RCDATA_WORD:
1851 windres_put_16 (wrbfd, hp, ri->u.word);
1852 break;
1853 case RCDATA_DWORD:
1854 windres_put_32 (wrbfd, hp, ri->u.dword);
1855 break;
1856 case RCDATA_STRING:
1857 hp = (bfd_byte *) ri->u.string.s;
252b5132 1858 break;
252b5132
RH
1859 case RCDATA_WSTRING:
1860 {
4a594fce 1861 rc_uint_type i;
252b5132 1862
4a594fce 1863 hp = (bfd_byte *) reswr_alloc (len);
252b5132 1864 for (i = 0; i < ri->u.wstring.length; i++)
4a594fce 1865 windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
252b5132 1866 }
4a594fce 1867 break;
252b5132 1868 case RCDATA_BUFFER:
4a594fce 1869 hp = (bfd_byte *) ri->u.buffer.data;
252b5132
RH
1870 break;
1871 }
4a594fce 1872 set_windres_bfd_content (wrbfd, hp, off, len);
252b5132 1873 }
4a594fce
NC
1874 off += len;
1875 }
1876 return off;
252b5132
RH
1877}
1878
1879/* Convert a stringtable resource to binary. */
1880
4a594fce
NC
1881static rc_uint_type
1882res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1883 const rc_stringtable *st)
252b5132 1884{
252b5132
RH
1885 int i;
1886
252b5132
RH
1887 for (i = 0; i < 16; i++)
1888 {
4a594fce 1889 rc_uint_type slen, length;
252b5132
RH
1890 unichar *s;
1891
4a594fce 1892 slen = (rc_uint_type) st->strings[i].length;
8b6efd89 1893 if (slen == 0xffffffff) slen = 0;
252b5132
RH
1894 s = st->strings[i].string;
1895
4a594fce
NC
1896 length = 2 + slen * 2;
1897 if (wrbfd)
1898 {
1899 bfd_byte *hp;
1900 rc_uint_type j;
252b5132 1901
4a594fce
NC
1902 hp = (bfd_byte *) reswr_alloc (length);
1903 windres_put_16 (wrbfd, hp, slen);
252b5132
RH
1904
1905 for (j = 0; j < slen; j++)
4a594fce
NC
1906 windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1907 set_windres_bfd_content (wrbfd, hp, off, length);
252b5132 1908 }
4a594fce
NC
1909 off += length;
1910 }
1911 return off;
252b5132
RH
1912}
1913
1914/* Convert an ASCII string to a unicode binary string. This always
1915 returns exactly one bindata structure. */
1916
4a594fce
NC
1917static rc_uint_type
1918string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
252b5132 1919{
4a594fce 1920 rc_uint_type len;
252b5132 1921
4a594fce 1922 len = (rc_uint_type) strlen (s);
252b5132 1923
4a594fce
NC
1924 if (wrbfd)
1925 {
1926 rc_uint_type i;
1927 bfd_byte *hp;
252b5132 1928
4a594fce 1929 hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
252b5132 1930
4a594fce
NC
1931 for (i = 0; i < len; i++)
1932 windres_put_16 (wrbfd, hp + i * 2, s[i]);
1933 windres_put_16 (wrbfd, hp + i * 2, 0);
1934 set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1935 }
1936 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1937 return off;
252b5132
RH
1938}
1939
4a594fce
NC
1940static rc_uint_type
1941res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
252b5132 1942{
4a594fce
NC
1943 if (wrbfd)
1944 {
1945 struct bin_toolbar bt;
1946 windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1947 windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1948 windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1949 set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1950 if (tb->nitems > 0)
1951 {
1952 rc_toolbar_item *it;
1953 bfd_byte *ids;
1954 rc_uint_type i = 0;
252b5132 1955
4a594fce
NC
1956 ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1957 it=tb->items;
1958 while(it != NULL)
1959 {
1960 windres_put_32 (wrbfd, ids + i, it->id.u.id);
1961 i += 4;
1962 it = it->next;
1963 }
1964 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1965 }
1966 }
1967 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
252b5132 1968
4a594fce
NC
1969 return off;
1970}
252b5132 1971
4a594fce 1972/* Convert a versioninfo resource to binary. */
252b5132 1973
4a594fce
NC
1974static rc_uint_type
1975res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1976 const rc_versioninfo *versioninfo)
1977{
1978 rc_uint_type off_delta = off;
1979 rc_uint_type start;
1980 struct bin_versioninfo bvi;
1981 rc_ver_info *vi;
252b5132 1982
4a594fce
NC
1983 start = off;
1984 off += BIN_VERSIONINFO_SIZE;
1985 off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1986 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132
RH
1987
1988 if (versioninfo->fixed != NULL)
1989 {
4a594fce
NC
1990 if (wrbfd)
1991 {
1992 struct bin_fixed_versioninfo bfv;
1993 const rc_fixed_versioninfo *fi;
252b5132
RH
1994
1995 fi = versioninfo->fixed;
4a594fce
NC
1996 windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1997 windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1998 windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1999 windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
2000 windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2001 windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2002 windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2003 windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2004 windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2005 windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2006 windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2007 windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2008 windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2009 set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2010 }
2011 off += BIN_FIXED_VERSIONINFO_SIZE;
252b5132
RH
2012 }
2013
2014 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2015 {
4a594fce
NC
2016 struct bin_ver_info bv;
2017 rc_uint_type bv_off;
252b5132 2018
4a594fce 2019 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2020
4a594fce 2021 bv_off = off;
252b5132 2022
4a594fce 2023 off += BIN_VER_INFO_SIZE;
252b5132
RH
2024
2025 switch (vi->type)
2026 {
2027 default:
2028 abort ();
252b5132
RH
2029 case VERINFO_STRING:
2030 {
bfb6c1ab 2031 const rc_ver_stringtable *vst;
252b5132 2032
4a594fce 2033 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
252b5132 2034
bfb6c1ab
NC
2035 if (!vi->u.string.stringtables)
2036 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2037
bfb6c1ab 2038 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
4a594fce 2039 {
bfb6c1ab
NC
2040 struct bin_ver_info bvst;
2041 rc_uint_type vst_off;
2042 const rc_ver_stringinfo *vs;
252b5132 2043
4a594fce 2044 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2045
bfb6c1ab 2046 vst_off = off;
4a594fce 2047 off += BIN_VER_INFO_SIZE;
252b5132 2048
bfb6c1ab 2049 off = unicode_to_bin (wrbfd, off, vst->language);
252b5132 2050
bfb6c1ab
NC
2051 for (vs = vst->strings; vs != NULL; vs = vs->next)
2052 {
2053 struct bin_ver_info bvs;
2054 rc_uint_type vs_off, str_off;
2055
2056 off += (4 - ((off - off_delta) & 3)) & 3;
2057
2058 vs_off = off;
2059 off += BIN_VER_INFO_SIZE;
2060
2061 off = unicode_to_bin (wrbfd, off, vs->key);
2062
2063 off += (4 - ((off - off_delta) & 3)) & 3;
2064
2065 str_off = off;
2066 off = unicode_to_bin (wrbfd, off, vs->value);
2067
2068 if (wrbfd)
2069 {
2070 windres_put_16 (wrbfd, bvs.size, off - vs_off);
2071 windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2072 windres_put_16 (wrbfd, bvs.sig2, 1);
2073 set_windres_bfd_content (wrbfd, &bvs, vs_off,
2074 BIN_VER_INFO_SIZE);
2075 }
2076 }
252b5132 2077
4a594fce
NC
2078 if (wrbfd)
2079 {
bfb6c1ab
NC
2080 windres_put_16 (wrbfd, bvst.size, off - vst_off);
2081 windres_put_16 (wrbfd, bvst.sig1, 0);
2082 windres_put_16 (wrbfd, bvst.sig2, 1);
2083 set_windres_bfd_content (wrbfd, &bvst, vst_off,
2084 BIN_VER_INFO_SIZE);
4a594fce
NC
2085 }
2086 }
252b5132
RH
2087 break;
2088 }
2089
2090 case VERINFO_VAR:
2091 {
4a594fce
NC
2092 rc_uint_type vvd_off, vvvd_off;
2093 struct bin_ver_info bvvd;
2094 const rc_ver_varinfo *vv;
252b5132 2095
4a594fce 2096 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
252b5132 2097
4a594fce 2098 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2099
4a594fce
NC
2100 vvd_off = off;
2101 off += BIN_VER_INFO_SIZE;
252b5132 2102
4a594fce 2103 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
252b5132 2104
4a594fce 2105 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2106
4a594fce 2107 vvvd_off = off;
252b5132
RH
2108
2109 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2110 {
4a594fce
NC
2111 if (wrbfd)
2112 {
2113 bfd_byte vvsd[4];
2114
2115 windres_put_16 (wrbfd, &vvsd[0], vv->language);
2116 windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2117 set_windres_bfd_content (wrbfd, vvsd, off, 4);
2118 }
2119 off += 4;
252b5132 2120 }
4a594fce
NC
2121 if (wrbfd)
2122 {
2123 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2124 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2125 windres_put_16 (wrbfd, bvvd.sig2, 0);
2126 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2127 BIN_VER_INFO_SIZE);
2128 }
252b5132
RH
2129
2130 break;
2131 }
2132 }
2133
4a594fce
NC
2134 if (wrbfd)
2135 {
bfb6c1ab 2136 windres_put_16 (wrbfd, bv.size, off - bv_off);
4a594fce 2137 windres_put_16 (wrbfd, bv.sig1, 0);
bfb6c1ab 2138 windres_put_16 (wrbfd, bv.sig2, 1);
4a594fce
NC
2139 set_windres_bfd_content (wrbfd, &bv, bv_off,
2140 BIN_VER_INFO_SIZE);
2141 }
252b5132
RH
2142 }
2143
4a594fce
NC
2144 if (wrbfd)
2145 {
2146 windres_put_16 (wrbfd, bvi.size, off - start);
2147 windres_put_16 (wrbfd, bvi.fixed_size,
2148 versioninfo->fixed == NULL ? 0
2149 : BIN_FIXED_VERSIONINFO_SIZE);
2150 windres_put_16 (wrbfd, bvi.sig2, 0);
2151 set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2152 }
2153 return off;
252b5132
RH
2154}
2155
2156/* Convert a generic resource to binary. */
2157
4a594fce
NC
2158static rc_uint_type
2159res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2160 const bfd_byte *data)
252b5132 2161{
4a594fce
NC
2162 if (wrbfd && length != 0)
2163 set_windres_bfd_content (wrbfd, data, off, length);
2164 return off + (rc_uint_type) length;
252b5132 2165}