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