Release 941017
[wine] / loader / ne_resource.c
1 static char RCSId[] = "$Id: ne_resource.c,v 1.4 1993/07/04 04:04:21 root Exp root $";
2 static char Copyright[] = "Copyright  Robert J. Amstadt, 1993";
3
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include "windows.h"
12 #include "neexe.h"
13 #include "peexe.h"
14 #include "arch.h"
15 #include "dlls.h"
16 #include "resource.h"
17
18 /* #define DEBUG_RESOURCE */
19
20 static int ResourceFd = -1;
21 static HANDLE ResourceInst = 0;
22 static struct w_files *ResourceFileInfo;
23 \f
24 /**********************************************************************
25  *                      RSC_LoadNameTable
26  */
27 void RSC_LoadNameTable(void)
28 {
29     struct resource_typeinfo_s typeinfo;
30     struct resource_nameinfo_s nameinfo;
31     unsigned short             size_shift;
32     RESNAMTAB                 *top, *new;
33     char                       read_buf[1024];
34     char                      *p;
35     int                        i;
36     unsigned short             len;
37     off_t                      rtoff;
38     off_t                      saved_pos;
39     
40     top = NULL;
41
42     /*
43      * Move to beginning of resource table.
44      */
45     rtoff = (ResourceFileInfo->mz_header->ne_offset +
46              ResourceFileInfo->ne->ne_header->resource_tab_offset);
47     lseek(ResourceFd, rtoff, SEEK_SET);
48     
49     /*
50      * Read block size.
51      */
52     if (read(ResourceFd, &size_shift, sizeof(size_shift)) != 
53         sizeof(size_shift))
54     {
55         return;
56     }
57     size_shift = CONV_SHORT(size_shift);
58
59     /*
60      * Find resource.
61      */
62     typeinfo.type_id = 0xffff;
63     while (typeinfo.type_id != 0) 
64     {
65         if (!load_typeinfo (ResourceFd, &typeinfo))
66             break;
67
68         if (typeinfo.type_id == 0) 
69             break;
70         if (typeinfo.type_id == 0x800f) 
71         {
72             for (i = 0; i < typeinfo.count; i++) 
73             {
74                 if (read(ResourceFd, &nameinfo, sizeof(nameinfo)) != 
75                     sizeof(nameinfo))
76                 {
77                     break;
78                 }
79                 
80                 saved_pos = lseek(ResourceFd, 0, SEEK_CUR);
81                 lseek(ResourceFd, (long) nameinfo.offset << size_shift, 
82                       SEEK_SET);
83                 read(ResourceFd, &len, sizeof(len));
84                 while (len)
85                 {
86                     new = (RESNAMTAB *) GlobalQuickAlloc(sizeof(*new));
87                     new->next = top;
88                     top = new;
89
90                     read(ResourceFd, &new->type_ord, 2);
91                     read(ResourceFd, &new->id_ord, 2);
92                     read(ResourceFd, read_buf, len - 6);
93                     
94                     p = read_buf + strlen(read_buf) + 1;
95                     strncpy(new->id, p, MAX_NAME_LENGTH);
96                     new->id[MAX_NAME_LENGTH - 1] = '\0';
97
98                     read(ResourceFd, &len, sizeof(len));
99                 }
100
101                 lseek(ResourceFd, saved_pos, SEEK_SET);
102             }
103             break;
104         }
105         else 
106         {
107             lseek(ResourceFd, (typeinfo.count * sizeof(nameinfo)), SEEK_CUR);
108         }
109     }
110     ResourceFileInfo->ne->resnamtab = top;
111 }
112
113 /**********************************************************************
114  *                                      OpenResourceFile
115  */
116 int
117 OpenResourceFile(HANDLE instance)
118 {
119     struct w_files *w;
120     char   *res_file;
121     
122     if (ResourceInst == instance)
123         return ResourceFd;
124
125     w = GetFileInfo(instance);
126     if (w == NULL)
127         return -1;
128     ResourceFileInfo = w;
129     res_file = w->filename;
130     
131     if (ResourceFd >= 0)
132         close(ResourceFd);
133     
134     ResourceInst = instance;
135     ResourceFd   = open (res_file, O_RDONLY);
136 #if 1
137 #ifndef WINELIB
138     if (w->ne->resnamtab == (RESNAMTAB *) -1)
139     {
140         RSC_LoadNameTable();
141     }
142 #endif
143 #endif
144
145 #ifdef DEBUG_RESOURCE
146     printf("OpenResourceFile(%04X) // file='%s' hFile=%04X !\n", 
147                 instance, w->filename, ResourceFd);
148 #endif
149     return ResourceFd;
150 }
151
152 int load_typeinfo (int fd, struct resource_typeinfo_s *typeinfo)
153 {
154     return read (fd, typeinfo, sizeof (*typeinfo)) == sizeof (*typeinfo);
155 }
156
157 int type_match(int type_id1, int type_id2, int fd, off_t off)
158 {
159         off_t old_pos;
160         unsigned char c;
161         size_t nbytes;
162         char name[256];
163
164         if (type_id1 == -1)
165                 return 1;
166         if ((type_id1 & 0xffff0000) == 0) {
167                 if ((type_id2 & 0x8000) == 0)
168                         return 0;
169                 return (type_id1 & 0x000f) == (type_id2 & 0x000f);
170         }
171         if ((type_id2 & 0x8000) != 0)
172                 return 0;
173 #ifdef DEBUG_RESOURCE
174         printf("type_compare: type_id2=%04X !\n", type_id2);
175 #endif
176         old_pos = lseek(fd, 0, SEEK_CUR);
177         lseek(fd, off + type_id2, SEEK_SET);
178         read(fd, &c, 1);
179         nbytes = CONV_CHAR_TO_LONG (c);
180 #ifdef DEBUG_RESOURCE
181         printf("type_compare: namesize=%d\n", nbytes);
182 #endif
183         read(fd, name, nbytes);
184         lseek(fd, old_pos, SEEK_SET);
185         name[nbytes] = '\0';
186 #ifdef DEBUG_RESOURCE
187         printf("type_compare: name=`%s'\n", name);
188 #endif
189         return strcasecmp((char *) type_id1, name) == 0;
190 }
191
192 /**********************************************************************
193  *                                      FindResourceByNumber
194  */
195 int
196 FindResourceByNumber(struct resource_nameinfo_s *result_p,
197                      int type_id, int resource_id)
198 {
199     struct resource_typeinfo_s typeinfo;
200     struct resource_nameinfo_s nameinfo;
201     unsigned short size_shift;
202     int i;
203     off_t rtoff;
204
205     /*
206      * Move to beginning of resource table.
207      */
208     rtoff = (ResourceFileInfo->mz_header->ne_offset +
209              ResourceFileInfo->ne->ne_header->resource_tab_offset);
210     lseek(ResourceFd, rtoff, SEEK_SET);
211     
212     /*
213      * Read block size.
214      */
215     if (read(ResourceFd, &size_shift, sizeof(size_shift)) != 
216         sizeof(size_shift))
217     {
218         printf("FindResourceByNumber (%d) bad block size !\n",(int) resource_id);
219         return -1;
220     }
221     size_shift = CONV_SHORT(size_shift);
222     /*
223      * Find resource.
224      */
225     for (;;) {
226         if (!load_typeinfo (ResourceFd, &typeinfo)){
227             printf("FindResourceByNumber (%X) bad typeinfo size !\n", resource_id);
228             return -1;
229             }
230 #ifdef DEBUG_RESOURCE
231         printf("FindResourceByNumber type=%X count=%d ?=%d searched=%08X\n", 
232                 typeinfo.type_id, typeinfo.count, typeinfo.reserved, type_id);
233 #endif
234         if (typeinfo.type_id == 0) break;
235         if (type_match(type_id, typeinfo.type_id, ResourceFd, rtoff)) {
236
237             for (i = 0; i < typeinfo.count; i++) {
238 #ifndef WINELIB
239                 if (read(ResourceFd, &nameinfo, sizeof(nameinfo)) != 
240                     sizeof(nameinfo))
241 #else
242                 if (!load_nameinfo (ResourceFd, &nameinfo))
243 #endif
244                 {
245                     printf("FindResourceByNumber (%X) bad nameinfo size !\n", resource_id);
246                     return -1;
247                     }
248 #ifdef DEBUG_RESOURCE
249                 printf("FindResource: search type=%X id=%X // type=%X id=%X\n",
250                         type_id, resource_id, typeinfo.type_id, nameinfo.id);
251 #endif
252                 if (nameinfo.id == resource_id) {
253                     memcpy(result_p, &nameinfo, sizeof(nameinfo));
254                     return size_shift;
255                     }
256                 }
257             }
258         else {
259             lseek(ResourceFd, (typeinfo.count * sizeof(nameinfo)), SEEK_CUR);
260             }
261         }
262     return -1;
263 }
264 \f
265 /**********************************************************************
266  *                                      FindResourceByName
267  */
268 int
269 FindResourceByName(struct resource_nameinfo_s *result_p,
270                      int type_id, char *resource_name)
271 {
272     struct resource_typeinfo_s typeinfo;
273     struct resource_nameinfo_s nameinfo;
274     unsigned short size_shift;
275     off_t old_pos, new_pos;
276     unsigned char nbytes;
277     char name[256];
278     int i;
279     off_t rtoff;
280
281     /*
282      * Check for loaded name table.
283      */
284     if (ResourceFileInfo->ne->resnamtab != NULL)
285     {
286         RESNAMTAB *e;
287
288         for (e = ResourceFileInfo->ne->resnamtab; e != NULL; e = e->next)
289         {
290             if (e->type_ord == (type_id & 0x000f) &&
291                 strcasecmp(e->id, resource_name) == 0)
292             {
293                 return FindResourceByNumber(result_p, type_id, e->id_ord);
294             }
295         }
296
297         return -1;
298     }
299
300     /*
301      * Move to beginning of resource table.
302      */
303     rtoff = (ResourceFileInfo->mz_header->ne_offset +
304              ResourceFileInfo->ne->ne_header->resource_tab_offset);
305     lseek(ResourceFd, rtoff, SEEK_SET);
306     
307     /*
308      * Read block size.
309      */
310     if (read(ResourceFd, &size_shift, sizeof(size_shift)) != 
311         sizeof(size_shift))
312     {
313         printf("FindResourceByName (%s) bad block size !\n", resource_name);
314         return -1;
315     }
316     size_shift = CONV_SHORT (size_shift);
317     
318     /*
319      * Find resource.
320      */
321     for (;;)
322     {
323         if (!load_typeinfo (ResourceFd, &typeinfo))
324         {
325             printf("FindResourceByName (%s) bad typeinfo size !\n", resource_name);
326             return -1;
327         }
328 #ifdef DEBUG_RESOURCE
329         printf("FindResourceByName typeinfo.type_id=%X count=%d type_id=%X\n",
330                         typeinfo.type_id, typeinfo.count, type_id);
331 #endif
332         if (typeinfo.type_id == 0) break;
333         if (type_match(type_id, typeinfo.type_id, ResourceFd, rtoff))
334         {
335             for (i = 0; i < typeinfo.count; i++)
336             {
337 #ifndef WINELIB
338                 if (read(ResourceFd, &nameinfo, sizeof(nameinfo)) != 
339                     sizeof(nameinfo))
340 #else
341                 if (!load_nameinfo (ResourceFd, &nameinfo))
342 #endif
343                 {
344                     printf("FindResourceByName (%s) bad nameinfo size !\n", resource_name);
345                     return -1;
346                 }
347 /*
348                 if ((nameinfo.id & 0x8000) != 0) continue;
349 */              
350 #ifdef DEBUG_RESOURCE
351                 printf("FindResourceByName // nameinfo.id=%04X !\n", nameinfo.id);
352 #endif
353                 old_pos = lseek(ResourceFd, 0, SEEK_CUR);
354                 new_pos = rtoff + nameinfo.id;
355                 lseek(ResourceFd, new_pos, SEEK_SET);
356                 read(ResourceFd, &nbytes, 1);
357 #ifdef DEBUG_RESOURCE
358                 printf("FindResourceByName // namesize=%d !\n", nbytes);
359 #endif
360                 nbytes = CONV_CHAR_TO_LONG (nbytes);
361                 read(ResourceFd, name, nbytes);
362                 lseek(ResourceFd, old_pos, SEEK_SET);
363                 name[nbytes] = '\0';
364 #ifdef DEBUG_RESOURCE
365                 printf("FindResourceByName type_id=%X (%d of %d) name='%s' resource_name='%s'\n", 
366                         typeinfo.type_id, i + 1, typeinfo.count, 
367                         name, resource_name);
368 #endif
369                 if (strcasecmp(name, resource_name) == 0)
370                 {
371                     memcpy(result_p, &nameinfo, sizeof(nameinfo));
372                     return size_shift;
373                 }
374             }
375         }
376         else {
377             lseek(ResourceFd, (typeinfo.count * sizeof(nameinfo)), SEEK_CUR);
378             }
379     }
380     return -1;
381 }
382
383
384 /**********************************************************************
385  *                                      GetRsrcCount            [internal]
386  */
387 int GetRsrcCount(HINSTANCE hInst, int type_id)
388 {
389     struct resource_typeinfo_s typeinfo;
390     struct resource_nameinfo_s nameinfo;
391     unsigned short size_shift;
392     off_t rtoff;
393
394     if (hInst == 0) return 0;
395 #ifdef DEBUG_RESOURCE
396     printf("GetRsrcCount hInst=%04X typename=%08X\n", hInst, type_id);
397 #endif
398     if (OpenResourceFile(hInst) < 0)    return 0;
399
400     /*
401      * Move to beginning of resource table.
402      */
403     rtoff = (ResourceFileInfo->mz_header->ne_offset +
404              ResourceFileInfo->ne->ne_header->resource_tab_offset);
405     lseek(ResourceFd, rtoff, SEEK_SET);
406     /*
407      * Read block size.
408      */
409     if (read(ResourceFd, &size_shift, sizeof(size_shift)) != sizeof(size_shift)) {
410                 printf("GetRsrcCount // bad block size !\n");
411                 return -1;
412                 }
413     size_shift = CONV_SHORT (size_shift);
414     for (;;) {
415                 if (!load_typeinfo (ResourceFd, &typeinfo))     {
416                         printf("GetRsrcCount // bad typeinfo size !\n");
417                         return 0;
418                         }
419 #ifdef DEBUG_RESOURCE
420                 printf("GetRsrcCount // typeinfo.type_id=%X count=%d type_id=%X\n",
421                                 typeinfo.type_id, typeinfo.count, type_id);
422 #endif
423                 if (typeinfo.type_id == 0) break;
424                 if (type_match(type_id, typeinfo.type_id, ResourceFd, rtoff)) {
425                         return typeinfo.count;
426                         }
427                 else {
428                         lseek(ResourceFd, (typeinfo.count * sizeof(nameinfo)), SEEK_CUR);
429                         }
430                 }
431     return 0;
432 }
433
434 /**********************************************************************
435  *                      NE_FindResource [KERNEL.60]
436  */
437 int
438 NE_FindResource(HANDLE instance, LPSTR resource_name, LPSTR type_name,
439                 RESOURCE *r)
440 {
441     int type;
442
443 #ifdef DEBUG_RESOURCE
444     printf("NE_FindResource hInst=%04X typename=%08X resname=%08X\n", 
445                         instance, type_name, resource_name);
446 #endif
447
448     ResourceFd = r->fd;
449     ResourceFileInfo = r->wpnt;
450
451     /* nametable loaded ? */
452     if (r->wpnt->ne->resnamtab == NULL)
453         RSC_LoadNameTable();
454
455     if (((int) type_name & 0xffff0000) == 0)
456     {
457         type = (int) type_name;
458     }
459     else if (type_name[0] == '\0')
460     {
461         type = -1;
462     }
463     else if (type_name[0] == '#')
464     {
465         type = atoi(type_name + 1);
466     }
467     else
468     {
469         type = (int) type_name;
470     }
471     if (((int) resource_name & 0xffff0000) == 0)
472     {
473         r->size_shift = FindResourceByNumber(&r->nameinfo, type,
474                                              (int) resource_name | 0x8000);
475     }
476     else if (resource_name[0] == '\0')
477     {
478         r->size_shift = FindResourceByNumber(&r->nameinfo, type, -1);
479     }
480     else if (resource_name[0] == '#')
481     {
482         r->size_shift = FindResourceByNumber(&r->nameinfo, type,
483                                              atoi(resource_name + 1));
484     }
485     else
486     {
487         r->size_shift = FindResourceByName(&r->nameinfo, type, resource_name);
488     }
489
490     if (r->size_shift == -1)
491     {
492         printf("NE_FindResource hInst=%04X typename=%08X resname=%08X not found!\n", 
493                 instance, (int) type_name, (int) resource_name);
494         return 0;
495     }
496     r->size = r->nameinfo.length << r->size_shift;
497     r->offset = r->nameinfo.offset << r->size_shift;
498     return 1;
499 }