fixed some warnings with gcc4 (mostly assignment differs in signedness warnings)
[reactos.git] / reactos / tools / wrc / readres.c
1 /*
2 * Read a .res file and create a resource-tree
3 *
4 * Copyright 1998 Bertho A. Stultiens
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "wrc.h"
29 #include "readres.h"
30 #include "newstruc.h"
31 #include "utils.h"
32 #include "genres.h"
33
34 struct resheader32 {
35 DWORD ressize; /* 0 */
36 DWORD hdrsize; /* 0x20 */
37 WORD restype1; /* 0xffff */
38 WORD restype2; /* 0 */
39 WORD resname1; /* 0xffff */
40 WORD resname2; /* 0 */
41 DWORD dversion; /* 0 */
42 WORD memopt; /* 0 */
43 WORD language; /* 0 */
44 DWORD version; /* 0 */
45 DWORD characts; /* 0 */
46 } emptyheader = {0, 0x20, 0xffff, 0, 0xffff, 0, 0, 0, 0, 0, 0},
47 emptyheaderSWAPPED = {0, BYTESWAP_DWORD(0x20), 0xffff, 0, 0xffff, 0, 0, 0, 0, 0, 0};
48
49 /*
50 *****************************************************************************
51 * Function :
52 * Syntax :
53 * Input :
54 * Output :
55 * Description :
56 * Remarks :
57 *****************************************************************************
58 */
59 /*
60 *****************************************************************************
61 * Function :
62 * Syntax :
63 * Input :
64 * Output :
65 * Description :
66 * Remarks :
67 *****************************************************************************
68 */
69 /*
70 *****************************************************************************
71 * Function :
72 * Syntax :
73 * Input :
74 * Output :
75 * Description :
76 * Remarks :
77 *****************************************************************************
78 */
79 static int read_data(FILE *fp, size_t size, void *buf)
80 {
81 unsigned int r;
82 int pos = ftell(fp);
83 r = fread(buf, 1, size, fp);
84 if(r == size)
85 return 0;
86 if(r == 0 && ftell(fp) - pos > 0)
87 return 1;
88 else
89 return -1;
90 }
91
92 /*
93 *****************************************************************************
94 * Function :
95 * Syntax :
96 * Input :
97 * Output :
98 * Description :
99 * Remarks :
100 *****************************************************************************
101 */
102 static enum res_e res_type_from_id(const name_id_t *nid)
103 {
104 if(nid->type == name_str)
105 return res_usr;
106
107 if(nid->type != name_ord)
108 internal_error(__FILE__, __LINE__, "Invalid name_id descriptor %d", nid->type);
109
110 switch(nid->name.i_name)
111 {
112 case WRC_RT_CURSOR: return res_cur;
113 case WRC_RT_BITMAP: return res_bmp;
114 case WRC_RT_ICON: return res_ico;
115 case WRC_RT_MENU: return res_men;
116 case WRC_RT_DIALOG: return res_dlg;
117 case WRC_RT_STRING: return res_stt;
118 case WRC_RT_FONTDIR: return res_fntdir;
119 case WRC_RT_FONT: return res_fnt;
120 case WRC_RT_ACCELERATOR: return res_acc;
121 case WRC_RT_RCDATA: return res_rdt;
122 case WRC_RT_MESSAGETABLE: return res_msg;
123 case WRC_RT_GROUP_CURSOR: return res_curg;
124 case WRC_RT_GROUP_ICON: return res_icog;
125 case WRC_RT_VERSION: return res_ver;
126 case WRC_RT_TOOLBAR: return res_toolbar;
127
128 default:
129 case WRC_RT_DLGINCLUDE:
130 case WRC_RT_PLUGPLAY:
131 case WRC_RT_VXD:
132 case WRC_RT_ANICURSOR:
133 case WRC_RT_ANIICON:
134 warning("Cannot be sure of resource type, using usertype settings");
135 return res_usr;
136 }
137 }
138
139 /*
140 *****************************************************************************
141 * Function :
142 * Syntax :
143 * Input :
144 * Output :
145 * Description :
146 * Remarks :
147 *****************************************************************************
148 */
149 #define get_word(idx) (*((WORD *)(&res->data[idx])))
150 #define get_dword(idx) (*((DWORD *)(&res->data[idx])))
151
152 static resource_t *read_res32(FILE *fp)
153 {
154 static const char wrong_format[] = "Wrong resfile format (32bit)";
155 DWORD ressize;
156 DWORD hdrsize;
157 DWORD totsize;
158 WORD memopt;
159 WORD language;
160 int err;
161 res_t *res;
162 resource_t *rsc;
163 resource_t *tail = NULL;
164 resource_t *list = NULL;
165 name_id_t *type = NULL;
166 name_id_t *name = NULL;
167 int idx;
168 enum res_e res_type;
169 user_t *usrres;
170
171 while(1)
172 {
173 /* Get headersize and resource size */
174 err = read_data(fp, sizeof(ressize), &ressize);
175 if(err < 0)
176 break;
177 else if(err > 0)
178 error(wrong_format);
179 err = read_data(fp, sizeof(hdrsize), &hdrsize);
180 if(err)
181 error(wrong_format);
182
183 /* Align sizes and compute total size */
184 totsize = hdrsize;
185 if(hdrsize & 3)
186 {
187 warning("Hu? .res header needed alignment (anything can happen now)");
188 totsize += 4 - (hdrsize & 3);
189 }
190 totsize += ressize;
191 if(ressize & 3)
192 totsize += 4 - (ressize & 3);
193
194 /* Read in entire data-block */
195 fseek(fp, -8, SEEK_CUR);
196 res = new_res();
197 if(res->allocsize < totsize)
198 grow_res(res, totsize - res->allocsize + 8);
199 err = read_data(fp, totsize, res->data);
200 if(err)
201 error(wrong_format);
202
203 res->dataidx = hdrsize;
204 res->size = hdrsize + ressize;
205
206 /* Analyse the content of the header */
207 idx = 8;
208 /* Get restype */
209 if(get_word(idx) == 0xffff)
210 {
211 idx += sizeof(WORD);
212 type = new_name_id();
213 type->type = name_ord;
214 type->name.i_name = get_word(idx);
215 idx += sizeof(WORD);
216 }
217 else if(get_word(idx) == 0)
218 {
219 error("ResType name has zero length (32 bit)");
220 }
221 else
222 {
223 int tag = idx;
224 string_t *str;
225 while(1)
226 {
227 idx += sizeof(WORD);
228 if(!get_word(idx))
229 break;
230 }
231 idx += sizeof(WORD);
232 str = new_string();
233 str->type = str_unicode;
234 str->size = (idx - tag) / 2;
235 str->str.wstr = (WCHAR *)xmalloc(idx-tag+2);
236 memcpy(str->str.wstr, &res->data[tag], idx-tag);
237 str->str.wstr[str->size] = 0;
238 type = new_name_id();
239 type->type = name_str;
240 type->name.s_name = str;
241 }
242 /* Get resname */
243 if(get_word(idx) == 0xffff)
244 {
245 idx += sizeof(WORD);
246 name = new_name_id();
247 name->type = name_ord;
248 name->name.i_name = get_word(idx);
249 idx += sizeof(WORD);
250 }
251 else if(get_word(idx) == 0)
252 {
253 error("ResName name has zero length (32 bit)");
254 }
255 else
256 {
257 int tag = idx;
258 string_t *str;
259 while(1)
260 {
261 idx += sizeof(WORD);
262 if(!get_word(idx))
263 break;
264 }
265 idx += sizeof(WORD);
266 str = new_string();
267 str->type = str_unicode;
268 str->size = (idx - tag) / 2;
269 str->str.wstr = (WCHAR *)xmalloc(idx-tag+2);
270 memcpy(str->str.wstr, &res->data[tag], idx-tag);
271 str->str.wstr[str->size] = 0;
272 name = new_name_id();
273 name->type = name_str;
274 name->name.s_name = str;
275 }
276
277 /* align */
278 if(idx & 0x3)
279 idx += 4 - (idx & 3);
280
281 idx += sizeof(DWORD); /* Skip DataVersion */
282 memopt = get_word(idx);
283 idx += sizeof(WORD);
284 language = get_word(idx);
285
286 /* Build a resource_t list */
287 res_type = res_type_from_id(type);
288 if(res_type == res_usr)
289 {
290 /* User-type has custom ResType for .[s|h] generation */
291 usrres = new_user(type, NULL, new_int(memopt));
292 }
293 else
294 usrres = NULL;
295 rsc = new_resource(res_type,
296 usrres,
297 memopt,
298 new_language(PRIMARYLANGID(language),
299 SUBLANGID(language)));
300 rsc->binres = res;
301 rsc->name = name;
302 rsc->c_name = make_c_name(get_c_typename(res_type), name, rsc->lan);
303 if(!list)
304 {
305 list = rsc;
306 tail = rsc;
307 }
308 else
309 {
310 rsc->prev = tail;
311 tail->next = rsc;
312 tail = rsc;
313 }
314 }
315 return list;
316 }
317
318 /*
319 *****************************************************************************
320 * Function :
321 * Syntax :
322 * Input :
323 * Output :
324 * Description :
325 * Remarks :
326 *****************************************************************************
327 */
328 static resource_t *read_res16(FILE *fp)
329 {
330 internal_error(__FILE__, __LINE__, "Can't yet read 16 bit .res files");
331 return NULL;
332 }
333
334 /*
335 *****************************************************************************
336 * Function : read_resfile
337 * Syntax : resource_t *read_resfile(char *inname)
338 * Input :
339 * Output :
340 * Description :
341 * Remarks :
342 *****************************************************************************
343 */
344 resource_t *read_resfile(char *inname)
345 {
346 FILE *fp;
347 struct resheader32 rh;
348 int is32bit = 1;
349 resource_t *top;
350
351 fp = fopen(inname, "rb");
352 if(!fp)
353 error("Could not open inputfile %s", inname);
354
355 /* Determine 16 or 32 bit .res file */
356 if(fread(&rh, 1, sizeof(rh), fp) != sizeof(rh))
357 is32bit = 0;
358 else
359 {
360 if(!memcmp(&emptyheader, &rh, sizeof(rh)))
361 is32bit = 1;
362 else if(!memcmp(&emptyheaderSWAPPED, &rh, sizeof(rh)))
363 error("Binary .res-file has its byteorder swapped");
364 else
365 is32bit = 0;
366 }
367
368 if(is32bit && !win32)
369 error("Cannot convert 32-bit .res-file into 16-bit resources (and will, hopefully never, implement it)");
370
371 if(!is32bit && win32)
372 error("Cannot (yet) convert 16-bit .res-file into 32-bit resources");
373
374 if(!is32bit)
375 {
376 fseek(fp, 0, SEEK_SET);
377 top = read_res16(fp);
378 }
379 else
380 {
381 top = read_res32(fp);
382 }
383
384 fclose(fp);
385
386 return top;
387 }