source: trunk/emx/src/emxbind/resource.c

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 8.8 KB
Line 
1/* resource.c -- Manage resources
2 Copyright (c) 1991-1998 Eberhard Mattes
3
4This file is part of emxbind.
5
6emxbind is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emxbind is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emxbind; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include "defs.h"
26#include "emxbind.h"
27
28
29/* Flags for resources. */
30
31#define RES_MOVEABLE 0x0010
32#define RES_PRELOAD 0x0040
33#define RES_DISCARDABLE 0x1000
34
35
36/* This is the layout of the header of a binary resource (in a .res
37 or .exe file). */
38
39#pragma pack(1)
40
41struct bin_res
42{
43 byte type_flag; /* Always 0xff (type is an integer)*/
44 word type_value; /* Type of the resource */
45 byte id_flag; /* Always 0xff (ID is an integer)*/
46 word id_value; /* Resources identifier */
47 word options; /* Load and memory options */
48 dword length; /* Size of the resource in bytes */
49};
50
51#pragma pack(4)
52
53/* Internal representation of a resource. */
54
55struct resource
56{
57 word type;
58 word id;
59 dword file_pos;
60 dword length;
61 dword offset;
62};
63
64/* Internal respresentation of a resource object. */
65
66struct res_obj
67{
68 struct resource *res;
69 size_t res_size;
70 size_t res_len;
71 word res_options;
72 word obj_number;
73 dword obj_size;
74};
75
76
77/* This table describes all the resource objects. There are
78 res_obj_count entries. */
79
80static struct res_obj *res_objs = NULL;
81
82/* This is the number of preload resource objects. */
83
84static int res_preload_obj_count;
85
86/* emxbind tries to use the last resource page for the a.out header.
87 If there isn't enough space left in the last resource page, this
88 flag is set to indicate that an extra page is to be allocated for
89 the a.out header. That page won't be referenced by the LX
90 header. */
91
92static int extra_aout_page;
93
94
95/* This function compares two resource table entries for qsort(). It
96 is used for sorting the resource table by resource attributes
97 (preload resources come first) and object number. */
98
99static int res_obj_compare (const void *x1, const void *x2)
100{
101 word opt1, opt2;
102
103 opt1 = ((struct res_obj *)x1)->res_options;
104 opt2 = ((struct res_obj *)x2)->res_options;
105 if ((opt1 & RES_PRELOAD) != (opt2 & RES_PRELOAD))
106 {
107 if (opt1 & RES_PRELOAD)
108 return -1;
109 else
110 return 1;
111 }
112 return ((int)((struct res_obj *)x1)->obj_number -
113 (int)((struct res_obj *)x2)->obj_number);
114}
115
116
117/* This function compares two resource table entries for qsort(). It
118 is used for sorting the resource table by type and ID. */
119
120static int res_compare (const void *x1, const void *x2)
121{
122 int a1, a2;
123
124 a1 = ((struct resource *)x1)->type;
125 a2 = ((struct resource *)x2)->type;
126 if (a1 != a2)
127 return a1 - a2;
128 a1 = ((struct resource *)x1)->id;
129 a2 = ((struct resource *)x2)->id;
130 return a1 - a2;
131}
132
133
134/* Read a binary resource file. */
135
136void read_res (void)
137{
138 struct bin_res br;
139 struct res_obj *rop;
140 struct resource *rp;
141 size_t i, j;
142 int obj_no;
143 long file_size;
144
145 res_count = 0; res_obj_count = 0; res_preload_pages = 0; res_pages = 0;
146 res_preload_obj_count = 0; extra_aout_page = FALSE;
147 if (opt_r == NULL)
148 return;
149 file_size = my_size (&res_file);
150 my_seek (&res_file, 0);
151 while (my_tell (&res_file) != file_size)
152 {
153 my_read (&br, sizeof (br), &res_file);
154 if (br.type_flag != 0xff || br.id_flag != 0xff)
155 error ("invalid binary resource file");
156
157 /* Resource types 22 and 23 are ignored for unknown reasons. */
158
159 if (br.type_value != 22 && br.type_value != 23)
160 {
161 ++res_count;
162 for (i = 0; i < res_obj_count; ++i)
163 if (res_objs[i].res_options == br.options)
164 break;
165 if (i < res_obj_count)
166 rop = &res_objs[i];
167 else
168 {
169 ++res_obj_count;
170 res_objs = xrealloc (res_objs, res_obj_count
171 * sizeof (struct res_obj));
172 rop = &res_objs[res_obj_count-1];
173 rop->res = NULL;
174 rop->res_size = 0;
175 rop->res_len = 0;
176 rop->res_options = br.options;
177 rop->obj_size = 0;
178 rop->obj_number = res_obj_count; /* for sorting */
179 if (br.options & RES_PRELOAD)
180 ++res_preload_obj_count;
181 }
182 if (rop->res_len >= rop->res_size)
183 {
184 rop->res_size += 16;
185 rop->res = xrealloc (rop->res, rop->res_size * sizeof (*rop->res));
186 }
187 rp = &rop->res[rop->res_len++];
188 rp->type = br.type_value;
189 rp->id = br.id_value;
190 rp->file_pos = my_tell (&res_file);
191 rp->length = br.length;
192 rp->offset = 0;
193 }
194 my_skip (&res_file, br.length);
195 }
196 if (verbosity > 0)
197 printf ("%d resource%s in %d object%s\n",
198 res_count, plural_s (res_count),
199 res_obj_count, plural_s (res_obj_count));
200 qsort (res_objs, res_obj_count, sizeof (struct res_obj), res_obj_compare);
201 obj_no = OBJECTS + 1;
202 for (i = 0, rop = res_objs; i < res_obj_count; ++i, ++rop)
203 {
204 qsort (rop->res, rop->res_len, sizeof (struct resource), res_compare);
205 rop->obj_number = obj_no++;
206 for (j = 0; j < rop->res_len; ++j)
207 {
208 rop->obj_size = round_4 (rop->obj_size);
209 rop->res[j].offset = rop->obj_size;
210 rop->obj_size += rop->res[j].length;
211 }
212 j = npages (rop->obj_size);
213 if (rop->res_options & RES_PRELOAD)
214 res_preload_pages += j;
215 res_pages += j;
216 }
217 extra_aout_page = (res_pages != 0
218 && ((res_objs[res_obj_count-1].obj_size & 0xfff)
219 > 0x1000 - A_OUT_OFFSET));
220 if (extra_aout_page)
221 ++res_pages; /* This one is for the a.out header */
222}
223
224
225/* Write resources to the destination executable file. */
226
227void write_res (void)
228{
229 struct res_obj *rop;
230 int i, j;
231 long pos;
232 enum {ro_unknown, ro_preload, ro_demand} ro_last, ro_this;
233
234 if (res_count == 0)
235 return;
236 ro_last = ro_unknown;
237 if (verbosity >= 2)
238 puts ("Writing resources");
239 for (i = 0, rop = res_objs; i < res_obj_count; ++i, ++rop)
240 {
241 if (verbosity >= 2)
242 {
243 if (rop->res_options & RES_PRELOAD)
244 ro_this = ro_preload;
245 else
246 ro_this = ro_demand;
247 if (ro_this != ro_last)
248 {
249 ro_last = ro_this;
250 if (ro_this == ro_preload)
251 printf ("Writing %d PRELOAD resource object%s\n",
252 res_preload_obj_count,
253 plural_s (res_preload_obj_count));
254 else
255 printf ("Writing %d DEMAND resource object%s\n",
256 res_obj_count - res_preload_obj_count,
257 plural_s (res_obj_count - res_preload_obj_count));
258 }
259 printf (" Writing: %ld bytes in %lu page%s\n",
260 round_4 (rop->obj_size),
261 npages (rop->obj_size), plural_s (npages (rop->obj_size)));
262 }
263 pos = 0;
264 for (j = 0; j < rop->res_len; ++j)
265 {
266 if (verbosity >= 2)
267 printf (" %d.%d (%lu byte%s)\n",
268 rop->res[j].id, rop->res[j].type,
269 rop->res[j].length, plural_s (rop->res[j].length));
270 fill (rop->res[j].offset - pos);
271 my_seek (&res_file, rop->res[j].file_pos);
272 copy (&res_file, rop->res[j].length);
273 pos = rop->res[j].offset + rop->res[j].length;
274 }
275 if (pos != rop->obj_size)
276 error ("internal error 2");
277 if (i < res_obj_count - 1)
278 fill (round_page (pos) - pos);
279 else if (extra_aout_page)
280 fill (round_page (pos) - pos + 0x1000 - A_OUT_OFFSET);
281 else
282 fill (round_page (pos) - pos - A_OUT_OFFSET);
283 }
284}
285
286
287void put_rsctab (void)
288{
289 int j, k;
290 const struct res_obj *rop;
291
292 os2_h.rsctab_count = res_count;
293 for (j = 0, rop = res_objs; j < res_obj_count; ++j, ++rop)
294 for (k = 0; k < rop->res_len; ++k)
295 {
296 put_header_word (rop->res[k].type);
297 put_header_word (rop->res[k].id);
298 put_header_dword (rop->res[k].length);
299 put_header_word (rop->obj_number);
300 put_header_dword (rop->res[k].offset);
301 }
302}
303
304
305void put_res_obj (int map)
306{
307 int j;
308 const struct res_obj *rop;
309 struct object obj_res;
310
311 for (j = 0, rop = res_objs; j < res_obj_count; ++j, ++rop)
312 {
313 obj_res.virt_size = rop->obj_size;
314 obj_res.virt_base = 0;
315 obj_res.attr_flags = 0x2029;
316 if (rop->res_options & RES_PRELOAD)
317 obj_res.attr_flags |= 0x0040;
318 if (rop->res_options & RES_DISCARDABLE)
319 obj_res.attr_flags |= 0x0010;
320 obj_res.map_first = map;
321 obj_res.map_count = npages (rop->obj_size);
322 obj_res.reserved = 0;
323 put_header_bytes (&obj_res, sizeof (obj_res));
324 map += obj_res.map_count;
325 }
326}
Note: See TracBrowser for help on using the repository browser.