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