Authors: Alexandre Julliard <julliard@codeweavers.com> (for Corel), Albert den Haan...
[wine/gsoc_dplay.git] / loader / pe_resource.c
blob94d16cd3b122c94a8a3ff32eb0ab73df823a41e4
1 /*
2 * PE (Portable Execute) File Resources
4 * Copyright 1995 Thomas Sandford
5 * Copyright 1996 Martin von Loewis
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
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include "wine/winestring.h"
16 #include "wine/unicode.h"
17 #include "windef.h"
18 #include "winnls.h"
19 #include "module.h"
20 #include "heap.h"
21 #include "task.h"
22 #include "process.h"
23 #include "stackframe.h"
24 #include "neexe.h"
25 #include "debugtools.h"
27 /**********************************************************************
28 * get_resdir
30 * Get the resource directory of a PE module
32 static IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
34 IMAGE_DATA_DIRECTORY *dir;
35 IMAGE_RESOURCE_DIRECTORY *ret = NULL;
37 if (!hmod) hmod = GetModuleHandleA( NULL );
38 dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
39 if (dir->Size && dir->VirtualAddress)
40 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress);
41 return ret;
45 /**********************************************************************
46 * GetResDirEntryW
48 * Helper function - goes down one level of PE resource tree
51 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr,
52 LPCWSTR name,DWORD root,
53 BOOL allowdefault)
55 int entrynum;
56 PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable;
57 int namelen;
59 if (HIWORD(name)) {
60 if (name[0]=='#') {
61 char buf[10];
62 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
63 return NULL;
64 return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault);
66 entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdirptr + 1);
67 namelen = strlenW(name);
68 for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++)
70 PIMAGE_RESOURCE_DIR_STRING_U str =
71 (PIMAGE_RESOURCE_DIR_STRING_U) (root +
72 entryTable[entrynum].u1.s.NameOffset);
73 if(namelen != str->Length)
74 continue;
75 if(strncmpiW(name,str->NameString,str->Length)==0)
76 return (PIMAGE_RESOURCE_DIRECTORY) (
77 root +
78 entryTable[entrynum].u2.s.OffsetToDirectory);
80 return NULL;
81 } else {
82 entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
83 (BYTE *) resdirptr +
84 sizeof(IMAGE_RESOURCE_DIRECTORY) +
85 resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
86 for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++)
87 if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name)
88 return (PIMAGE_RESOURCE_DIRECTORY) (
89 root +
90 entryTable[entrynum].u2.s.OffsetToDirectory);
91 /* just use first entry if no default can be found */
92 if (allowdefault && !name && resdirptr->NumberOfIdEntries)
93 return (PIMAGE_RESOURCE_DIRECTORY) (
94 root +
95 entryTable[0].u2.s.OffsetToDirectory);
96 return NULL;
100 /**********************************************************************
101 * GetResDirEntryA
103 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr,
104 LPCSTR name, DWORD root,
105 BOOL allowdefault )
107 PIMAGE_RESOURCE_DIRECTORY retv;
108 LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name )
109 : (LPWSTR)name;
111 retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault );
113 if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW );
115 return retv;
118 /**********************************************************************
119 * PE_FindResourceExW
121 * FindResourceExA/W does search in the following order:
122 * 1. Exact specified language
123 * 2. Language with neutral sublanguage
124 * 3. Neutral language with neutral sublanguage
125 * 4. Neutral language with default sublanguage
127 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
129 PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod);
130 DWORD root;
131 HRSRC result;
133 if (!resdirptr) return 0;
135 root = (DWORD) resdirptr;
136 if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
137 return 0;
138 if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
139 return 0;
141 /* 1. Exact specified language */
142 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
144 if (!result)
146 /* 2. Language with neutral sublanguage */
147 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
148 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
151 if (!result)
153 /* 3. Neutral language with neutral sublanguage */
154 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
155 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
158 if (!result)
160 /* 4. Neutral language with default sublanguage */
161 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
162 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
165 return result;
168 /**********************************************************************
169 * PE_FindResourceW
171 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
172 * FindResourceA/W does search in the following order:
173 * 1. Neutral language with neutral sublanguage
174 * 2. Neutral language with default sublanguage
175 * 3. Current locale lang id
176 * 4. Current locale lang id with neutral sublanguage
177 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
178 * 6. Return first in the list
180 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
182 PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod);
183 DWORD root;
184 HRSRC result;
185 WORD lang;
187 if (!resdirptr) return 0;
189 root = (DWORD) resdirptr;
190 if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
191 return 0;
192 if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
193 return 0;
195 /* 1. Neutral language with neutral sublanguage */
196 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
197 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
199 if (!result)
201 /* 2. Neutral language with default sublanguage */
202 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
203 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
206 if (!result)
208 /* 3. Current locale lang id */
209 lang = LANGIDFROMLCID(GetUserDefaultLCID());
210 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
213 if (!result)
215 /* 4. Current locale lang id with neutral sublanguage */
216 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
217 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
220 if (!result)
222 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
223 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
224 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
227 if (!result)
229 /* 6. Return first in the list */
230 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)0, root, TRUE);
233 return result;
237 /**********************************************************************
238 * PE_LoadResource
240 HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc )
242 if (!hRsrc) return 0;
243 return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
247 /**********************************************************************
248 * PE_SizeofResource
250 DWORD PE_SizeofResource( HANDLE hRsrc )
252 if (!hRsrc) return 0;
253 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
257 /**********************************************************************
258 * EnumResourceTypesA (KERNEL32.90)
260 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
262 int i;
263 PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod);
264 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
265 BOOL ret;
266 HANDLE heap = GetProcessHeap();
268 if (!resdir) return FALSE;
270 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
271 ret = FALSE;
272 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
273 LPSTR name;
275 if (et[i].u1.s.NameIsString)
276 name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)resdir + et[i].u1.s.NameOffset));
277 else
278 name = (LPSTR)(int)et[i].u1.Id;
279 ret = lpfun(hmod,name,lparam);
280 if (HIWORD(name))
281 HeapFree(heap,0,name);
282 if (!ret)
283 break;
285 return ret;
289 /**********************************************************************
290 * EnumResourceTypesW (KERNEL32.91)
292 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
294 int i;
295 PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod);
296 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
297 BOOL ret;
299 if (!resdir) return FALSE;
301 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
302 ret = FALSE;
303 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
304 LPWSTR type;
305 if (et[i].u1.s.NameIsString)
306 type = (LPWSTR)((LPBYTE)resdir + et[i].u1.s.NameOffset);
307 else
308 type = (LPWSTR)(int)et[i].u1.Id;
310 ret = lpfun(hmod,type,lparam);
311 if (!ret)
312 break;
314 return ret;
318 /**********************************************************************
319 * EnumResourceNamesA (KERNEL32.88)
321 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
323 int i;
324 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
325 PIMAGE_RESOURCE_DIRECTORY resdir;
326 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
327 BOOL ret;
328 HANDLE heap = GetProcessHeap();
329 LPWSTR typeW;
331 if (!basedir) return FALSE;
333 if (HIWORD(type))
334 typeW = HEAP_strdupAtoW(heap,0,type);
335 else
336 typeW = (LPWSTR)type;
337 resdir = GetResDirEntryW(basedir,typeW,(DWORD)basedir,FALSE);
338 if (HIWORD(typeW))
339 HeapFree(heap,0,typeW);
340 if (!resdir)
341 return FALSE;
342 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
343 ret = FALSE;
344 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
345 LPSTR name;
347 if (et[i].u1.s.NameIsString)
348 name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)basedir + et[i].u1.s.NameOffset));
349 else
350 name = (LPSTR)(int)et[i].u1.Id;
351 ret = lpfun(hmod,type,name,lparam);
352 if (HIWORD(name)) HeapFree(heap,0,name);
353 if (!ret)
354 break;
356 return ret;
360 /**********************************************************************
361 * EnumResourceNamesW (KERNEL32.89)
363 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
365 int i;
366 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
367 PIMAGE_RESOURCE_DIRECTORY resdir;
368 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
369 BOOL ret;
371 if (!basedir) return FALSE;
373 resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE);
374 if (!resdir)
375 return FALSE;
376 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
377 ret = FALSE;
378 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
379 LPWSTR name;
380 if (et[i].u1.s.NameIsString)
381 name = (LPWSTR)((LPBYTE)basedir + et[i].u1.s.NameOffset);
382 else
383 name = (LPWSTR)(int)et[i].u1.Id;
384 ret = lpfun(hmod,type,name,lparam);
385 if (!ret)
386 break;
388 return ret;
392 /**********************************************************************
393 * EnumResourceLanguagesA (KERNEL32.86)
395 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
396 ENUMRESLANGPROCA lpfun, LONG lparam )
398 int i;
399 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
400 PIMAGE_RESOURCE_DIRECTORY resdir;
401 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
402 BOOL ret;
403 HANDLE heap = GetProcessHeap();
405 if (!basedir) return FALSE;
407 if (HIWORD(type))
409 LPWSTR typeW = HEAP_strdupAtoW(heap,0,type);
410 resdir = GetResDirEntryW(basedir,typeW,(DWORD)basedir,FALSE);
411 HeapFree(heap,0,typeW);
413 else resdir = GetResDirEntryW(basedir,(LPWSTR)type,(DWORD)basedir,FALSE);
414 if (!resdir)
415 return FALSE;
417 if (HIWORD(name))
419 LPWSTR nameW = HEAP_strdupAtoW(heap,0,name);
420 resdir = GetResDirEntryW(resdir,nameW,(DWORD)basedir,FALSE);
421 HeapFree(heap,0,nameW);
423 else resdir = GetResDirEntryW(resdir,(LPWSTR)name,(DWORD)basedir,FALSE);
424 if (!resdir)
425 return FALSE;
427 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
428 ret = FALSE;
429 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
430 /* languages are just ids... I hope */
431 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
432 if (!ret)
433 break;
435 return ret;
439 /**********************************************************************
440 * EnumResourceLanguagesW (KERNEL32.87)
442 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
443 ENUMRESLANGPROCW lpfun, LONG lparam )
445 int i;
446 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
447 PIMAGE_RESOURCE_DIRECTORY resdir;
448 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
449 BOOL ret;
451 if (!basedir) return FALSE;
453 resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE);
454 if (!resdir)
455 return FALSE;
456 resdir = GetResDirEntryW(resdir,name,(DWORD)basedir,FALSE);
457 if (!resdir)
458 return FALSE;
459 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
460 ret = FALSE;
461 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
462 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
463 if (!ret)
464 break;
466 return ret;