Framework for the doppler effect.
[wine] / loader / pe_resource.c
1 /*
2  * PE (Portable Execute) File Resources
3  *
4  * Copyright 1995 Thomas Sandford
5  * Copyright 1996 Martin von Loewis
6  *
7  * Based on the Win16 resource handling code in loader/resource.c
8  * Copyright 1993 Robert J. Amstadt
9  * Copyright 1995 Alexandre Julliard
10  * Copyright 1997 Marcus Meissner
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include "config.h"
28
29 #include <stdlib.h>
30 #include <sys/types.h>
31
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "wine/unicode.h"
35 #include "windef.h"
36 #include "winnls.h"
37 #include "winternl.h"
38 #include "winerror.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(resource);
42
43
44 /**********************************************************************
45  *  is_data_file_module
46  *
47  * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
48  */
49 inline static int is_data_file_module( HMODULE hmod )
50 {
51     return (ULONG_PTR)hmod & 1;
52 }
53
54
55 /**********************************************************************
56  *  get_resdir
57  *
58  * Get the resource directory of a PE module
59  */
60 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
61 {
62     DWORD size;
63
64     if (!hmod) hmod = GetModuleHandleA( NULL );
65     else if (!HIWORD(hmod))
66     {
67         FIXME("Enumeration of 16-bit resources is not supported\n");
68         SetLastError(ERROR_INVALID_HANDLE);
69         return NULL;
70     }
71     return RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
72 }
73
74
75 /**********************************************************************
76  *  find_entry_by_id
77  *
78  * Find an entry by id in a resource directory
79  */
80 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
81                                                          WORD id, const void *root )
82 {
83     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
84     int min, max, pos;
85
86     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
87     min = dir->NumberOfNamedEntries;
88     max = min + dir->NumberOfIdEntries - 1;
89     while (min <= max)
90     {
91         pos = (min + max) / 2;
92         if (entry[pos].u1.s2.Id == id)
93             return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
94         if (entry[pos].u1.s2.Id > id) max = pos - 1;
95         else min = pos + 1;
96     }
97     return NULL;
98 }
99
100
101 /**********************************************************************
102  *  find_entry_by_nameW
103  *
104  * Find an entry by name in a resource directory
105  */
106 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
107                                                             LPCWSTR name, const void *root )
108 {
109     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
110     const IMAGE_RESOURCE_DIR_STRING_U *str;
111     int min, max, res, pos, namelen;
112
113     if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
114     if (name[0] == '#')
115     {
116         char buf[16];
117         if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
118             return NULL;
119         return find_entry_by_id( dir, atoi(buf), root );
120     }
121
122     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
123     namelen = strlenW(name);
124     min = 0;
125     max = dir->NumberOfNamedEntries - 1;
126     while (min <= max)
127     {
128         pos = (min + max) / 2;
129         str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
130         res = strncmpiW( name, str->NameString, str->Length );
131         if (!res && namelen == str->Length)
132             return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
133         if (res < 0) max = pos - 1;
134         else min = pos + 1;
135     }
136     return NULL;
137 }
138
139
140 /**********************************************************************
141  *  find_entry_by_nameA
142  *
143  * Find an entry by name in a resource directory
144  */
145 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
146                                                             LPCSTR name, const void *root )
147 {
148     const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
149     LPWSTR nameW;
150     INT len;
151
152     if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
153     if (name[0] == '#')
154     {
155         return find_entry_by_id( dir, atoi(name+1), root );
156     }
157
158     len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
159     if ((nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
160     {
161         MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
162         ret = find_entry_by_nameW( dir, nameW, root );
163         HeapFree( GetProcessHeap(), 0, nameW );
164     }
165     return ret;
166 }
167
168
169 /**********************************************************************
170  *  find_entry_default
171  *
172  * Find a default entry in a resource directory
173  */
174 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
175                                                            const void *root )
176 {
177     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
178
179     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
180     return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
181 }
182
183
184 /**********************************************************************
185  *          PE_FindResourceExW
186  *
187  * FindResourceExA/W does search in the following order:
188  * 1. Exact specified language
189  * 2. Language with neutral sublanguage
190  * 3. Neutral language with neutral sublanguage
191  * 4. Neutral language with default sublanguage
192  */
193 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
194 {
195     const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
196     const void *root;
197     HRSRC result;
198
199     if (!resdirptr) return 0;
200
201     root = resdirptr;
202     if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
203     if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
204
205     /* 1. Exact specified language */
206     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
207
208     /* 2. Language with neutral sublanguage */
209     lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
210     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
211
212     /* 3. Neutral language with neutral sublanguage */
213     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
214     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
215
216     /* 4. Neutral language with default sublanguage */
217     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
218     result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
219
220  found:
221     return result;
222 }
223
224 /**********************************************************************
225  *          PE_FindResourceW
226  *
227  * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
228  * FindResourceA/W does search in the following order:
229  * 1. Neutral language with neutral sublanguage
230  * 2. Neutral language with default sublanguage
231  * 3. Current locale lang id
232  * 4. Current locale lang id with neutral sublanguage
233  * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
234  * 6. Return first in the list
235  */
236 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
237 {
238     const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
239     const void *root;
240     HRSRC result;
241     WORD lang;
242
243     if (!resdirptr) return 0;
244
245     root = resdirptr;
246     if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
247     if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
248
249     /* 1. Neutral language with neutral sublanguage */
250     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
251     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
252
253     /* 2. Neutral language with default sublanguage */
254     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
255     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
256
257     /* 3. Current locale lang id */
258     lang = LANGIDFROMLCID(GetUserDefaultLCID());
259     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
260
261     /* 4. Current locale lang id with neutral sublanguage */
262     lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
263     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
264
265     /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
266     lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
267     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
268
269     /* 6. Return first in the list */
270     result = (HRSRC)find_entry_default( resdirptr, root );
271
272  found:
273     return result;
274 }
275
276
277 /**********************************************************************
278  *          PE_LoadResource
279  */
280 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
281 {
282     DWORD offset;
283
284     if (!hRsrc) return 0;
285     if (!hmod) hmod = GetModuleHandleA( NULL );
286
287     offset = ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData;
288
289     if (is_data_file_module(hmod))
290     {
291         hmod = (HMODULE)((ULONG_PTR)hmod & ~1);
292         return (HGLOBAL)RtlImageRvaToVa( RtlImageNtHeader(hmod), hmod, offset, NULL );
293     }
294     else
295         return (HGLOBAL)((char *)hmod + offset);
296 }
297
298
299 /**********************************************************************
300  *          PE_SizeofResource
301  */
302 DWORD PE_SizeofResource( HRSRC hRsrc )
303 {
304     if (!hRsrc) return 0;
305     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
306 }
307
308
309 /**********************************************************************
310  *      EnumResourceTypesA      (KERNEL32.@)
311  */
312 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
313 {
314     int         i;
315     const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
316     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
317     BOOL        ret;
318
319     if (!resdir) return FALSE;
320
321     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
322     ret = FALSE;
323     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
324         LPSTR type;
325
326         if (et[i].u1.s1.NameIsString)
327         {
328             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
329             DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
330                                              NULL, 0, NULL, NULL);
331             if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
332                 return FALSE;
333             WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
334                                  type, len, NULL, NULL);
335             type[len] = '\0';
336             ret = lpfun(hmod,type,lparam);
337             HeapFree(GetProcessHeap(), 0, type);
338         }
339         else
340         {
341             type = (LPSTR)(int)et[i].u1.s2.Id;
342             ret = lpfun(hmod,type,lparam);
343         }
344         if (!ret)
345                 break;
346     }
347     return ret;
348 }
349
350
351 /**********************************************************************
352  *      EnumResourceTypesW      (KERNEL32.@)
353  */
354 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
355 {
356     int         i;
357     const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
358     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
359     BOOL        ret;
360
361     if (!resdir) return FALSE;
362
363     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
364     ret = FALSE;
365     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
366         LPWSTR  type;
367
368         if (et[i].u1.s1.NameIsString)
369         {
370             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
371             if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
372                 return FALSE;
373             memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
374             type[pResString->Length] = '\0';
375             ret = lpfun(hmod,type,lparam);
376             HeapFree(GetProcessHeap(), 0, type);
377         }
378         else
379         {
380             type = (LPWSTR)(int)et[i].u1.s2.Id;
381             ret = lpfun(hmod,type,lparam);
382         }
383         if (!ret)
384                 break;
385     }
386     return ret;
387 }
388
389
390 /**********************************************************************
391  *      EnumResourceNamesA      (KERNEL32.@)
392  */
393 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
394 {
395     int         i;
396     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
397     const IMAGE_RESOURCE_DIRECTORY *resdir;
398     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
399     BOOL        ret;
400
401     if (!basedir) return FALSE;
402
403     if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
404
405     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
406     ret = FALSE;
407     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
408         LPSTR name;
409
410         if (et[i].u1.s1.NameIsString)
411         {
412             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
413             DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
414                                             NULL, 0, NULL, NULL);
415             if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
416                 return FALSE;
417             WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
418                                  name, len, NULL, NULL );
419             name[len] = '\0';
420             ret = lpfun(hmod,type,name,lparam);
421             HeapFree( GetProcessHeap(), 0, name );
422         }
423         else
424         {
425             name = (LPSTR)(int)et[i].u1.s2.Id;
426             ret = lpfun(hmod,type,name,lparam);
427         }
428         if (!ret)
429                 break;
430     }
431     return ret;
432 }
433
434
435 /**********************************************************************
436  *      EnumResourceNamesW      (KERNEL32.@)
437  */
438 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
439 {
440     int         i;
441     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
442     const IMAGE_RESOURCE_DIRECTORY *resdir;
443     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
444     BOOL        ret;
445
446     if (!basedir) return FALSE;
447
448     if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
449
450     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
451     ret = FALSE;
452     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
453         LPWSTR name;
454
455         if (et[i].u1.s1.NameIsString)
456         {
457             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
458             if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
459                 return FALSE;
460             memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
461             name[pResString->Length] = '\0';
462             ret = lpfun(hmod,type,name,lparam);
463             HeapFree(GetProcessHeap(), 0, name);
464         }
465         else
466         {
467             name = (LPWSTR)(int)et[i].u1.s2.Id;
468             ret = lpfun(hmod,type,name,lparam);
469         }
470         if (!ret)
471                 break;
472     }
473     return ret;
474 }
475
476
477 /**********************************************************************
478  *      EnumResourceLanguagesA  (KERNEL32.@)
479  */
480 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
481                                     ENUMRESLANGPROCA lpfun, LONG lparam )
482 {
483     int         i;
484     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
485     const IMAGE_RESOURCE_DIRECTORY *resdir;
486     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
487     BOOL        ret;
488
489     if (!basedir) return FALSE;
490     if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
491     if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
492
493     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
494     ret = FALSE;
495     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
496         /* languages are just ids... I hope */
497         ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
498         if (!ret)
499                 break;
500     }
501     return ret;
502 }
503
504
505 /**********************************************************************
506  *      EnumResourceLanguagesW  (KERNEL32.@)
507  */
508 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
509                                     ENUMRESLANGPROCW lpfun, LONG lparam )
510 {
511     int         i;
512     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
513     const IMAGE_RESOURCE_DIRECTORY *resdir;
514     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
515     BOOL        ret;
516
517     if (!basedir) return FALSE;
518
519     if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
520     if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
521
522     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
523     ret = FALSE;
524     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
525         ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
526         if (!ret)
527                 break;
528     }
529     return ret;
530 }