Implemented _CheckNotSysLevel.
[wine/multimedia.git] / loader / pe_resource.c
blob31340f174e482c0d1000549d35eeb5612b4dbe4d
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>
16 #include "config.h"
18 #include "wine/unicode.h"
19 #include "windef.h"
20 #include "winnls.h"
21 #include "winerror.h"
22 #include "module.h"
23 #include "heap.h"
24 #include "stackframe.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(resource);
30 /**********************************************************************
31 * get_module_base
33 * Get the base address of a module
35 static const void *get_module_base( HMODULE hmod )
37 if (!hmod) hmod = GetModuleHandleA( NULL );
38 else if (!HIWORD(hmod))
40 FIXME("Enumeration of 16-bit resources is not supported\n");
41 SetLastError(ERROR_INVALID_HANDLE);
42 return NULL;
45 /* clear low order bit in case of LOAD_LIBRARY_AS_DATAFILE module */
46 return (void *)((ULONG_PTR)hmod & ~1);
50 /**********************************************************************
51 * get_resdir
53 * Get the resource directory of a PE module
55 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
57 const IMAGE_DATA_DIRECTORY *dir;
58 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
59 const void *base = get_module_base( hmod );
61 if (base)
63 dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
64 if (dir->Size && dir->VirtualAddress)
65 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)base + dir->VirtualAddress);
67 return ret;
71 /**********************************************************************
72 * find_entry_by_id
74 * Find an entry by id in a resource directory
76 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
77 WORD id, const void *root )
79 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
80 int min, max, pos;
82 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
83 min = dir->NumberOfNamedEntries;
84 max = min + dir->NumberOfIdEntries - 1;
85 while (min <= max)
87 pos = (min + max) / 2;
88 if (entry[pos].u1.s2.Id == id)
89 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
90 if (entry[pos].u1.s2.Id > id) max = pos - 1;
91 else min = pos + 1;
93 return NULL;
97 /**********************************************************************
98 * find_entry_by_nameW
100 * Find an entry by name in a resource directory
102 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
103 LPCWSTR name, const void *root )
105 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
106 const IMAGE_RESOURCE_DIR_STRING_U *str;
107 int min, max, res, pos, namelen;
109 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
110 if (name[0] == '#')
112 char buf[16];
113 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
114 return NULL;
115 return find_entry_by_id( dir, atoi(buf), root );
118 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
119 namelen = strlenW(name);
120 min = 0;
121 max = dir->NumberOfNamedEntries - 1;
122 while (min <= max)
124 pos = (min + max) / 2;
125 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
126 res = strncmpiW( name, str->NameString, str->Length );
127 if (!res && namelen == str->Length)
128 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
129 if (res < 0) max = pos - 1;
130 else min = pos + 1;
132 return NULL;
136 /**********************************************************************
137 * find_entry_by_nameA
139 * Find an entry by name in a resource directory
141 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
142 LPCSTR name, const void *root )
144 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
145 LPWSTR nameW;
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 if ((nameW = HEAP_strdupAtoW( GetProcessHeap(), 0, name )))
155 ret = find_entry_by_nameW( dir, nameW, root );
156 HeapFree( GetProcessHeap(), 0, nameW );
158 return ret;
162 /**********************************************************************
163 * find_entry_default
165 * Find a default entry in a resource directory
167 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
168 const void *root )
170 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
172 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
173 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
177 /**********************************************************************
178 * PE_FindResourceExW
180 * FindResourceExA/W does search in the following order:
181 * 1. Exact specified language
182 * 2. Language with neutral sublanguage
183 * 3. Neutral language with neutral sublanguage
184 * 4. Neutral language with default sublanguage
186 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
188 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
189 const void *root;
190 HRSRC result;
192 if (!resdirptr) return 0;
194 root = resdirptr;
195 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
196 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
198 /* 1. Exact specified language */
199 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
201 /* 2. Language with neutral sublanguage */
202 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
203 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
205 /* 3. Neutral language with neutral sublanguage */
206 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
207 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
209 /* 4. Neutral language with default sublanguage */
210 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
211 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
213 found:
214 return result;
217 /**********************************************************************
218 * PE_FindResourceW
220 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
221 * FindResourceA/W does search in the following order:
222 * 1. Neutral language with neutral sublanguage
223 * 2. Neutral language with default sublanguage
224 * 3. Current locale lang id
225 * 4. Current locale lang id with neutral sublanguage
226 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
227 * 6. Return first in the list
229 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
231 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
232 const void *root;
233 HRSRC result;
234 WORD lang;
236 if (!resdirptr) return 0;
238 root = resdirptr;
239 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
240 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
242 /* 1. Neutral language with neutral sublanguage */
243 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
244 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
246 /* 2. Neutral language with default sublanguage */
247 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
248 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
250 /* 3. Current locale lang id */
251 lang = LANGIDFROMLCID(GetUserDefaultLCID());
252 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
254 /* 4. Current locale lang id with neutral sublanguage */
255 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
256 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
258 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
259 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
260 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
262 /* 6. Return first in the list */
263 result = (HRSRC)find_entry_default( resdirptr, root );
265 found:
266 return result;
270 /**********************************************************************
271 * PE_LoadResource
273 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
275 const void *base = get_module_base( hmod );
276 if (!hRsrc) return 0;
277 return (HANDLE)((char *)base + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
281 /**********************************************************************
282 * PE_SizeofResource
284 DWORD PE_SizeofResource( HRSRC hRsrc )
286 if (!hRsrc) return 0;
287 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
291 /**********************************************************************
292 * EnumResourceTypesA (KERNEL32.@)
294 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
296 int i;
297 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
298 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
299 BOOL ret;
301 if (!resdir) return FALSE;
303 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
304 ret = FALSE;
305 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
306 LPSTR type;
308 if (et[i].u1.s1.NameIsString)
310 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
311 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
312 NULL, 0, NULL, NULL);
313 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
314 return FALSE;
315 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
316 type, len, NULL, NULL);
317 type[len] = '\0';
318 ret = lpfun(hmod,type,lparam);
319 HeapFree(GetProcessHeap(), 0, type);
321 else
323 type = (LPSTR)(int)et[i].u1.s2.Id;
324 ret = lpfun(hmod,type,lparam);
326 if (!ret)
327 break;
329 return ret;
333 /**********************************************************************
334 * EnumResourceTypesW (KERNEL32.@)
336 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
338 int i;
339 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
340 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
341 BOOL ret;
343 if (!resdir) return FALSE;
345 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
346 ret = FALSE;
347 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
348 LPWSTR type;
350 if (et[i].u1.s1.NameIsString)
352 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
353 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
354 return FALSE;
355 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
356 type[pResString->Length] = '\0';
357 ret = lpfun(hmod,type,lparam);
358 HeapFree(GetProcessHeap(), 0, type);
360 else
362 type = (LPWSTR)(int)et[i].u1.s2.Id;
363 ret = lpfun(hmod,type,lparam);
365 if (!ret)
366 break;
368 return ret;
372 /**********************************************************************
373 * EnumResourceNamesA (KERNEL32.@)
375 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
377 int i;
378 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
379 const IMAGE_RESOURCE_DIRECTORY *resdir;
380 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
381 BOOL ret;
383 if (!basedir) return FALSE;
385 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
387 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
388 ret = FALSE;
389 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
390 LPSTR name;
392 if (et[i].u1.s1.NameIsString)
394 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
395 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
396 NULL, 0, NULL, NULL);
397 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
398 return FALSE;
399 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
400 name, len, NULL, NULL );
401 name[len] = '\0';
402 ret = lpfun(hmod,type,name,lparam);
403 HeapFree( GetProcessHeap(), 0, name );
405 else
407 name = (LPSTR)(int)et[i].u1.s2.Id;
408 ret = lpfun(hmod,type,name,lparam);
410 if (!ret)
411 break;
413 return ret;
417 /**********************************************************************
418 * EnumResourceNamesW (KERNEL32.@)
420 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
422 int i;
423 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
424 const IMAGE_RESOURCE_DIRECTORY *resdir;
425 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
426 BOOL ret;
428 if (!basedir) return FALSE;
430 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
432 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
433 ret = FALSE;
434 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
435 LPWSTR name;
437 if (et[i].u1.s1.NameIsString)
439 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
440 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
441 return FALSE;
442 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
443 name[pResString->Length] = '\0';
444 ret = lpfun(hmod,type,name,lparam);
445 HeapFree(GetProcessHeap(), 0, name);
447 else
449 name = (LPWSTR)(int)et[i].u1.s2.Id;
450 ret = lpfun(hmod,type,name,lparam);
452 if (!ret)
453 break;
455 return ret;
459 /**********************************************************************
460 * EnumResourceLanguagesA (KERNEL32.@)
462 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
463 ENUMRESLANGPROCA lpfun, LONG lparam )
465 int i;
466 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
467 const IMAGE_RESOURCE_DIRECTORY *resdir;
468 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
469 BOOL ret;
471 if (!basedir) return FALSE;
472 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
473 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
475 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
476 ret = FALSE;
477 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
478 /* languages are just ids... I hope */
479 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
480 if (!ret)
481 break;
483 return ret;
487 /**********************************************************************
488 * EnumResourceLanguagesW (KERNEL32.@)
490 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
491 ENUMRESLANGPROCW lpfun, LONG lparam )
493 int i;
494 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
495 const IMAGE_RESOURCE_DIRECTORY *resdir;
496 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
497 BOOL ret;
499 if (!basedir) return FALSE;
501 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
502 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
504 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
505 ret = FALSE;
506 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
507 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
508 if (!ret)
509 break;
511 return ret;