Added one safety check to AFM parsing.
[wine/multimedia.git] / loader / pe_resource.c
blob41aefdd6639513ba8f22fb08a0e4efec0d101f5e
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 "task.h"
25 #include "stackframe.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(resource);
30 /**********************************************************************
31 * get_resdir
33 * Get the resource directory of a PE module
35 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
37 const IMAGE_DATA_DIRECTORY *dir;
38 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
40 if (!hmod) hmod = GetModuleHandleA( NULL );
41 else if (!HIWORD(hmod))
43 FIXME("Enumeration of 16-bit resources is not supported\n");
44 SetLastError(ERROR_INVALID_HANDLE);
45 return NULL;
47 dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
48 if (dir->Size && dir->VirtualAddress)
49 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress);
50 return ret;
54 /**********************************************************************
55 * find_entry_by_id
57 * Find an entry by id in a resource directory
59 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
60 WORD id, const void *root )
62 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
63 int min, max, pos;
65 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
66 min = dir->NumberOfNamedEntries;
67 max = min + dir->NumberOfIdEntries - 1;
68 while (min <= max)
70 pos = (min + max) / 2;
71 if (entry[pos].u1.s2.Id == id)
72 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
73 if (entry[pos].u1.s2.Id > id) max = pos - 1;
74 else min = pos + 1;
76 return NULL;
80 /**********************************************************************
81 * find_entry_by_nameW
83 * Find an entry by name in a resource directory
85 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
86 LPCWSTR name, const void *root )
88 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
89 const IMAGE_RESOURCE_DIR_STRING_U *str;
90 int min, max, res, pos, namelen;
92 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
93 if (name[0] == '#')
95 char buf[16];
96 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
97 return NULL;
98 return find_entry_by_id( dir, atoi(buf), root );
101 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
102 namelen = strlenW(name);
103 min = 0;
104 max = dir->NumberOfNamedEntries - 1;
105 while (min <= max)
107 pos = (min + max) / 2;
108 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
109 res = strncmpiW( name, str->NameString, str->Length );
110 if (!res && namelen == str->Length)
111 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
112 if (res < 0) max = pos - 1;
113 else min = pos + 1;
115 return NULL;
119 /**********************************************************************
120 * find_entry_by_nameA
122 * Find an entry by name in a resource directory
124 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
125 LPCSTR name, const void *root )
127 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
128 LPWSTR nameW;
130 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
131 if (name[0] == '#')
133 return find_entry_by_id( dir, atoi(name+1), root );
136 if ((nameW = HEAP_strdupAtoW( GetProcessHeap(), 0, name )))
138 ret = find_entry_by_nameW( dir, nameW, root );
139 HeapFree( GetProcessHeap(), 0, nameW );
141 return ret;
145 /**********************************************************************
146 * find_entry_default
148 * Find a default entry in a resource directory
150 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
151 const void *root )
153 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
155 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
156 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
160 /**********************************************************************
161 * PE_FindResourceExW
163 * FindResourceExA/W does search in the following order:
164 * 1. Exact specified language
165 * 2. Language with neutral sublanguage
166 * 3. Neutral language with neutral sublanguage
167 * 4. Neutral language with default sublanguage
169 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
171 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
172 const void *root;
173 HRSRC result;
175 if (!resdirptr) return 0;
177 root = resdirptr;
178 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
179 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
181 /* 1. Exact specified language */
182 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
184 /* 2. Language with neutral sublanguage */
185 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
186 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
188 /* 3. Neutral language with neutral sublanguage */
189 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
190 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
192 /* 4. Neutral language with default sublanguage */
193 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
194 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
196 found:
197 return result;
200 /**********************************************************************
201 * PE_FindResourceW
203 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
204 * FindResourceA/W does search in the following order:
205 * 1. Neutral language with neutral sublanguage
206 * 2. Neutral language with default sublanguage
207 * 3. Current locale lang id
208 * 4. Current locale lang id with neutral sublanguage
209 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
210 * 6. Return first in the list
212 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
214 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
215 const void *root;
216 HRSRC result;
217 WORD lang;
219 if (!resdirptr) return 0;
221 root = resdirptr;
222 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
223 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
225 /* 1. Neutral language with neutral sublanguage */
226 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
227 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
229 /* 2. Neutral language with default sublanguage */
230 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
231 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
233 /* 3. Current locale lang id */
234 lang = LANGIDFROMLCID(GetUserDefaultLCID());
235 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
237 /* 4. Current locale lang id with neutral sublanguage */
238 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
239 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
241 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
242 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
243 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
245 /* 6. Return first in the list */
246 result = (HRSRC)find_entry_default( resdirptr, root );
248 found:
249 return result;
253 /**********************************************************************
254 * PE_LoadResource
256 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
258 if (!hRsrc) return 0;
259 return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
263 /**********************************************************************
264 * PE_SizeofResource
266 DWORD PE_SizeofResource( HRSRC hRsrc )
268 if (!hRsrc) return 0;
269 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
273 /**********************************************************************
274 * EnumResourceTypesA (KERNEL32.90)
276 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
278 int i;
279 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
280 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
281 BOOL ret;
283 if (!resdir) return FALSE;
285 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
286 ret = FALSE;
287 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
288 LPSTR type;
290 if (et[i].u1.s1.NameIsString)
292 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
293 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
294 NULL, 0, NULL, NULL);
295 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
296 return FALSE;
297 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
298 type, len, NULL, NULL);
299 type[len] = '\0';
300 ret = lpfun(hmod,type,lparam);
301 HeapFree(GetProcessHeap(), 0, type);
303 else
305 type = (LPSTR)(int)et[i].u1.s2.Id;
306 ret = lpfun(hmod,type,lparam);
308 if (!ret)
309 break;
311 return ret;
315 /**********************************************************************
316 * EnumResourceTypesW (KERNEL32.91)
318 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
320 int i;
321 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
322 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
323 BOOL ret;
325 if (!resdir) return FALSE;
327 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
328 ret = FALSE;
329 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
330 LPWSTR type;
332 if (et[i].u1.s1.NameIsString)
334 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
335 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
336 return FALSE;
337 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
338 type[pResString->Length] = '\0';
339 ret = lpfun(hmod,type,lparam);
340 HeapFree(GetProcessHeap(), 0, type);
342 else
344 type = (LPWSTR)(int)et[i].u1.s2.Id;
345 ret = lpfun(hmod,type,lparam);
347 if (!ret)
348 break;
350 return ret;
354 /**********************************************************************
355 * EnumResourceNamesA (KERNEL32.88)
357 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
359 int i;
360 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
361 const IMAGE_RESOURCE_DIRECTORY *resdir;
362 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
363 BOOL ret;
365 if (!basedir) return FALSE;
367 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
369 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
370 ret = FALSE;
371 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
372 LPSTR name;
374 if (et[i].u1.s1.NameIsString)
376 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
377 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
378 NULL, 0, NULL, NULL);
379 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
380 return FALSE;
381 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
382 name, len, NULL, NULL );
383 name[len] = '\0';
384 ret = lpfun(hmod,type,name,lparam);
385 HeapFree( GetProcessHeap(), 0, name );
387 else
389 name = (LPSTR)(int)et[i].u1.s2.Id;
390 ret = lpfun(hmod,type,name,lparam);
392 if (!ret)
393 break;
395 return ret;
399 /**********************************************************************
400 * EnumResourceNamesW (KERNEL32.89)
402 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
404 int i;
405 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
406 const IMAGE_RESOURCE_DIRECTORY *resdir;
407 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
408 BOOL ret;
410 if (!basedir) return FALSE;
412 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
414 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
415 ret = FALSE;
416 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
417 LPWSTR name;
419 if (et[i].u1.s1.NameIsString)
421 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
422 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
423 return FALSE;
424 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
425 name[pResString->Length] = '\0';
426 ret = lpfun(hmod,type,name,lparam);
427 HeapFree(GetProcessHeap(), 0, name);
429 else
431 name = (LPWSTR)(int)et[i].u1.s2.Id;
432 ret = lpfun(hmod,type,name,lparam);
434 if (!ret)
435 break;
437 return ret;
441 /**********************************************************************
442 * EnumResourceLanguagesA (KERNEL32.86)
444 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
445 ENUMRESLANGPROCA lpfun, LONG lparam )
447 int i;
448 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
449 const IMAGE_RESOURCE_DIRECTORY *resdir;
450 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
451 BOOL ret;
453 if (!basedir) return FALSE;
454 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
455 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
457 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
458 ret = FALSE;
459 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
460 /* languages are just ids... I hope */
461 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
462 if (!ret)
463 break;
465 return ret;
469 /**********************************************************************
470 * EnumResourceLanguagesW (KERNEL32.87)
472 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
473 ENUMRESLANGPROCW lpfun, LONG lparam )
475 int i;
476 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
477 const IMAGE_RESOURCE_DIRECTORY *resdir;
478 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
479 BOOL ret;
481 if (!basedir) return FALSE;
483 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
484 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
486 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
487 ret = FALSE;
488 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
489 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
490 if (!ret)
491 break;
493 return ret;