No longer directly accessing debuggee memory.
[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 "callback.h"
23 #include "debugtools.h"
24
25 DEFAULT_DEBUG_CHANNEL(resource)
26
27 #define NEXT_TYPEINFO(pTypeInfo) ((NE_TYPEINFO *)((char*)((pTypeInfo) + 1) + \
28                                    (pTypeInfo)->count * sizeof(NE_NAMEINFO)))
29
30 static FARPROC16 DefResourceHandlerProc = (FARPROC16)0xffffffff;
31
32 /***********************************************************************
33  *           NE_FindNameTableId
34  *
35  * Find the type and resource id from their names.
36  * Return value is MAKELONG( typeId, resId ), or 0 if not found.
37  */
38 static DWORD NE_FindNameTableId( NE_MODULE *pModule, LPCSTR typeId, LPCSTR resId )
39 {
40     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
41     NE_NAMEINFO *pNameInfo;
42     HGLOBAL16 handle;
43     WORD *p;
44     DWORD ret = 0;
45     int count;
46
47     for (; pTypeInfo->type_id != 0;
48            pTypeInfo = (NE_TYPEINFO *)((char*)(pTypeInfo+1) +
49                                         pTypeInfo->count * sizeof(NE_NAMEINFO)))
50     {
51         if (pTypeInfo->type_id != 0x800f) continue;
52         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
53         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
54         {
55             TRACE("NameTable entry: type=%04x id=%04x\n",
56                               pTypeInfo->type_id, pNameInfo->id );
57             handle = LoadResource16( pModule->self, 
58                                    (HRSRC16)((int)pNameInfo - (int)pModule) );
59             for(p = (WORD*)LockResource16(handle); p && *p; p = (WORD *)((char*)p+*p))
60             {
61                 TRACE("  type=%04x '%s' id=%04x '%s'\n",
62                                   p[1], (char *)(p+3), p[2],
63                                   (char *)(p+3)+strlen((char *)(p+3))+1 );
64                 /* Check for correct type */
65
66                 if (p[1] & 0x8000)
67                 {
68                     if (!HIWORD(typeId)) continue;
69                     if (lstrcmpiA( typeId,
70                                      (char *)(p + 3) )) continue;
71                 }
72                 else if (HIWORD(typeId) || (((DWORD)typeId & ~0x8000)!= p[1]))
73                   continue;
74
75                 /* Now check for the id */
76
77                 if (p[2] & 0x8000)
78                 {
79                     if (!HIWORD(resId)) continue;
80                     if (lstrcmpiA( resId,
81                                (char*)(p+3)+strlen((char*)(p+3))+1 )) continue;
82                     
83                 }
84                 else if (HIWORD(resId) || (((DWORD)resId & ~0x8000) != p[2]))
85                   continue;
86
87                 /* If we get here, we've found the entry */
88
89                 TRACE("  Found!\n" );
90                 ret = MAKELONG( p[1], p[2] );
91                 break;
92             }
93             FreeResource16( handle );
94             if (ret) return ret;
95         }
96     }
97     return 0;
98 }
99
100 /***********************************************************************
101  *           NE_FindTypeSection
102  *
103  * Find header struct for a particular resource type.
104  */
105 NE_TYPEINFO *NE_FindTypeSection( LPBYTE pResTab, 
106                                  NE_TYPEINFO *pTypeInfo, LPCSTR typeId )
107 {
108     /* start from pTypeInfo */
109
110     if (HIWORD(typeId) != 0)  /* Named type */
111     {
112         LPCSTR str = typeId;
113         BYTE len = strlen( str );
114         while (pTypeInfo->type_id)
115         {
116             if (!(pTypeInfo->type_id & 0x8000))
117             {
118                 BYTE *p = pResTab + pTypeInfo->type_id;
119                 if ((*p == len) && !lstrncmpiA( p+1, str, len ))
120                 {
121                     TRACE("  Found type '%s'\n", str );
122                     return pTypeInfo;
123                 }
124             }
125             TRACE("  Skipping type %04x\n", pTypeInfo->type_id );
126             pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
127         }
128     }
129     else  /* Numeric type id */
130     {
131         WORD id = LOWORD(typeId) | 0x8000;
132         while (pTypeInfo->type_id)
133         {
134             if (pTypeInfo->type_id == id)
135             {
136                 TRACE("  Found type %04x\n", id );
137                 return pTypeInfo;
138             }
139             TRACE("  Skipping type %04x\n", pTypeInfo->type_id );
140             pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
141         }
142     }
143     return NULL;
144 }
145
146 /***********************************************************************
147  *           NE_FindResourceFromType
148  *
149  * Find a resource once the type info structure has been found.
150  */
151 NE_NAMEINFO *NE_FindResourceFromType( LPBYTE pResTab,
152                                       NE_TYPEINFO *pTypeInfo, LPCSTR resId )
153 {
154     BYTE *p;
155     int count;
156     NE_NAMEINFO *pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
157
158     if (HIWORD(resId) != 0)  /* Named resource */
159     {
160         LPCSTR str = resId;
161         BYTE len = strlen( str );
162         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
163         {
164             if (pNameInfo->id & 0x8000) continue;
165             p = pResTab + pNameInfo->id;
166             if ((*p == len) && !lstrncmpiA( p+1, str, len ))
167                 return pNameInfo;
168         }
169     }
170     else  /* Numeric resource id */
171     {
172         WORD id = LOWORD(resId) | 0x8000;
173         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
174             if (pNameInfo->id == id) 
175                 return pNameInfo;
176     }
177     return NULL;
178 }
179
180
181 /***********************************************************************
182  *           NE_DefResourceHandler
183  *
184  * This is the default LoadProc() function. 
185  */
186 HGLOBAL16 WINAPI NE_DefResourceHandler( HGLOBAL16 hMemObj, HMODULE16 hModule,
187                                         HRSRC16 hRsrc )
188 {
189     HANDLE fd;
190     NE_MODULE* pModule = NE_GetPtr( hModule );
191     if (pModule && (pModule->flags & NE_FFLAGS_BUILTIN))
192     {
193         HGLOBAL16 handle;
194         WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
195         NE_NAMEINFO* pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
196     
197         if ( hMemObj )
198             handle = GlobalReAlloc16( hMemObj, pNameInfo->length << sizeShift, 0 );
199         else
200             handle = AllocResource16( hModule, hRsrc, 0 );
201
202         if ( handle )
203         {
204             /* NOTE: hRsrcMap points to start of built-in resource data */
205             memcpy( GlobalLock16( handle ), 
206                     (char *)pModule->hRsrcMap + (pNameInfo->offset << sizeShift),
207                     pNameInfo->length << sizeShift );
208         }
209         return handle;
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 }