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