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