]> 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.
219d1afa 2 Copyright (C) 1997-2018 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 {
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
RH
969
970 data += off;
971 length -= off;
972
973 if (vallen == 0)
974 fi = NULL;
975 else
976 {
977 unsigned long signature, fiv;
978
979 if (vallen != 52)
4a594fce 980 fatal (_("unexpected fixed version information length %ld"), (long) vallen);
252b5132
RH
981
982 if (length < 52)
983 toosmall (_("fixed version info"));
984
4a594fce 985 signature = windres_get_32 (wrbfd, data, 4);
252b5132
RH
986 if (signature != 0xfeef04bd)
987 fatal (_("unexpected fixed version signature %lu"), signature);
988
4a594fce 989 fiv = windres_get_32 (wrbfd, data + 4, 4);
252b5132
RH
990 if (fiv != 0 && fiv != 0x10000)
991 fatal (_("unexpected fixed version info version %lu"), fiv);
992
4a594fce 993 fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
252b5132 994
4a594fce
NC
995 fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
996 fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
997 fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
998 fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
999 fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1000 fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1001 fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1002 fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1003 fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1004 fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1005 fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
252b5132
RH
1006
1007 data += 52;
1008 length -= 52;
1009 }
1010
1011 first = NULL;
1012 pp = &first;
1013
1014 while (length > 0)
1015 {
4a594fce 1016 rc_ver_info *vi;
252b5132
RH
1017 int ch;
1018
1019 if (length < 8)
1020 toosmall (_("version var info"));
1021
4a594fce 1022 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
252b5132 1023
4a594fce 1024 ch = windres_get_16 (wrbfd, data + 6, 2);
252b5132
RH
1025
1026 if (ch == 'S')
1027 {
bfb6c1ab 1028 rc_ver_stringtable **ppvst;
252b5132
RH
1029
1030 vi->type = VERINFO_STRING;
1031
4a594fce 1032 get_version_header (wrbfd, data, length, "StringFileInfo",
7e8d45b7 1033 (unichar **) NULL, &verlen, &vallen, &type,
252b5132
RH
1034 &off);
1035
1036 if (vallen != 0)
4a594fce 1037 fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
252b5132
RH
1038
1039 data += off;
1040 length -= off;
1041
fb98f7b7 1042 verlen -= off;
252b5132 1043
bfb6c1ab
NC
1044 vi->u.string.stringtables = NULL;
1045 ppvst = &vi->u.string.stringtables;
1046
252b5132 1047 while (verlen > 0)
bfb6c1ab
NC
1048 {
1049 rc_ver_stringtable *vst;
1050 rc_uint_type stverlen;
1051 rc_ver_stringinfo **ppvs;
1052
1053 if (length < 8)
1054 toosmall (_("version stringtable"));
1055
1056 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1057
1058 get_version_header (wrbfd, data, length, (const char *) NULL,
1059 &vst->language, &stverlen, &vallen, &type, &off);
1060
1061 if (vallen != 0)
1062 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1063
1064 data += off;
1065 length -= off;
1066 verlen -= off;
1067
fb98f7b7 1068 stverlen -= off;
3aade688 1069
bfb6c1ab
NC
1070 vst->strings = NULL;
1071 ppvs = &vst->strings;
1072
1073 while (stverlen > 0)
252b5132 1074 {
4a594fce 1075 rc_ver_stringinfo *vs;
bfb6c1ab
NC
1076 rc_uint_type sverlen, vslen, valoff;
1077
1078 if (length < 8)
1079 toosmall (_("version string"));
252b5132 1080
bfb6c1ab 1081 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
252b5132 1082
bfb6c1ab
NC
1083 get_version_header (wrbfd, data, length, (const char *) NULL,
1084 &vs->key, &sverlen, &vallen, &type, &off);
252b5132 1085
252b5132
RH
1086 data += off;
1087 length -= off;
1088
4a594fce 1089 vs->value = get_unicode (wrbfd, data, length, &vslen);
252b5132 1090 valoff = vslen * 2 + 2;
fb98f7b7 1091 valoff = (valoff + 3) & ~3;
252b5132 1092
bfb6c1ab 1093 if (off + valoff != sverlen)
4a594fce 1094 fatal (_("unexpected version string length %ld != %ld + %ld"),
bfb6c1ab 1095 (long) sverlen, (long) off, (long) valoff);
252b5132
RH
1096
1097 data += valoff;
1098 length -= valoff;
1099
bfb6c1ab 1100 if (stverlen < sverlen)
4a594fce 1101 fatal (_("unexpected version string length %ld < %ld"),
bfb6c1ab
NC
1102 (long) verlen, (long) sverlen);
1103 stverlen -= sverlen;
fb98f7b7 1104 verlen -= sverlen;
bfb6c1ab
NC
1105
1106 vs->next = NULL;
1107 *ppvs = vs;
1108 ppvs = &vs->next;
1109 }
252b5132 1110
bfb6c1ab
NC
1111 vst->next = NULL;
1112 *ppvst = vst;
1113 ppvst = &vst->next;
252b5132
RH
1114 }
1115 }
1116 else if (ch == 'V')
1117 {
4a594fce 1118 rc_ver_varinfo **ppvv;
252b5132
RH
1119
1120 vi->type = VERINFO_VAR;
1121
4a594fce 1122 get_version_header (wrbfd, data, length, "VarFileInfo",
7e8d45b7 1123 (unichar **) NULL, &verlen, &vallen, &type,
252b5132
RH
1124 &off);
1125
1126 if (vallen != 0)
4a594fce 1127 fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
252b5132
RH
1128
1129 data += off;
1130 length -= off;
1131
4a594fce 1132 get_version_header (wrbfd, data, length, (const char *) NULL,
252b5132
RH
1133 &vi->u.var.key, &verlen, &vallen, &type, &off);
1134
1135 data += off;
1136 length -= off;
1137
1138 vi->u.var.var = NULL;
1139 ppvv = &vi->u.var.var;
1140
1141 while (vallen > 0)
1142 {
4a594fce 1143 rc_ver_varinfo *vv;
252b5132
RH
1144
1145 if (length < 4)
1146 toosmall (_("version varfileinfo"));
1147
4a594fce 1148 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
252b5132 1149
4a594fce
NC
1150 vv->language = windres_get_16 (wrbfd, data, 2);
1151 vv->charset = windres_get_16 (wrbfd, data + 2, 2);
252b5132
RH
1152
1153 vv->next = NULL;
1154 *ppvv = vv;
1155 ppvv = &vv->next;
1156
1157 data += 4;
1158 length -= 4;
1159
1160 if (vallen < 4)
4a594fce 1161 fatal (_("unexpected version value length %ld"), (long) vallen);
252b5132
RH
1162
1163 vallen -= 4;
1164 }
1165 }
4931146e
NC
1166 else if (ch == 0)
1167 {
1168 if (length == 8)
1169 /* Padding - skip. */
1170 break;
1171 fatal (_("nul bytes found in version string"));
1172 }
252b5132 1173 else
4931146e 1174 fatal (_("unexpected version string character: %x"), ch);
252b5132
RH
1175
1176 vi->next = NULL;
1177 *pp = vi;
53c7db4b 1178 pp = &vi->next;
252b5132
RH
1179 }
1180
4a594fce 1181 v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
252b5132
RH
1182 v->fixed = fi;
1183 v->var = first;
1184
4a594fce 1185 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
1186 r->type = RES_TYPE_VERSIONINFO;
1187 r->u.versioninfo = v;
1188
53c7db4b 1189 return r;
252b5132
RH
1190}
1191
1192/* Convert an arbitrary user defined resource from binary. */
1193
4a594fce
NC
1194static rc_res_resource *
1195bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1196 rc_uint_type length)
252b5132 1197{
4a594fce
NC
1198 rc_rcdata_item *ri;
1199 rc_res_resource *r;
252b5132 1200
4a594fce 1201 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
1202
1203 ri->next = NULL;
1204 ri->type = RCDATA_BUFFER;
1205 ri->u.buffer.length = length;
1206 ri->u.buffer.data = data;
1207
4a594fce 1208 r = (rc_res_resource *) res_alloc (sizeof *r);
252b5132
RH
1209 r->type = RES_TYPE_USERDATA;
1210 r->u.rcdata = ri;
1211
1212 return r;
1213}
1214\f
4a594fce
NC
1215static rc_res_resource *
1216bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1217{
1218 rc_toolbar *ri;
1219 rc_res_resource *r;
1220 rc_uint_type i;
1221
1222 ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1223 ri->button_width = windres_get_32 (wrbfd, data, 4);
1224 ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1225 ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1226 ri->items = NULL;
1227
1228 data += 12;
1229 length -= 12;
1230 for (i=0 ; i < ri->nitems; i++)
1231 {
1232 rc_toolbar_item *it;
1233 it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1234 it->id.named = 0;
1235 it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1236 it->prev = it->next = NULL;
1237 data += 4;
1238 length -= 4;
1239 if(ri->items) {
1240 rc_toolbar_item *ii = ri->items;
1241 while (ii->next != NULL)
1242 ii = ii->next;
1243 it->prev = ii;
1244 ii->next = it;
1245 }
1246 else
1247 ri->items = it;
1248 }
1249 r = (rc_res_resource *) res_alloc (sizeof *r);
1250 r->type = RES_TYPE_TOOLBAR;
1251 r->u.toolbar = ri;
1252 return r;
1253}
252b5132 1254
252b5132
RH
1255
1256/* Local functions used to convert resources to binary format. */
1257
4a594fce
NC
1258static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1259static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1260static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1261static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1262static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1263static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1264static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1265static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1266static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1267static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1268static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1269static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1270static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1271static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1272static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1273static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1274static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1275 const bfd_byte *);
252b5132
RH
1276
1277/* Convert a resource to binary. */
1278
4a594fce
NC
1279rc_uint_type
1280res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
252b5132
RH
1281{
1282 switch (res->type)
1283 {
252b5132
RH
1284 case RES_TYPE_BITMAP:
1285 case RES_TYPE_FONT:
1286 case RES_TYPE_ICON:
1287 case RES_TYPE_MESSAGETABLE:
4a594fce 1288 return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
252b5132 1289 case RES_TYPE_ACCELERATOR:
4a594fce 1290 return res_to_bin_accelerator (wrbfd, off, res->u.acc);
252b5132 1291 case RES_TYPE_CURSOR:
4a594fce 1292 return res_to_bin_cursor (wrbfd, off, res->u.cursor);
252b5132 1293 case RES_TYPE_GROUP_CURSOR:
4a594fce 1294 return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
252b5132 1295 case RES_TYPE_DIALOG:
4a594fce 1296 return res_to_bin_dialog (wrbfd, off, res->u.dialog);
252b5132 1297 case RES_TYPE_FONTDIR:
4a594fce 1298 return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
252b5132 1299 case RES_TYPE_GROUP_ICON:
4a594fce 1300 return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
252b5132 1301 case RES_TYPE_MENU:
4a594fce 1302 return res_to_bin_menu (wrbfd, off, res->u.menu);
252b5132 1303 case RES_TYPE_STRINGTABLE:
4a594fce 1304 return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
252b5132 1305 case RES_TYPE_VERSIONINFO:
4a594fce
NC
1306 return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1307 case RES_TYPE_TOOLBAR:
1308 return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1309 case RES_TYPE_USERDATA:
1310 case RES_TYPE_RCDATA:
1311 default:
1312 return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
252b5132
RH
1313 }
1314}
1315
252b5132
RH
1316/* Convert a resource ID to binary. This always returns exactly one
1317 bindata structure. */
1318
4a594fce
NC
1319static rc_uint_type
1320resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
252b5132 1321{
252b5132
RH
1322 if (! id.named)
1323 {
4a594fce
NC
1324 if (wrbfd)
1325 {
1326 struct bin_res_id bri;
3aade688 1327
4a594fce
NC
1328 windres_put_16 (wrbfd, bri.sig, 0xffff);
1329 windres_put_16 (wrbfd, bri.id, id.u.id);
1330 set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1331 }
1332 off += BIN_RES_ID;
252b5132
RH
1333 }
1334 else
1335 {
4a594fce
NC
1336 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1337 if (wrbfd)
1338 {
1339 bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1340 rc_uint_type i;
1341 for (i = 0; i < len; i++)
1342 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1343 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1344 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
252b5132 1345 }
4a594fce
NC
1346 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1347 }
1348 return off;
252b5132
RH
1349}
1350
1351/* Convert a null terminated unicode string to binary. This always
1352 returns exactly one bindata structure. */
1353
4a594fce
NC
1354static rc_uint_type
1355unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
252b5132 1356{
4a594fce 1357 rc_uint_type len = 0;
252b5132 1358
252b5132 1359 if (str != NULL)
4a594fce 1360 len = unichar_len (str);
252b5132 1361
4a594fce 1362 if (wrbfd)
252b5132 1363 {
4a594fce
NC
1364 bfd_byte *d;
1365 rc_uint_type i;
1366 d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1367 for (i = 0; i < len; i++)
1368 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1369 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1370 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
252b5132 1371 }
4a594fce 1372 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
252b5132 1373
4a594fce 1374 return off;
252b5132
RH
1375}
1376
1377/* Convert an accelerator resource to binary. */
1378
4a594fce
NC
1379static rc_uint_type
1380res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1381 const rc_accelerator *accelerators)
252b5132 1382{
4a594fce 1383 const rc_accelerator *a;
252b5132 1384
252b5132
RH
1385 for (a = accelerators; a != NULL; a = a->next)
1386 {
4a594fce
NC
1387 if (wrbfd)
1388 {
1389 struct bin_accelerator ba;
252b5132 1390
4a594fce
NC
1391 windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1392 windres_put_16 (wrbfd, ba.key, a->key);
1393 windres_put_16 (wrbfd, ba.id, a->id);
1394 windres_put_16 (wrbfd, ba.pad, 0);
1395 set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1396 }
1397 off += BIN_ACCELERATOR_SIZE;
1398 }
1399 return off;
252b5132
RH
1400}
1401
1402/* Convert a cursor resource to binary. */
1403
4a594fce
NC
1404static rc_uint_type
1405res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
252b5132 1406{
4a594fce
NC
1407 if (wrbfd)
1408 {
1409 struct bin_cursor bc;
252b5132 1410
4a594fce
NC
1411 windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1412 windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1413 set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1414 if (c->length)
1415 set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1416 }
1417 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1418 return off;
252b5132
RH
1419}
1420
1421/* Convert a group cursor resource to binary. */
1422
4a594fce
NC
1423static rc_uint_type
1424res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1425 const rc_group_cursor *group_cursors)
252b5132 1426{
4a594fce
NC
1427 int c = 0;
1428 const rc_group_cursor *gc;
1429 struct bin_group_cursor bgc;
1430 struct bin_group_cursor_item bgci;
1431 rc_uint_type start = off;
252b5132 1432
4a594fce 1433 off += BIN_GROUP_CURSOR_SIZE;
252b5132 1434
4a594fce 1435 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
252b5132 1436 {
4a594fce
NC
1437 if (wrbfd)
1438 {
1439 windres_put_16 (wrbfd, bgci.width, gc->width);
1440 windres_put_16 (wrbfd, bgci.height, gc->height);
1441 windres_put_16 (wrbfd, bgci.planes, gc->planes);
1442 windres_put_16 (wrbfd, bgci.bits, gc->bits);
1443 windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1444 windres_put_16 (wrbfd, bgci.index, gc->index);
1445 set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
252b5132
RH
1446 }
1447
4a594fce
NC
1448 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1449 }
1450 if (wrbfd)
1451 {
1452 windres_put_16 (wrbfd, bgc.sig1, 0);
1453 windres_put_16 (wrbfd, bgc.sig2, 2);
1454 windres_put_16 (wrbfd, bgc.nitems, c);
1455 set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1456 }
1457 return off;
252b5132
RH
1458}
1459
1460/* Convert a dialog resource to binary. */
1461
4a594fce
NC
1462static rc_uint_type
1463res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
252b5132 1464{
4a594fce
NC
1465 rc_uint_type off_delta;
1466 rc_uint_type start, marker;
252b5132 1467 int dialogex;
4a594fce
NC
1468 int c;
1469 rc_dialog_control *dc;
1470 struct bin_dialogex bdx;
1471 struct bin_dialog bd;
252b5132 1472
4a594fce
NC
1473 off_delta = off;
1474 start = off;
252b5132
RH
1475 dialogex = extended_dialog (dialog);
1476
4a594fce
NC
1477 if (wrbfd)
1478 {
252b5132
RH
1479 if (! dialogex)
1480 {
4a594fce
NC
1481 windres_put_32 (wrbfd, bd.style, dialog->style);
1482 windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1483 windres_put_16 (wrbfd, bd.x, dialog->x);
1484 windres_put_16 (wrbfd, bd.y, dialog->y);
1485 windres_put_16 (wrbfd, bd.width, dialog->width);
1486 windres_put_16 (wrbfd, bd.height, dialog->height);
252b5132
RH
1487 }
1488 else
1489 {
4a594fce
NC
1490 windres_put_16 (wrbfd, bdx.sig1, 1);
1491 windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1492 windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1493 windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1494 windres_put_32 (wrbfd, bdx.style, dialog->style);
1495 windres_put_16 (wrbfd, bdx.x, dialog->x);
1496 windres_put_16 (wrbfd, bdx.y, dialog->y);
1497 windres_put_16 (wrbfd, bdx.width, dialog->width);
1498 windres_put_16 (wrbfd, bdx.height, dialog->height);
1499 }
252b5132
RH
1500 }
1501
4a594fce 1502 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
252b5132 1503
4a594fce
NC
1504 off = resid_to_bin (wrbfd, off, dialog->menu);
1505 off = resid_to_bin (wrbfd, off, dialog->class);
1506 off = unicode_to_bin (wrbfd, off, dialog->caption);
252b5132
RH
1507
1508 if ((dialog->style & DS_SETFONT) != 0)
1509 {
4a594fce 1510 if (wrbfd)
252b5132 1511 {
4a594fce 1512 if (! dialogex)
252b5132 1513 {
4a594fce
NC
1514 struct bin_dialogfont bdf;
1515 windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1516 set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
252b5132
RH
1517 }
1518 else
1519 {
4a594fce
NC
1520 struct bin_dialogexfont bdxf;
1521 windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1522 windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1523 windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1524 windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1525 set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
252b5132
RH
1526 }
1527 }
4a594fce
NC
1528 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1529 off = unicode_to_bin (wrbfd, off, dialog->font);
252b5132 1530 }
4a594fce 1531 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
252b5132 1532 {
4a594fce 1533 bfd_byte dc_rclen[2];
252b5132 1534
4a594fce
NC
1535 off += (4 - ((off - off_delta) & 3)) & 3;
1536 if (wrbfd)
1537 {
252b5132
RH
1538 if (! dialogex)
1539 {
4a594fce
NC
1540 struct bin_dialog_control bdc;
1541
1542 windres_put_32 (wrbfd, bdc.style, dc->style);
1543 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1544 windres_put_16 (wrbfd, bdc.x, dc->x);
1545 windres_put_16 (wrbfd, bdc.y, dc->y);
1546 windres_put_16 (wrbfd, bdc.width, dc->width);
1547 windres_put_16 (wrbfd, bdc.height, dc->height);
1548 windres_put_16 (wrbfd, bdc.id, dc->id);
1549 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
252b5132
RH
1550 }
1551 else
1552 {
4a594fce
NC
1553 struct bin_dialogex_control bdc;
1554
1555 windres_put_32 (wrbfd, bdc.help, dc->help);
1556 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1557 windres_put_32 (wrbfd, bdc.style, dc->style);
1558 windres_put_16 (wrbfd, bdc.x, dc->x);
1559 windres_put_16 (wrbfd, bdc.y, dc->y);
1560 windres_put_16 (wrbfd, bdc.width, dc->width);
1561 windres_put_16 (wrbfd, bdc.height, dc->height);
1562 windres_put_32 (wrbfd, bdc.id, dc->id);
1563 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1564 }
3aade688 1565 }
4a594fce 1566 off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
252b5132 1567
4a594fce
NC
1568 off = resid_to_bin (wrbfd, off, dc->class);
1569 off = resid_to_bin (wrbfd, off, dc->text);
252b5132 1570
4a594fce
NC
1571 marker = off; /* Save two bytes for size of optional data. */
1572 off += 2;
252b5132
RH
1573
1574 if (dc->data == NULL)
4a594fce
NC
1575 {
1576 if (wrbfd)
1577 windres_put_16 (wrbfd, dc_rclen, 0);
1578 }
252b5132
RH
1579 else
1580 {
4a594fce
NC
1581 rc_uint_type saved_off = off;
1582 rc_uint_type old_off;
4a594fce
NC
1583
1584 old_off = off;
1585 off = res_to_bin_rcdata (wrbfd, off, dc->data);
1586 if ((off - old_off) == 0)
1587 old_off = off = saved_off;
1588 if (wrbfd)
1589 windres_put_16 (wrbfd, dc_rclen, off - old_off);
6bb21700 1590 }
4a594fce
NC
1591 if (wrbfd)
1592 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
6bb21700 1593 }
4a594fce
NC
1594
1595 if (wrbfd)
1596 {
1597 windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1598 if (! dialogex)
1599 set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1600 else
1601 set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
252b5132 1602 }
252b5132 1603
4a594fce 1604 return off;
252b5132
RH
1605}
1606
1607/* Convert a fontdir resource to binary. */
4a594fce
NC
1608static rc_uint_type
1609res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
252b5132 1610{
4a594fce 1611 rc_uint_type start;
252b5132 1612 int c;
4a594fce 1613 const rc_fontdir *fd;
252b5132 1614
4a594fce
NC
1615 start = off;
1616 off += 2;
252b5132 1617
4a594fce 1618 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
252b5132 1619 {
4a594fce
NC
1620 if (wrbfd)
1621 {
1622 bfd_byte d[2];
1623 windres_put_16 (wrbfd, d, fd->index);
1624 set_windres_bfd_content (wrbfd, d, off, 2);
1625 if (fd->length)
1626 set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1627 }
1628 off += (rc_uint_type) fd->length + 2;
252b5132
RH
1629 }
1630
4a594fce
NC
1631 if (wrbfd)
1632 {
1633 bfd_byte d[2];
1634 windres_put_16 (wrbfd, d, c);
1635 set_windres_bfd_content (wrbfd, d, start, 2);
1636 }
1637 return off;
252b5132
RH
1638}
1639
1640/* Convert a group icon resource to binary. */
1641
4a594fce
NC
1642static rc_uint_type
1643res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
252b5132 1644{
4a594fce
NC
1645 rc_uint_type start;
1646 struct bin_group_icon bgi;
252b5132 1647 int c;
4a594fce 1648 const rc_group_icon *gi;
252b5132 1649
4a594fce
NC
1650 start = off;
1651 off += BIN_GROUP_ICON_SIZE;
252b5132 1652
4a594fce 1653 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
252b5132 1654 {
4a594fce 1655 struct bin_group_icon_item bgii;
252b5132 1656
4a594fce
NC
1657 if (wrbfd)
1658 {
1659 windres_put_8 (wrbfd, bgii.width, gi->width);
1660 windres_put_8 (wrbfd, bgii.height, gi->height);
1661 windres_put_8 (wrbfd, bgii.colors, gi->colors);
1662 windres_put_8 (wrbfd, bgii.pad, 0);
1663 windres_put_16 (wrbfd, bgii.planes, gi->planes);
1664 windres_put_16 (wrbfd, bgii.bits, gi->bits);
1665 windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1666 windres_put_16 (wrbfd, bgii.index, gi->index);
1667 set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1668 }
1669 off += BIN_GROUP_ICON_ITEM_SIZE;
252b5132
RH
1670 }
1671
4a594fce
NC
1672 if (wrbfd)
1673 {
1674 windres_put_16 (wrbfd, bgi.sig1, 0);
1675 windres_put_16 (wrbfd, bgi.sig2, 1);
1676 windres_put_16 (wrbfd, bgi.count, c);
1677 set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1678 }
1679 return off;
252b5132
RH
1680}
1681
1682/* Convert a menu resource to binary. */
1683
4a594fce
NC
1684static rc_uint_type
1685res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
252b5132
RH
1686{
1687 int menuex;
252b5132
RH
1688
1689 menuex = extended_menu (menu);
1690
4a594fce
NC
1691 if (wrbfd)
1692 {
252b5132
RH
1693 if (! menuex)
1694 {
4a594fce
NC
1695 struct bin_menu bm;
1696 windres_put_16 (wrbfd, bm.sig1, 0);
1697 windres_put_16 (wrbfd, bm.sig2, 0);
1698 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
252b5132
RH
1699 }
1700 else
1701 {
4a594fce
NC
1702 struct bin_menuex bm;
1703 windres_put_16 (wrbfd, bm.sig1, 1);
1704 windres_put_16 (wrbfd, bm.sig2, 4);
1705 windres_put_32 (wrbfd, bm.help, menu->help);
1706 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
252b5132 1707 }
4a594fce
NC
1708 }
1709 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1710 if (! menuex)
1711 {
1712 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1713 }
1714 else
1715 {
1716 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1717 }
1718 return off;
252b5132
RH
1719}
1720
1721/* Convert menu items to binary. */
1722
4a594fce
NC
1723static rc_uint_type
1724res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
252b5132 1725{
4a594fce 1726 const rc_menuitem *mi;
252b5132
RH
1727
1728 for (mi = items; mi != NULL; mi = mi->next)
1729 {
4a594fce 1730 struct bin_menuitem bmi;
252b5132
RH
1731 int flags;
1732
252b5132
RH
1733 flags = mi->type;
1734 if (mi->next == NULL)
1735 flags |= MENUITEM_ENDMENU;
1736 if (mi->popup != NULL)
1737 flags |= MENUITEM_POPUP;
1738
4a594fce
NC
1739 if (wrbfd)
1740 {
1741 windres_put_16 (wrbfd, bmi.flags, flags);
252b5132 1742 if (mi->popup == NULL)
4a594fce
NC
1743 windres_put_16 (wrbfd, bmi.id, mi->id);
1744 set_windres_bfd_content (wrbfd, &bmi, off,
1745 mi->popup == NULL ? BIN_MENUITEM_SIZE
1746 : BIN_MENUITEM_POPUP_SIZE);
1747 }
1748 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
252b5132 1749
4a594fce 1750 off = unicode_to_bin (wrbfd, off, mi->text);
252b5132
RH
1751
1752 if (mi->popup != NULL)
1753 {
4a594fce 1754 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
252b5132
RH
1755 }
1756 }
4a594fce 1757 return off;
252b5132
RH
1758}
1759
1760/* Convert menuex items to binary. */
1761
4a594fce
NC
1762static rc_uint_type
1763res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
252b5132 1764{
4a594fce
NC
1765 rc_uint_type off_delta = off;
1766 const rc_menuitem *mi;
252b5132
RH
1767
1768 for (mi = items; mi != NULL; mi = mi->next)
1769 {
4a594fce 1770 struct bin_menuitemex bmi;
252b5132
RH
1771 int flags;
1772
4a594fce 1773 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132
RH
1774
1775 flags = 0;
1776 if (mi->next == NULL)
1777 flags |= 0x80;
1778 if (mi->popup != NULL)
1779 flags |= 1;
252b5132 1780
4a594fce
NC
1781 if (wrbfd)
1782 {
1783 windres_put_32 (wrbfd, bmi.type, mi->type);
1784 windres_put_32 (wrbfd, bmi.state, mi->state);
1785 windres_put_32 (wrbfd, bmi.id, mi->id);
1786 windres_put_16 (wrbfd, bmi.flags, flags);
1787 set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1788 }
1789 off += BIN_MENUITEMEX_SIZE;
252b5132 1790
4a594fce 1791 off = unicode_to_bin (wrbfd, off, mi->text);
252b5132
RH
1792
1793 if (mi->popup != NULL)
1794 {
4a594fce 1795 bfd_byte help[4];
252b5132 1796
4a594fce 1797 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 1798
4a594fce 1799 if (wrbfd)
252b5132 1800 {
4a594fce
NC
1801 windres_put_32 (wrbfd, help, mi->help);
1802 set_windres_bfd_content (wrbfd, help, off, 4);
252b5132 1803 }
4a594fce
NC
1804 off += 4;
1805 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
252b5132
RH
1806 }
1807 }
4a594fce 1808 return off;
252b5132
RH
1809}
1810
1811/* Convert an rcdata resource to binary. This is also used to convert
4a594fce 1812 other information which happens to be stored in rc_rcdata_item lists
252b5132
RH
1813 to binary. */
1814
4a594fce
NC
1815static rc_uint_type
1816res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
252b5132 1817{
4a594fce 1818 const rc_rcdata_item *ri;
252b5132
RH
1819
1820 for (ri = items; ri != NULL; ri = ri->next)
1821 {
4a594fce 1822 rc_uint_type len;
252b5132
RH
1823 switch (ri->type)
1824 {
1825 default:
1826 abort ();
252b5132 1827 case RCDATA_WORD:
4a594fce 1828 len = 2;
252b5132 1829 break;
252b5132 1830 case RCDATA_DWORD:
4a594fce 1831 len = 4;
252b5132 1832 break;
252b5132 1833 case RCDATA_STRING:
4a594fce
NC
1834 len = ri->u.string.length;
1835 break;
1836 case RCDATA_WSTRING:
1837 len = ri->u.wstring.length * sizeof (unichar);
1838 break;
1839 case RCDATA_BUFFER:
1840 len = ri->u.buffer.length;
1841 break;
1842 }
1843 if (wrbfd)
1844 {
1845 bfd_byte h[4];
1846 bfd_byte *hp = &h[0];
1847 switch (ri->type)
1848 {
1849 case RCDATA_WORD:
1850 windres_put_16 (wrbfd, hp, ri->u.word);
1851 break;
1852 case RCDATA_DWORD:
1853 windres_put_32 (wrbfd, hp, ri->u.dword);
1854 break;
1855 case RCDATA_STRING:
1856 hp = (bfd_byte *) ri->u.string.s;
252b5132 1857 break;
252b5132
RH
1858 case RCDATA_WSTRING:
1859 {
4a594fce 1860 rc_uint_type i;
252b5132 1861
4a594fce 1862 hp = (bfd_byte *) reswr_alloc (len);
252b5132 1863 for (i = 0; i < ri->u.wstring.length; i++)
4a594fce 1864 windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
252b5132 1865 }
4a594fce 1866 break;
252b5132 1867 case RCDATA_BUFFER:
4a594fce 1868 hp = (bfd_byte *) ri->u.buffer.data;
252b5132
RH
1869 break;
1870 }
4a594fce 1871 set_windres_bfd_content (wrbfd, hp, off, len);
252b5132 1872 }
4a594fce
NC
1873 off += len;
1874 }
1875 return off;
252b5132
RH
1876}
1877
1878/* Convert a stringtable resource to binary. */
1879
4a594fce
NC
1880static rc_uint_type
1881res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1882 const rc_stringtable *st)
252b5132 1883{
252b5132
RH
1884 int i;
1885
252b5132
RH
1886 for (i = 0; i < 16; i++)
1887 {
4a594fce 1888 rc_uint_type slen, length;
252b5132
RH
1889 unichar *s;
1890
4a594fce 1891 slen = (rc_uint_type) st->strings[i].length;
8b6efd89 1892 if (slen == 0xffffffff) slen = 0;
252b5132
RH
1893 s = st->strings[i].string;
1894
4a594fce
NC
1895 length = 2 + slen * 2;
1896 if (wrbfd)
1897 {
1898 bfd_byte *hp;
1899 rc_uint_type j;
252b5132 1900
4a594fce
NC
1901 hp = (bfd_byte *) reswr_alloc (length);
1902 windres_put_16 (wrbfd, hp, slen);
252b5132
RH
1903
1904 for (j = 0; j < slen; j++)
4a594fce
NC
1905 windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1906 set_windres_bfd_content (wrbfd, hp, off, length);
252b5132 1907 }
4a594fce
NC
1908 off += length;
1909 }
1910 return off;
252b5132
RH
1911}
1912
1913/* Convert an ASCII string to a unicode binary string. This always
1914 returns exactly one bindata structure. */
1915
4a594fce
NC
1916static rc_uint_type
1917string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
252b5132 1918{
4a594fce 1919 rc_uint_type len;
252b5132 1920
4a594fce 1921 len = (rc_uint_type) strlen (s);
252b5132 1922
4a594fce
NC
1923 if (wrbfd)
1924 {
1925 rc_uint_type i;
1926 bfd_byte *hp;
252b5132 1927
4a594fce 1928 hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
252b5132 1929
4a594fce
NC
1930 for (i = 0; i < len; i++)
1931 windres_put_16 (wrbfd, hp + i * 2, s[i]);
1932 windres_put_16 (wrbfd, hp + i * 2, 0);
1933 set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1934 }
1935 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1936 return off;
252b5132
RH
1937}
1938
4a594fce
NC
1939static rc_uint_type
1940res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
252b5132 1941{
4a594fce
NC
1942 if (wrbfd)
1943 {
1944 struct bin_toolbar bt;
1945 windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1946 windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1947 windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1948 set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1949 if (tb->nitems > 0)
1950 {
1951 rc_toolbar_item *it;
1952 bfd_byte *ids;
1953 rc_uint_type i = 0;
252b5132 1954
4a594fce
NC
1955 ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1956 it=tb->items;
1957 while(it != NULL)
1958 {
1959 windres_put_32 (wrbfd, ids + i, it->id.u.id);
1960 i += 4;
1961 it = it->next;
1962 }
1963 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1964 }
1965 }
1966 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
252b5132 1967
4a594fce
NC
1968 return off;
1969}
252b5132 1970
4a594fce 1971/* Convert a versioninfo resource to binary. */
252b5132 1972
4a594fce
NC
1973static rc_uint_type
1974res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1975 const rc_versioninfo *versioninfo)
1976{
1977 rc_uint_type off_delta = off;
1978 rc_uint_type start;
1979 struct bin_versioninfo bvi;
1980 rc_ver_info *vi;
252b5132 1981
4a594fce
NC
1982 start = off;
1983 off += BIN_VERSIONINFO_SIZE;
1984 off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1985 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132
RH
1986
1987 if (versioninfo->fixed != NULL)
1988 {
4a594fce
NC
1989 if (wrbfd)
1990 {
1991 struct bin_fixed_versioninfo bfv;
1992 const rc_fixed_versioninfo *fi;
252b5132
RH
1993
1994 fi = versioninfo->fixed;
4a594fce
NC
1995 windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1996 windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1997 windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1998 windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1999 windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2000 windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2001 windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2002 windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2003 windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2004 windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2005 windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2006 windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2007 windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2008 set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2009 }
2010 off += BIN_FIXED_VERSIONINFO_SIZE;
252b5132
RH
2011 }
2012
2013 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2014 {
4a594fce
NC
2015 struct bin_ver_info bv;
2016 rc_uint_type bv_off;
252b5132 2017
4a594fce 2018 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2019
4a594fce 2020 bv_off = off;
252b5132 2021
4a594fce 2022 off += BIN_VER_INFO_SIZE;
252b5132
RH
2023
2024 switch (vi->type)
2025 {
2026 default:
2027 abort ();
252b5132
RH
2028 case VERINFO_STRING:
2029 {
bfb6c1ab 2030 const rc_ver_stringtable *vst;
252b5132 2031
4a594fce 2032 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
252b5132 2033
bfb6c1ab
NC
2034 if (!vi->u.string.stringtables)
2035 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2036
bfb6c1ab 2037 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
4a594fce 2038 {
bfb6c1ab
NC
2039 struct bin_ver_info bvst;
2040 rc_uint_type vst_off;
2041 const rc_ver_stringinfo *vs;
252b5132 2042
4a594fce 2043 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2044
bfb6c1ab 2045 vst_off = off;
4a594fce 2046 off += BIN_VER_INFO_SIZE;
252b5132 2047
bfb6c1ab 2048 off = unicode_to_bin (wrbfd, off, vst->language);
252b5132 2049
bfb6c1ab
NC
2050 for (vs = vst->strings; vs != NULL; vs = vs->next)
2051 {
2052 struct bin_ver_info bvs;
2053 rc_uint_type vs_off, str_off;
2054
2055 off += (4 - ((off - off_delta) & 3)) & 3;
2056
2057 vs_off = off;
2058 off += BIN_VER_INFO_SIZE;
2059
2060 off = unicode_to_bin (wrbfd, off, vs->key);
2061
2062 off += (4 - ((off - off_delta) & 3)) & 3;
2063
2064 str_off = off;
2065 off = unicode_to_bin (wrbfd, off, vs->value);
2066
2067 if (wrbfd)
2068 {
2069 windres_put_16 (wrbfd, bvs.size, off - vs_off);
2070 windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2071 windres_put_16 (wrbfd, bvs.sig2, 1);
2072 set_windres_bfd_content (wrbfd, &bvs, vs_off,
2073 BIN_VER_INFO_SIZE);
2074 }
2075 }
252b5132 2076
4a594fce
NC
2077 if (wrbfd)
2078 {
bfb6c1ab
NC
2079 windres_put_16 (wrbfd, bvst.size, off - vst_off);
2080 windres_put_16 (wrbfd, bvst.sig1, 0);
2081 windres_put_16 (wrbfd, bvst.sig2, 1);
2082 set_windres_bfd_content (wrbfd, &bvst, vst_off,
2083 BIN_VER_INFO_SIZE);
4a594fce
NC
2084 }
2085 }
252b5132
RH
2086 break;
2087 }
2088
2089 case VERINFO_VAR:
2090 {
4a594fce
NC
2091 rc_uint_type vvd_off, vvvd_off;
2092 struct bin_ver_info bvvd;
2093 const rc_ver_varinfo *vv;
252b5132 2094
4a594fce 2095 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
252b5132 2096
4a594fce 2097 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2098
4a594fce
NC
2099 vvd_off = off;
2100 off += BIN_VER_INFO_SIZE;
252b5132 2101
4a594fce 2102 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
252b5132 2103
4a594fce 2104 off += (4 - ((off - off_delta) & 3)) & 3;
252b5132 2105
4a594fce 2106 vvvd_off = off;
252b5132
RH
2107
2108 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2109 {
4a594fce
NC
2110 if (wrbfd)
2111 {
2112 bfd_byte vvsd[4];
2113
2114 windres_put_16 (wrbfd, &vvsd[0], vv->language);
2115 windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2116 set_windres_bfd_content (wrbfd, vvsd, off, 4);
2117 }
2118 off += 4;
252b5132 2119 }
4a594fce
NC
2120 if (wrbfd)
2121 {
2122 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2123 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2124 windres_put_16 (wrbfd, bvvd.sig2, 0);
2125 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2126 BIN_VER_INFO_SIZE);
2127 }
252b5132
RH
2128
2129 break;
2130 }
2131 }
2132
4a594fce
NC
2133 if (wrbfd)
2134 {
bfb6c1ab 2135 windres_put_16 (wrbfd, bv.size, off - bv_off);
4a594fce 2136 windres_put_16 (wrbfd, bv.sig1, 0);
bfb6c1ab 2137 windres_put_16 (wrbfd, bv.sig2, 1);
4a594fce
NC
2138 set_windres_bfd_content (wrbfd, &bv, bv_off,
2139 BIN_VER_INFO_SIZE);
2140 }
252b5132
RH
2141 }
2142
4a594fce
NC
2143 if (wrbfd)
2144 {
2145 windres_put_16 (wrbfd, bvi.size, off - start);
2146 windres_put_16 (wrbfd, bvi.fixed_size,
2147 versioninfo->fixed == NULL ? 0
2148 : BIN_FIXED_VERSIONINFO_SIZE);
2149 windres_put_16 (wrbfd, bvi.sig2, 0);
2150 set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2151 }
2152 return off;
252b5132
RH
2153}
2154
2155/* Convert a generic resource to binary. */
2156
4a594fce
NC
2157static rc_uint_type
2158res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2159 const bfd_byte *data)
252b5132 2160{
4a594fce
NC
2161 if (wrbfd && length != 0)
2162 set_windres_bfd_content (wrbfd, data, off, length);
2163 return off + (rc_uint_type) length;
252b5132 2164}