Fixed Win16 documentation not fixed because of a bug in winapi_check.
[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 "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, 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, WINE_LDT_FLAGS_DATA );
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, WINE_LDT_FLAGS_DATA );
401 }
402
403
404 /**********************************************************************
405  *          AccessResource16 (KERNEL.64)
406  */
407 INT16 WINAPI AccessResource16( HINSTANCE16 hModule, HRSRC16 hRsrc )
408 {
409     HFILE16 fd;
410     NE_MODULE *pModule = NE_GetPtr( hModule );
411
412     if (!pModule || !pModule->res_table || !hRsrc) return -1;
413
414     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
415
416     if ((fd = _lopen16( NE_MODULE_NAME(pModule), OF_READ )) != HFILE_ERROR16)
417     {
418         WORD sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
419         NE_NAMEINFO *pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
420         _llseek16( fd, (int)pNameInfo->offset << sizeShift, SEEK_SET );
421     }
422     return fd;
423 }
424
425
426 /**********************************************************************
427  *          NE_SizeofResource
428  */
429 DWORD NE_SizeofResource( NE_MODULE *pModule, HRSRC16 hRsrc )
430 {
431     NE_NAMEINFO *pNameInfo=NULL;
432     WORD sizeShift;
433
434     if (!pModule || !pModule->res_table) return 0;
435
436     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
437
438     sizeShift = *(WORD *)((char *)pModule + pModule->res_table);
439     pNameInfo = (NE_NAMEINFO*)((char*)pModule + hRsrc);
440     return (DWORD)pNameInfo->length << sizeShift;
441 }
442
443
444 /**********************************************************************
445  *          NE_LoadResource
446  */
447 HGLOBAL16 NE_LoadResource( NE_MODULE *pModule, HRSRC16 hRsrc )
448 {
449     NE_TYPEINFO *pTypeInfo;
450     NE_NAMEINFO *pNameInfo = NULL;
451     int d;
452
453     TRACE("module=%04x res=%04x\n", pModule->self, hRsrc );
454     if (!hRsrc || !pModule || !pModule->res_table) return 0;
455
456     /* First, verify hRsrc (just an offset from pModule to the needed pNameInfo) */
457
458     d = pModule->res_table + 2;
459     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + d);
460     while( hRsrc > d )
461     {
462         if (pTypeInfo->type_id == 0)
463                 break; /* terminal entry */
464         d += sizeof(NE_TYPEINFO) + pTypeInfo->count * sizeof(NE_NAMEINFO);
465         if (hRsrc < d)
466         {
467             if( ((d - hRsrc)%sizeof(NE_NAMEINFO)) == 0 )
468             {
469                 pNameInfo = (NE_NAMEINFO *)(((char *)pModule) + hRsrc);
470                 break;
471             }
472             else 
473                 break; /* NE_NAMEINFO boundary mismatch */
474         }
475         pTypeInfo = (NE_TYPEINFO *)(((char *)pModule) + d);
476     }
477
478     if (pNameInfo)
479     {
480         if (pNameInfo->handle
481             && !(GlobalFlags16(pNameInfo->handle) & GMEM_DISCARDED))
482         {
483             pNameInfo->usage++;
484             TRACE("  Already loaded, new count=%d\n",
485                               pNameInfo->usage );
486         }
487         else
488         {
489             if (    pTypeInfo->resloader 
490                  && pTypeInfo->resloader != DefResourceHandlerProc )
491                 pNameInfo->handle = NE_CallTo16_word_www(
492                     pTypeInfo->resloader, pNameInfo->handle, pModule->self, hRsrc );
493             else
494                 pNameInfo->handle = NE_DefResourceHandler(
495                                          pNameInfo->handle, pModule->self, hRsrc );
496
497             if (pNameInfo->handle)
498             {
499                 pNameInfo->usage++;
500                 pNameInfo->flags |= NE_SEGFLAGS_LOADED;
501             }
502         }
503         return pNameInfo->handle;
504     }
505     return 0;
506 }
507
508
509 /**********************************************************************
510  *          NE_FreeResource
511  */
512 BOOL16 NE_FreeResource( NE_MODULE *pModule, HGLOBAL16 handle )
513 {
514     NE_TYPEINFO *pTypeInfo;
515     NE_NAMEINFO *pNameInfo;
516     WORD count;
517
518     if (!handle || !pModule || !pModule->res_table) return handle;
519
520     TRACE("handle=%04x\n", handle );
521
522     pTypeInfo = (NE_TYPEINFO *)((char *)pModule + pModule->res_table + 2);
523     while (pTypeInfo->type_id)
524     {
525         pNameInfo = (NE_NAMEINFO *)(pTypeInfo + 1);
526         for (count = pTypeInfo->count; count > 0; count--)
527         {
528             if (pNameInfo->handle == handle)
529             {
530                 if (pNameInfo->usage > 0) pNameInfo->usage--;
531                 if (pNameInfo->usage == 0)
532                 {
533                     GlobalFree16( pNameInfo->handle );
534                     pNameInfo->handle = 0;
535                     pNameInfo->flags &= ~NE_SEGFLAGS_LOADED;
536                 }
537                 return 0;
538             }
539             pNameInfo++;
540         }
541         pTypeInfo = (NE_TYPEINFO *)pNameInfo;
542     }
543
544     return handle;
545 }