Release 980927
[wine] / loader / ne / resource.c
1 /*
2  * NE resource functions
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  * Copyright 1997 Alex Korobka
7  */
8
9 #include <assert.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include "windows.h"
18 #include "global.h"
19 #include "ldt.h"
20 #include "module.h"
21 #include "neexe.h"
22 #include "resource.h"
23 #include "callback.h"
24 #include "debug.h"
25
26 #define NEXT_TYPEINFO(pTypeInfo) ((NE_TYPEINFO *)((char*)((pTypeInfo) + 1) + \
27                                    (pTypeInfo)->count * sizeof(NE_NAMEINFO)))
28
29 /***********************************************************************
30  *           NE_FindNameTableId
31  *
32  * Find the type and resource id from their names.
33  * Return value is MAKELONG( typeId, resId ), or 0 if not found.
34  */
35 static DWORD NE_FindNameTableId( NE_MODULE *pModule, SEGPTR typeId, SEGPTR resId )
36 {
37     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
38     NE_NAMEINFO *pNameInfo;
39     HGLOBAL16 handle;
40     WORD *p;
41     DWORD ret = 0;
42     int count;
43
44     for (; pTypeInfo->type_id != 0;
45            pTypeInfo = (NE_TYPEINFO *)((char*)(pTypeInfo+1) +
46                                         pTypeInfo->count * sizeof(NE_NAMEINFO)))
47     {
48         if (pTypeInfo->type_id != 0x800f) continue;
49         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
50         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
51         {
52             TRACE(resource, "NameTable entry: type=%04x id=%04x\n",
53                               pTypeInfo->type_id, pNameInfo->id );
54             handle = LoadResource16( pModule->self, 
55                                    (HRSRC16)((int)pNameInfo - (int)pModule) );
56             for(p = (WORD*)LockResource16(handle); p && *p; p = (WORD *)((char*)p+*p))
57             {
58                 TRACE(resource,"  type=%04x '%s' id=%04x '%s'\n",
59                                   p[1], (char *)(p+3), p[2],
60                                   (char *)(p+3)+strlen((char *)(p+3))+1 );
61                 /* Check for correct type */
62
63                 if (p[1] & 0x8000)
64                 {
65                     if (!HIWORD(typeId)) continue;
66                     if (lstrcmpi32A( (char *)PTR_SEG_TO_LIN(typeId),
67                                      (char *)(p + 3) )) continue;
68                 }
69                 else if (HIWORD(typeId) || ((typeId & ~0x8000)!= p[1]))
70                   continue;
71
72                 /* Now check for the id */
73
74                 if (p[2] & 0x8000)
75                 {
76                     if (!HIWORD(resId)) continue;
77                     if (lstrcmpi32A( (char *)PTR_SEG_TO_LIN(resId),
78                                (char*)(p+3)+strlen((char*)(p+3))+1 )) continue;
79                     
80                 }
81                 else if (HIWORD(resId) || ((resId & ~0x8000) != p[2]))
82                   continue;
83
84                 /* If we get here, we've found the entry */
85
86                 TRACE(resource, "  Found!\n" );
87                 ret = MAKELONG( p[1], p[2] );
88                 break;
89             }
90             FreeResource16( handle );
91             if (ret) return ret;
92         }
93     }
94     return 0;
95 }
96
97 /***********************************************************************
98  *           NE_FindTypeSection
99  *
100  * Find header struct for a particular resource type.
101  */
102 static NE_TYPEINFO* NE_FindTypeSection( NE_MODULE *pModule, 
103                                         NE_TYPEINFO *pTypeInfo, SEGPTR typeId )
104 {
105     /* start from pTypeInfo */
106
107     if (HIWORD(typeId) != 0)  /* Named type */
108     {
109         char *str = (char *)PTR_SEG_TO_LIN( typeId );
110         BYTE len = strlen( str );
111         while (pTypeInfo->type_id)
112         {
113             if (!(pTypeInfo->type_id & 0x8000))
114             {
115                 BYTE *p = (BYTE*)pModule + pModule->res_table + pTypeInfo->type_id;
116                 if ((*p == len) && !lstrncmpi32A( p+1, str, len ))
117                 {
118                     TRACE(resource, "  Found type '%s'\n", str );
119                     return pTypeInfo;
120                 }
121             }
122             TRACE(resource, "  Skipping type %04x\n", pTypeInfo->type_id );
123             pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
124         }
125     }
126     else  /* Numeric type id */
127     {
128         WORD id = LOWORD(typeId) | 0x8000;
129         while (pTypeInfo->type_id)
130         {
131             if (pTypeInfo->type_id == id)
132             {
133                 TRACE(resource, "  Found type %04x\n", id );
134                 return pTypeInfo;
135             }
136             TRACE(resource, "  Skipping type %04x\n", pTypeInfo->type_id );
137             pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
138         }
139     }
140     return NULL;
141 }
142
143 /***********************************************************************
144  *           NE_FindResourceFromType
145  *
146  * Find a resource once the type info structure has been found.
147  */
148 static HRSRC16 NE_FindResourceFromType( NE_MODULE *pModule,
149                                         NE_TYPEINFO *pTypeInfo, SEGPTR resId )
150 {
151     BYTE *p;
152     int count;
153     NE_NAMEINFO *pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
154
155     if (HIWORD(resId) != 0)  /* Named resource */
156     {
157         char *str = (char *)PTR_SEG_TO_LIN( resId );
158         BYTE len = strlen( str );
159         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
160         {
161             if (pNameInfo->id & 0x8000) continue;
162             p = (BYTE *)pModule + pModule->res_table + pNameInfo->id;
163             if ((*p == len) && !lstrncmpi32A( p+1, str, len ))
164                 return (HRSRC16)((int)pNameInfo - (int)pModule);
165         }
166     }
167     else  /* Numeric resource id */
168     {
169         WORD id = LOWORD(resId) | 0x8000;
170         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
171             if (pNameInfo->id == id) 
172               return (HRSRC16)((int)pNameInfo - (int)pModule);
173     }
174     return 0;
175 }
176
177
178 /***********************************************************************
179  *           NE_DefResourceHandler
180  *
181  * This is the default LoadProc() function. 
182  */
183 HGLOBAL16 WINAPI NE_DefResourceHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
184                                         HRSRC16 hRsrc )
185 {
186     int  fd;
187     NE_MODULE* pModule = NE_GetPtr( hModule );
188     if (pModule && (fd = NE_OpenFile( pModule )) >= 0)
189     {
190         HGLOBAL16 handle;
191         WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
192         NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
193
194         TRACE(resource, "loading, pos=%d, len=%d\n",
195                      (int)pNameInfo->offset << sizeShift,
196                      (int)pNameInfo->length << sizeShift );
197         if( hMemObj )
198             handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
199         else
200             handle = AllocResource( hModule, hRsrc, 0 );
201
202         if( handle )
203         {
204             lseek( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
205             read( fd, GlobalLock16( handle ), (int)pNameInfo->length << sizeShift );
206         }
207         return handle;
208     }
209     return (HGLOBAL16)0;
210 }
211
212 /***********************************************************************
213  *           NE_InitResourceHandler
214  *
215  * Fill in 'resloader' fields in the resource table.
216  */
217 BOOL32 NE_InitResourceHandler( HMODULE16 hModule )
218 {
219     NE_MODULE *pModule = NE_GetPtr( hModule );
220     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
221
222     FARPROC16 handler = MODULE_GetWndProcEntry16("DefResourceHandler");
223
224     TRACE(resource,"InitResourceHandler[%04x]\n", hModule );
225
226     while(pTypeInfo->type_id)
227     {
228         pTypeInfo->resloader = handler;
229         pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
230     }
231     return TRUE;
232 }
233
234
235 /**********************************************************************
236  *      SetResourceHandler      (KERNEL.43)
237  */
238 FARPROC16 WINAPI SetResourceHandler( HMODULE16 hModule, SEGPTR typeId,
239                                      FARPROC16 resourceHandler )
240 {
241     FARPROC16 prevHandler = NULL;
242     NE_MODULE *pModule = NE_GetPtr( hModule );
243     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
244
245     if (!pModule || !pModule->res_table) return NULL;
246
247     TRACE( resource, "module=%04x type=%s\n",
248            hModule, debugres_a(PTR_SEG_TO_LIN(typeId)) );
249
250     for (;;)
251     {
252         if (!(pTypeInfo = NE_FindTypeSection( pModule, pTypeInfo, typeId )))
253             break;
254         prevHandler = pTypeInfo->resloader;
255         pTypeInfo->resloader = resourceHandler;
256         pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
257     }
258     return prevHandler;
259 }
260
261
262 /**********************************************************************
263  *          FindResource16    (KERNEL.60)
264  */
265 HRSRC16 WINAPI FindResource16( HMODULE16 hModule, SEGPTR name, SEGPTR type )
266 {
267     NE_TYPEINFO *pTypeInfo;
268     HRSRC16 hRsrc;
269
270     NE_MODULE *pModule = NE_GetPtr( hModule );
271     if (!pModule || !pModule->res_table) return 0;
272
273     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
274
275     TRACE( resource, "module=%04x name=%s type=%s\n", 
276            hModule, debugres_a(PTR_SEG_TO_LIN(name)),
277            debugres_a(PTR_SEG_TO_LIN(type)) );
278
279     if (HIWORD(name))  /* Check for '#xxx' name */
280     {
281         char *ptr = PTR_SEG_TO_LIN( name );
282         if (ptr[0] == '#')
283             if (!(name = (SEGPTR)atoi( ptr + 1 )))
284             {
285                 WARN(resource, "Incorrect resource name: %s\n", ptr);
286                 return 0;
287             }
288     }
289
290     if (HIWORD(type))  /* Check for '#xxx' type */
291     {
292         char *ptr = PTR_SEG_TO_LIN( type );
293         if (ptr[0] == '#')
294             if (!(type = (SEGPTR)atoi( ptr + 1 )))
295             {
296                 WARN(resource, "Incorrect resource type: %s\n", ptr);
297                 return 0;
298             }
299     }
300
301     if (HIWORD(type) || HIWORD(name))
302     {
303         DWORD id = NE_FindNameTableId( pModule, type, name );
304         if (id)  /* found */
305         {
306             type = LOWORD(id);
307             name = HIWORD(id);
308         }
309     }
310
311     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
312
313     for (;;)
314     {
315         if (!(pTypeInfo = NE_FindTypeSection( pModule, pTypeInfo, type )))
316             break;
317         if ((hRsrc = NE_FindResourceFromType(pModule, pTypeInfo, name)))
318         {
319             TRACE(resource, "    Found id %08lx\n", name );
320             return hRsrc;
321         }
322         TRACE(resource, "    Not found, going on\n" );
323         pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
324     }
325
326     WARN(resource, "failed!\n");
327     return 0;
328 }
329
330
331 /**********************************************************************
332  *          AllocResource    (KERNEL.66)
333  */
334 HGLOBAL16 WINAPI AllocResource( HMODULE16 hModule, HRSRC16 hRsrc, DWORD size)
335 {
336     NE_NAMEINFO *pNameInfo=NULL;
337     WORD sizeShift;
338
339     NE_MODULE *pModule = NE_GetPtr( hModule );
340     if (!pModule || !pModule->res_table || !hRsrc) return 0;
341
342     TRACE( resource, "module=%04x res=%04x size=%ld\n", hModule, hRsrc, size );
343
344     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
345
346     sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
347     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
348     if (size < (DWORD)pNameInfo->length << sizeShift)
349         size = (DWORD)pNameInfo->length << sizeShift;
350     return GLOBAL_Alloc( GMEM_FIXED, size, hModule, FALSE, FALSE, FALSE );
351 }
352
353
354 /**********************************************************************
355  *      DirectResAlloc    (KERNEL.168)
356  *
357  * Check Schulman, p. 232 for details
358  */
359 HGLOBAL16 WINAPI DirectResAlloc( HINSTANCE16 hInstance, WORD wType,
360                                  UINT16 wSize )
361 {
362     TRACE(resource,"(%04x,%04x,%04x)\n",
363                      hInstance, wType, wSize );
364     if (!(hInstance = GetExePtr( hInstance ))) return 0;
365     if(wType != 0x10)   /* 0x10 is the only observed value, passed from
366                            CreateCursorIndirect. */
367         TRACE(resource, "(wType=%x)\n", wType);
368     return GLOBAL_Alloc(GMEM_MOVEABLE, wSize, hInstance, FALSE, FALSE, FALSE);
369 }
370
371
372 /**********************************************************************
373  *          AccessResource16    (KERNEL.64)
374  */
375 INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
376 {
377     HFILE16 fd;
378
379     NE_MODULE *pModule = NE_GetPtr( hModule );
380     if (!pModule || !pModule->res_table || !hRsrc) return -1;
381
382     TRACE(resource, "module=%04x res=%04x\n", hModule, hRsrc );
383
384     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
385
386     if ((fd = _lopen16( NE_MODULE_NAME(pModule), OF_READ )) != HFILE_ERROR16)
387     {
388         WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
389         NE_NAMEINFO *pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
390         _llseek16( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
391     }
392     return fd;
393 }
394
395
396 /**********************************************************************
397  *          SizeofResource16    (KERNEL.65)
398  */
399 DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
400 {
401     NE_NAMEINFO *pNameInfo=NULL;
402     WORD sizeShift;
403
404     NE_MODULE *pModule = NE_GetPtr( hModule );
405     if (!pModule || !pModule->res_table) return 0;
406
407     TRACE(resource, "module=%04x res=%04x\n", hModule, hRsrc );
408
409     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
410
411     sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
412     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
413     return (DWORD)pNameInfo->length << sizeShift;
414 }
415
416
417 /**********************************************************************
418  *          LoadResource16    (KERNEL.61)
419  */
420 HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
421 {
422     NE_TYPEINFO *pTypeInfo;
423     NE_NAMEINFO *pNameInfo = NULL;
424     NE_MODULE *pModule = NE_GetPtr( hModule );
425     int d;
426
427     TRACE( resource, "module=%04x res=%04x\n", hModule, hRsrc );
428     if (!hRsrc || !pModule || !pModule->res_table) return 0;
429
430     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
431
432     /* First, verify hRsrc (just an offset from pModule to the needed pNameInfo) */
433
434     d = pModule->res_table + 2;
435     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + d);
436     while( hRsrc > d )
437     {
438         if (pTypeInfo->type_id == 0)
439                 break; /* terminal entry */
440         d += sizeof(NE_TYPEINFO) + pTypeInfo->count * sizeof(NE_NAMEINFO);
441         if (hRsrc < d)
442         {
443             if( ((d - hRsrc)%sizeof(NE_NAMEINFO)) == 0 )
444             {
445                 pNameInfo = (NE_NAMEINFO *)(((char *)pModule) + hRsrc);
446                 break;
447             }
448             else 
449                 break; /* NE_NAMEINFO boundary mismatch */
450         }
451         pTypeInfo = (NE_TYPEINFO *)(((char *)pModule) + d);
452     }
453
454     if (pNameInfo)
455     {
456         if (pNameInfo->handle
457             && !(GlobalFlags16(pNameInfo->handle) & GMEM_DISCARDED))
458         {
459             pNameInfo->usage++;
460             TRACE(resource, "  Already loaded, new count=%d\n",
461                               pNameInfo->usage );
462         }
463         else
464         {
465             if (pTypeInfo->resloader)
466                 pNameInfo->handle = Callbacks->CallResourceHandlerProc(
467                     pTypeInfo->resloader, pNameInfo->handle, hModule, hRsrc );
468             else /* this is really bad */
469             {
470                 ERR(resource, "[%04x]: Missing resource handler!\n", hModule);
471                 pNameInfo->handle = NE_DefResourceHandler(
472                                          pNameInfo->handle, hModule, hRsrc );
473             }
474
475             if (pNameInfo->handle)
476             {
477                 pNameInfo->usage++;
478                 pNameInfo->flags |= NE_SEGFLAGS_LOADED;
479             }
480         }
481         return pNameInfo->handle;
482     }
483     return 0;
484 }
485
486
487 /**********************************************************************
488  *          LockResource16    (KERNEL.62)
489  */
490 /* 16-bit version */
491 SEGPTR WINAPI WIN16_LockResource16( HGLOBAL16 handle )
492 {
493     TRACE( resource, "handle=%04x\n", handle );
494     if (!handle) return (SEGPTR)0;
495
496     /* May need to reload the resource if discarded */
497
498     return (SEGPTR)WIN16_GlobalLock16( handle );
499 }
500
501 /* Winelib 16-bit version */
502 LPVOID WINAPI LockResource16( HGLOBAL16 handle )
503 {
504     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
505
506     return (LPVOID)PTR_SEG_TO_LIN( WIN16_LockResource16( handle ) );
507 }
508
509
510 /**********************************************************************
511  *          FreeResource16    (KERNEL.63)
512  */
513 BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
514 {
515     NE_TYPEINFO *pTypeInfo;
516     NE_NAMEINFO *pNameInfo;
517     WORD count;
518     NE_MODULE *pModule = NE_GetPtr( FarGetOwner(handle) );
519
520     if (!handle || !pModule || !pModule->res_table) return handle;
521
522     TRACE(resource, "handle=%04x\n", handle );
523
524     assert( !__winelib );  /* Can't use Win16 resource functions in Winelib */
525
526     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
527     while (pTypeInfo->type_id)
528     {
529         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
530         for (count = pTypeInfo->count; count > 0; count--)
531         {
532             if (pNameInfo->handle == handle)
533             {
534                 if (pNameInfo->usage > 0) pNameInfo->usage--;
535                 if (pNameInfo->usage == 0)
536                 {
537                     GlobalFree16( pNameInfo->handle );
538                     pNameInfo->handle = 0;
539                     pNameInfo->flags &= ~NE_SEGFLAGS_LOADED;
540                 }
541                 return 0;
542             }
543             pNameInfo++;
544         }
545         pTypeInfo = (NE_TYPEINFO *)pNameInfo;
546     }
547
548     TRACE(resource, "[%04x]: no intrinsic resource for %04x, assuming DirectResAlloc()!\n", 
549           pModule->self, handle );
550     GlobalFree16( handle ); 
551     return handle;
552 }