Removed some unnecessary includes.
[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
13 #include <stdlib.h>
14 #include <sys/types.h>
15
16 #include "wine/unicode.h"
17 #include "windef.h"
18 #include "winnls.h"
19 #include "winerror.h"
20 #include "module.h"
21 #include "heap.h"
22 #include "task.h"
23 #include "process.h"
24 #include "stackframe.h"
25 #include "debugtools.h"
26
27 DEFAULT_DEBUG_CHANNEL(resource);
28
29 /**********************************************************************
30  *  get_resdir
31  *
32  * Get the resource directory of a PE module
33  */
34 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
35 {
36     const IMAGE_DATA_DIRECTORY *dir;
37     const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
38
39     if (!hmod) hmod = GetModuleHandleA( NULL );
40     else if (!HIWORD(hmod))
41     {
42         FIXME("Enumeration of 16-bit resources is not supported\n");
43         SetLastError(ERROR_INVALID_HANDLE);
44         return NULL;
45     }
46     dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
47     if (dir->Size && dir->VirtualAddress)
48         ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress);
49     return ret;
50 }
51
52
53 /**********************************************************************
54  *  find_entry_by_id
55  *
56  * Find an entry by id in a resource directory
57  */
58 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
59                                                          WORD id, const void *root )
60 {
61     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
62     int min, max, pos;
63
64     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
65     min = dir->NumberOfNamedEntries;
66     max = min + dir->NumberOfIdEntries - 1;
67     while (min <= max)
68     {
69         pos = (min + max) / 2;
70         if (entry[pos].u1.Id == id)
71             return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s2.OffsetToDirectory);
72         if (entry[pos].u1.Id > id) max = pos - 1;
73         else min = pos + 1;
74     }
75     return NULL;
76 }
77
78
79 /**********************************************************************
80  *  find_entry_by_nameW
81  *
82  * Find an entry by name in a resource directory
83  */
84 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
85                                                             LPCWSTR name, const void *root )
86 {
87     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
88     const IMAGE_RESOURCE_DIR_STRING_U *str;
89     int min, max, res, pos, namelen;
90
91     if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
92     if (name[0] == '#')
93     {
94         char buf[16];
95         if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
96             return NULL;
97         return find_entry_by_id( dir, atoi(buf), root );
98     }
99
100     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
101     namelen = strlenW(name);
102     min = 0;
103     max = dir->NumberOfNamedEntries - 1;
104     while (min <= max)
105     {
106         pos = (min + max) / 2;
107         str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
108         res = strncmpiW( name, str->NameString, str->Length );
109         if (!res && namelen == str->Length)
110             return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s2.OffsetToDirectory);
111         if (res < 0) max = pos - 1;
112         else min = pos + 1;
113     }
114     return NULL;
115 }
116
117
118 /**********************************************************************
119  *  find_entry_by_nameA
120  *
121  * Find an entry by name in a resource directory
122  */
123 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
124                                                             LPCSTR name, const void *root )
125 {
126     const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
127     LPWSTR nameW;
128
129     if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
130     if (name[0] == '#')
131     {
132         return find_entry_by_id( dir, atoi(name+1), root );
133     }
134
135     if ((nameW = HEAP_strdupAtoW( GetProcessHeap(), 0, name )))
136     {
137         ret = find_entry_by_nameW( dir, nameW, root );
138         HeapFree( GetProcessHeap(), 0, nameW );
139     }
140     return ret;
141 }
142
143
144 /**********************************************************************
145  *  find_entry_default
146  *
147  * Find a default entry in a resource directory
148  */
149 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
150                                                            const void *root )
151 {
152     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
153
154     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
155     return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s2.OffsetToDirectory);
156 }
157
158
159 /**********************************************************************
160  *          PE_FindResourceExW
161  *
162  * FindResourceExA/W does search in the following order:
163  * 1. Exact specified language
164  * 2. Language with neutral sublanguage
165  * 3. Neutral language with neutral sublanguage
166  * 4. Neutral language with default sublanguage
167  */
168 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
169 {
170     const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
171     const void *root;
172     HRSRC result;
173
174     if (!resdirptr) return 0;
175
176     root = resdirptr;
177     if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
178     if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
179
180     /* 1. Exact specified language */
181     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
182
183     /* 2. Language with neutral sublanguage */
184     lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
185     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
186
187     /* 3. Neutral language with neutral sublanguage */
188     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
189     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
190
191     /* 4. Neutral language with default sublanguage */
192     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
193     result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
194
195  found:
196     return result;
197 }
198
199 /**********************************************************************
200  *          PE_FindResourceW
201  *
202  * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
203  * FindResourceA/W does search in the following order:
204  * 1. Neutral language with neutral sublanguage
205  * 2. Neutral language with default sublanguage
206  * 3. Current locale lang id
207  * 4. Current locale lang id with neutral sublanguage
208  * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
209  * 6. Return first in the list
210  */
211 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
212 {
213     const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
214     const void *root;
215     HRSRC result;
216     WORD lang;
217
218     if (!resdirptr) return 0;
219
220     root = resdirptr;
221     if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
222     if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
223
224     /* 1. Neutral language with neutral sublanguage */
225     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
226     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
227
228     /* 2. Neutral language with default sublanguage */
229     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
230     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
231
232     /* 3. Current locale lang id */
233     lang = LANGIDFROMLCID(GetUserDefaultLCID());
234     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
235
236     /* 4. Current locale lang id with neutral sublanguage */
237     lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
238     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
239
240     /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
241     lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
242     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
243
244     /* 6. Return first in the list */
245     result = (HRSRC)find_entry_default( resdirptr, root );
246
247  found:
248     return result;
249 }
250
251
252 /**********************************************************************
253  *          PE_LoadResource
254  */
255 HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc )
256 {
257     if (!hRsrc) return 0;
258     return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
259 }
260
261
262 /**********************************************************************
263  *          PE_SizeofResource
264  */
265 DWORD PE_SizeofResource( HANDLE hRsrc )
266 {
267     if (!hRsrc) return 0;
268     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
269 }
270
271
272 /**********************************************************************
273  *      EnumResourceTypesA      (KERNEL32.90)
274  */
275 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
276 {
277     int         i;
278     const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
279     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
280     BOOL        ret;
281
282     if (!resdir) return FALSE;
283
284     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
285     ret = FALSE;
286     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
287         LPSTR type;
288
289         if (et[i].u1.s1.NameIsString)
290         {
291             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
292             DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
293                                              NULL, 0, NULL, NULL);
294             if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
295                 return FALSE;
296             WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
297                                  type, len, NULL, NULL);
298             type[len] = '\0';
299             ret = lpfun(hmod,type,lparam);
300             HeapFree(GetProcessHeap(), 0, type);
301         }
302         else
303         {
304             type = (LPSTR)(int)et[i].u1.Id;
305             ret = lpfun(hmod,type,lparam);
306         }
307         if (!ret)
308                 break;
309     }
310     return ret;
311 }
312
313
314 /**********************************************************************
315  *      EnumResourceTypesW      (KERNEL32.91)
316  */
317 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
318 {
319     int         i;
320     const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
321     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
322     BOOL        ret;
323
324     if (!resdir) return FALSE;
325
326     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
327     ret = FALSE;
328     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
329         LPWSTR  type;
330
331         if (et[i].u1.s1.NameIsString)
332         {
333             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
334             if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
335                 return FALSE;
336             memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
337             type[pResString->Length] = '\0';
338             ret = lpfun(hmod,type,lparam);
339             HeapFree(GetProcessHeap(), 0, type);
340         }
341         else
342         {
343             type = (LPWSTR)(int)et[i].u1.Id;
344             ret = lpfun(hmod,type,lparam);
345         }
346         if (!ret)
347                 break;
348     }
349     return ret;
350 }
351
352
353 /**********************************************************************
354  *      EnumResourceNamesA      (KERNEL32.88)
355  */
356 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
357 {
358     int         i;
359     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
360     const IMAGE_RESOURCE_DIRECTORY *resdir;
361     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
362     BOOL        ret;
363
364     if (!basedir) return FALSE;
365
366     if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
367
368     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
369     ret = FALSE;
370     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
371         LPSTR name;
372
373         if (et[i].u1.s1.NameIsString)
374         {
375             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
376             DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
377                                             NULL, 0, NULL, NULL);
378             if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
379                 return FALSE;
380             WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
381                                  name, len, NULL, NULL );
382             name[len] = '\0';
383             ret = lpfun(hmod,type,name,lparam);
384             HeapFree( GetProcessHeap(), 0, name );
385         }
386         else
387         {
388             name = (LPSTR)(int)et[i].u1.Id;
389             ret = lpfun(hmod,type,name,lparam);
390         }
391         if (!ret)
392                 break;
393     }
394     return ret;
395 }
396
397
398 /**********************************************************************
399  *      EnumResourceNamesW      (KERNEL32.89)
400  */
401 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
402 {
403     int         i;
404     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
405     const IMAGE_RESOURCE_DIRECTORY *resdir;
406     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
407     BOOL        ret;
408
409     if (!basedir) return FALSE;
410
411     if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
412
413     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
414     ret = FALSE;
415     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
416         LPWSTR name;
417
418         if (et[i].u1.s1.NameIsString)
419         {
420             PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
421             if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
422                 return FALSE;
423             memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
424             name[pResString->Length] = '\0';
425             ret = lpfun(hmod,type,name,lparam);
426             HeapFree(GetProcessHeap(), 0, name);
427         }
428         else
429         {
430             name = (LPWSTR)(int)et[i].u1.Id;
431             ret = lpfun(hmod,type,name,lparam);
432         }
433         if (!ret)
434                 break;
435     }
436     return ret;
437 }
438
439
440 /**********************************************************************
441  *      EnumResourceLanguagesA  (KERNEL32.86)
442  */
443 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
444                                     ENUMRESLANGPROCA lpfun, LONG lparam )
445 {
446     int         i;
447     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
448     const IMAGE_RESOURCE_DIRECTORY *resdir;
449     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
450     BOOL        ret;
451
452     if (!basedir) return FALSE;
453     if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
454     if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
455
456     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
457     ret = FALSE;
458     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
459         /* languages are just ids... I hope */
460         ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
461         if (!ret)
462                 break;
463     }
464     return ret;
465 }
466
467
468 /**********************************************************************
469  *      EnumResourceLanguagesW  (KERNEL32.87)
470  */
471 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
472                                     ENUMRESLANGPROCW lpfun, LONG lparam )
473 {
474     int         i;
475     const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
476     const IMAGE_RESOURCE_DIRECTORY *resdir;
477     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
478     BOOL        ret;
479
480     if (!basedir) return FALSE;
481
482     if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
483     if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
484
485     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
486     ret = FALSE;
487     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
488         ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
489         if (!ret)
490                 break;
491     }
492     return ret;
493 }