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