wrc: Explicitly define structure creation functions instead of playing with macros.
[wine.git] / tools / wrc / newstruc.c
blobc157cb41eea24e834e41ab05e4dc6c1bf5c0c097
1 /*
2 * Create dynamic new structures of various types
3 * and some utils in that trend.
5 * Copyright 1998 Bertho A. Stultiens
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <ctype.h>
30 #include "wrc.h"
31 #include "newstruc.h"
32 #include "utils.h"
33 #include "parser.h"
35 #include "wingdi.h" /* for BITMAPINFOHEADER */
37 #include <pshpack2.h>
38 typedef struct
40 DWORD biSize;
41 WORD biWidth;
42 WORD biHeight;
43 WORD biPlanes;
44 WORD biBitCount;
45 } BITMAPOS2HEADER;
46 #include <poppack.h>
48 /* New instances for all types of structures */
49 /* Very inefficient (in size), but very functional :-]
50 * Especially for type-checking.
53 dialog_t *new_dialog(void)
55 dialog_t *ret = xmalloc( sizeof(*ret) );
56 memset( ret, 0, sizeof(*ret) );
57 return ret;
60 name_id_t *new_name_id(void)
62 name_id_t *ret = xmalloc( sizeof(*ret) );
63 memset( ret, 0, sizeof(*ret) );
64 return ret;
67 menu_t *new_menu(void)
69 menu_t *ret = xmalloc( sizeof(*ret) );
70 memset( ret, 0, sizeof(*ret) );
71 return ret;
74 menu_item_t *new_menu_item(void)
76 menu_item_t *ret = xmalloc( sizeof(*ret) );
77 memset( ret, 0, sizeof(*ret) );
78 return ret;
81 control_t *new_control(void)
83 control_t *ret = xmalloc( sizeof(*ret) );
84 memset( ret, 0, sizeof(*ret) );
85 return ret;
88 icon_t *new_icon(void)
90 icon_t *ret = xmalloc( sizeof(*ret) );
91 memset( ret, 0, sizeof(*ret) );
92 return ret;
95 cursor_t *new_cursor(void)
97 cursor_t *ret = xmalloc( sizeof(*ret) );
98 memset( ret, 0, sizeof(*ret) );
99 return ret;
102 versioninfo_t *new_versioninfo(void)
104 versioninfo_t *ret = xmalloc( sizeof(*ret) );
105 memset( ret, 0, sizeof(*ret) );
106 return ret;
109 ver_value_t *new_ver_value(void)
111 ver_value_t *ret = xmalloc( sizeof(*ret) );
112 memset( ret, 0, sizeof(*ret) );
113 return ret;
116 ver_block_t *new_ver_block(void)
118 ver_block_t *ret = xmalloc( sizeof(*ret) );
119 memset( ret, 0, sizeof(*ret) );
120 return ret;
123 stt_entry_t *new_stt_entry(void)
125 stt_entry_t *ret = xmalloc( sizeof(*ret) );
126 memset( ret, 0, sizeof(*ret) );
127 return ret;
130 accelerator_t *new_accelerator(void)
132 accelerator_t *ret = xmalloc( sizeof(*ret) );
133 memset( ret, 0, sizeof(*ret) );
134 return ret;
137 event_t *new_event(void)
139 event_t *ret = xmalloc( sizeof(*ret) );
140 memset( ret, 0, sizeof(*ret) );
141 return ret;
144 raw_data_t *new_raw_data(void)
146 raw_data_t *ret = xmalloc( sizeof(*ret) );
147 memset( ret, 0, sizeof(*ret) );
148 return ret;
151 lvc_t *new_lvc(void)
153 lvc_t *ret = xmalloc( sizeof(*ret) );
154 memset( ret, 0, sizeof(*ret) );
155 return ret;
158 res_count_t *new_res_count(void)
160 res_count_t *ret = xmalloc( sizeof(*ret) );
161 memset( ret, 0, sizeof(*ret) );
162 return ret;
165 string_t *new_string(void)
167 string_t *ret = xmalloc( sizeof(*ret) );
168 memset( ret, 0, sizeof(*ret) );
169 return ret;
172 toolbar_item_t *new_toolbar_item(void)
174 toolbar_item_t *ret = xmalloc( sizeof(*ret) );
175 memset( ret, 0, sizeof(*ret) );
176 return ret;
179 ani_any_t *new_ani_any(void)
181 ani_any_t *ret = xmalloc( sizeof(*ret) );
182 memset( ret, 0, sizeof(*ret) );
183 return ret;
186 resource_t *new_resource(enum res_e t, void *res, int memopt, language_t *lan)
188 resource_t *r = xmalloc(sizeof(resource_t));
189 memset( r, 0, sizeof(*r) );
190 r->type = t;
191 r->res.overlay = res;
192 r->memopt = memopt;
193 r->lan = lan;
194 return r;
197 version_t *new_version(DWORD v)
199 version_t *vp = xmalloc(sizeof(version_t));
200 *vp = v;
201 return vp;
204 characts_t *new_characts(DWORD c)
206 characts_t *cp = xmalloc(sizeof(characts_t));
207 *cp = c;
208 return cp;
211 language_t *new_language(int id, int sub)
213 language_t *lan = xmalloc(sizeof(language_t));
214 lan->id = id;
215 lan->sub = sub;
216 return lan;
219 language_t *dup_language(language_t *l)
221 if(!l) return NULL;
222 return new_language(l->id, l->sub);
225 version_t *dup_version(version_t *v)
227 if(!v) return NULL;
228 return new_version(*v);
231 characts_t *dup_characts(characts_t *c)
233 if(!c) return NULL;
234 return new_characts(*c);
237 html_t *new_html(raw_data_t *rd, int *memopt)
239 html_t *html = xmalloc(sizeof(html_t));
240 html->data = rd;
241 if(memopt)
243 html->memopt = *memopt;
244 free(memopt);
246 else
247 html->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
248 return html;
251 rcdata_t *new_rcdata(raw_data_t *rd, int *memopt)
253 rcdata_t *rc = xmalloc(sizeof(rcdata_t));
254 rc->data = rd;
255 if(memopt)
257 rc->memopt = *memopt;
258 free(memopt);
260 else
261 rc->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
262 return rc;
265 font_id_t *new_font_id(int size, string_t *face, int weight, int italic)
267 font_id_t *fid = xmalloc(sizeof(font_id_t));
268 fid->name = face;
269 fid->size = size;
270 fid->weight = weight;
271 fid->italic = italic;
272 return fid;
275 user_t *new_user(name_id_t *type, raw_data_t *rd, int *memopt)
277 user_t *usr = xmalloc(sizeof(user_t));
278 usr->data = rd;
279 if(memopt)
281 usr->memopt = *memopt;
282 free(memopt);
284 else
285 usr->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
286 usr->type = type;
287 return usr;
290 font_t *new_font(raw_data_t *rd, int *memopt)
292 font_t *fnt = xmalloc(sizeof(font_t));
293 fnt->data = rd;
294 if(memopt)
296 fnt->memopt = *memopt;
297 free(memopt);
299 else
300 fnt->memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE;
301 return fnt;
304 fontdir_t *new_fontdir(raw_data_t *rd, int *memopt)
306 fontdir_t *fnd = xmalloc(sizeof(fontdir_t));
307 fnd->data = rd;
308 if(memopt)
310 fnd->memopt = *memopt;
311 free(memopt);
313 else
314 fnd->memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE;
315 return fnd;
320 * Convert bitmaps to proper endian
322 static void convert_bitmap_swap(BITMAPV5HEADER *bh, DWORD size)
324 bh->bV5Size = BYTESWAP_DWORD(bh->bV5Size);
325 bh->bV5Width = BYTESWAP_DWORD(bh->bV5Width);
326 bh->bV5Height = BYTESWAP_DWORD(bh->bV5Height);
327 bh->bV5Planes = BYTESWAP_WORD(bh->bV5Planes);
328 bh->bV5BitCount = BYTESWAP_WORD(bh->bV5BitCount);
329 bh->bV5Compression = BYTESWAP_DWORD(bh->bV5Compression);
330 bh->bV5SizeImage = BYTESWAP_DWORD(bh->bV5SizeImage);
331 bh->bV5XPelsPerMeter = BYTESWAP_DWORD(bh->bV5XPelsPerMeter);
332 bh->bV5YPelsPerMeter = BYTESWAP_DWORD(bh->bV5YPelsPerMeter);
333 bh->bV5ClrUsed = BYTESWAP_DWORD(bh->bV5ClrUsed);
334 bh->bV5ClrImportant = BYTESWAP_DWORD(bh->bV5ClrImportant);
335 if (size == sizeof(BITMAPINFOHEADER)) return;
336 bh->bV5RedMask = BYTESWAP_DWORD(bh->bV5RedMask);
337 bh->bV5GreenMask = BYTESWAP_DWORD(bh->bV5GreenMask);
338 bh->bV5BlueMask = BYTESWAP_DWORD(bh->bV5BlueMask);
339 bh->bV5AlphaMask = BYTESWAP_DWORD(bh->bV5AlphaMask);
340 bh->bV5CSType = BYTESWAP_DWORD(bh->bV5CSType);
341 bh->bV5Endpoints.ciexyzRed.ciexyzX = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzRed.ciexyzX);
342 bh->bV5Endpoints.ciexyzRed.ciexyzY = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzRed.ciexyzY);
343 bh->bV5Endpoints.ciexyzRed.ciexyzZ = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzRed.ciexyzZ);
344 bh->bV5Endpoints.ciexyzGreen.ciexyzX = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzGreen.ciexyzX);
345 bh->bV5Endpoints.ciexyzGreen.ciexyzY = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzGreen.ciexyzY);
346 bh->bV5Endpoints.ciexyzGreen.ciexyzZ = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzGreen.ciexyzZ);
347 bh->bV5Endpoints.ciexyzBlue.ciexyzX = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzBlue.ciexyzX);
348 bh->bV5Endpoints.ciexyzBlue.ciexyzY = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzBlue.ciexyzY);
349 bh->bV5Endpoints.ciexyzBlue.ciexyzZ = BYTESWAP_DWORD(bh->bV5Endpoints.ciexyzBlue.ciexyzZ);
350 bh->bV5GammaRed = BYTESWAP_DWORD(bh->bV5GammaRed);
351 bh->bV5GammaGreen = BYTESWAP_DWORD(bh->bV5GammaGreen);
352 bh->bV5GammaBlue = BYTESWAP_DWORD(bh->bV5GammaBlue);
353 if (size == sizeof(BITMAPV4HEADER)) return;
354 bh->bV5Intent = BYTESWAP_DWORD(bh->bV5Intent);
355 bh->bV5ProfileData = BYTESWAP_DWORD(bh->bV5ProfileData);
356 bh->bV5ProfileSize = BYTESWAP_DWORD(bh->bV5ProfileSize);
357 bh->bV5Reserved = BYTESWAP_DWORD(bh->bV5Reserved);
360 static void convert_bitmap_swap_os2(BITMAPOS2HEADER *boh)
362 boh->biSize = BYTESWAP_DWORD(boh->biSize);
363 boh->biWidth = BYTESWAP_WORD(boh->biWidth);
364 boh->biHeight = BYTESWAP_WORD(boh->biHeight);
365 boh->biPlanes = BYTESWAP_WORD(boh->biPlanes);
366 boh->biBitCount = BYTESWAP_WORD(boh->biBitCount);
369 #define FL_SIGBE 0x01
370 #define FL_SIZEBE 0x02
371 static int convert_bitmap(char *data, int size)
373 BITMAPV5HEADER *bih = (BITMAPV5HEADER *)data;
374 BITMAPOS2HEADER *boh = (BITMAPOS2HEADER *)data;
375 DWORD bmsize;
376 int type = 0;
377 int returnSize = 0; /* size to be returned */
380 * Originally the bih and b4h pointers were simply incremented here,
381 * and memmoved at the end of the function. This causes alignment
382 * issues on solaris, so we do the memmove here rather than at the end.
384 if(data[0] == 'B' && data[1] == 'M')
386 /* Little endian signature */
387 memmove(data, data+sizeof(BITMAPFILEHEADER), size - sizeof(BITMAPFILEHEADER));
388 returnSize = sizeof(BITMAPFILEHEADER);
390 else if(data[0] == 'M' && data[1] == 'B')
392 type |= FL_SIGBE; /* Big endian signature */
393 memmove(data, data+sizeof(BITMAPFILEHEADER), size - sizeof(BITMAPFILEHEADER));
394 returnSize = sizeof(BITMAPFILEHEADER);
398 bmsize = bih->bV5Size;
399 if (bmsize >> 16) /* assume swapped */
401 #ifndef WORDS_BIGENDIAN
402 type |= FL_SIZEBE;
403 #endif
404 bmsize = BYTESWAP_DWORD( bmsize );
406 else
408 #ifdef WORDS_BIGENDIAN
409 type |= FL_SIZEBE;
410 #endif
413 switch (bmsize)
415 case sizeof(BITMAPOS2HEADER):
416 case sizeof(BITMAPINFOHEADER):
417 case sizeof(BITMAPV4HEADER):
418 case sizeof(BITMAPV5HEADER):
419 break;
420 default:
421 parser_error("Invalid bitmap format, bih->biSize = %d", bih->bV5Size);
424 switch(type)
426 case FL_SIZEBE:
427 parser_warning("Bitmap signature little-endian, but size big-endian\n");
428 break;
429 case FL_SIGBE:
430 parser_warning("Bitmap signature big-endian, but size little-endian\n");
431 break;
434 switch(byteorder)
436 #ifdef WORDS_BIGENDIAN
437 default:
438 #endif
439 case WRC_BO_BIG:
440 if(!(type & FL_SIZEBE))
442 if (bmsize == sizeof(BITMAPOS2HEADER))
443 convert_bitmap_swap_os2(boh);
444 else
445 convert_bitmap_swap(bih, bmsize);
447 break;
448 #ifndef WORDS_BIGENDIAN
449 default:
450 #endif
451 case WRC_BO_LITTLE:
452 if(type & FL_SIZEBE)
454 if (bmsize == sizeof(BITMAPOS2HEADER))
455 convert_bitmap_swap_os2(boh);
456 else
457 convert_bitmap_swap(bih, bmsize);
459 break;
462 if(size && (void *)data != (void *)bih)
464 /* We have the fileheader still attached, remove it */
465 memmove(data, data+sizeof(BITMAPFILEHEADER), size - sizeof(BITMAPFILEHEADER));
466 return sizeof(BITMAPFILEHEADER);
468 return returnSize;
470 #undef FL_SIGBE
471 #undef FL_SIZEBE
474 * Cursor and icon splitter functions used when allocating
475 * cursor- and icon-groups.
477 typedef struct {
478 language_t lan;
479 int id;
480 } id_alloc_t;
482 static int get_new_id(id_alloc_t **list, int *n, language_t *lan)
484 int i;
485 assert(lan != NULL);
486 assert(list != NULL);
487 assert(n != NULL);
489 if(!*list)
491 *list = xmalloc(sizeof(id_alloc_t));
492 *n = 1;
493 (*list)[0].lan = *lan;
494 (*list)[0].id = 1;
495 return 1;
498 for(i = 0; i < *n; i++)
500 if((*list)[i].lan.id == lan->id && (*list)[i].lan.sub == lan->sub)
501 return ++((*list)[i].id);
504 *list = xrealloc(*list, sizeof(id_alloc_t) * (*n+1));
505 (*list)[*n].lan = *lan;
506 (*list)[*n].id = 1;
507 *n += 1;
508 return 1;
511 static int alloc_icon_id(language_t *lan)
513 static id_alloc_t *idlist = NULL;
514 static int nid = 0;
516 return get_new_id(&idlist, &nid, lan);
519 static int alloc_cursor_id(language_t *lan)
521 static id_alloc_t *idlist = NULL;
522 static int nid = 0;
524 return get_new_id(&idlist, &nid, lan);
527 static void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico)
529 int cnt;
530 int i;
531 icon_t *ico;
532 icon_t *list = NULL;
533 icon_header_t *ih = (icon_header_t *)rd->data;
534 int swap = 0;
536 if(ih->type == 1)
537 swap = 0;
538 else if(BYTESWAP_WORD(ih->type) == 1)
539 swap = 1;
540 else
541 parser_error("Icon resource data has invalid type id %d", ih->type);
543 cnt = swap ? BYTESWAP_WORD(ih->count) : ih->count;
544 for(i = 0; i < cnt; i++)
546 icon_dir_entry_t ide;
547 BITMAPINFOHEADER info;
548 memcpy(&ide, rd->data + sizeof(icon_header_t)
549 + i*sizeof(icon_dir_entry_t), sizeof(ide));
551 ico = new_icon();
552 ico->id = alloc_icon_id(icog->lvc.language);
553 ico->lvc = icog->lvc;
554 if(swap)
556 ide.offset = BYTESWAP_DWORD(ide.offset);
557 ide.ressize= BYTESWAP_DWORD(ide.ressize);
559 if(ide.offset > rd->size
560 || ide.offset + ide.ressize > rd->size)
561 parser_error("Icon resource data corrupt");
562 ico->width = ide.width;
563 ico->height = ide.height;
564 ico->nclr = ide.nclr;
565 ico->planes = swap ? BYTESWAP_WORD(ide.planes) : ide.planes;
566 ico->bits = swap ? BYTESWAP_WORD(ide.bits) : ide.bits;
567 memcpy(&info, rd->data + ide.offset, sizeof(info));
568 convert_bitmap((char *) &info, 0);
569 memcpy(rd->data + ide.offset, &info, sizeof(info));
571 if(!ico->planes)
573 /* Argh! They did not fill out the resdir structure */
574 /* The bitmap is in destination byteorder. We want native for our structures */
575 switch(byteorder)
577 #ifdef WORDS_BIGENDIAN
578 case WRC_BO_LITTLE:
579 #else
580 case WRC_BO_BIG:
581 #endif
582 ico->planes = BYTESWAP_WORD(info.biPlanes);
583 break;
584 default:
585 ico->planes = info.biPlanes;
588 if(!ico->bits)
590 /* Argh! They did not fill out the resdir structure */
591 /* The bitmap is in destination byteorder. We want native for our structures */
592 switch(byteorder)
594 #ifdef WORDS_BIGENDIAN
595 case WRC_BO_LITTLE:
596 #else
597 case WRC_BO_BIG:
598 #endif
599 ico->bits = BYTESWAP_WORD(info.biBitCount);
600 break;
601 default:
602 ico->bits = info.biBitCount;
605 ico->data = new_raw_data();
606 copy_raw_data(ico->data, rd, ide.offset, ide.ressize);
607 if(!list)
609 list = ico;
611 else
613 ico->next = list;
614 list->prev = ico;
615 list = ico;
618 icog->iconlist = list;
619 *nico = cnt;
622 static void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur)
624 int cnt;
625 int i;
626 cursor_t *cur;
627 cursor_t *list = NULL;
628 cursor_header_t *ch = (cursor_header_t *)rd->data;
629 int swap = 0;
631 if(ch->type == 2)
632 swap = 0;
633 else if(BYTESWAP_WORD(ch->type) == 2)
634 swap = 1;
635 else
636 parser_error("Cursor resource data has invalid type id %d", ch->type);
637 cnt = swap ? BYTESWAP_WORD(ch->count) : ch->count;
638 for(i = 0; i < cnt; i++)
640 cursor_dir_entry_t cde;
641 BITMAPINFOHEADER info;
642 memcpy(&cde, rd->data + sizeof(cursor_header_t)
643 + i*sizeof(cursor_dir_entry_t), sizeof(cde));
645 cur = new_cursor();
646 cur->id = alloc_cursor_id(curg->lvc.language);
647 cur->lvc = curg->lvc;
648 if(swap)
650 cde.offset = BYTESWAP_DWORD(cde.offset);
651 cde.ressize= BYTESWAP_DWORD(cde.ressize);
653 if(cde.offset > rd->size
654 || cde.offset + cde.ressize > rd->size)
655 parser_error("Cursor resource data corrupt");
656 cur->width = cde.width;
657 cur->height = cde.height;
658 cur->nclr = cde.nclr;
659 memcpy(&info, rd->data + cde.offset, sizeof(info));
660 convert_bitmap((char *)&info, 0);
661 memcpy(rd->data + cde.offset, &info, sizeof(info));
662 /* The bitmap is in destination byteorder. We want native for our structures */
663 switch(byteorder)
665 #ifdef WORDS_BIGENDIAN
666 case WRC_BO_LITTLE:
667 #else
668 case WRC_BO_BIG:
669 #endif
670 cur->planes = BYTESWAP_WORD(info.biPlanes);
671 cur->bits = BYTESWAP_WORD(info.biBitCount);
672 break;
673 default:
674 cur->planes = info.biPlanes;
675 cur->bits = info.biBitCount;
677 if(!win32 && (cur->planes != 1 || cur->bits != 1))
678 parser_warning("Win16 cursor contains colors\n");
679 cur->xhot = swap ? BYTESWAP_WORD(cde.xhot) : cde.xhot;
680 cur->yhot = swap ? BYTESWAP_WORD(cde.yhot) : cde.yhot;
681 cur->data = new_raw_data();
682 copy_raw_data(cur->data, rd, cde.offset, cde.ressize);
683 if(!list)
685 list = cur;
687 else
689 cur->next = list;
690 list->prev = cur;
691 list = cur;
694 curg->cursorlist = list;
695 *ncur = cnt;
699 icon_group_t *new_icon_group(raw_data_t *rd, int *memopt)
701 icon_group_t *icog = xmalloc(sizeof(icon_group_t));
702 if(memopt)
704 icog->memopt = *memopt;
705 free(memopt);
707 else
708 icog->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
709 icog->lvc = rd->lvc;
710 split_icons(rd, icog, &(icog->nicon));
711 free(rd->data);
712 free(rd);
713 return icog;
716 cursor_group_t *new_cursor_group(raw_data_t *rd, int *memopt)
718 cursor_group_t *curg = xmalloc(sizeof(cursor_group_t));
719 if(memopt)
721 curg->memopt = *memopt;
722 free(memopt);
724 else
725 curg->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
726 curg->lvc = rd->lvc;
727 split_cursors(rd, curg, &(curg->ncursor));
728 free(rd->data);
729 free(rd);
730 return curg;
734 * Animated cursors and icons
736 * The format of animated cursors and icons is yet another example
737 * of bad design by "The Company". The entire RIFF structure is
738 * flawed by design because it is inconsistent and single minded:
739 * - some tags have lengths attached, others don't. The use of these
740 * non-length tags is absolutely unclear;
741 * - the content of "icon" tags can be both icons and cursors;
742 * - tags lack proper alignment constraints. It seems that everything
743 * is 16bit aligned, but I could not find that in any docu. Just be
744 * prepared to eat anything;
745 * - there are no strict constraints on tag-nesting and the organization
746 * is highly illogical;
748 * Anyhow, here is the basic structure:
749 * "RIFF" { dword taglength }
750 * "ACON" // What does it do?
751 * "LIST" { dword taglength }
752 * "INFO" // And what does this do?
753 * "INAM" { dword taglength } // Icon/cursor name
754 * {inam data}
755 * "IART" { dword taglength } // The artist
756 * {iart data}
757 * "fram" // Is followed by "icon"s
758 * "icon" { dword taglength } // First frame
759 * { icon/cursor data }
760 * "icon" { dword taglength } // Second frame
761 * { icon/cursor data }
762 * ... // ...
763 * "anih" { dword taglength } // Header structure
764 * { aniheader_t structure }
765 * "rate" { dword taglength } // The rate for each frame
766 * { `steps' dwords }
767 * "seq " { dword taglength } // The frame blit-order
768 * { `steps' dwords }
770 * Tag length are bytelength without the header and length field (i.e. -8).
771 * The "LIST" tag may occur several times and may encapsulate different
772 * tags. The `steps' is the number of "icon" tags found (actually the
773 * number of steps specified in the aniheader_t structure). The "seq "uence
774 * tag can be omitted, in which case the sequence is equal to the sequence
775 * of "icon"s found in the file. Also "rate" may be omitted, in which case
776 * the default from the aniheader_t structure is used.
778 * An animated cursor puts `.cur' formatted files into each "icon" tag,
779 * whereas animated icons contain `.ico' formatted files.
781 * Note about the code: Yes, it can be shorter/compressed. Some tags can be
782 * dealt with in the same code. However, this version shows what is going on
783 * and is better debug-able.
785 static const char riff[4] = "RIFF";
786 static const char acon[4] = "ACON";
787 static const char list[4] = "LIST";
788 static const char info[4] = "INFO";
789 static const char inam[4] = "INAM";
790 static const char iart[4] = "IART";
791 static const char fram[4] = "fram";
792 static const char icon[4] = "icon";
793 static const char anih[4] = "anih";
794 static const char rate[4] = "rate";
795 static const char seq[4] = "seq ";
797 #define SKIP_TAG(p,size) ((riff_tag_t *)(((char *)p) + (size)))
799 #define NEXT_TAG(p) SKIP_TAG(p,(isswapped ? BYTESWAP_DWORD(p->size) : p->size) + sizeof(*p))
801 static void handle_ani_icon(riff_tag_t *rtp, enum res_e type, int isswapped)
803 cursor_dir_entry_t *cdp;
804 cursor_header_t *chp;
805 int count;
806 int ctype;
807 int i;
808 static int once = 0; /* This will trigger only once per file! */
809 const char *anistr = type == res_aniico ? "icon" : "cursor";
810 /* Notes:
811 * Both cursor and icon directories are similar
812 * Both cursor and icon headers are similar
815 chp = (cursor_header_t *)(rtp+1);
816 cdp = (cursor_dir_entry_t *)(chp+1);
817 count = isswapped ? BYTESWAP_WORD(chp->count) : chp->count;
818 ctype = isswapped ? BYTESWAP_WORD(chp->type) : chp->type;
819 chp->reserved = BYTESWAP_WORD(chp->reserved);
820 chp->type = BYTESWAP_WORD(chp->type);
821 chp->count = BYTESWAP_WORD(chp->count);
823 if(type == res_anicur && ctype != 2 && !once)
825 parser_warning("Animated cursor contains invalid \"icon\" tag cursor-file (%d->%s)\n",
826 ctype,
827 ctype == 1 ? "icontype" : "?");
828 once++;
830 else if(type == res_aniico && ctype != 1 && !once)
832 parser_warning("Animated icon contains invalid \"icon\" tag icon-file (%d->%s)\n",
833 ctype,
834 ctype == 2 ? "cursortype" : "?");
835 once++;
837 else if(ctype != 1 && ctype != 2 && !once)
839 parser_warning("Animated %s contains invalid \"icon\" tag file-type (%d; neither icon nor cursor)\n", anistr, ctype);
840 once++;
843 for(i = 0; i < count; i++)
845 DWORD ofs = isswapped ? BYTESWAP_DWORD(cdp[i].offset) : cdp[i].offset;
846 DWORD sze = isswapped ? BYTESWAP_DWORD(cdp[i].ressize) : cdp[i].ressize;
847 if(ofs > rtp->size || ofs+sze > rtp->size)
848 parser_error("Animated %s's data corrupt", anistr);
849 convert_bitmap((char *)chp + ofs, 0);
850 cdp[i].xhot = BYTESWAP_WORD(cdp->xhot);
851 cdp[i].yhot = BYTESWAP_WORD(cdp->yhot);
852 cdp[i].ressize = BYTESWAP_DWORD(cdp->ressize);
853 cdp[i].offset = BYTESWAP_DWORD(cdp->offset);
857 static void handle_ani_list(riff_tag_t *lst, enum res_e type, int isswapped)
859 riff_tag_t *rtp = lst+1; /* Skip the "LIST" tag */
861 while((char *)rtp < (char *)lst + lst->size + sizeof(*lst))
863 if(!memcmp(rtp->tag, info, sizeof(info)))
865 rtp = SKIP_TAG(rtp,4);
867 else if(!memcmp(rtp->tag, inam, sizeof(inam)))
869 /* Ignore the icon/cursor name; its a string */
870 rtp = NEXT_TAG(rtp);
872 else if(!memcmp(rtp->tag, iart, sizeof(iart)))
874 /* Ignore the author's name; it's a string */
875 rtp = NEXT_TAG(rtp);
877 else if(!memcmp(rtp->tag, fram, sizeof(fram)))
879 /* This should be followed by "icon"s, but we
880 * simply ignore this because it is pure
881 * non-information.
883 rtp = SKIP_TAG(rtp,4);
885 else if(!memcmp(rtp->tag, icon, sizeof(icon)))
887 handle_ani_icon(rtp, type, isswapped);
888 rtp = NEXT_TAG(rtp);
890 else
891 internal_error(__FILE__, __LINE__, "Unknown tag \"%c%c%c%c\" in RIFF file\n",
892 isprint(rtp->tag[0]) ? rtp->tag[0] : '.',
893 isprint(rtp->tag[1]) ? rtp->tag[1] : '.',
894 isprint(rtp->tag[2]) ? rtp->tag[2] : '.',
895 isprint(rtp->tag[3]) ? rtp->tag[3] : '.');
897 if((UINT_PTR)rtp & 1)
898 rtp = SKIP_TAG(rtp,1);
902 ani_curico_t *new_ani_curico(enum res_e type, raw_data_t *rd, int *memopt)
904 ani_curico_t *ani = xmalloc(sizeof(ani_curico_t));
905 riff_tag_t *rtp;
906 int isswapped = 0;
907 int doswap;
908 const char *anistr = type == res_aniico ? "icon" : "cursor";
910 assert(!memcmp(rd->data, riff, sizeof(riff)));
911 assert(type == res_anicur || type == res_aniico);
913 rtp = (riff_tag_t *)rd->data;
915 if(BYTESWAP_DWORD(rtp->size) + 2*sizeof(DWORD) == rd->size)
916 isswapped = 1;
917 else if(rtp->size + 2*sizeof(DWORD) == rd->size)
918 isswapped = 0;
919 else
920 parser_error("Animated %s has an invalid RIFF length", anistr);
922 switch(byteorder)
924 #ifdef WORDS_BIGENDIAN
925 case WRC_BO_LITTLE:
926 #else
927 case WRC_BO_BIG:
928 #endif
929 doswap = !isswapped;
930 break;
931 default:
932 doswap = isswapped;
936 * When to swap what:
937 * isswapped | doswap |
938 * ----------+--------+---------------------------------
939 * 0 | 0 | read native; don't convert
940 * 1 | 0 | read swapped size; don't convert
941 * 0 | 1 | read native; convert
942 * 1 | 1 | read swapped size; convert
943 * Reading swapped size if necessary to calculate in native
944 * format. E.g. a little-endian source on a big-endian
945 * processor.
947 if(doswap)
949 /* We only go through the RIFF file if we need to swap
950 * bytes in words/dwords. Else we couldn't care less
951 * what the file contains. This is consistent with
952 * MS' rc.exe, which doesn't complain at all, even though
953 * the file format might not be entirely correct.
955 rtp++; /* Skip the "RIFF" tag */
957 while((char *)rtp < (char *)rd->data + rd->size)
959 if(!memcmp(rtp->tag, acon, sizeof(acon)))
961 rtp = SKIP_TAG(rtp,4);
963 else if(!memcmp(rtp->tag, list, sizeof(list)))
965 handle_ani_list(rtp, type, isswapped);
966 rtp = NEXT_TAG(rtp);
968 else if(!memcmp(rtp->tag, anih, sizeof(anih)))
970 aniheader_t *ahp = (aniheader_t *)((char *)(rtp+1));
971 ahp->structsize = BYTESWAP_DWORD(ahp->structsize);
972 ahp->frames = BYTESWAP_DWORD(ahp->frames);
973 ahp->steps = BYTESWAP_DWORD(ahp->steps);
974 ahp->cx = BYTESWAP_DWORD(ahp->cx);
975 ahp->cy = BYTESWAP_DWORD(ahp->cy);
976 ahp->bitcount = BYTESWAP_DWORD(ahp->bitcount);
977 ahp->planes = BYTESWAP_DWORD(ahp->planes);
978 ahp->rate = BYTESWAP_DWORD(ahp->rate);
979 ahp->flags = BYTESWAP_DWORD(ahp->flags);
980 rtp = NEXT_TAG(rtp);
982 else if(!memcmp(rtp->tag, rate, sizeof(rate)))
984 int cnt = rtp->size / sizeof(DWORD);
985 DWORD *dwp = (DWORD *)(rtp+1);
986 int i;
987 for(i = 0; i < cnt; i++)
988 dwp[i] = BYTESWAP_DWORD(dwp[i]);
989 rtp = NEXT_TAG(rtp);
991 else if(!memcmp(rtp->tag, seq, sizeof(seq)))
993 int cnt = rtp->size / sizeof(DWORD);
994 DWORD *dwp = (DWORD *)(rtp+1);
995 int i;
996 for(i = 0; i < cnt; i++)
997 dwp[i] = BYTESWAP_DWORD(dwp[i]);
998 rtp = NEXT_TAG(rtp);
1000 else
1001 internal_error(__FILE__, __LINE__, "Unknown tag \"%c%c%c%c\" in RIFF file\n",
1002 isprint(rtp->tag[0]) ? rtp->tag[0] : '.',
1003 isprint(rtp->tag[1]) ? rtp->tag[1] : '.',
1004 isprint(rtp->tag[2]) ? rtp->tag[2] : '.',
1005 isprint(rtp->tag[3]) ? rtp->tag[3] : '.');
1007 if((UINT_PTR)rtp & 1)
1008 rtp = SKIP_TAG(rtp,1);
1011 /* We must end correctly here */
1012 if((char *)rtp != (char *)rd->data + rd->size)
1013 parser_error("Animated %s contains invalid field size(s)", anistr);
1016 ani->data = rd;
1017 if(memopt)
1019 ani->memopt = *memopt;
1020 free(memopt);
1022 else
1023 ani->memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE;
1024 return ani;
1026 #undef NEXT_TAG
1028 /* Bitmaps */
1029 bitmap_t *new_bitmap(raw_data_t *rd, int *memopt)
1031 bitmap_t *bmp = xmalloc(sizeof(bitmap_t));
1033 bmp->data = rd;
1034 if(memopt)
1036 bmp->memopt = *memopt;
1037 free(memopt);
1039 else
1040 bmp->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
1041 rd->size -= convert_bitmap(rd->data, rd->size);
1042 return bmp;
1045 ver_words_t *new_ver_words(int i)
1047 ver_words_t *w = xmalloc(sizeof(ver_words_t));
1048 w->words = xmalloc(sizeof(WORD));
1049 w->words[0] = (WORD)i;
1050 w->nwords = 1;
1051 return w;
1054 ver_words_t *add_ver_words(ver_words_t *w, int i)
1056 w->words = xrealloc(w->words, (w->nwords+1) * sizeof(WORD));
1057 w->words[w->nwords] = (WORD)i;
1058 w->nwords++;
1059 return w;
1062 #define MSGTAB_BAD_PTR(p, b, l, r) (((l) - ((char *)(p) - (char *)(b))) > (r))
1063 messagetable_t *new_messagetable(raw_data_t *rd, int *memopt)
1065 messagetable_t *msg = xmalloc(sizeof(messagetable_t));
1066 msgtab_block_t *mbp;
1067 DWORD nblk;
1068 DWORD i;
1069 WORD lo;
1070 WORD hi;
1072 msg->data = rd;
1073 if(memopt)
1075 msg->memopt = *memopt;
1076 free(memopt);
1078 else
1079 msg->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
1081 if(rd->size < sizeof(DWORD))
1082 parser_error("Invalid messagetable, size too small");
1084 nblk = *(DWORD *)rd->data;
1085 lo = WRC_LOWORD(nblk);
1086 hi = WRC_HIWORD(nblk);
1088 /* FIXME:
1089 * This test will fail for all n*2^16 blocks in the messagetable.
1090 * However, no sane person would want to have so many blocks
1091 * and have a table of megabytes attached.
1092 * So, I will assume that we have less than 2^16 blocks in the table
1093 * and all will just work out fine. Otherwise, we would need to test
1094 * the ID, offset and length (and flag) fields to be very sure.
1096 if(hi && lo)
1097 internal_error(__FILE__, __LINE__, "Messagetable contains more than 65535 blocks; cannot determine endian\n");
1098 if(!hi && !lo)
1099 parser_error("Invalid messagetable block count 0");
1101 if(!hi && lo) /* Messagetable byteorder == native byteorder */
1103 #ifdef WORDS_BIGENDIAN
1104 if(byteorder != WRC_BO_LITTLE) goto out;
1105 #else
1106 if(byteorder != WRC_BO_BIG) goto out;
1107 #endif
1108 /* Resource byteorder != native byteorder */
1110 mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]);
1111 if(MSGTAB_BAD_PTR(mbp, rd->data, rd->size, nblk * sizeof(*mbp)))
1112 parser_error("Messagetable's blocks are outside of defined data");
1113 for(i = 0; i < nblk; i++)
1115 msgtab_entry_t *mep, *next_mep;
1116 DWORD id;
1118 mep = (msgtab_entry_t *)(((char *)rd->data) + mbp[i].offset);
1120 for(id = mbp[i].idlo; id <= mbp[i].idhi; id++)
1122 if(MSGTAB_BAD_PTR(mep, rd->data, rd->size, mep->length))
1123 parser_error("Messagetable's data for block %d, ID 0x%08x is outside of defined data", i, id);
1124 if(mep->flags == 1) /* Docu says 'flags == 0x0001' for unicode */
1126 WORD *wp = (WORD *)&mep[1];
1127 int l = mep->length/2 - 2; /* Length included header */
1128 int n;
1130 if(mep->length & 1)
1131 parser_error("Message 0x%08x is unicode (block %d), but has odd length (%d)", id, i, mep->length);
1132 for(n = 0; n < l; n++)
1133 wp[n] = BYTESWAP_WORD(wp[n]);
1136 next_mep = (msgtab_entry_t *)(((char *)mep) + mep->length);
1137 mep->length = BYTESWAP_WORD(mep->length);
1138 mep->flags = BYTESWAP_WORD(mep->flags);
1139 mep = next_mep;
1142 mbp[i].idlo = BYTESWAP_DWORD(mbp[i].idlo);
1143 mbp[i].idhi = BYTESWAP_DWORD(mbp[i].idhi);
1144 mbp[i].offset = BYTESWAP_DWORD(mbp[i].offset);
1147 if(hi && !lo) /* Messagetable byteorder != native byteorder */
1149 #ifdef WORDS_BIGENDIAN
1150 if(byteorder == WRC_BO_LITTLE) goto out;
1151 #else
1152 if(byteorder == WRC_BO_BIG) goto out;
1153 #endif
1154 /* Resource byteorder == native byteorder */
1156 mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]);
1157 nblk = BYTESWAP_DWORD(nblk);
1158 if(MSGTAB_BAD_PTR(mbp, rd->data, rd->size, nblk * sizeof(*mbp)))
1159 parser_error("Messagetable's blocks are outside of defined data");
1160 for(i = 0; i < nblk; i++)
1162 msgtab_entry_t *mep;
1163 DWORD id;
1165 mbp[i].idlo = BYTESWAP_DWORD(mbp[i].idlo);
1166 mbp[i].idhi = BYTESWAP_DWORD(mbp[i].idhi);
1167 mbp[i].offset = BYTESWAP_DWORD(mbp[i].offset);
1168 mep = (msgtab_entry_t *)(((char *)rd->data) + mbp[i].offset);
1170 for(id = mbp[i].idlo; id <= mbp[i].idhi; id++)
1172 mep->length = BYTESWAP_WORD(mep->length);
1173 mep->flags = BYTESWAP_WORD(mep->flags);
1175 if(MSGTAB_BAD_PTR(mep, rd->data, rd->size, mep->length))
1176 parser_error("Messagetable's data for block %d, ID 0x%08x is outside of defined data", i, id);
1177 if(mep->flags == 1) /* Docu says 'flags == 0x0001' for unicode */
1179 WORD *wp = (WORD *)&mep[1];
1180 int l = mep->length/2 - 2; /* Length included header */
1181 int n;
1183 if(mep->length & 1)
1184 parser_error("Message 0x%08x is unicode (block %d), but has odd length (%d)", id, i, mep->length);
1185 for(n = 0; n < l; n++)
1186 wp[n] = BYTESWAP_WORD(wp[n]);
1189 mep = (msgtab_entry_t *)(((char *)mep) + mep->length);
1194 out:
1195 return msg;
1197 #undef MSGTAB_BAD_PTR
1199 void copy_raw_data(raw_data_t *dst, raw_data_t *src, unsigned int offs, int len)
1201 assert(offs <= src->size);
1202 assert(offs + len <= src->size);
1203 if(!dst->data)
1205 dst->data = xmalloc(len);
1206 dst->size = 0;
1208 else
1209 dst->data = xrealloc(dst->data, dst->size + len);
1210 /* dst->size holds the offset to copy to */
1211 memcpy(dst->data + dst->size, src->data + offs, len);
1212 dst->size += len;
1215 int *new_int(int i)
1217 int *ip = xmalloc(sizeof(int));
1218 *ip = i;
1219 return ip;
1222 stringtable_t *new_stringtable(lvc_t *lvc)
1224 stringtable_t *stt = xmalloc(sizeof(stringtable_t));
1226 memset( stt, 0, sizeof(*stt) );
1227 if(lvc)
1228 stt->lvc = *lvc;
1230 return stt;
1233 toolbar_t *new_toolbar(int button_width, int button_height, toolbar_item_t *items, int nitems)
1235 toolbar_t *tb = xmalloc(sizeof(toolbar_t));
1236 memset( tb, 0, sizeof(*tb) );
1237 tb->button_width = button_width;
1238 tb->button_height = button_height;
1239 tb->nitems = nitems;
1240 tb->items = items;
1241 return tb;
1244 dlginit_t *new_dlginit(raw_data_t *rd, int *memopt)
1246 dlginit_t *di = xmalloc(sizeof(dlginit_t));
1247 di->data = rd;
1248 if(memopt)
1250 di->memopt = *memopt;
1251 free(memopt);
1253 else
1254 di->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
1256 return di;
1259 style_pair_t *new_style_pair(style_t *style, style_t *exstyle)
1261 style_pair_t *sp = xmalloc(sizeof(style_pair_t));
1262 sp->style = style;
1263 sp->exstyle = exstyle;
1264 return sp;
1267 style_t *new_style(DWORD or_mask, DWORD and_mask)
1269 style_t *st = xmalloc(sizeof(style_t));
1270 st->or_mask = or_mask;
1271 st->and_mask = and_mask;
1272 return st;