]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/resbin.c
[GOLD] Don't assert in powerpc stub_table
[thirdparty/binutils-gdb.git] / binutils / resbin.c
CommitLineData
252b5132 1/* resbin.c -- manipulate the Windows binary resource format.
6f2750fe 2 Copyright (C) 1997-2016 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);
57static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
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:
108 return bin_to_res_toolbar (wrbfd, data, length);
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 {
577 off = (off + 3) &~ 3;
578
579 if (length < off + datalen)
580 toosmall (_("dialog control data"));
581
4a594fce
NC
582 dc->data = ((rc_rcdata_item *)
583 res_alloc (sizeof (rc_rcdata_item)));
252b5132
RH
584 dc->data->next = NULL;
585 dc->data->type = RCDATA_BUFFER;
586 dc->data->u.buffer.length = datalen;
587 dc->data->u.buffer.data = data + off;
588
53c7db4b 589 off += datalen;
252b5132
RH
590 }
591
592 dc->next = NULL;
593 *pp = dc;
594 pp = &dc->next;
595 }
596
4a594fce 597 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
598 r->type = RES_TYPE_DIALOG;
599 r->u.dialog = d;
600
601 return r;
602}
603
604/* Convert a stringtable resource from binary. */
605
4a594fce
NC
606static rc_res_resource *
607bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 608{
4a594fce 609 rc_stringtable *st;
252b5132 610 int i;
4a594fce 611 rc_res_resource *r;
252b5132 612
4a594fce 613 st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
252b5132
RH
614
615 for (i = 0; i < 16; i++)
616 {
617 unsigned int slen;
618
619 if (length < 2)
620 toosmall (_("stringtable string length"));
4a594fce 621 slen = windres_get_16 (wrbfd, data, 2);
252b5132
RH
622 st->strings[i].length = slen;
623
624 if (slen > 0)
625 {
626 unichar *s;
627 unsigned int j;
628
629 if (length < 2 + 2 * slen)
630 toosmall (_("stringtable string"));
631
632 s = (unichar *) res_alloc (slen * sizeof (unichar));
633 st->strings[i].string = s;
634
635 for (j = 0; j < slen; j++)
4a594fce 636 s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
252b5132
RH
637 }
638
639 data += 2 + 2 * slen;
640 length -= 2 + 2 * slen;
641 }
642
4a594fce 643 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
644 r->type = RES_TYPE_STRINGTABLE;
645 r->u.stringtable = st;
646
647 return r;
648}
649
650/* Convert a fontdir resource from binary. */
651
4a594fce
NC
652static rc_res_resource *
653bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 654{
4a594fce
NC
655 rc_uint_type c, i;
656 rc_fontdir *first, **pp;
657 rc_res_resource *r;
252b5132
RH
658
659 if (length < 2)
660 toosmall (_("fontdir header"));
661
4a594fce 662 c = windres_get_16 (wrbfd, data, 2);
252b5132
RH
663
664 first = NULL;
665 pp = &first;
666
667 for (i = 0; i < c; i++)
668 {
4a594fce
NC
669 const struct bin_fontdir_item *bfi;
670 rc_fontdir *fd;
252b5132
RH
671 unsigned int off;
672
673 if (length < 56)
674 toosmall (_("fontdir"));
675
4a594fce
NC
676 bfi = (const struct bin_fontdir_item *) data;
677 fd = (rc_fontdir *) res_alloc (sizeof *fd);
678 fd->index = windres_get_16 (wrbfd, bfi->index, 2);
252b5132
RH
679
680 /* To work out the length of the fontdir data, we must get the
681 length of the device name and face name strings, even though
4a594fce 682 we don't store them in the rc_fontdir. The
252b5132
RH
683 documentation says that these are NULL terminated char
684 strings, not Unicode strings. */
685
686 off = 56;
687
688 while (off < length && data[off] != '\0')
689 ++off;
690 if (off >= length)
691 toosmall (_("fontdir device name"));
692 ++off;
693
694 while (off < length && data[off] != '\0')
695 ++off;
696 if (off >= length)
697 toosmall (_("fontdir face name"));
698 ++off;
699
700 fd->length = off;
701 fd->data = data;
702
703 fd->next = NULL;
704 *pp = fd;
705 pp = &fd->next;
706
707 /* The documentation does not indicate that any rounding is
708 required. */
709
710 data += off;
711 length -= off;
712 }
713
4a594fce 714 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
715 r->type = RES_TYPE_FONTDIR;
716 r->u.fontdir = first;
717
718 return r;
719}
720
721/* Convert an accelerators resource from binary. */
722
4a594fce
NC
723static rc_res_resource *
724bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 725{
4a594fce
NC
726 rc_accelerator *first, **pp;
727 rc_res_resource *r;
252b5132
RH
728
729 first = NULL;
730 pp = &first;
731
732 while (1)
733 {
4a594fce 734 rc_accelerator *a;
252b5132
RH
735
736 if (length < 8)
737 toosmall (_("accelerator"));
738
4a594fce 739 a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
252b5132 740
4a594fce
NC
741 a->flags = windres_get_16 (wrbfd, data, 2);
742 a->key = windres_get_16 (wrbfd, data + 2, 2);
743 a->id = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
744
745 a->next = NULL;
746 *pp = a;
747 pp = &a->next;
748
749 if ((a->flags & ACC_LAST) != 0)
750 break;
751
752 data += 8;
753 length -= 8;
754 }
755
4a594fce 756 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
252b5132
RH
757 r->type = RES_TYPE_ACCELERATOR;
758 r->u.acc = first;
759
760 return r;
761}
762
763/* Convert an rcdata resource from binary. */
764
4a594fce
NC
765static rc_res_resource *
766bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
767 rc_uint_type length, int rctyp)
252b5132 768{
4a594fce
NC
769 rc_rcdata_item *ri;
770 rc_res_resource *r;
252b5132 771
4a594fce 772 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
773
774 ri->next = NULL;
775 ri->type = RCDATA_BUFFER;
776 ri->u.buffer.length = length;
777 ri->u.buffer.data = data;
778
4a594fce
NC
779 r = (rc_res_resource *) res_alloc (sizeof *r);
780 r->type = rctyp;
252b5132
RH
781 r->u.rcdata = ri;
782
783 return r;
784}
785
786/* Convert a group cursor resource from binary. */
787
4a594fce
NC
788static rc_res_resource *
789bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132
RH
790{
791 int type, c, i;
4a594fce
NC
792 rc_group_cursor *first, **pp;
793 rc_res_resource *r;
252b5132
RH
794
795 if (length < 6)
796 toosmall (_("group cursor header"));
797
4a594fce 798 type = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
799 if (type != 2)
800 fatal (_("unexpected group cursor type %d"), type);
801
4a594fce 802 c = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
803
804 data += 6;
805 length -= 6;
806
807 first = NULL;
808 pp = &first;
809
810 for (i = 0; i < c; i++)
811 {
4a594fce 812 rc_group_cursor *gc;
252b5132
RH
813
814 if (length < 14)
815 toosmall (_("group cursor"));
816
4a594fce 817 gc = (rc_group_cursor *) res_alloc (sizeof *gc);
252b5132 818
4a594fce
NC
819 gc->width = windres_get_16 (wrbfd, data, 2);
820 gc->height = windres_get_16 (wrbfd, data + 2, 2);
821 gc->planes = windres_get_16 (wrbfd, data + 4, 2);
822 gc->bits = windres_get_16 (wrbfd, data + 6, 2);
823 gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
824 gc->index = windres_get_16 (wrbfd, data + 12, 2);
252b5132
RH
825
826 gc->next = NULL;
827 *pp = gc;
828 pp = &gc->next;
829
830 data += 14;
831 length -= 14;
832 }
833
4a594fce 834 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
252b5132
RH
835 r->type = RES_TYPE_GROUP_CURSOR;
836 r->u.group_cursor = first;
837
838 return r;
839}
840
841/* Convert a group icon resource from binary. */
842
4a594fce
NC
843static rc_res_resource *
844bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132
RH
845{
846 int type, c, i;
4a594fce
NC
847 rc_group_icon *first, **pp;
848 rc_res_resource *r;
252b5132
RH
849
850 if (length < 6)
851 toosmall (_("group icon header"));
852
4a594fce 853 type = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
854 if (type != 1)
855 fatal (_("unexpected group icon type %d"), type);
856
4a594fce 857 c = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
858
859 data += 6;
860 length -= 6;
861
862 first = NULL;
863 pp = &first;
864
865 for (i = 0; i < c; i++)
866 {
4a594fce 867 rc_group_icon *gi;
252b5132
RH
868
869 if (length < 14)
870 toosmall (_("group icon"));
871
4a594fce 872 gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
252b5132 873
4a594fce
NC
874 gi->width = windres_get_8 (wrbfd, data, 1);
875 gi->height = windres_get_8 (wrbfd, data + 1, 1);
876 gi->colors = windres_get_8 (wrbfd, data + 2, 1);
877 gi->planes = windres_get_16 (wrbfd, data + 4, 2);
878 gi->bits = windres_get_16 (wrbfd, data + 6, 2);
879 gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
880 gi->index = windres_get_16 (wrbfd, data + 12, 2);
252b5132
RH
881
882 gi->next = NULL;
883 *pp = gi;
884 pp = &gi->next;
885
886 data += 14;
887 length -= 14;
888 }
889
4a594fce 890 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
891 r->type = RES_TYPE_GROUP_ICON;
892 r->u.group_icon = first;
893
894 return r;
895}
896
897/* Extract data from a version header. If KEY is not NULL, then the
898 key must be KEY; otherwise, the key is returned in *PKEY. This
899 sets *LEN to the total length, *VALLEN to the value length, *TYPE
900 to the type, and *OFF to the offset to the children. */
901
902static void
4a594fce
NC
903get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
904 const char *key, unichar **pkey,
905 rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
906 rc_uint_type *off)
252b5132
RH
907{
908 if (length < 8)
909 toosmall (key);
910
fb98f7b7 911 *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
4a594fce
NC
912 *vallen = windres_get_16 (wrbfd, data + 2, 2);
913 *type = windres_get_16 (wrbfd, data + 4, 2);
252b5132
RH
914
915 *off = 6;
916
917 length -= 6;
918 data += 6;
919
920 if (key == NULL)
921 {
4a594fce 922 rc_uint_type sublen;
252b5132 923
4a594fce
NC
924 *pkey = get_unicode (wrbfd, data, length, &sublen);
925 *off += (sublen + 1) * sizeof (unichar);
252b5132
RH
926 }
927 else
928 {
929 while (1)
930 {
931 if (length < 2)
932 toosmall (key);
4a594fce 933 if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
252b5132
RH
934 fatal (_("unexpected version string"));
935
936 *off += 2;
937 length -= 2;
938 data += 2;
939
940 if (*key == '\0')
941 break;
942
943 ++key;
944 }
945 }
946
947 *off = (*off + 3) &~ 3;
948}
949
950/* Convert a version resource from binary. */
951
4a594fce
NC
952static rc_res_resource *
953bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
252b5132 954{
4a594fce
NC
955 rc_uint_type verlen, vallen, type, off;
956 rc_fixed_versioninfo *fi;
957 rc_ver_info *first, **pp;
958 rc_versioninfo *v;
959 rc_res_resource *r;
252b5132 960
4a594fce 961 get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
7e8d45b7 962 (unichar **) NULL, &verlen, &vallen, &type, &off);
252b5132 963
4931146e
NC
964 /* PR 17512: The verlen field does not include padding length. */
965 if (verlen > length)
966 fatal (_("version length %lu greater than resource length %lu"),
2d5bddc1 967 (unsigned long) verlen, (unsigned long) length);
252b5132
RH
968
969 if (type != 0)
4a594fce 970 fatal (_("unexpected version type %d"), (int) type);
252b5132
RH
971
972 data += off;
973 length -= off;
974
975 if (vallen == 0)
976 fi = NULL;
977 else
978 {
979 unsigned long signature, fiv;
980
981 if (vallen != 52)
4a594fce 982 fatal (_("unexpected fixed version information length %ld"), (long) vallen);
252b5132
RH
983
984 if (length < 52)
985 toosmall (_("fixed version info"));
986
4a594fce 987 signature = windres_get_32 (wrbfd, data, 4);
252b5132
RH
988 if (signature != 0xfeef04bd)
989 fatal (_("unexpected fixed version signature %lu"), signature);
990
4a594fce 991 fiv = windres_get_32 (wrbfd, data + 4, 4);
252b5132
RH
992 if (fiv != 0 && fiv != 0x10000)
993 fatal (_("unexpected fixed version info version %lu"), fiv);
994
4a594fce 995 fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
252b5132 996
4a594fce
NC
997 fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
998 fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
999 fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
1000 fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1001 fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1002 fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1003 fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1004 fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1005 fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1006 fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1007 fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
252b5132
RH
1008
1009 data += 52;
1010 length -= 52;
1011 }
1012
1013 first = NULL;
1014 pp = &first;
1015
1016 while (length > 0)
1017 {
4a594fce 1018 rc_ver_info *vi;
252b5132
RH
1019 int ch;
1020
1021 if (length < 8)
1022 toosmall (_("version var info"));
1023
4a594fce 1024 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
252b5132 1025
4a594fce 1026 ch = windres_get_16 (wrbfd, data + 6, 2);
252b5132
RH
1027
1028 if (ch == 'S')
1029 {
bfb6c1ab 1030 rc_ver_stringtable **ppvst;
252b5132
RH
1031
1032 vi->type = VERINFO_STRING;
1033
4a594fce 1034 get_version_header (wrbfd, data, length, "StringFileInfo",
7e8d45b7 1035 (unichar **) NULL, &verlen, &vallen, &type,
252b5132
RH
1036 &off);
1037
1038 if (vallen != 0)
4a594fce 1039 fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
252b5132
RH
1040
1041 data += off;
1042 length -= off;
1043
fb98f7b7 1044 verlen -= off;
252b5132 1045
bfb6c1ab
NC
1046 vi->u.string.stringtables = NULL;
1047 ppvst = &vi->u.string.stringtables;
1048
252b5132 1049 while (verlen > 0)
bfb6c1ab
NC
1050 {
1051 rc_ver_stringtable *vst;
1052 rc_uint_type stverlen;
1053 rc_ver_stringinfo **ppvs;
1054
1055 if (length < 8)
1056 toosmall (_("version stringtable"));
1057
1058 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1059
1060 get_version_header (wrbfd, data, length, (const char *) NULL,
1061 &vst->language, &stverlen, &vallen, &type, &off);
1062
1063 if (vallen != 0)
1064 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1065
1066 data += off;
1067 length -= off;
1068 verlen -= off;
1069
fb98f7b7 1070 stverlen -= off;
3aade688 1071
bfb6c1ab
NC
1072 vst->strings = NULL;
1073 ppvs = &vst->strings;
1074
1075 while (stverlen > 0)
252b5132 1076 {
4a594fce 1077 rc_ver_stringinfo *vs;
bfb6c1ab
NC
1078 rc_uint_type sverlen, vslen, valoff;
1079
1080 if (length < 8)
1081 toosmall (_("version string"));
252b5132 1082
bfb6c1ab 1083 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
252b5132 1084
bfb6c1ab
NC
1085 get_version_header (wrbfd, data, length, (const char *) NULL,
1086 &vs->key, &sverlen, &vallen, &type, &off);
252b5132 1087
252b5132
RH
1088 data += off;
1089 length -= off;
1090
4a594fce 1091 vs->value = get_unicode (wrbfd, data, length, &vslen);
252b5132 1092 valoff = vslen * 2 + 2;
fb98f7b7 1093 valoff = (valoff + 3) & ~3;
252b5132 1094
bfb6c1ab 1095 if (off + valoff != sverlen)
4a594fce 1096 fatal (_("unexpected version string length %ld != %ld + %ld"),
bfb6c1ab 1097 (long) sverlen, (long) off, (long) valoff);
252b5132
RH
1098
1099 data += valoff;
1100 length -= valoff;
1101
bfb6c1ab 1102 if (stverlen < sverlen)
4a594fce 1103 fatal (_("unexpected version string length %ld < %ld"),
bfb6c1ab
NC
1104 (long) verlen, (long) sverlen);
1105 stverlen -= sverlen;
fb98f7b7 1106 verlen -= sverlen;
bfb6c1ab
NC
1107
1108 vs->next = NULL;
1109 *ppvs = vs;
1110 ppvs = &vs->next;
1111 }
252b5132 1112
bfb6c1ab
NC
1113 vst->next = NULL;
1114 *ppvst = vst;
1115 ppvst = &vst->next;
252b5132
RH
1116 }
1117 }
1118 else if (ch == 'V')
1119 {
4a594fce 1120 rc_ver_varinfo **ppvv;
252b5132
RH
1121
1122 vi->type = VERINFO_VAR;
1123
4a594fce 1124 get_version_header (wrbfd, data, length, "VarFileInfo",
7e8d45b7 1125 (unichar **) NULL, &verlen, &vallen, &type,
252b5132
RH
1126 &off);
1127
1128 if (vallen != 0)
4a594fce 1129 fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
252b5132
RH
1130
1131 data += off;
1132 length -= off;
1133
4a594fce 1134 get_version_header (wrbfd, data, length, (const char *) NULL,
252b5132
RH
1135 &vi->u.var.key, &verlen, &vallen, &type, &off);
1136
1137 data += off;
1138 length -= off;
1139
1140 vi->u.var.var = NULL;
1141 ppvv = &vi->u.var.var;
1142
1143 while (vallen > 0)
1144 {
4a594fce 1145 rc_ver_varinfo *vv;
252b5132
RH
1146
1147 if (length < 4)
1148 toosmall (_("version varfileinfo"));
1149
4a594fce 1150 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
252b5132 1151
4a594fce
NC
1152 vv->language = windres_get_16 (wrbfd, data, 2);
1153 vv->charset = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
1154
1155 vv->next = NULL;
1156 *ppvv = vv;
1157 ppvv = &vv->next;
1158
1159 data += 4;
1160 length -= 4;
1161
1162 if (vallen < 4)
4a594fce 1163 fatal (_("unexpected version value length %ld"), (long) vallen);
252b5132
RH
1164
1165 vallen -= 4;
1166 }
1167 }
4931146e
NC
1168 else if (ch == 0)
1169 {
1170 if (length == 8)
1171 /* Padding - skip. */
1172 break;
1173 fatal (_("nul bytes found in version string"));
1174 }
252b5132 1175 else
4931146e 1176 fatal (_("unexpected version string character: %x"), ch);
252b5132
RH
1177
1178 vi->next = NULL;
1179 *pp = vi;
53c7db4b 1180 pp = &vi->next;
252b5132
RH
1181 }
1182
4a594fce 1183 v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
252b5132
RH
1184 v->fixed = fi;
1185 v->var = first;
1186
4a594fce 1187 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
1188 r->type = RES_TYPE_VERSIONINFO;
1189 r->u.versioninfo = v;
1190
53c7db4b 1191 return r;
252b5132
RH
1192}
1193
1194/* Convert an arbitrary user defined resource from binary. */
1195
4a594fce
NC
1196static rc_res_resource *
1197bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1198 rc_uint_type length)
252b5132 1199{
4a594fce
NC
1200 rc_rcdata_item *ri;
1201 rc_res_resource *r;
252b5132 1202
4a594fce 1203 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
1204
1205 ri->next = NULL;
1206 ri->type = RCDATA_BUFFER;
1207 ri->u.buffer.length = length;
1208 ri->u.buffer.data = data;
1209
4a594fce 1210 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
1211 r->type = RES_TYPE_USERDATA;
1212 r->u.rcdata = ri;
1213
1214 return r;
1215}
1216\f
4a594fce
NC
1217static rc_res_resource *
1218bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1219{
1220 rc_toolbar *ri;
1221 rc_res_resource *r;
1222 rc_uint_type i;
1223
1224 ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1225 ri->button_width = windres_get_32 (wrbfd, data, 4);
1226 ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1227 ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1228 ri->items = NULL;
1229
1230 data += 12;
1231 length -= 12;
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;
1240 length -= 4;
1241 if(ri->items) {
1242 rc_toolbar_item *ii = ri->items;
1243 while (ii->next != NULL)
1244 ii = ii->next;
1245 it->prev = ii;
1246 ii->next = it;
1247 }
1248 else
1249 ri->items = it;
1250 }
1251 r = (rc_res_resource *) res_alloc (sizeof *r);
1252 r->type = RES_TYPE_TOOLBAR;
1253 r->u.toolbar = ri;
1254 return r;
1255}
252b5132 1256
252b5132
RH
1257
1258/* Local functions used to convert resources to binary format. */
1259
4a594fce
NC
1260static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1261static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1262static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1263static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1264static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1265static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1266static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1267static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1268static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1269static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1270static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1271static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1272static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1273static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1274static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1275static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1276static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1277 const bfd_byte *);
252b5132
RH
1278
1279/* Convert a resource to binary. */
1280
4a594fce
NC
1281rc_uint_type
1282res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
252b5132
RH
1283{
1284 switch (res->type)
1285 {
252b5132
RH
1286 case RES_TYPE_BITMAP:
1287 case RES_TYPE_FONT:
1288 case RES_TYPE_ICON:
1289 case RES_TYPE_MESSAGETABLE:
4a594fce 1290 return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
252b5132 1291 case RES_TYPE_ACCELERATOR:
4a594fce 1292 return res_to_bin_accelerator (wrbfd, off, res->u.acc);
252b5132 1293 case RES_TYPE_CURSOR:
4a594fce 1294 return res_to_bin_cursor (wrbfd, off, res->u.cursor);
252b5132 1295 case RES_TYPE_GROUP_CURSOR:
4a594fce 1296 return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
252b5132 1297 case RES_TYPE_DIALOG:
4a594fce 1298 return res_to_bin_dialog (wrbfd, off, res->u.dialog);
252b5132 1299 case RES_TYPE_FONTDIR:
4a594fce 1300 return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
252b5132 1301 case RES_TYPE_GROUP_ICON:
4a594fce 1302 return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
252b5132 1303 case RES_TYPE_MENU:
4a594fce 1304 return res_to_bin_menu (wrbfd, off, res->u.menu);
252b5132 1305 case RES_TYPE_STRINGTABLE:
4a594fce 1306 return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
252b5132 1307 case RES_TYPE_VERSIONINFO:
4a594fce
NC
1308 return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1309 case RES_TYPE_TOOLBAR:
1310 return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1311 case RES_TYPE_USERDATA:
1312 case RES_TYPE_RCDATA:
1313 default:
1314 return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
252b5132
RH
1315 }
1316}
1317
252b5132
RH
1318/* Convert a resource ID to binary. This always returns exactly one
1319 bindata structure. */
1320
4a594fce
NC
1321static rc_uint_type
1322resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
252b5132 1323{
252b5132
RH
1324 if (! id.named)
1325 {
4a594fce
NC
1326 if (wrbfd)
1327 {
1328 struct bin_res_id bri;
3aade688 1329
4a594fce
NC
1330 windres_put_16 (wrbfd, bri.sig, 0xffff);
1331 windres_put_16 (wrbfd, bri.id, id.u.id);
1332 set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1333 }
1334 off += BIN_RES_ID;
252b5132
RH
1335 }
1336 else
1337 {
4a594fce
NC
1338 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1339 if (wrbfd)
1340 {
1341 bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1342 rc_uint_type i;
1343 for (i = 0; i < len; i++)
1344 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1345 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1346 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
252b5132 1347 }
4a594fce
NC
1348 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1349 }
1350 return off;
252b5132
RH
1351}
1352
1353/* Convert a null terminated unicode string to binary. This always
1354 returns exactly one bindata structure. */
1355
4a594fce
NC
1356static rc_uint_type
1357unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
252b5132 1358{
4a594fce 1359 rc_uint_type len = 0;
252b5132 1360
252b5132 1361 if (str != NULL)
4a594fce 1362 len = unichar_len (str);
252b5132 1363
4a594fce 1364 if (wrbfd)
252b5132 1365 {
4a594fce
NC
1366 bfd_byte *d;
1367 rc_uint_type i;
1368 d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1369 for (i = 0; i < len; i++)
1370 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1371 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1372 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
252b5132 1373 }
4a594fce 1374 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
252b5132 1375
4a594fce 1376 return off;
252b5132
RH
1377}
1378
1379/* Convert an accelerator resource to binary. */
1380
4a594fce
NC
1381static rc_uint_type
1382res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1383 const rc_accelerator *accelerators)
252b5132 1384{
4a594fce 1385 const rc_accelerator *a;
252b5132 1386
252b5132
RH
1387 for (a = accelerators; a != NULL; a = a->next)
1388 {
4a594fce
NC
1389 if (wrbfd)
1390 {
1391 struct bin_accelerator ba;
252b5132 1392
4a594fce
NC
1393 windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1394 windres_put_16 (wrbfd, ba.key, a->key);
1395 windres_put_16 (wrbfd, ba.id, a->id);
1396 windres_put_16 (wrbfd, ba.pad, 0);
1397 set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1398 }
1399 off += BIN_ACCELERATOR_SIZE;
1400 }
1401 return off;
252b5132
RH
1402}
1403
1404/* Convert a cursor resource to binary. */
1405
4a594fce
NC
1406static rc_uint_type
1407res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
252b5132 1408{
4a594fce
NC
1409 if (wrbfd)
1410 {
1411 struct bin_cursor bc;
252b5132 1412
4a594fce
NC
1413 windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1414 windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1415 set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1416 if (c->length)
1417 set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1418 }
1419 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1420 return off;
252b5132
RH
1421}
1422
1423/* Convert a group cursor resource to binary. */
1424
4a594fce
NC
1425static rc_uint_type
1426res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1427 const rc_group_cursor *group_cursors)
252b5132 1428{
4a594fce
NC
1429 int c = 0;
1430 const rc_group_cursor *gc;
1431 struct bin_group_cursor bgc;
1432 struct bin_group_cursor_item bgci;
1433 rc_uint_type start = off;
252b5132 1434
4a594fce 1435 off += BIN_GROUP_CURSOR_SIZE;
252b5132 1436
4a594fce 1437 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
252b5132 1438 {
4a594fce
NC
1439 if (wrbfd)
1440 {
1441 windres_put_16 (wrbfd, bgci.width, gc->width);
1442 windres_put_16 (wrbfd, bgci.height, gc->height);
1443 windres_put_16 (wrbfd, bgci.planes, gc->planes);
1444 windres_put_16 (wrbfd, bgci.bits, gc->bits);
1445 windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1446 windres_put_16 (wrbfd, bgci.index, gc->index);
1447 set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
252b5132
RH
1448 }
1449
4a594fce
NC
1450 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1451 }
1452 if (wrbfd)
1453 {
1454 windres_put_16 (wrbfd, bgc.sig1, 0);
1455 windres_put_16 (wrbfd, bgc.sig2, 2);
1456 windres_put_16 (wrbfd, bgc.nitems, c);
1457 set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1458 }
1459 return off;
252b5132
RH
1460}
1461
1462/* Convert a dialog resource to binary. */
1463
4a594fce
NC
1464static rc_uint_type
1465res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
252b5132 1466{
4a594fce
NC
1467 rc_uint_type off_delta;
1468 rc_uint_type start, marker;
252b5132 1469 int dialogex;
4a594fce
NC
1470 int c;
1471 rc_dialog_control *dc;
1472 struct bin_dialogex bdx;
1473 struct bin_dialog bd;
252b5132 1474
4a594fce
NC
1475 off_delta = off;
1476 start = off;
252b5132
RH
1477 dialogex = extended_dialog (dialog);
1478
4a594fce
NC
1479 if (wrbfd)
1480 {
252b5132
RH
1481 if (! dialogex)
1482 {
4a594fce
NC
1483 windres_put_32 (wrbfd, bd.style, dialog->style);
1484 windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1485 windres_put_16 (wrbfd, bd.x, dialog->x);
1486 windres_put_16 (wrbfd, bd.y, dialog->y);
1487 windres_put_16 (wrbfd, bd.width, dialog->width);
1488 windres_put_16 (wrbfd, bd.height, dialog->height);
252b5132
RH
1489 }
1490 else
1491 {
4a594fce
NC
1492 windres_put_16 (wrbfd, bdx.sig1, 1);
1493 windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1494 windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1495 windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1496 windres_put_32 (wrbfd, bdx.style, dialog->style);
1497 windres_put_16 (wrbfd, bdx.x, dialog->x);
1498 windres_put_16 (wrbfd, bdx.y, dialog->y);
1499 windres_put_16 (wrbfd, bdx.width, dialog->width);
1500 windres_put_16 (wrbfd, bdx.height, dialog->height);
1501 }
252b5132
RH
1502 }
1503
4a594fce 1504 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
252b5132 1505
4a594fce
NC
1506 off = resid_to_bin (wrbfd, off, dialog->menu);
1507 off = resid_to_bin (wrbfd, off, dialog->class);
1508 off = unicode_to_bin (wrbfd, off, dialog->caption);
252b5132
RH
1509
1510 if ((dialog->style & DS_SETFONT) != 0)
1511 {
4a594fce 1512 if (wrbfd)
252b5132 1513 {
4a594fce 1514 if (! dialogex)
252b5132 1515 {
4a594fce
NC
1516 struct bin_dialogfont bdf;
1517 windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1518 set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
252b5132
RH
1519 }
1520 else
1521 {
4a594fce
NC
1522 struct bin_dialogexfont bdxf;
1523 windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1524 windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1525 windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1526 windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1527 set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
252b5132
RH
1528 }
1529 }
4a594fce
NC
1530 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1531 off = unicode_to_bin (wrbfd, off, dialog->font);
252b5132 1532 }
4a594fce 1533 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
252b5132 1534 {
4a594fce 1535 bfd_byte dc_rclen[2];
252b5132 1536
4a594fce
NC
1537 off += (4 - ((off - off_delta) & 3)) & 3;
1538 if (wrbfd)
1539 {
252b5132
RH
1540 if (! dialogex)
1541 {
4a594fce
NC
1542 struct bin_dialog_control bdc;
1543
1544 windres_put_32 (wrbfd, bdc.style, dc->style);
1545 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1546 windres_put_16 (wrbfd, bdc.x, dc->x);
1547 windres_put_16 (wrbfd, bdc.y, dc->y);
1548 windres_put_16 (wrbfd, bdc.width, dc->width);
1549 windres_put_16 (wrbfd, bdc.height, dc->height);
1550 windres_put_16 (wrbfd, bdc.id, dc->id);
1551 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
252b5132
RH
1552 }
1553 else
1554 {
4a594fce
NC
1555 struct bin_dialogex_control bdc;
1556
1557 windres_put_32 (wrbfd, bdc.help, dc->help);
1558 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1559 windres_put_32 (wrbfd, bdc.style, dc->style);
1560 windres_put_16 (wrbfd, bdc.x, dc->x);
1561 windres_put_16 (wrbfd, bdc.y, dc->y);
1562 windres_put_16 (wrbfd, bdc.width, dc->width);
1563 windres_put_16 (wrbfd, bdc.height, dc->height);
1564 windres_put_32 (wrbfd, bdc.id, dc->id);
1565 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1566 }
3aade688 1567 }
4a594fce 1568 off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
252b5132 1569
4a594fce
NC
1570 off = resid_to_bin (wrbfd, off, dc->class);
1571 off = resid_to_bin (wrbfd, off, dc->text);
252b5132 1572
4a594fce
NC
1573 marker = off; /* Save two bytes for size of optional data. */
1574 off += 2;
252b5132
RH
1575
1576 if (dc->data == NULL)
4a594fce
NC
1577 {
1578 if (wrbfd)
1579 windres_put_16 (wrbfd, dc_rclen, 0);
1580 }
252b5132
RH
1581 else
1582 {
4a594fce
NC
1583 rc_uint_type saved_off = off;
1584 rc_uint_type old_off;
1585 off += (4 - ((off - off_delta) & 3)) & 3;
1586
1587 old_off = off;
1588 off = res_to_bin_rcdata (wrbfd, off, dc->data);
1589 if ((off - old_off) == 0)
1590 old_off = off = saved_off;
1591 if (wrbfd)
1592 windres_put_16 (wrbfd, dc_rclen, off - old_off);
252b5132 1593 }
4a594fce
NC
1594 if (wrbfd)
1595 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
252b5132 1596 }
4a594fce
NC
1597
1598 if (wrbfd)
1599 {
1600 windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1601 if (! dialogex)
1602 set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1603 else
1604 set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
252b5132 1605 }
252b5132 1606
4a594fce 1607 return off;
252b5132
RH
1608}
1609
1610/* Convert a fontdir resource to binary. */
4a594fce
NC
1611static rc_uint_type
1612res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
252b5132 1613{
4a594fce 1614 rc_uint_type start;
252b5132 1615 int c;
4a594fce 1616 const rc_fontdir *fd;
252b5132 1617
4a594fce
NC
1618 start = off;
1619 off += 2;
252b5132 1620
4a594fce 1621 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
252b5132 1622 {
4a594fce
NC
1623 if (wrbfd)
1624 {
1625 bfd_byte d[2];
1626 windres_put_16 (wrbfd, d, fd->index);
1627 set_windres_bfd_content (wrbfd, d, off, 2);
1628 if (fd->length)
1629 set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1630 }
1631 off += (rc_uint_type) fd->length + 2;
252b5132
RH
1632 }
1633
4a594fce
NC
1634 if (wrbfd)
1635 {
1636 bfd_byte d[2];
1637 windres_put_16 (wrbfd, d, c);
1638 set_windres_bfd_content (wrbfd, d, start, 2);
1639 }
1640 return off;
252b5132
RH
1641}
1642
1643/* Convert a group icon resource to binary. */
1644
4a594fce
NC
1645static rc_uint_type
1646res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
252b5132 1647{
4a594fce
NC
1648 rc_uint_type start;
1649 struct bin_group_icon bgi;
252b5132 1650 int c;
4a594fce 1651 const rc_group_icon *gi;
252b5132 1652
4a594fce
NC
1653 start = off;
1654 off += BIN_GROUP_ICON_SIZE;
252b5132 1655
4a594fce 1656 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
252b5132 1657 {
4a594fce 1658 struct bin_group_icon_item bgii;
252b5132 1659
4a594fce
NC
1660 if (wrbfd)
1661 {
1662 windres_put_8 (wrbfd, bgii.width, gi->width);
1663 windres_put_8 (wrbfd, bgii.height, gi->height);
1664 windres_put_8 (wrbfd, bgii.colors, gi->colors);
1665 windres_put_8 (wrbfd, bgii.pad, 0);
1666 windres_put_16 (wrbfd, bgii.planes, gi->planes);
1667 windres_put_16 (wrbfd, bgii.bits, gi->bits);
1668 windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1669 windres_put_16 (wrbfd, bgii.index, gi->index);
1670 set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1671 }
1672 off += BIN_GROUP_ICON_ITEM_SIZE;
252b5132
RH
1673 }
1674
4a594fce
NC
1675 if (wrbfd)
1676 {
1677 windres_put_16 (wrbfd, bgi.sig1, 0);
1678 windres_put_16 (wrbfd, bgi.sig2, 1);
1679 windres_put_16 (wrbfd, bgi.count, c);
1680 set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1681 }
1682 return off;
252b5132
RH
1683}
1684
1685/* Convert a menu resource to binary. */
1686
4a594fce
NC
1687static rc_uint_type
1688res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
252b5132
RH
1689{
1690 int menuex;
252b5132
RH
1691
1692 menuex = extended_menu (menu);
1693
4a594fce
NC
1694 if (wrbfd)
1695 {
252b5132
RH
1696 if (! menuex)
1697 {
4a594fce
NC
1698 struct bin_menu bm;
1699 windres_put_16 (wrbfd, bm.sig1, 0);
1700 windres_put_16 (wrbfd, bm.sig2, 0);
1701 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
252b5132
RH
1702 }
1703 else
1704 {
4a594fce
NC
1705 struct bin_menuex bm;
1706 windres_put_16 (wrbfd, bm.sig1, 1);
1707 windres_put_16 (wrbfd, bm.sig2, 4);
1708 windres_put_32 (wrbfd, bm.help, menu->help);
1709 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
252b5132 1710 }
4a594fce
NC
1711 }
1712 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1713 if (! menuex)
1714 {
1715 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1716 }
1717 else
1718 {
1719 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1720 }
1721 return off;
252b5132
RH
1722}
1723
1724/* Convert menu items to binary. */
1725
4a594fce
NC
1726static rc_uint_type
1727res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
252b5132 1728{
4a594fce 1729 const rc_menuitem *mi;
252b5132
RH
1730
1731 for (mi = items; mi != NULL; mi = mi->next)
1732 {
4a594fce 1733 struct bin_menuitem bmi;
252b5132
RH
1734 int flags;
1735
252b5132
RH
1736 flags = mi->type;
1737 if (mi->next == NULL)
1738 flags |= MENUITEM_ENDMENU;
1739 if (mi->popup != NULL)
1740 flags |= MENUITEM_POPUP;
1741
4a594fce
NC
1742 if (wrbfd)
1743 {
1744 windres_put_16 (wrbfd, bmi.flags, flags);
252b5132 1745 if (mi->popup == NULL)
4a594fce
NC
1746 windres_put_16 (wrbfd, bmi.id, mi->id);
1747 set_windres_bfd_content (wrbfd, &bmi, off,
1748 mi->popup == NULL ? BIN_MENUITEM_SIZE
1749 : BIN_MENUITEM_POPUP_SIZE);
1750 }
1751 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
252b5132 1752
4a594fce 1753 off = unicode_to_bin (wrbfd, off, mi->text);
252b5132
RH
1754
1755 if (mi->popup != NULL)
1756 {
4a594fce 1757 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
252b5132
RH
1758 }
1759 }
4a594fce 1760 return off;
252b5132
RH
1761}
1762
1763/* Convert menuex items to binary. */
1764
4a594fce
NC
1765static rc_uint_type
1766res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
252b5132 1767{
4a594fce
NC
1768 rc_uint_type off_delta = off;
1769 const rc_menuitem *mi;
252b5132
RH
1770
1771 for (mi = items; mi != NULL; mi = mi->next)
1772 {
4a594fce 1773 struct bin_menuitemex bmi;
252b5132
RH
1774 int flags;
1775
4a594fce 1776 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132
RH
1777
1778 flags = 0;
1779 if (mi->next == NULL)
1780 flags |= 0x80;
1781 if (mi->popup != NULL)
1782 flags |= 1;
252b5132 1783
4a594fce
NC
1784 if (wrbfd)
1785 {
1786 windres_put_32 (wrbfd, bmi.type, mi->type);
1787 windres_put_32 (wrbfd, bmi.state, mi->state);
1788 windres_put_32 (wrbfd, bmi.id, mi->id);
1789 windres_put_16 (wrbfd, bmi.flags, flags);
1790 set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1791 }
1792 off += BIN_MENUITEMEX_SIZE;
252b5132 1793
4a594fce 1794 off = unicode_to_bin (wrbfd, off, mi->text);
252b5132
RH
1795
1796 if (mi->popup != NULL)
1797 {
4a594fce 1798 bfd_byte help[4];
252b5132 1799
4a594fce 1800 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 1801
4a594fce 1802 if (wrbfd)
252b5132 1803 {
4a594fce
NC
1804 windres_put_32 (wrbfd, help, mi->help);
1805 set_windres_bfd_content (wrbfd, help, off, 4);
252b5132 1806 }
4a594fce
NC
1807 off += 4;
1808 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
252b5132
RH
1809 }
1810 }
4a594fce 1811 return off;
252b5132
RH
1812}
1813
1814/* Convert an rcdata resource to binary. This is also used to convert
4a594fce 1815 other information which happens to be stored in rc_rcdata_item lists
252b5132
RH
1816 to binary. */
1817
4a594fce
NC
1818static rc_uint_type
1819res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
252b5132 1820{
4a594fce 1821 const rc_rcdata_item *ri;
252b5132
RH
1822
1823 for (ri = items; ri != NULL; ri = ri->next)
1824 {
4a594fce 1825 rc_uint_type len;
252b5132
RH
1826 switch (ri->type)
1827 {
1828 default:
1829 abort ();
252b5132 1830 case RCDATA_WORD:
4a594fce 1831 len = 2;
252b5132 1832 break;
252b5132 1833 case RCDATA_DWORD:
4a594fce 1834 len = 4;
252b5132 1835 break;
252b5132 1836 case RCDATA_STRING:
4a594fce
NC
1837 len = ri->u.string.length;
1838 break;
1839 case RCDATA_WSTRING:
1840 len = ri->u.wstring.length * sizeof (unichar);
1841 break;
1842 case RCDATA_BUFFER:
1843 len = ri->u.buffer.length;
1844 break;
1845 }
1846 if (wrbfd)
1847 {
1848 bfd_byte h[4];
1849 bfd_byte *hp = &h[0];
1850 switch (ri->type)
1851 {
1852 case RCDATA_WORD:
1853 windres_put_16 (wrbfd, hp, ri->u.word);
1854 break;
1855 case RCDATA_DWORD:
1856 windres_put_32 (wrbfd, hp, ri->u.dword);
1857 break;
1858 case RCDATA_STRING:
1859 hp = (bfd_byte *) ri->u.string.s;
252b5132 1860 break;
252b5132
RH
1861 case RCDATA_WSTRING:
1862 {
4a594fce 1863 rc_uint_type i;
252b5132 1864
4a594fce 1865 hp = (bfd_byte *) reswr_alloc (len);
252b5132 1866 for (i = 0; i < ri->u.wstring.length; i++)
4a594fce 1867 windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
252b5132 1868 }
4a594fce 1869 break;
252b5132 1870 case RCDATA_BUFFER:
4a594fce 1871 hp = (bfd_byte *) ri->u.buffer.data;
252b5132
RH
1872 break;
1873 }
4a594fce 1874 set_windres_bfd_content (wrbfd, hp, off, len);
252b5132 1875 }
4a594fce
NC
1876 off += len;
1877 }
1878 return off;
252b5132
RH
1879}
1880
1881/* Convert a stringtable resource to binary. */
1882
4a594fce
NC
1883static rc_uint_type
1884res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1885 const rc_stringtable *st)
252b5132 1886{
252b5132
RH
1887 int i;
1888
252b5132
RH
1889 for (i = 0; i < 16; i++)
1890 {
4a594fce 1891 rc_uint_type slen, length;
252b5132
RH
1892 unichar *s;
1893
4a594fce 1894 slen = (rc_uint_type) st->strings[i].length;
8b6efd89 1895 if (slen == 0xffffffff) slen = 0;
252b5132
RH
1896 s = st->strings[i].string;
1897
4a594fce
NC
1898 length = 2 + slen * 2;
1899 if (wrbfd)
1900 {
1901 bfd_byte *hp;
1902 rc_uint_type j;
252b5132 1903
4a594fce
NC
1904 hp = (bfd_byte *) reswr_alloc (length);
1905 windres_put_16 (wrbfd, hp, slen);
252b5132
RH
1906
1907 for (j = 0; j < slen; j++)
4a594fce
NC
1908 windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1909 set_windres_bfd_content (wrbfd, hp, off, length);
252b5132 1910 }
4a594fce
NC
1911 off += length;
1912 }
1913 return off;
252b5132
RH
1914}
1915
1916/* Convert an ASCII string to a unicode binary string. This always
1917 returns exactly one bindata structure. */
1918
4a594fce
NC
1919static rc_uint_type
1920string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
252b5132 1921{
4a594fce 1922 rc_uint_type len;
252b5132 1923
4a594fce 1924 len = (rc_uint_type) strlen (s);
252b5132 1925
4a594fce
NC
1926 if (wrbfd)
1927 {
1928 rc_uint_type i;
1929 bfd_byte *hp;
252b5132 1930
4a594fce 1931 hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
252b5132 1932
4a594fce
NC
1933 for (i = 0; i < len; i++)
1934 windres_put_16 (wrbfd, hp + i * 2, s[i]);
1935 windres_put_16 (wrbfd, hp + i * 2, 0);
1936 set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1937 }
1938 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1939 return off;
252b5132
RH
1940}
1941
4a594fce
NC
1942static rc_uint_type
1943res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
252b5132 1944{
4a594fce
NC
1945 if (wrbfd)
1946 {
1947 struct bin_toolbar bt;
1948 windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1949 windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1950 windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1951 set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1952 if (tb->nitems > 0)
1953 {
1954 rc_toolbar_item *it;
1955 bfd_byte *ids;
1956 rc_uint_type i = 0;
252b5132 1957
4a594fce
NC
1958 ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1959 it=tb->items;
1960 while(it != NULL)
1961 {
1962 windres_put_32 (wrbfd, ids + i, it->id.u.id);
1963 i += 4;
1964 it = it->next;
1965 }
1966 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1967 }
1968 }
1969 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
252b5132 1970
4a594fce
NC
1971 return off;
1972}
252b5132 1973
4a594fce 1974/* Convert a versioninfo resource to binary. */
252b5132 1975
4a594fce
NC
1976static rc_uint_type
1977res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1978 const rc_versioninfo *versioninfo)
1979{
1980 rc_uint_type off_delta = off;
1981 rc_uint_type start;
1982 struct bin_versioninfo bvi;
1983 rc_ver_info *vi;
252b5132 1984
4a594fce
NC
1985 start = off;
1986 off += BIN_VERSIONINFO_SIZE;
1987 off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1988 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132
RH
1989
1990 if (versioninfo->fixed != NULL)
1991 {
4a594fce
NC
1992 if (wrbfd)
1993 {
1994 struct bin_fixed_versioninfo bfv;
1995 const rc_fixed_versioninfo *fi;
252b5132
RH
1996
1997 fi = versioninfo->fixed;
4a594fce
NC
1998 windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1999 windres_put_32 (wrbfd, bfv.sig2, 0x10000);
2000 windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
2001 windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
2002 windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2003 windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2004 windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2005 windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2006 windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2007 windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2008 windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2009 windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2010 windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2011 set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2012 }
2013 off += BIN_FIXED_VERSIONINFO_SIZE;
252b5132
RH
2014 }
2015
2016 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2017 {
4a594fce
NC
2018 struct bin_ver_info bv;
2019 rc_uint_type bv_off;
252b5132 2020
4a594fce 2021 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2022
4a594fce 2023 bv_off = off;
252b5132 2024
4a594fce 2025 off += BIN_VER_INFO_SIZE;
252b5132
RH
2026
2027 switch (vi->type)
2028 {
2029 default:
2030 abort ();
252b5132
RH
2031 case VERINFO_STRING:
2032 {
bfb6c1ab 2033 const rc_ver_stringtable *vst;
252b5132 2034
4a594fce 2035 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
252b5132 2036
bfb6c1ab
NC
2037 if (!vi->u.string.stringtables)
2038 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2039
bfb6c1ab 2040 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
4a594fce 2041 {
bfb6c1ab
NC
2042 struct bin_ver_info bvst;
2043 rc_uint_type vst_off;
2044 const rc_ver_stringinfo *vs;
252b5132 2045
4a594fce 2046 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2047
bfb6c1ab 2048 vst_off = off;
4a594fce 2049 off += BIN_VER_INFO_SIZE;
252b5132 2050
bfb6c1ab 2051 off = unicode_to_bin (wrbfd, off, vst->language);
252b5132 2052
bfb6c1ab
NC
2053 for (vs = vst->strings; vs != NULL; vs = vs->next)
2054 {
2055 struct bin_ver_info bvs;
2056 rc_uint_type vs_off, str_off;
2057
2058 off += (4 - ((off - off_delta) & 3)) & 3;
2059
2060 vs_off = off;
2061 off += BIN_VER_INFO_SIZE;
2062
2063 off = unicode_to_bin (wrbfd, off, vs->key);
2064
2065 off += (4 - ((off - off_delta) & 3)) & 3;
2066
2067 str_off = off;
2068 off = unicode_to_bin (wrbfd, off, vs->value);
2069
2070 if (wrbfd)
2071 {
2072 windres_put_16 (wrbfd, bvs.size, off - vs_off);
2073 windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2074 windres_put_16 (wrbfd, bvs.sig2, 1);
2075 set_windres_bfd_content (wrbfd, &bvs, vs_off,
2076 BIN_VER_INFO_SIZE);
2077 }
2078 }
252b5132 2079
4a594fce
NC
2080 if (wrbfd)
2081 {
bfb6c1ab
NC
2082 windres_put_16 (wrbfd, bvst.size, off - vst_off);
2083 windres_put_16 (wrbfd, bvst.sig1, 0);
2084 windres_put_16 (wrbfd, bvst.sig2, 1);
2085 set_windres_bfd_content (wrbfd, &bvst, vst_off,
2086 BIN_VER_INFO_SIZE);
4a594fce
NC
2087 }
2088 }
252b5132
RH
2089 break;
2090 }
2091
2092 case VERINFO_VAR:
2093 {
4a594fce
NC
2094 rc_uint_type vvd_off, vvvd_off;
2095 struct bin_ver_info bvvd;
2096 const rc_ver_varinfo *vv;
252b5132 2097
4a594fce 2098 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
252b5132 2099
4a594fce 2100 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2101
4a594fce
NC
2102 vvd_off = off;
2103 off += BIN_VER_INFO_SIZE;
252b5132 2104
4a594fce 2105 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
252b5132 2106
4a594fce 2107 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2108
4a594fce 2109 vvvd_off = off;
252b5132
RH
2110
2111 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2112 {
4a594fce
NC
2113 if (wrbfd)
2114 {
2115 bfd_byte vvsd[4];
2116
2117 windres_put_16 (wrbfd, &vvsd[0], vv->language);
2118 windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2119 set_windres_bfd_content (wrbfd, vvsd, off, 4);
2120 }
2121 off += 4;
252b5132 2122 }
4a594fce
NC
2123 if (wrbfd)
2124 {
2125 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2126 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2127 windres_put_16 (wrbfd, bvvd.sig2, 0);
2128 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2129 BIN_VER_INFO_SIZE);
2130 }
252b5132
RH
2131
2132 break;
2133 }
2134 }
2135
4a594fce
NC
2136 if (wrbfd)
2137 {
bfb6c1ab 2138 windres_put_16 (wrbfd, bv.size, off - bv_off);
4a594fce 2139 windres_put_16 (wrbfd, bv.sig1, 0);
bfb6c1ab 2140 windres_put_16 (wrbfd, bv.sig2, 1);
4a594fce
NC
2141 set_windres_bfd_content (wrbfd, &bv, bv_off,
2142 BIN_VER_INFO_SIZE);
2143 }
252b5132
RH
2144 }
2145
4a594fce
NC
2146 if (wrbfd)
2147 {
2148 windres_put_16 (wrbfd, bvi.size, off - start);
2149 windres_put_16 (wrbfd, bvi.fixed_size,
2150 versioninfo->fixed == NULL ? 0
2151 : BIN_FIXED_VERSIONINFO_SIZE);
2152 windres_put_16 (wrbfd, bvi.sig2, 0);
2153 set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2154 }
2155 return off;
252b5132
RH
2156}
2157
2158/* Convert a generic resource to binary. */
2159
4a594fce
NC
2160static rc_uint_type
2161res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2162 const bfd_byte *data)
252b5132 2163{
4a594fce
NC
2164 if (wrbfd && length != 0)
2165 set_windres_bfd_content (wrbfd, data, off, length);
2166 return off + (rc_uint_type) length;
252b5132 2167}