Fixed some issues found by winapi_check.
[wine] / loader / resource.c
1 /*
2  * Resources
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wine/winbase16.h"
37 #include "wine/exception.h"
38 #include "heap.h"
39 #include "cursoricon.h"
40 #include "module.h"
41 #include "file.h"
42 #include "wine/debug.h"
43 #include "winerror.h"
44 #include "winnls.h"
45 #include "msvcrt/excpt.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(resource);
48
49 #define HRSRC_MAP_BLOCKSIZE 16
50
51 /* handle conversions */
52 #define HRSRC_32(h16)           ((HRSRC)(ULONG_PTR)(h16))
53
54 typedef struct _HRSRC_ELEM
55 {
56     HRSRC hRsrc;
57     WORD  type;
58 } HRSRC_ELEM;
59
60 typedef struct _HRSRC_MAP
61 {
62     int nAlloc;
63     int nUsed;
64     HRSRC_ELEM *elem;
65 } HRSRC_MAP;
66
67 /**********************************************************************
68  *          MapHRsrc32To16
69  */
70 static HRSRC MapHRsrc32To16( NE_MODULE *pModule, HRSRC hRsrc32, WORD type )
71 {
72     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
73     HRSRC_ELEM *newElem;
74     int i;
75
76     /* On first call, initialize HRSRC map */
77     if ( !map )
78     {
79         if ( !(map = (HRSRC_MAP *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
80                                              sizeof(HRSRC_MAP) ) ) )
81         {
82             ERR("Cannot allocate HRSRC map\n" );
83             return 0;
84         }
85         pModule->hRsrcMap = (LPVOID)map;
86     }
87
88     /* Check whether HRSRC32 already in map */
89     for ( i = 0; i < map->nUsed; i++ )
90         if ( map->elem[i].hRsrc == hRsrc32 )
91             return (HRSRC)(i + 1);
92
93     /* If no space left, grow table */
94     if ( map->nUsed == map->nAlloc )
95     {
96         if ( !(newElem = (HRSRC_ELEM *)HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
97                                                     map->elem,
98                                                     (map->nAlloc + HRSRC_MAP_BLOCKSIZE)
99                                                     * sizeof(HRSRC_ELEM) ) ))
100         {
101             ERR("Cannot grow HRSRC map\n" );
102             return 0;
103         }
104         map->elem = newElem;
105         map->nAlloc += HRSRC_MAP_BLOCKSIZE;
106     }
107
108     /* Add HRSRC32 to table */
109     map->elem[map->nUsed].hRsrc = hRsrc32;
110     map->elem[map->nUsed].type  = type;
111     map->nUsed++;
112
113     return (HRSRC)map->nUsed;
114 }
115
116 /**********************************************************************
117  *          MapHRsrc16To32
118  */
119 static HRSRC MapHRsrc16To32( NE_MODULE *pModule, HRSRC hRsrc16 )
120 {
121     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
122     if ( !map || !hRsrc16 || (int)hRsrc16 > map->nUsed ) return 0;
123
124     return map->elem[(int)hRsrc16-1].hRsrc;
125 }
126
127 /**********************************************************************
128  *          MapHRsrc16ToType
129  */
130 static WORD MapHRsrc16ToType( NE_MODULE *pModule, HRSRC hRsrc16 )
131 {
132     HRSRC_MAP *map = (HRSRC_MAP *)pModule->hRsrcMap;
133     if ( !map || !hRsrc16 || (int)hRsrc16 > map->nUsed ) return 0;
134
135     return map->elem[(int)hRsrc16-1].type;
136 }
137
138
139 /* filter for page-fault exceptions */
140 static WINE_EXCEPTION_FILTER(page_fault)
141 {
142     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
143         return EXCEPTION_EXECUTE_HANDLER;
144     return EXCEPTION_CONTINUE_SEARCH;
145 }
146
147 static HRSRC RES_FindResource2( HMODULE hModule, LPCSTR type,
148                                 LPCSTR name, WORD lang,
149                                 BOOL bUnicode, BOOL bRet16 )
150 {
151     HRSRC hRsrc = 0;
152
153     TRACE("(%08x, %08x%s, %08x%s, %04x, %s, %s)\n",
154           hModule,
155           (UINT)type, HIWORD(type)? (bUnicode? debugstr_w((LPWSTR)type) : debugstr_a(type)) : "",
156           (UINT)name, HIWORD(name)? (bUnicode? debugstr_w((LPWSTR)name) : debugstr_a(name)) : "",
157           lang,
158           bUnicode? "W"  : "A",
159           bRet16?   "NE" : "PE" );
160
161     if (!HIWORD(hModule))
162     {
163         HMODULE16 hMod16   = MapHModuleLS( hModule );
164         NE_MODULE *pModule = NE_GetPtr( hMod16 );
165         if (!pModule) return 0;
166         if (!pModule->module32)
167         {
168             /* 16-bit NE module */
169             LPSTR typeStr, nameStr;
170
171             if ( HIWORD( type ) && bUnicode )
172                 typeStr = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)type );
173             else
174                 typeStr = (LPSTR)type;
175             if ( HIWORD( name ) && bUnicode )
176                 nameStr = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)name );
177             else
178                 nameStr = (LPSTR)name;
179
180             hRsrc = NE_FindResource( pModule, nameStr, typeStr );
181
182             if ( HIWORD( type ) && bUnicode )
183                 HeapFree( GetProcessHeap(), 0, typeStr );
184             if ( HIWORD( name ) && bUnicode )
185                 HeapFree( GetProcessHeap(), 0, nameStr );
186
187             /* If we need to return 32-bit HRSRC, no conversion is necessary,
188                we simply use the 16-bit HRSRC as 32-bit HRSRC */
189         }
190         else
191         {
192             /* 32-bit PE module */
193             hRsrc = RES_FindResource2( pModule->module32, type, name, lang, bUnicode, FALSE );
194             /* If we need to return 16-bit HRSRC, perform conversion */
195             if ( bRet16 )
196                 hRsrc = MapHRsrc32To16( pModule, hRsrc,
197                                         HIWORD( type )? 0 : LOWORD( type ) );
198         }
199     }
200     else
201     {
202         /* 32-bit PE module */
203         LPWSTR typeStr, nameStr;
204
205         if ( HIWORD( type ) && !bUnicode )
206             typeStr = HEAP_strdupAtoW( GetProcessHeap(), 0, type );
207         else
208             typeStr = (LPWSTR)type;
209         if ( HIWORD( name ) && !bUnicode )
210             nameStr = HEAP_strdupAtoW( GetProcessHeap(), 0, name );
211         else
212             nameStr = (LPWSTR)name;
213
214         /* Here is the real difference between FindResouce and FindResourceEx */
215         if(lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ||
216                 lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) ||
217                 lang == MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT) ||
218                 lang == MAKELANGID(LANG_NEUTRAL, 3)) /* FIXME: real name? */
219             hRsrc = PE_FindResourceW( hModule, nameStr, typeStr );
220         else
221             hRsrc = PE_FindResourceExW( hModule, nameStr, typeStr, lang );
222
223         if ( HIWORD( type ) && !bUnicode )
224             HeapFree( GetProcessHeap(), 0, typeStr );
225         if ( HIWORD( name ) && !bUnicode )
226             HeapFree( GetProcessHeap(), 0, nameStr );
227     }
228     return hRsrc;
229 }
230
231 /**********************************************************************
232  *          RES_FindResource
233  */
234
235 static HRSRC RES_FindResource( HMODULE hModule, LPCSTR type,
236                                LPCSTR name, WORD lang,
237                                BOOL bUnicode, BOOL bRet16 )
238 {
239     HRSRC hRsrc;
240     __TRY
241     {
242         hRsrc = RES_FindResource2(hModule, type, name, lang, bUnicode, bRet16);
243     }
244     __EXCEPT(page_fault)
245     {
246         WARN("page fault\n");
247         SetLastError(ERROR_INVALID_PARAMETER);
248         return 0;
249     }
250     __ENDTRY
251     return hRsrc;
252 }
253
254 /**********************************************************************
255  *          RES_SizeofResource
256  */
257 static DWORD RES_SizeofResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
258 {
259     if (!hRsrc) return 0;
260
261     TRACE("(%08x, %08x, %s)\n", hModule, hRsrc, bRet16? "NE" : "PE" );
262
263     if (!HIWORD(hModule))
264     {
265         HMODULE16 hMod16   = MapHModuleLS( hModule );
266         NE_MODULE *pModule = NE_GetPtr( hMod16 );
267         if (!pModule) return 0;
268
269         if (!pModule->module32)  /* 16-bit NE module */
270         {
271             /* If we got a 32-bit hRsrc, we don't need to convert it */
272             return NE_SizeofResource( pModule, hRsrc );
273         }
274
275         /* If we got a 16-bit hRsrc, convert it */
276         if (!HIWORD(hRsrc)) hRsrc = MapHRsrc16To32( pModule, hRsrc );
277     }
278
279     /* 32-bit PE module */
280     return PE_SizeofResource( hRsrc );
281 }
282
283 /**********************************************************************
284  *          RES_LoadResource
285  */
286 static HGLOBAL RES_LoadResource( HMODULE hModule, HRSRC hRsrc, BOOL bRet16 )
287 {
288     HGLOBAL hMem = 0;
289
290     TRACE("(%08x, %08x, %s)\n", hModule, hRsrc, bRet16? "NE" : "PE" );
291
292     if (!hRsrc) return 0;
293
294     if (!HIWORD(hModule))
295     {
296         HMODULE16 hMod16   = MapHModuleLS( hModule );
297         NE_MODULE *pModule = NE_GetPtr( hMod16 );
298         if (!pModule) return 0;
299         if (!pModule->module32)
300         {
301             /* 16-bit NE module */
302
303             /* If we got a 32-bit hRsrc, we don't need to convert it */
304             hMem = NE_LoadResource( pModule, LOWORD(hRsrc) );
305
306             /* If we are to return a 32-bit resource, we should probably
307                convert it but we don't for now.  FIXME !!! */
308             return hMem;
309         }
310         else
311         {
312             /* If we got a 16-bit hRsrc, convert it */
313             HRSRC hRsrc32 = HIWORD(hRsrc)? hRsrc : MapHRsrc16To32( pModule, hRsrc );
314
315             hMem = PE_LoadResource( pModule->module32, hRsrc32 );
316
317             /* If we need to return a 16-bit resource, convert it */
318             if ( bRet16 )
319             {
320                 WORD type   = MapHRsrc16ToType( pModule, hRsrc );
321                 DWORD size  = SizeofResource( hModule, hRsrc );
322                 LPVOID bits = LockResource( hMem );
323
324                 hMem = NE_LoadPEResource( pModule, type, bits, size );
325             }
326         }
327     }
328     else
329     {
330         /* 32-bit PE module */
331         hMem = PE_LoadResource( hModule, hRsrc );
332     }
333
334     return hMem;
335 }
336
337 /**********************************************************************
338  *          FindResource     (KERNEL.60)
339  */
340 HRSRC16 WINAPI FindResource16( HMODULE16 hModule, LPCSTR name, LPCSTR type )
341 {
342     return LOWORD( RES_FindResource( hModule, type, name,
343                                      MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), FALSE, TRUE ) );
344 }
345
346 /**********************************************************************
347  *          FindResourceA    (KERNEL32.@)
348  */
349 HRSRC WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
350 {
351     return RES_FindResource( hModule, type, name,
352                     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), FALSE, FALSE );
353 }
354
355 /**********************************************************************
356  *          FindResourceExA  (KERNEL32.@)
357  */
358 HRSRC WINAPI FindResourceExA( HMODULE hModule,
359                                LPCSTR type, LPCSTR name, WORD lang )
360 {
361     return RES_FindResource( hModule, type, name,
362                              lang, FALSE, FALSE );
363 }
364
365 /**********************************************************************
366  *          FindResourceExW  (KERNEL32.@)
367  */
368 HRSRC WINAPI FindResourceExW( HMODULE hModule,
369                               LPCWSTR type, LPCWSTR name, WORD lang )
370 {
371     return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name,
372                              lang, TRUE, FALSE );
373 }
374
375 /**********************************************************************
376  *          FindResourceW    (KERNEL32.@)
377  */
378 HRSRC WINAPI FindResourceW(HINSTANCE hModule, LPCWSTR name, LPCWSTR type)
379 {
380     return RES_FindResource( hModule, (LPCSTR)type, (LPCSTR)name,
381                     MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), TRUE, FALSE );
382 }
383
384 /**********************************************************************
385  *          LoadResource     (KERNEL.61)
386  */
387 HGLOBAL16 WINAPI LoadResource16( HMODULE16 hModule, HRSRC16 hRsrc )
388 {
389     return RES_LoadResource( hModule, HRSRC_32(hRsrc), TRUE );
390 }
391
392 /**********************************************************************
393  *          LoadResource     (KERNEL32.@)
394  */
395 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
396 {
397     return RES_LoadResource( hModule, hRsrc, FALSE );
398 }
399
400 /**********************************************************************
401  *          LockResource   (KERNEL.62)
402  */
403 SEGPTR WINAPI WIN16_LockResource16( HGLOBAL16 handle )
404 {
405     TRACE("(%04x)\n", handle );
406     /* May need to reload the resource if discarded */
407     return K32WOWGlobalLock16( handle );
408 }
409
410 /**********************************************************************
411  *          LockResource16 (KERNEL32.@)
412  */
413 LPVOID WINAPI LockResource16( HGLOBAL16 handle )
414 {
415     return MapSL( WIN16_LockResource16(handle) );
416 }
417
418 /**********************************************************************
419  *          LockResource     (KERNEL32.@)
420  */
421 LPVOID WINAPI LockResource( HGLOBAL handle )
422 {
423     TRACE("(%08x)\n", handle );
424
425     if (HIWORD( handle ))  /* 32-bit memory handle */
426         return (LPVOID)handle;
427
428     /* 16-bit memory handle */
429     return LockResource16( LOWORD(handle) );
430 }
431
432 typedef WORD (WINAPI *pDestroyIcon32Proc)( HGLOBAL16 handle, UINT16 flags );
433
434
435 /**********************************************************************
436  *          FreeResource     (KERNEL.63)
437  */
438 BOOL16 WINAPI FreeResource16( HGLOBAL16 handle )
439 {
440     HGLOBAL16 retv = handle;
441     NE_MODULE *pModule = NE_GetPtr( FarGetOwner16( handle ) );
442
443     TRACE("(%04x)\n", handle );
444
445     /* Try NE resource first */
446     retv = NE_FreeResource( pModule, handle );
447
448     /* If this failed, call USER.DestroyIcon32; this will check
449        whether it is a shared cursor/icon; if not it will call
450        GlobalFree16() */
451     if ( retv )
452     {
453         pDestroyIcon32Proc proc;
454         HMODULE user = GetModuleHandleA( "user32.dll" );
455
456         if (user && (proc = (pDestroyIcon32Proc)GetProcAddress( user, "DestroyIcon32" )))
457             retv = proc( handle, CID_RESOURCE );
458         else
459             retv = GlobalFree16( handle );
460     }
461     return (BOOL)retv;
462 }
463
464 /**********************************************************************
465  *          FreeResource     (KERNEL32.@)
466  */
467 BOOL WINAPI FreeResource( HGLOBAL handle )
468 {
469     if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
470
471     return FreeResource16( LOWORD(handle) );
472 }
473
474 /**********************************************************************
475  *          SizeofResource   (KERNEL.65)
476  */
477 DWORD WINAPI SizeofResource16( HMODULE16 hModule, HRSRC16 hRsrc )
478 {
479     return RES_SizeofResource( hModule, HRSRC_32(hRsrc), TRUE );
480 }
481
482 /**********************************************************************
483  *          SizeofResource   (KERNEL32.@)
484  */
485 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
486 {
487     return RES_SizeofResource( hModule, hRsrc, FALSE );
488 }