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