Replaced PTR_SEG_TO_LIN macro by exported MapSL function.
[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 "wine/library.h"
19 #include "global.h"
20 #include "module.h"
21 #include "callback.h"
22 #include "debugtools.h"
23
24 DEFAULT_DEBUG_CHANNEL(resource);
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 /* already defined in segment.c glue code */
32 extern WORD CALLBACK NE_CallTo16_word_www(FARPROC16,WORD,WORD,WORD);
33
34 /***********************************************************************
35  *           NE_FindNameTableId
36  *
37  * Find the type and resource id from their names.
38  * Return value is MAKELONG( typeId, resId ), or 0 if not found.
39  */
40 static DWORD NE_FindNameTableId( NE_MODULE *pModule, LPCSTR typeId, LPCSTR resId )
41 {
42     NE_TYPEINFO *pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
43     NE_NAMEINFO *pNameInfo;
44     HGLOBAL16 handle;
45     WORD *p;
46     DWORD ret = 0;
47     int count;
48
49     for (; pTypeInfo->type_id != 0;
50            pTypeInfo = (NE_TYPEINFO *)((char*)(pTypeInfo+1) +
51                                         pTypeInfo->count * sizeof(NE_NAMEINFO)))
52     {
53         if (pTypeInfo->type_id != 0x800f) continue;
54         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
55         for (count = pTypeInfo->count; count > 0; count--, pNameInfo++)
56         {
57             TRACE("NameTable entry: type=%04x id=%04x\n",
58                               pTypeInfo->type_id, pNameInfo->id );
59             handle = LoadResource16( pModule->self, 
60                                    (HRSRC16)((int)pNameInfo - (int)pModule) );
61             for(p = (WORD*)LockResource16(handle); p && *p; p = (WORD *)((char*)p+*p))
62             {
63                 TRACE("  type=%04x '%s' id=%04x '%s'\n",
64                                   p[1], (char *)(p+3), p[2],
65                                   (char *)(p+3)+strlen((char *)(p+3))+1 );
66                 /* Check for correct type */
67
68                 if (p[1] & 0x8000)
69                 {
70                     if (!HIWORD(typeId)) continue;
71                     if (strcasecmp( typeId, (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 (strcasecmp( resId, (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) && !strncasecmp( 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) && !strncasecmp( 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, LPCSTR 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", hModule, debugres_a(typeId) );
283
284     for (;;)
285     {
286         if (!(pTypeInfo = NE_FindTypeSection( pResTab, pTypeInfo, typeId )))
287             break;
288         prevHandler = pTypeInfo->resloader;
289         pTypeInfo->resloader = resourceHandler;
290         pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
291     }
292     return prevHandler;
293 }
294
295
296 /**********************************************************************
297  *          NE_FindResource
298  */
299 HRSRC16 NE_FindResource( NE_MODULE *pModule, LPCSTR name, LPCSTR type )
300 {
301     NE_TYPEINFO *pTypeInfo;
302     NE_NAMEINFO *pNameInfo;
303     LPBYTE pResTab;
304
305     if (!pModule || !pModule->res_table) return 0;
306
307     TRACE("module=%04x name=%s type=%s\n", pModule->self, debugres_a(name), debugres_a(type) );
308
309     if (HIWORD(name))  /* Check for '#xxx' name */
310     {
311         LPCSTR ptr = name;
312         if (ptr[0] == '#')
313             if (!(name = (LPCSTR)atoi( ptr + 1 )))
314             {
315                 WARN("Incorrect resource name: %s\n", ptr);
316                 return 0;
317             }
318     }
319
320     if (HIWORD(type))  /* Check for '#xxx' type */
321     {
322         LPCSTR ptr = type;
323         if (ptr[0] == '#')
324             if (!(type = (LPCSTR)atoi( ptr + 1 )))
325             {
326                 WARN("Incorrect resource type: %s\n", ptr);
327                 return 0;
328             }
329     }
330
331     if (HIWORD(type) || HIWORD(name))
332     {
333         DWORD id = NE_FindNameTableId( pModule, type, name );
334         if (id)  /* found */
335         {
336             type = (LPCSTR)(int)LOWORD(id);
337             name = (LPCSTR)(int)HIWORD(id);
338         }
339     }
340
341     pResTab = (LPBYTE)pModule + pModule->res_table;
342     pTypeInfo = (NE_TYPEINFO *)( pResTab + 2 );
343
344     for (;;)
345     {
346         if (!(pTypeInfo = NE_FindTypeSection( pResTab, pTypeInfo, type )))
347             break;
348         if ((pNameInfo = NE_FindResourceFromType( pResTab, pTypeInfo, name )))
349         {
350             TRACE("    Found id %08lx\n", (DWORD)name );
351             return (HRSRC16)( (int)pNameInfo - (int)pModule );
352         }
353         TRACE("    Not found, going on\n" );
354         pTypeInfo = NEXT_TYPEINFO(pTypeInfo);
355     }
356
357     WARN("failed!\n");
358     return 0;
359 }
360
361
362 /**********************************************************************
363  *          AllocResource    (KERNEL.66)
364  */
365 HGLOBAL16 WINAPI AllocResource16( HMODULE16 hModule, HRSRC16 hRsrc, DWORD size)
366 {
367     NE_NAMEINFO *pNameInfo=NULL;
368     WORD sizeShift;
369
370     NE_MODULE *pModule = NE_GetPtr( hModule );
371     if (!pModule || !pModule->res_table || !hRsrc) return 0;
372
373     TRACE("module=%04x res=%04x size=%ld\n", hModule, hRsrc, size );
374
375     sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
376     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
377     if (size < (DWORD)pNameInfo->length << sizeShift)
378         size = (DWORD)pNameInfo->length << sizeShift;
379     return GLOBAL_Alloc( GMEM_FIXED, size, hModule, WINE_LDT_FLAGS_DATA );
380 }
381
382
383 /**********************************************************************
384  *      DirectResAlloc    (KERNEL.168)
385  *
386  * Check Schulman, p. 232 for details
387  */
388 HGLOBAL16 WINAPI DirectResAlloc16( HINSTANCE16 hInstance, WORD wType,
389                                  UINT16 wSize )
390 {
391     TRACE("(%04x,%04x,%04x)\n",
392                      hInstance, wType, wSize );
393     if (!(hInstance = GetExePtr( hInstance ))) return 0;
394     if(wType != 0x10)   /* 0x10 is the only observed value, passed from
395                            CreateCursorIndirect. */
396         TRACE("(wType=%x)\n", wType);
397     return GLOBAL_Alloc(GMEM_MOVEABLE, wSize, hInstance, WINE_LDT_FLAGS_DATA );
398 }
399
400
401 /**********************************************************************
402  *          AccessResource16 (KERNEL.64)
403  */
404 INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
405 {
406     HFILE16 fd;
407     NE_MODULE *pModule = NE_GetPtr( hModule );
408
409     if (!pModule || !pModule->res_table || !hRsrc) return -1;
410
411     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
412
413     if ((fd = _lopen16( NE_MODULE_NAME(pModule), OF_READ )) != HFILE_ERROR16)
414     {
415         WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
416         NE_NAMEINFO *pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
417         _llseek16( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
418     }
419     return fd;
420 }
421
422
423 /**********************************************************************
424  *          NE_SizeofResource
425  */
426 DWORD NE_SizeofResource( NE_MODULE *pModule, HRSRC16 hRsrc )
427 {
428     NE_NAMEINFO *pNameInfo=NULL;
429     WORD sizeShift;
430
431     if (!pModule || !pModule->res_table) return 0;
432
433     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
434
435     sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
436     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
437     return (DWORD)pNameInfo->length << sizeShift;
438 }
439
440
441 /**********************************************************************
442  *          NE_LoadResource
443  */
444 HGLOBAL16 NE_LoadResource( NE_MODULE *pModule, HRSRC16 hRsrc )
445 {
446     NE_TYPEINFO *pTypeInfo;
447     NE_NAMEINFO *pNameInfo = NULL;
448     int d;
449
450     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
451     if (!hRsrc || !pModule || !pModule->res_table) return 0;
452
453     /* First, verify hRsrc (just an offset from pModule to the needed pNameInfo) */
454
455     d = pModule->res_table + 2;
456     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + d);
457     while( hRsrc > d )
458     {
459         if (pTypeInfo->type_id == 0)
460                 break; /* terminal entry */
461         d += sizeof(NE_TYPEINFO) + pTypeInfo->count * sizeof(NE_NAMEINFO);
462         if (hRsrc < d)
463         {
464             if( ((d - hRsrc)%sizeof(NE_NAMEINFO)) == 0 )
465             {
466                 pNameInfo = (NE_NAMEINFO *)(((char *)pModule) + hRsrc);
467                 break;
468             }
469             else 
470                 break; /* NE_NAMEINFO boundary mismatch */
471         }
472         pTypeInfo = (NE_TYPEINFO *)(((char *)pModule) + d);
473     }
474
475     if (pNameInfo)
476     {
477         if (pNameInfo->handle
478             && !(GlobalFlags16(pNameInfo->handle) & GMEM_DISCARDED))
479         {
480             pNameInfo->usage++;
481             TRACE("  Already loaded, new count=%d\n",
482                               pNameInfo->usage );
483         }
484         else
485         {
486             if (    pTypeInfo->resloader 
487                  && pTypeInfo->resloader != DefResourceHandlerProc )
488                 pNameInfo->handle = NE_CallTo16_word_www(
489                     pTypeInfo->resloader, pNameInfo->handle, pModule->self, hRsrc );
490             else
491                 pNameInfo->handle = NE_DefResourceHandler(
492                                          pNameInfo->handle, pModule->self, hRsrc );
493
494             if (pNameInfo->handle)
495             {
496                 pNameInfo->usage++;
497                 pNameInfo->flags |= NE_SEGFLAGS_LOADED;
498             }
499         }
500         return pNameInfo->handle;
501     }
502     return 0;
503 }
504
505
506 /**********************************************************************
507  *          NE_FreeResource
508  */
509 BOOL16 NE_FreeResource( NE_MODULE *pModule, HGLOBAL16 handle )
510 {
511     NE_TYPEINFO *pTypeInfo;
512     NE_NAMEINFO *pNameInfo;
513     WORD count;
514
515     if (!handle || !pModule || !pModule->res_table) return handle;
516
517     TRACE("handle=%04x\n", handle );
518
519     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
520     while (pTypeInfo->type_id)
521     {
522         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
523         for (count = pTypeInfo->count; count > 0; count--)
524         {
525             if (pNameInfo->handle == handle)
526             {
527                 if (pNameInfo->usage > 0) pNameInfo->usage--;
528                 if (pNameInfo->usage == 0)
529                 {
530                     GlobalFree16( pNameInfo->handle );
531                     pNameInfo->handle = 0;
532                     pNameInfo->flags &= ~NE_SEGFLAGS_LOADED;
533                 }
534                 return 0;
535             }
536             pNameInfo++;
537         }
538         pTypeInfo = (NE_TYPEINFO *)pNameInfo;
539     }
540
541     return handle;
542 }