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