which is more portable than type (FreeBSD).
[wine/wine-kai.git] / loader / pe_resource.c
blob12f14557cd9f161ce10ee00634a3868ee8ba1649
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 "config.h"
15 #include <stdlib.h>
16 #include <sys/types.h>
18 #include "wine/unicode.h"
19 #include "windef.h"
20 #include "winnls.h"
21 #include "winerror.h"
22 #include "module.h"
23 #include "stackframe.h"
24 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(resource);
29 /**********************************************************************
30 * get_module_base
32 * Get the base address of a module
34 static const void *get_module_base( HMODULE hmod )
36 if (!hmod) hmod = GetModuleHandleA( NULL );
37 else if (!HIWORD(hmod))
39 FIXME("Enumeration of 16-bit resources is not supported\n");
40 SetLastError(ERROR_INVALID_HANDLE);
41 return NULL;
44 /* clear low order bit in case of LOAD_LIBRARY_AS_DATAFILE module */
45 return (void *)((ULONG_PTR)hmod & ~1);
49 /**********************************************************************
50 * get_resdir
52 * Get the resource directory of a PE module
54 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
56 const IMAGE_DATA_DIRECTORY *dir;
57 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
58 const void *base = get_module_base( hmod );
60 if (base)
62 dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
63 if (dir->Size && dir->VirtualAddress)
64 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)base + dir->VirtualAddress);
66 return ret;
70 /**********************************************************************
71 * find_entry_by_id
73 * Find an entry by id in a resource directory
75 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
76 WORD id, const void *root )
78 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
79 int min, max, pos;
81 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
82 min = dir->NumberOfNamedEntries;
83 max = min + dir->NumberOfIdEntries - 1;
84 while (min <= max)
86 pos = (min + max) / 2;
87 if (entry[pos].u1.s2.Id == id)
88 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
89 if (entry[pos].u1.s2.Id > id) max = pos - 1;
90 else min = pos + 1;
92 return NULL;
96 /**********************************************************************
97 * find_entry_by_nameW
99 * Find an entry by name in a resource directory
101 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
102 LPCWSTR name, const void *root )
104 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
105 const IMAGE_RESOURCE_DIR_STRING_U *str;
106 int min, max, res, pos, namelen;
108 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
109 if (name[0] == '#')
111 char buf[16];
112 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
113 return NULL;
114 return find_entry_by_id( dir, atoi(buf), root );
117 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
118 namelen = strlenW(name);
119 min = 0;
120 max = dir->NumberOfNamedEntries - 1;
121 while (min <= max)
123 pos = (min + max) / 2;
124 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
125 res = strncmpiW( name, str->NameString, str->Length );
126 if (!res && namelen == str->Length)
127 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
128 if (res < 0) max = pos - 1;
129 else min = pos + 1;
131 return NULL;
135 /**********************************************************************
136 * find_entry_by_nameA
138 * Find an entry by name in a resource directory
140 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
141 LPCSTR name, const void *root )
143 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
144 LPWSTR nameW;
145 INT len;
147 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
148 if (name[0] == '#')
150 return find_entry_by_id( dir, atoi(name+1), root );
153 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
154 if ((nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
156 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
157 ret = find_entry_by_nameW( dir, nameW, root );
158 HeapFree( GetProcessHeap(), 0, nameW );
160 return ret;
164 /**********************************************************************
165 * find_entry_default
167 * Find a default entry in a resource directory
169 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
170 const void *root )
172 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
174 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
175 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
179 /**********************************************************************
180 * PE_FindResourceExW
182 * FindResourceExA/W does search in the following order:
183 * 1. Exact specified language
184 * 2. Language with neutral sublanguage
185 * 3. Neutral language with neutral sublanguage
186 * 4. Neutral language with default sublanguage
188 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
190 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
191 const void *root;
192 HRSRC result;
194 if (!resdirptr) return 0;
196 root = resdirptr;
197 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
198 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
200 /* 1. Exact specified language */
201 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
203 /* 2. Language with neutral sublanguage */
204 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
205 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
207 /* 3. Neutral language with neutral sublanguage */
208 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
209 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
211 /* 4. Neutral language with default sublanguage */
212 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
213 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
215 found:
216 return result;
219 /**********************************************************************
220 * PE_FindResourceW
222 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
223 * FindResourceA/W does search in the following order:
224 * 1. Neutral language with neutral sublanguage
225 * 2. Neutral language with default sublanguage
226 * 3. Current locale lang id
227 * 4. Current locale lang id with neutral sublanguage
228 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
229 * 6. Return first in the list
231 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
233 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
234 const void *root;
235 HRSRC result;
236 WORD lang;
238 if (!resdirptr) return 0;
240 root = resdirptr;
241 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
242 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
244 /* 1. Neutral language with neutral sublanguage */
245 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
246 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
248 /* 2. Neutral language with default sublanguage */
249 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
250 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
252 /* 3. Current locale lang id */
253 lang = LANGIDFROMLCID(GetUserDefaultLCID());
254 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
256 /* 4. Current locale lang id with neutral sublanguage */
257 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
258 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
260 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
261 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
262 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
264 /* 6. Return first in the list */
265 result = (HRSRC)find_entry_default( resdirptr, root );
267 found:
268 return result;
272 /**********************************************************************
273 * PE_LoadResource
275 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
277 const void *base = get_module_base( hmod );
278 if (!hRsrc) return 0;
279 return (HANDLE)((char *)base + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
283 /**********************************************************************
284 * PE_SizeofResource
286 DWORD PE_SizeofResource( HRSRC hRsrc )
288 if (!hRsrc) return 0;
289 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
293 /**********************************************************************
294 * EnumResourceTypesA (KERNEL32.@)
296 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
298 int i;
299 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
300 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
301 BOOL ret;
303 if (!resdir) return FALSE;
305 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
306 ret = FALSE;
307 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
308 LPSTR type;
310 if (et[i].u1.s1.NameIsString)
312 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
313 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
314 NULL, 0, NULL, NULL);
315 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
316 return FALSE;
317 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
318 type, len, NULL, NULL);
319 type[len] = '\0';
320 ret = lpfun(hmod,type,lparam);
321 HeapFree(GetProcessHeap(), 0, type);
323 else
325 type = (LPSTR)(int)et[i].u1.s2.Id;
326 ret = lpfun(hmod,type,lparam);
328 if (!ret)
329 break;
331 return ret;
335 /**********************************************************************
336 * EnumResourceTypesW (KERNEL32.@)
338 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
340 int i;
341 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
342 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
343 BOOL ret;
345 if (!resdir) return FALSE;
347 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
348 ret = FALSE;
349 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
350 LPWSTR type;
352 if (et[i].u1.s1.NameIsString)
354 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
355 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
356 return FALSE;
357 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
358 type[pResString->Length] = '\0';
359 ret = lpfun(hmod,type,lparam);
360 HeapFree(GetProcessHeap(), 0, type);
362 else
364 type = (LPWSTR)(int)et[i].u1.s2.Id;
365 ret = lpfun(hmod,type,lparam);
367 if (!ret)
368 break;
370 return ret;
374 /**********************************************************************
375 * EnumResourceNamesA (KERNEL32.@)
377 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
379 int i;
380 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
381 const IMAGE_RESOURCE_DIRECTORY *resdir;
382 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
383 BOOL ret;
385 if (!basedir) return FALSE;
387 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
389 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
390 ret = FALSE;
391 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
392 LPSTR name;
394 if (et[i].u1.s1.NameIsString)
396 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
397 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
398 NULL, 0, NULL, NULL);
399 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
400 return FALSE;
401 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
402 name, len, NULL, NULL );
403 name[len] = '\0';
404 ret = lpfun(hmod,type,name,lparam);
405 HeapFree( GetProcessHeap(), 0, name );
407 else
409 name = (LPSTR)(int)et[i].u1.s2.Id;
410 ret = lpfun(hmod,type,name,lparam);
412 if (!ret)
413 break;
415 return ret;
419 /**********************************************************************
420 * EnumResourceNamesW (KERNEL32.@)
422 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
424 int i;
425 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
426 const IMAGE_RESOURCE_DIRECTORY *resdir;
427 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
428 BOOL ret;
430 if (!basedir) return FALSE;
432 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
434 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
435 ret = FALSE;
436 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
437 LPWSTR name;
439 if (et[i].u1.s1.NameIsString)
441 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
442 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
443 return FALSE;
444 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
445 name[pResString->Length] = '\0';
446 ret = lpfun(hmod,type,name,lparam);
447 HeapFree(GetProcessHeap(), 0, name);
449 else
451 name = (LPWSTR)(int)et[i].u1.s2.Id;
452 ret = lpfun(hmod,type,name,lparam);
454 if (!ret)
455 break;
457 return ret;
461 /**********************************************************************
462 * EnumResourceLanguagesA (KERNEL32.@)
464 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
465 ENUMRESLANGPROCA lpfun, LONG lparam )
467 int i;
468 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
469 const IMAGE_RESOURCE_DIRECTORY *resdir;
470 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
471 BOOL ret;
473 if (!basedir) return FALSE;
474 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
475 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
477 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
478 ret = FALSE;
479 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
480 /* languages are just ids... I hope */
481 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
482 if (!ret)
483 break;
485 return ret;
489 /**********************************************************************
490 * EnumResourceLanguagesW (KERNEL32.@)
492 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
493 ENUMRESLANGPROCW lpfun, LONG lparam )
495 int i;
496 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
497 const IMAGE_RESOURCE_DIRECTORY *resdir;
498 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
499 BOOL ret;
501 if (!basedir) return FALSE;
503 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
504 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
506 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
507 ret = FALSE;
508 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
509 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
510 if (!ret)
511 break;
513 return ret;