Fixed typo in BITMAPV4HEADER stucture.
[wine] / tools / wrc / newstruc.c
1 /*
2  * Create dynamic new structures of various types
3  * and some utils in that trend.
4  *
5  * Copyright 1998 Bertho A. Stultiens
6  *
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.
11  *
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.
16  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <ctype.h>
29
30 #include "wrc.h"
31 #include "newstruc.h"
32 #include "utils.h"
33 #include "parser.h"
34
35 #include "wingdi.h"     /* for BITMAPINFOHEADER */
36
37 /* Generate new_* functions that have no parameters (NOTE: no ';') */
38 __NEW_STRUCT_FUNC(dialog)
39 __NEW_STRUCT_FUNC(dialogex)
40 __NEW_STRUCT_FUNC(name_id)
41 __NEW_STRUCT_FUNC(menu)
42 __NEW_STRUCT_FUNC(menuex)
43 __NEW_STRUCT_FUNC(menu_item)
44 __NEW_STRUCT_FUNC(menuex_item)
45 __NEW_STRUCT_FUNC(control)
46 __NEW_STRUCT_FUNC(icon)
47 __NEW_STRUCT_FUNC(cursor)
48 __NEW_STRUCT_FUNC(versioninfo)
49 __NEW_STRUCT_FUNC(ver_value)
50 __NEW_STRUCT_FUNC(ver_block)
51 __NEW_STRUCT_FUNC(stt_entry)
52 __NEW_STRUCT_FUNC(accelerator)
53 __NEW_STRUCT_FUNC(event)
54 __NEW_STRUCT_FUNC(raw_data)
55 __NEW_STRUCT_FUNC(lvc)
56 __NEW_STRUCT_FUNC(res_count)
57 __NEW_STRUCT_FUNC(string)
58 __NEW_STRUCT_FUNC(toolbar_item)
59 __NEW_STRUCT_FUNC(ani_any)
60
61 /* New instances for all types of structures */
62 /* Very inefficient (in size), but very functional :-]
63  * Especially for type-checking.
64  */
65 resource_t *new_resource(enum res_e t, void *res, int memopt, language_t *lan)
66 {
67         resource_t *r = (resource_t *)xmalloc(sizeof(resource_t));
68         r->type = t;
69         r->res.overlay = res;
70         r->memopt = memopt;
71         r->lan = lan;
72         return r;
73 }
74
75 version_t *new_version(DWORD v)
76 {
77         version_t *vp = (version_t *)xmalloc(sizeof(version_t));
78         *vp = v;
79         return vp;
80 }
81
82 characts_t *new_characts(DWORD c)
83 {
84         characts_t *cp = (characts_t *)xmalloc(sizeof(characts_t));
85         *cp = c;
86         return cp;
87 }
88
89 language_t *new_language(int id, int sub)
90 {
91         language_t *lan = (language_t *)xmalloc(sizeof(language_t));
92         lan->id = id;
93         lan->sub = sub;
94         return lan;
95 }
96
97 language_t *dup_language(language_t *l)
98 {
99         if(!l) return NULL;
100         return new_language(l->id, l->sub);
101 }
102
103 version_t *dup_version(version_t *v)
104 {
105         if(!v) return NULL;
106         return new_version(*v);
107 }
108
109 characts_t *dup_characts(characts_t *c)
110 {
111         if(!c) return NULL;
112         return new_characts(*c);
113 }
114
115 rcdata_t *new_rcdata(raw_data_t *rd, int *memopt)
116 {
117         rcdata_t *rc = (rcdata_t *)xmalloc(sizeof(rcdata_t));
118         rc->data = rd;
119         if(memopt)
120         {
121                 rc->memopt = *memopt;
122                 free(memopt);
123         }
124         else
125                 rc->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
126         return rc;
127 }
128
129 font_id_t *new_font_id(int size, string_t *face, int weight, int italic)
130 {
131         font_id_t *fid = (font_id_t *)xmalloc(sizeof(font_id_t));
132         fid->name = face;
133         fid->size = size;
134         fid->weight = weight;
135         fid->italic = italic;
136         return fid;
137 }
138
139 user_t *new_user(name_id_t *type, raw_data_t *rd, int *memopt)
140 {
141         user_t *usr = (user_t *)xmalloc(sizeof(user_t));
142         usr->data = rd;
143         if(memopt)
144         {
145                 usr->memopt = *memopt;
146                 free(memopt);
147         }
148         else
149                 usr->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
150         usr->type = type;
151         return usr;
152 }
153
154 font_t *new_font(raw_data_t *rd, int *memopt)
155 {
156         font_t *fnt = (font_t *)xmalloc(sizeof(font_t));
157         fnt->data = rd;
158         if(memopt)
159         {
160                 fnt->memopt = *memopt;
161                 free(memopt);
162         }
163         else
164                 fnt->memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE;
165         return fnt;
166 }
167
168 fontdir_t *new_fontdir(raw_data_t *rd, int *memopt)
169 {
170         fontdir_t *fnd = (fontdir_t *)xmalloc(sizeof(fontdir_t));
171         fnd->data = rd;
172         if(memopt)
173         {
174                 fnd->memopt = *memopt;
175                 free(memopt);
176         }
177         else
178                 fnd->memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE;
179         return fnd;
180 }
181
182
183 /*
184  * Convert bitmaps to proper endian
185  */
186 static void convert_bitmap_swap_v3(BITMAPINFOHEADER *bih)
187 {
188         bih->biSize             = BYTESWAP_DWORD(bih->biSize);
189         bih->biWidth            = BYTESWAP_DWORD(bih->biWidth);
190         bih->biHeight           = BYTESWAP_DWORD(bih->biHeight);
191         bih->biPlanes           = BYTESWAP_WORD(bih->biPlanes);
192         bih->biBitCount         = BYTESWAP_WORD(bih->biBitCount);
193         bih->biCompression      = BYTESWAP_DWORD(bih->biCompression);
194         bih->biSizeImage        = BYTESWAP_DWORD(bih->biSizeImage);
195         bih->biXPelsPerMeter    = BYTESWAP_DWORD(bih->biXPelsPerMeter);
196         bih->biYPelsPerMeter    = BYTESWAP_DWORD(bih->biYPelsPerMeter);
197         bih->biClrUsed          = BYTESWAP_DWORD(bih->biClrUsed);
198         bih->biClrImportant     = BYTESWAP_DWORD(bih->biClrImportant);
199 }
200
201 static void convert_bitmap_swap_v4(BITMAPV4HEADER *b4h)
202 {
203         convert_bitmap_swap_v3((BITMAPINFOHEADER *)b4h);
204         b4h->bV4RedMask         = BYTESWAP_DWORD(b4h->bV4RedMask);
205         b4h->bV4GreenMask       = BYTESWAP_DWORD(b4h->bV4GreenMask);
206         b4h->bV4BlueMask        = BYTESWAP_DWORD(b4h->bV4BlueMask);
207         b4h->bV4AlphaMask       = BYTESWAP_DWORD(b4h->bV4AlphaMask);
208         b4h->bV4CSType          = BYTESWAP_DWORD(b4h->bV4CSType);
209         b4h->bV4Endpoints.ciexyzRed.ciexyzX     = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzRed.ciexyzX);
210         b4h->bV4Endpoints.ciexyzRed.ciexyzY     = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzRed.ciexyzY);
211         b4h->bV4Endpoints.ciexyzRed.ciexyzZ     = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzRed.ciexyzZ);
212         b4h->bV4Endpoints.ciexyzGreen.ciexyzX   = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzGreen.ciexyzX);
213         b4h->bV4Endpoints.ciexyzGreen.ciexyzY   = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzGreen.ciexyzY);
214         b4h->bV4Endpoints.ciexyzGreen.ciexyzZ   = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzGreen.ciexyzZ);
215         b4h->bV4Endpoints.ciexyzBlue.ciexyzX    = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzBlue.ciexyzX);
216         b4h->bV4Endpoints.ciexyzBlue.ciexyzY    = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzBlue.ciexyzY);
217         b4h->bV4Endpoints.ciexyzBlue.ciexyzZ    = BYTESWAP_DWORD(b4h->bV4Endpoints.ciexyzBlue.ciexyzZ);
218         b4h->bV4GammaRed        = BYTESWAP_DWORD(b4h->bV4GammaRed);
219         b4h->bV4GammaGreen      = BYTESWAP_DWORD(b4h->bV4GammaGreen);
220         b4h->bV4GammaBlue       = BYTESWAP_DWORD(b4h->bV4GammaBlue);
221 }
222
223 #define FL_SIGBE        0x01
224 #define FL_SIZEBE       0x02
225 #define FL_V4           0x04
226 static int convert_bitmap(char *data, int size)
227 {
228         BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *)data;
229         BITMAPV4HEADER *b4h = (BITMAPV4HEADER *)data;
230         int type = 0;
231     int returnSize = 0;           /* size to be returned */
232 #ifdef WORDS_BIGENDIAN
233         DWORD bisizel = BYTESWAP_DWORD(sizeof(BITMAPINFOHEADER));
234         DWORD b4sizel = BYTESWAP_DWORD(sizeof(BITMAPV4HEADER));
235         DWORD bisizeb = sizeof(BITMAPINFOHEADER);
236         DWORD b4sizeb = sizeof(BITMAPV4HEADER);
237 #else
238         DWORD bisizel = sizeof(BITMAPINFOHEADER);
239         DWORD b4sizel = sizeof(BITMAPV4HEADER);
240         DWORD bisizeb = BYTESWAP_DWORD(sizeof(BITMAPINFOHEADER));
241         DWORD b4sizeb = BYTESWAP_DWORD(sizeof(BITMAPV4HEADER));
242 #endif
243
244
245     /*
246      * Originally the bih and b4h pointers were simply incremented here,
247      * and memmoved at the end of the function.  This causes alignment
248      * issues on solaris, so we do the memmove here rather than at the end.
249      */
250         if(data[0] == 'B' && data[1] == 'M')
251         {
252                 /* Little endian signature */
253          memmove(data, data+sizeof(BITMAPFILEHEADER), size - sizeof(BITMAPFILEHEADER));
254          returnSize = sizeof(BITMAPFILEHEADER);
255         }
256         else if(data[0] == 'M' && data[1] == 'B')
257         {
258                 type |= FL_SIGBE;       /* Big endian signature */
259          memmove(data, data+sizeof(BITMAPFILEHEADER), size - sizeof(BITMAPFILEHEADER));
260          returnSize = sizeof(BITMAPFILEHEADER);
261
262         }
263
264         if(bih->biSize == bisizel)
265         {
266                 /* Little endian */
267         }
268         else if(bih->biSize == b4sizel)
269         {
270                 type |= FL_V4;
271         }
272         else if(bih->biSize == bisizeb)
273         {
274                 type |= FL_SIZEBE;
275         }
276         else if(bih->biSize == b4sizeb)
277         {
278                 type |= FL_SIZEBE | FL_V4;
279         }
280         else
281                 type = -1;
282
283         switch(type)
284         {
285         default:
286                 break;
287         case FL_SIZEBE:
288         case FL_SIZEBE | FL_V4:
289                 yywarning("Bitmap v%c signature little-endian, but size big-endian", type & FL_V4 ? '4' : '3');
290                 break;
291         case FL_SIGBE:
292         case FL_SIGBE | FL_V4:
293                 yywarning("Bitmap v%c signature big-endian, but size little-endian", type & FL_V4 ? '4' : '3');
294                 break;
295         case -1:
296                 yyerror("Invalid bitmap format");
297                 break;
298         }
299
300         switch(byteorder)
301         {
302 #ifdef WORDS_BIGENDIAN
303         default:
304 #endif
305         case WRC_BO_BIG:
306                 if(!(type & FL_SIZEBE))
307                 {
308                         if(type & FL_V4)
309                                 convert_bitmap_swap_v4(b4h);
310                         else
311                                 convert_bitmap_swap_v3(bih);
312                 }
313                 break;
314 #ifndef WORDS_BIGENDIAN
315         default:
316 #endif
317         case WRC_BO_LITTLE:
318                 if(type & FL_SIZEBE)
319                 {
320                         if(type & FL_V4)
321                                 convert_bitmap_swap_v4(b4h);
322                         else
323                                 convert_bitmap_swap_v3(bih);
324                 }
325                 break;
326         }
327
328         if(size && (void *)data != (void *)bih)
329         {
330                 /* We have the fileheader still attached, remove it */
331                 memmove(data, data+sizeof(BITMAPFILEHEADER), size - sizeof(BITMAPFILEHEADER));
332                 return sizeof(BITMAPFILEHEADER);
333         }
334     return returnSize;
335 }
336 #undef FL_SIGBE
337 #undef FL_SIZEBE
338 #undef FL_V4
339
340 /*
341  * Cursor and icon splitter functions used when allocating
342  * cursor- and icon-groups.
343  */
344 typedef struct {
345         language_t      lan;
346         int             id;
347 } id_alloc_t;
348
349 static int get_new_id(id_alloc_t **list, int *n, language_t *lan)
350 {
351         int i;
352         assert(lan != NULL);
353         assert(list != NULL);
354         assert(n != NULL);
355
356         if(!*list)
357         {
358                 *list = (id_alloc_t *)xmalloc(sizeof(id_alloc_t));
359                 *n = 1;
360                 (*list)[0].lan = *lan;
361                 (*list)[0].id = 1;
362                 return 1;
363         }
364
365         for(i = 0; i < *n; i++)
366         {
367                 if((*list)[i].lan.id == lan->id && (*list)[i].lan.sub == lan->sub)
368                         return ++((*list)[i].id);
369         }
370
371         *list = (id_alloc_t *)xrealloc(*list, sizeof(id_alloc_t) * (*n+1));
372         (*list)[*n].lan = *lan;
373         (*list)[*n].id = 1;
374         *n += 1;
375         return 1;
376 }
377
378 static int alloc_icon_id(language_t *lan)
379 {
380         static id_alloc_t *idlist = NULL;
381         static int nid = 0;
382
383         return get_new_id(&idlist, &nid, lan);
384 }
385
386 static int alloc_cursor_id(language_t *lan)
387 {
388         static id_alloc_t *idlist = NULL;
389         static int nid = 0;
390
391         return get_new_id(&idlist, &nid, lan);
392 }
393
394 static void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico)
395 {
396         int cnt;
397         int i;
398         icon_t *ico;
399         icon_t *list = NULL;
400         icon_header_t *ih = (icon_header_t *)rd->data;
401         int swap = 0;
402
403         if(ih->type == 1)
404                 swap = 0;
405         else if(BYTESWAP_WORD(ih->type) == 1)
406                 swap = 1;
407         else
408                 yyerror("Icon resource data has invalid type id %d", ih->type);
409
410         cnt = swap ? BYTESWAP_WORD(ih->count) : ih->count;
411         for(i = 0; i < cnt; i++)
412         {
413                 icon_dir_entry_t ide;
414                 BITMAPINFOHEADER info;
415                 memcpy(&ide, rd->data + sizeof(icon_header_t)
416                                       + i*sizeof(icon_dir_entry_t), sizeof(ide));
417
418                 ico = new_icon();
419                 ico->id = alloc_icon_id(icog->lvc.language);
420                 ico->lvc = icog->lvc;
421                 if(swap)
422                 {
423                         ide.offset = BYTESWAP_DWORD(ide.offset);
424                         ide.ressize= BYTESWAP_DWORD(ide.ressize);
425                 }
426                 if(ide.offset > rd->size
427                 || ide.offset + ide.ressize > rd->size)
428                         yyerror("Icon resource data corrupt");
429                 ico->width = ide.width;
430                 ico->height = ide.height;
431                 ico->nclr = ide.nclr;
432                 ico->planes = swap ? BYTESWAP_WORD(ide.planes) : ide.planes;
433                 ico->bits = swap ? BYTESWAP_WORD(ide.bits) : ide.bits;
434                 memcpy(&info, rd->data + ide.offset, sizeof(info));
435          convert_bitmap((char *) &info, 0);
436          memcpy(rd->data + ide.offset, &info, sizeof(info));
437
438                 if(!ico->planes)
439                 {
440                         /* Argh! They did not fill out the resdir structure */
441                         /* The bitmap is in destination byteorder. We want native for our structures */
442                         switch(byteorder)
443                         {
444 #ifdef WORDS_BIGENDIAN
445                         case WRC_BO_LITTLE:
446 #else
447                         case WRC_BO_BIG:
448 #endif
449                                 ico->planes = BYTESWAP_WORD(info.biPlanes);
450                                 break;
451                         default:
452                                 ico->planes = info.biPlanes;
453                         }
454                 }
455                 if(!ico->bits)
456                 {
457                         /* Argh! They did not fill out the resdir structure */
458                         /* The bitmap is in destination byteorder. We want native for our structures */
459                         switch(byteorder)
460                         {
461 #ifdef WORDS_BIGENDIAN
462                         case WRC_BO_LITTLE:
463 #else
464                         case WRC_BO_BIG:
465 #endif
466                                 ico->bits = BYTESWAP_WORD(info.biBitCount);
467                                 break;
468                         default:
469                                 ico->bits = info.biBitCount;
470                         }
471                 }
472                 ico->data = new_raw_data();
473                 copy_raw_data(ico->data, rd, ide.offset, ide.ressize);
474                 if(!list)
475                 {
476                         list = ico;
477                 }
478                 else
479                 {
480                         ico->next = list;
481                         list->prev = ico;
482                         list = ico;
483                 }
484         }
485         icog->iconlist = list;
486         *nico = cnt;
487 }
488
489 static void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur)
490 {
491         int cnt;
492         int i;
493         cursor_t *cur;
494         cursor_t *list = NULL;
495         cursor_header_t *ch = (cursor_header_t *)rd->data;
496         int swap = 0;
497
498         if(ch->type == 2)
499                 swap = 0;
500         else if(BYTESWAP_WORD(ch->type) == 2)
501                 swap = 1;
502         else
503                 yyerror("Cursor resource data has invalid type id %d", ch->type);
504         cnt = swap ? BYTESWAP_WORD(ch->count) : ch->count;
505         for(i = 0; i < cnt; i++)
506         {
507                 cursor_dir_entry_t cde;
508                 BITMAPINFOHEADER info;
509                 memcpy(&cde, rd->data + sizeof(cursor_header_t)
510                                       + i*sizeof(cursor_dir_entry_t), sizeof(cde));
511
512                 cur = new_cursor();
513                 cur->id = alloc_cursor_id(curg->lvc.language);
514                 cur->lvc = curg->lvc;
515                 if(swap)
516                 {
517                         cde.offset = BYTESWAP_DWORD(cde.offset);
518                         cde.ressize= BYTESWAP_DWORD(cde.ressize);
519                 }
520                 if(cde.offset > rd->size
521                 || cde.offset + cde.ressize > rd->size)
522                         yyerror("Cursor resource data corrupt");
523                 cur->width = cde.width;
524                 cur->height = cde.height;
525                 cur->nclr = cde.nclr;
526                 memcpy(&info, rd->data + cde.offset, sizeof(info));
527          convert_bitmap((char *)&info, 0);
528          memcpy(rd->data + cde.offset, &info, sizeof(info));
529                 /* The bitmap is in destination byteorder. We want native for our structures */
530                 switch(byteorder)
531                 {
532 #ifdef WORDS_BIGENDIAN
533                 case WRC_BO_LITTLE:
534 #else
535                 case WRC_BO_BIG:
536 #endif
537                         cur->planes = BYTESWAP_WORD(info.biPlanes);
538                         cur->bits = BYTESWAP_WORD(info.biBitCount);
539                         break;
540                 default:
541                         cur->planes = info.biPlanes;
542                         cur->bits = info.biBitCount;
543                 }
544                 if(!win32 && (cur->planes != 1 || cur->bits != 1))
545                         yywarning("Win16 cursor contains colors");
546                 cur->xhot = swap ? BYTESWAP_WORD(cde.xhot) : cde.xhot;
547                 cur->yhot = swap ? BYTESWAP_WORD(cde.yhot) : cde.yhot;
548                 cur->data = new_raw_data();
549                 copy_raw_data(cur->data, rd, cde.offset, cde.ressize);
550                 if(!list)
551                 {
552                         list = cur;
553                 }
554                 else
555                 {
556                         cur->next = list;
557                         list->prev = cur;
558                         list = cur;
559                 }
560         }
561         curg->cursorlist = list;
562         *ncur = cnt;
563 }
564
565
566 icon_group_t *new_icon_group(raw_data_t *rd, int *memopt)
567 {
568         icon_group_t *icog = (icon_group_t *)xmalloc(sizeof(icon_group_t));
569         if(memopt)
570         {
571                 icog->memopt = *memopt;
572                 free(memopt);
573         }
574         else
575                 icog->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
576         icog->lvc = rd->lvc;
577         split_icons(rd, icog, &(icog->nicon));
578         free(rd->data);
579         free(rd);
580         return icog;
581 }
582
583 cursor_group_t *new_cursor_group(raw_data_t *rd, int *memopt)
584 {
585         cursor_group_t *curg = (cursor_group_t *)xmalloc(sizeof(cursor_group_t));
586         if(memopt)
587         {
588                 curg->memopt = *memopt;
589                 free(memopt);
590         }
591         else
592                 curg->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
593         curg->lvc = rd->lvc;
594         split_cursors(rd, curg, &(curg->ncursor));
595         free(rd->data);
596         free(rd);
597         return curg;
598 }
599
600 /*
601  * Animated cursors and icons
602  *
603  * The format of animated cursors and icons is yet another example
604  * of bad design by "The Company". The entire RIFF structure is
605  * flawed by design because it is inconsistent and single minded:
606  * - some tags have lengths attached, others don't. The use of these
607  *   non-length tags is absolutely unclear;
608  * - the content of "icon" tags can be both icons and cursors;
609  * - tags lack proper alignment constraints. It seems that everything
610  *   is 16bit aligned, but I could not find that in any docu. Just be
611  *   prepared to eat anything;
612  * - there are no strict constraints on tag-nesting and the organization
613  *   is highly illogical;
614  *
615  * Anyhow, here is the basic structure:
616  * "RIFF" { dword taglength }
617  *      "ACON"                                  // What does it do?
618  *      "LIST" { dword taglength }
619  *              "INFO"                          // And what does this do?
620  *              "INAM" { dword taglength }      // Icon/cursor name
621  *                      {inam data}
622  *              "IART" { dword taglength }      // The artist
623  *                      {iart data}
624  *              "fram"                          // Is followed by "icon"s
625  *              "icon" { dword taglength }      // First frame
626  *                      { icon/cursor data }
627  *              "icon" { dword taglength }      // Second frame
628  *                      { icon/cursor data }
629  *                      ...                     // ...
630  *      "anih" { dword taglength }              // Header structure
631  *              { aniheader_t structure }
632  *      "rate" { dword taglength }              // The rate for each frame
633  *              { `steps' dwords }
634  *      "seq " { dword taglength }              // The frame blit-order
635  *              { `steps' dwords }
636  *
637  * Tag length are bytelength without the header and length field (i.e. -8).
638  * The "LIST" tag may occur several times and may encapsulate different
639  * tags. The `steps' is the number of "icon" tags found (actually the
640  * number of steps specified in the aniheader_t structure). The "seq "uence
641  * tag can be ommitted, in which case the sequence is equal to the sequence
642  * of "icon"s found in the file. Also "rate" may be ommitted, in which case
643  * the default from the aniheader_t structure is used.
644  *
645  * An animated cursor puts `.cur' formatted files into each "icon" tag,
646  * whereas animated icons contain `.ico' formatted files.
647  *
648  * Note about the code: Yes, it can be shorter/compressed. Some tags can be
649  * dealt with in the same code. However, this version shows what is going on
650  * and is better debug-able.
651  */
652 static const char riff[4] = "RIFF";
653 static const char acon[4] = "ACON";
654 static const char list[4] = "LIST";
655 static const char info[4] = "INFO";
656 static const char inam[4] = "INAM";
657 static const char iart[4] = "IART";
658 static const char fram[4] = "fram";
659 static const char icon[4] = "icon";
660 static const char anih[4] = "anih";
661 static const char rate[4] = "rate";
662 static const char seq[4]  = "seq ";
663
664 #define NEXT_TAG(p)     ((riff_tag_t *)(((char *)p) + (isswapped ? BYTESWAP_DWORD(p->size) : p->size) + sizeof(*p)))
665
666 static void handle_ani_icon(riff_tag_t *rtp, enum res_e type, int isswapped)
667 {
668         cursor_dir_entry_t *cdp;
669         cursor_header_t *chp;
670         int count;
671         int ctype;
672         int i;
673         static int once = 0;    /* This will trigger only once per file! */
674         const char *anistr = type == res_aniico ? "icon" : "cursor";
675         /* Notes:
676          * Both cursor and icon directories are similar
677          * Both cursor and icon headers are similar
678          */
679
680         chp = (cursor_header_t *)(rtp+1);
681         cdp = (cursor_dir_entry_t *)(chp+1);
682         count = isswapped ? BYTESWAP_WORD(chp->count) : chp->count;
683         ctype = isswapped ? BYTESWAP_WORD(chp->type) : chp->type;
684         chp->reserved   = BYTESWAP_WORD(chp->reserved);
685         chp->type       = BYTESWAP_WORD(chp->type);
686         chp->count      = BYTESWAP_WORD(chp->count);
687
688         if(type == res_anicur && ctype != 2 && !once)
689         {
690                 yywarning("Animated cursor contains invalid \"icon\" tag cursor-file (%d->%s)",
691                                 ctype,
692                                 ctype == 1 ? "icontype" : "?");
693                 once++;
694         }
695         else if(type == res_aniico && ctype != 1 && !once)
696         {
697                 yywarning("Animated icon contains invalid \"icon\" tag icon-file (%d->%s)",
698                                 ctype,
699                                 ctype == 2 ? "cursortype" : "?");
700                 once++;
701         }
702         else if(ctype != 1 && ctype != 2 && !once)
703         {
704                 yywarning("Animated %s contains invalid \"icon\" tag file-type (%d; neither icon nor cursor)", anistr, ctype);
705                 once++;
706         }
707
708         for(i = 0; i < count; i++)
709         {
710                 DWORD ofs = isswapped ? BYTESWAP_DWORD(cdp[i].offset) : cdp[i].offset;
711                 DWORD sze = isswapped ? BYTESWAP_DWORD(cdp[i].ressize) : cdp[i].ressize;
712                 if(ofs > rtp->size || ofs+sze > rtp->size)
713                         yyerror("Animated %s's data corrupt", anistr);
714                 convert_bitmap((char *)chp + ofs, 0);
715                 cdp[i].xhot     = BYTESWAP_WORD(cdp->xhot);
716                 cdp[i].yhot     = BYTESWAP_WORD(cdp->yhot);
717                 cdp[i].ressize  = BYTESWAP_DWORD(cdp->ressize);
718                 cdp[i].offset   = BYTESWAP_DWORD(cdp->offset);
719         }
720 }
721
722 static void handle_ani_list(riff_tag_t *lst, enum res_e type, int isswapped)
723 {
724         riff_tag_t *rtp = lst+1;        /* Skip the "LIST" tag */
725
726         while((char *)rtp < (char *)lst + lst->size + sizeof(*lst))
727         {
728                 if(!memcmp(rtp->tag, info, sizeof(info)))
729                 {
730                         rtp = (riff_tag_t *)(((char *)rtp) + 4);
731                 }
732                 else if(!memcmp(rtp->tag, inam, sizeof(inam)))
733                 {
734                         /* Ignore the icon/cursor name; its a string */
735                         rtp = NEXT_TAG(rtp);
736                 }
737                 else if(!memcmp(rtp->tag, iart, sizeof(iart)))
738                 {
739                         /* Ignore the author's name; its a string */
740                         rtp = NEXT_TAG(rtp);
741                 }
742                 else if(!memcmp(rtp->tag, fram, sizeof(fram)))
743                 {
744                         /* This should be followed by "icon"s, but we
745                          * simply ignore this because it is pure
746                          * non-information.
747                          */
748                         rtp = (riff_tag_t *)(((char *)rtp) + 4);
749                 }
750                 else if(!memcmp(rtp->tag, icon, sizeof(icon)))
751                 {
752                         handle_ani_icon(rtp, type, isswapped);
753                         rtp = NEXT_TAG(rtp);
754                 }
755                 else
756                         internal_error(__FILE__, __LINE__, "Unknown tag \"%c%c%c%c\" in RIFF file",
757                                        isprint(rtp->tag[0]) ? rtp->tag[0] : '.',
758                                        isprint(rtp->tag[1]) ? rtp->tag[1] : '.',
759                                        isprint(rtp->tag[2]) ? rtp->tag[2] : '.',
760                                        isprint(rtp->tag[3]) ? rtp->tag[3] : '.');
761
762                 /* FIXME: This relies in sizeof(DWORD) == sizeof(pointer_type) */
763                 if((DWORD)rtp & 1)
764                         ((char *)rtp)++;
765         }
766 }
767
768 ani_curico_t *new_ani_curico(enum res_e type, raw_data_t *rd, int *memopt)
769 {
770         ani_curico_t *ani = (ani_curico_t *)xmalloc(sizeof(ani_curico_t));
771         riff_tag_t *rtp;
772         int isswapped = 0;
773         int doswap;
774         const char *anistr = type == res_aniico ? "icon" : "cursor";
775
776         assert(!memcmp(rd->data, riff, sizeof(riff)));
777         assert(type == res_anicur || type == res_aniico);
778
779         rtp = (riff_tag_t *)rd->data;
780
781         if(BYTESWAP_DWORD(rtp->size) + 2*sizeof(DWORD) == rd->size)
782                 isswapped = 1;
783         else if(rtp->size + 2*sizeof(DWORD) == rd->size)
784                 isswapped = 0;
785         else
786                 yyerror("Animated %s has an invalid RIFF length", anistr);
787
788         switch(byteorder)
789         {
790 #ifdef WORDS_BIGENDIAN
791         case WRC_BO_LITTLE:
792 #else
793         case WRC_BO_BIG:
794 #endif
795                 doswap = !isswapped;
796                 break;
797         default:
798                 doswap = isswapped;
799         }
800
801         /*
802          * When to swap what:
803          * isswapped | doswap |
804          * ----------+--------+---------------------------------
805          *     0     |    0   | read native; don't convert
806          *     1     |    0   | read swapped size; don't convert
807          *     0     |    1   | read native; convert
808          *     1     |    1   | read swapped size; convert
809          * Reading swapped size if necessary to calculate in native
810          * format. E.g. a little-endian source on a big-endian
811          * processor.
812          */
813         if(doswap)
814         {
815                 /* We only go through the RIFF file if we need to swap
816                  * bytes in words/dwords. Else we couldn't care less
817                  * what the file contains. This is consistent with
818                  * MS' rc.exe, which doesn't complain at all, eventhough
819                  * the fileformat might not be entirely correct.
820                  */
821                 rtp++;  /* Skip the "RIFF" tag */
822
823                 while((char *)rtp < (char *)rd->data + rd->size)
824                 {
825                         if(!memcmp(rtp->tag, acon, sizeof(acon)))
826                         {
827                                 rtp = (riff_tag_t *)(((char *)rtp) + 4);
828                         }
829                         else if(!memcmp(rtp->tag, list, sizeof(list)))
830                         {
831                                 handle_ani_list(rtp, type, isswapped);
832                                 rtp = NEXT_TAG(rtp);
833                         }
834                         else if(!memcmp(rtp->tag, anih, sizeof(anih)))
835                         {
836                                 aniheader_t *ahp = (aniheader_t *)((char *)(rtp+1));
837                                 ahp->structsize = BYTESWAP_DWORD(ahp->structsize);
838                                 ahp->frames     = BYTESWAP_DWORD(ahp->frames);
839                                 ahp->steps      = BYTESWAP_DWORD(ahp->steps);
840                                 ahp->cx         = BYTESWAP_DWORD(ahp->cx);
841                                 ahp->cy         = BYTESWAP_DWORD(ahp->cy);
842                                 ahp->bitcount   = BYTESWAP_DWORD(ahp->bitcount);
843                                 ahp->planes     = BYTESWAP_DWORD(ahp->planes);
844                                 ahp->rate       = BYTESWAP_DWORD(ahp->rate);
845                                 ahp->flags      = BYTESWAP_DWORD(ahp->flags);
846                                 rtp = NEXT_TAG(rtp);
847                         }
848                         else if(!memcmp(rtp->tag, rate, sizeof(rate)))
849                         {
850                                 int cnt = rtp->size / sizeof(DWORD);
851                                 DWORD *dwp = (DWORD *)(rtp+1);
852                                 int i;
853                                 for(i = 0; i < cnt; i++)
854                                         dwp[i] = BYTESWAP_DWORD(dwp[i]);
855                                 rtp = NEXT_TAG(rtp);
856                         }
857                         else if(!memcmp(rtp->tag, seq, sizeof(seq)))
858                         {
859                                 int cnt = rtp->size / sizeof(DWORD);
860                                 DWORD *dwp = (DWORD *)(rtp+1);
861                                 int i;
862                                 for(i = 0; i < cnt; i++)
863                                         dwp[i] = BYTESWAP_DWORD(dwp[i]);
864                                 rtp = NEXT_TAG(rtp);
865                         }
866                         else
867                                 internal_error(__FILE__, __LINE__, "Unknown tag \"%c%c%c%c\" in RIFF file",
868                                        isprint(rtp->tag[0]) ? rtp->tag[0] : '.',
869                                        isprint(rtp->tag[1]) ? rtp->tag[1] : '.',
870                                        isprint(rtp->tag[2]) ? rtp->tag[2] : '.',
871                                        isprint(rtp->tag[3]) ? rtp->tag[3] : '.');
872
873                         /* FIXME: This relies in sizeof(DWORD) == sizeof(pointer_type) */
874                         if((DWORD)rtp & 1)
875                                 ((char *)rtp)++;
876                 }
877
878                 /* We must end correctly here */
879                 if((char *)rtp != (char *)rd->data + rd->size)
880                         yyerror("Animated %s contains invalid field size(s)", anistr);
881         }
882
883         ani->data = rd;
884         if(memopt)
885         {
886                 ani->memopt = *memopt;
887                 free(memopt);
888         }
889         else
890                 ani->memopt = WRC_MO_MOVEABLE | WRC_MO_DISCARDABLE;
891         return ani;
892 }
893 #undef NEXT_TAG
894
895 /* Bitmaps */
896 bitmap_t *new_bitmap(raw_data_t *rd, int *memopt)
897 {
898         bitmap_t *bmp = (bitmap_t *)xmalloc(sizeof(bitmap_t));
899
900         bmp->data = rd;
901         if(memopt)
902         {
903                 bmp->memopt = *memopt;
904                 free(memopt);
905         }
906         else
907                 bmp->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
908         rd->size -= convert_bitmap(rd->data, rd->size);
909         return bmp;
910 }
911
912 ver_words_t *new_ver_words(int i)
913 {
914         ver_words_t *w = (ver_words_t *)xmalloc(sizeof(ver_words_t));
915         w->words = (WORD *)xmalloc(sizeof(WORD));
916         w->words[0] = (WORD)i;
917         w->nwords = 1;
918         return w;
919 }
920
921 ver_words_t *add_ver_words(ver_words_t *w, int i)
922 {
923         w->words = (WORD *)xrealloc(w->words, (w->nwords+1) * sizeof(WORD));
924         w->words[w->nwords] = (WORD)i;
925         w->nwords++;
926         return w;
927 }
928
929 #define MSGTAB_BAD_PTR(p, b, l, r)      (((l) - ((char *)(p) - (char *)(b))) > (r))
930 messagetable_t *new_messagetable(raw_data_t *rd, int *memopt)
931 {
932         messagetable_t *msg = (messagetable_t *)xmalloc(sizeof(messagetable_t));
933         msgtab_block_t *mbp;
934         DWORD nblk;
935         DWORD i;
936         WORD lo;
937         WORD hi;
938
939         msg->data = rd;
940         if(memopt)
941         {
942                 msg->memopt = *memopt;
943                 free(memopt);
944         }
945         else
946                 msg->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE;
947
948         if(rd->size < sizeof(DWORD))
949                 yyerror("Invalid messagetable, size too small");
950
951         nblk = *(DWORD *)rd->data;
952         lo = WRC_LOWORD(nblk);
953         hi = WRC_HIWORD(nblk);
954
955         /* FIXME:
956          * This test will fail for all n*2^16 blocks in the messagetable.
957          * However, no sane person would want to have so many blocks
958          * and have a table of megabytes attached.
959          * So, I will assume that we have less than 2^16 blocks in the table
960          * and all will just work out fine. Otherwise, we would need to test
961          * the ID, offset and length (and flag) fields to be very sure.
962          */
963         if(hi && lo)
964                 internal_error(__FILE__, __LINE__, "Messagetable contains more than 65535 blocks; cannot determine endian");
965         if(!hi && !lo)
966                 yyerror("Invalid messagetable block count 0");
967
968         if(!hi && lo)  /* Messagetable byteorder == native byteorder */
969         {
970 #ifdef WORDS_BIGENDIAN
971                 if(byteorder != WRC_BO_LITTLE) goto out;
972 #else
973                 if(byteorder != WRC_BO_BIG) goto out;
974 #endif
975                 /* Resource byteorder != native byteorder */
976
977                 mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]);
978                 if(MSGTAB_BAD_PTR(mbp, rd->data, rd->size, nblk * sizeof(*mbp)))
979                         yyerror("Messagetable's blocks are outside of defined data");
980                 for(i = 0; i < nblk; i++)
981                 {
982                         msgtab_entry_t *mep, *next_mep;
983                         DWORD id;
984
985                         mep = (msgtab_entry_t *)(((char *)rd->data) + mbp[i].offset);
986
987                         for(id = mbp[i].idlo; id <= mbp[i].idhi; id++)
988                         {
989                                 if(MSGTAB_BAD_PTR(mep, rd->data, rd->size, mep->length))
990                                         yyerror("Messagetable's data for block %d, ID 0x%08lx is outside of defined data", (int)i, id);
991                                 if(mep->flags == 1)     /* Docu says 'flags == 0x0001' for unicode */
992                                 {
993                                         WORD *wp = (WORD *)&mep[1];
994                                         int l = mep->length/2 - 2; /* Length included header */
995                                         int n;
996
997                                         if(mep->length & 1)
998                                                 yyerror("Message 0x%08lx is unicode (block %d), but has odd length (%d)", id, (int)i, mep->length);
999                                         for(n = 0; n < l; n++)
1000                                                 wp[n] = BYTESWAP_WORD(wp[n]);
1001
1002                                 }
1003                                 next_mep = (msgtab_entry_t *)(((char *)mep) + mep->length);
1004                                 mep->length = BYTESWAP_WORD(mep->length);
1005                                 mep->flags  = BYTESWAP_WORD(mep->flags);
1006                                 mep = next_mep;
1007                         }
1008
1009                         mbp[i].idlo   = BYTESWAP_DWORD(mbp[i].idlo);
1010                         mbp[i].idhi   = BYTESWAP_DWORD(mbp[i].idhi);
1011                         mbp[i].offset = BYTESWAP_DWORD(mbp[i].offset);
1012                 }
1013         }
1014         if(hi && !lo)  /* Messagetable byteorder != native byteorder */
1015         {
1016 #ifdef WORDS_BIGENDIAN
1017                 if(byteorder == WRC_BO_LITTLE) goto out;
1018 #else
1019                 if(byteorder == WRC_BO_BIG) goto out;
1020 #endif
1021                 /* Resource byteorder == native byteorder */
1022
1023                 mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]);
1024                 nblk = BYTESWAP_DWORD(nblk);
1025                 if(MSGTAB_BAD_PTR(mbp, rd->data, rd->size, nblk * sizeof(*mbp)))
1026                         yyerror("Messagetable's blocks are outside of defined data");
1027                 for(i = 0; i < nblk; i++)
1028                 {
1029                         msgtab_entry_t *mep;
1030                         DWORD id;
1031
1032                         mbp[i].idlo   = BYTESWAP_DWORD(mbp[i].idlo);
1033                         mbp[i].idhi   = BYTESWAP_DWORD(mbp[i].idhi);
1034                         mbp[i].offset = BYTESWAP_DWORD(mbp[i].offset);
1035                         mep = (msgtab_entry_t *)(((char *)rd->data) + mbp[i].offset);
1036
1037                         for(id = mbp[i].idlo; id <= mbp[i].idhi; id++)
1038                         {
1039                                 mep->length = BYTESWAP_WORD(mep->length);
1040                                 mep->flags  = BYTESWAP_WORD(mep->flags);
1041
1042                                 if(MSGTAB_BAD_PTR(mep, rd->data, rd->size, mep->length))
1043                                         yyerror("Messagetable's data for block %d, ID 0x%08lx is outside of defined data", (int)i, id);
1044                                 if(mep->flags == 1)     /* Docu says 'flags == 0x0001' for unicode */
1045                                 {
1046                                         WORD *wp = (WORD *)&mep[1];
1047                                         int l = mep->length/2 - 2; /* Length included header */
1048                                         int n;
1049
1050                                         if(mep->length & 1)
1051                                                 yyerror("Message 0x%08lx is unicode (block %d), but has odd length (%d)", id, (int)i, mep->length);
1052                                         for(n = 0; n < l; n++)
1053                                                 wp[n] = BYTESWAP_WORD(wp[n]);
1054
1055                                 }
1056                                 mep = (msgtab_entry_t *)(((char *)mep) + mep->length);
1057                         }
1058                 }
1059         }
1060
1061  out:
1062         return msg;
1063 }
1064 #undef MSGTAB_BAD_PTR
1065
1066 void copy_raw_data(raw_data_t *dst, raw_data_t *src, unsigned int offs, int len)
1067 {
1068         assert(offs <= src->size);
1069         assert(offs + len <= src->size);
1070         if(!dst->data)
1071         {
1072                 dst->data = (char *)xmalloc(len);
1073                 dst->size = 0;
1074         }
1075         else
1076                 dst->data = (char *)xrealloc(dst->data, dst->size + len);
1077         /* dst->size holds the offset to copy to */
1078         memcpy(dst->data + dst->size, src->data + offs, len);
1079         dst->size += len;
1080 }
1081
1082 int *new_int(int i)
1083 {
1084         int *ip = (int *)xmalloc(sizeof(int));
1085         *ip = i;
1086         return ip;
1087 }
1088
1089 stringtable_t *new_stringtable(lvc_t *lvc)
1090 {
1091         stringtable_t *stt = (stringtable_t *)xmalloc(sizeof(stringtable_t));
1092
1093         if(lvc)
1094                 stt->lvc = *lvc;
1095
1096         return stt;
1097 }
1098
1099 toolbar_t *new_toolbar(int button_width, int button_height, toolbar_item_t *items, int nitems)
1100 {
1101         toolbar_t *tb = (toolbar_t *)xmalloc(sizeof(toolbar_t));
1102         tb->button_width = button_width;
1103         tb->button_height = button_height;
1104         tb->nitems = nitems;
1105         tb->items = items;
1106         return tb;
1107 }
1108
1109 dlginit_t *new_dlginit(raw_data_t *rd, int *memopt)
1110 {
1111         dlginit_t *di = (dlginit_t *)xmalloc(sizeof(dlginit_t));
1112         di->data = rd;
1113         if(memopt)
1114         {
1115                 di->memopt = *memopt;
1116                 free(memopt);
1117         }
1118         else
1119                 di->memopt = WRC_MO_MOVEABLE | WRC_MO_PURE | WRC_MO_DISCARDABLE;
1120
1121         return di;
1122 }
1123
1124 style_pair_t *new_style_pair(style_t *style, style_t *exstyle)
1125 {
1126         style_pair_t *sp = (style_pair_t *)xmalloc(sizeof(style_pair_t));
1127         sp->style = style;
1128         sp->exstyle = exstyle;
1129         return sp;
1130 }
1131
1132 style_t *new_style(DWORD or_mask, DWORD and_mask)
1133 {
1134         style_t *st = (style_t *)xmalloc(sizeof(style_t));
1135         st->or_mask = or_mask;
1136         st->and_mask = and_mask;
1137         return st;
1138 }