16-bit resource size must be scaled by alignment.
[wine/multimedia.git] / loader / pe_resource.c
blob50fd714f7c0f00efd5c63f11ea345437c1097afc
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 "wine/winestring.h"
17 #include "wine/unicode.h"
18 #include "windef.h"
19 #include "winnls.h"
20 #include "winerror.h"
21 #include "module.h"
22 #include "heap.h"
23 #include "task.h"
24 #include "process.h"
25 #include "stackframe.h"
26 #include "neexe.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(resource);
31 /**********************************************************************
32 * get_resdir
34 * Get the resource directory of a PE module
36 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
38 const IMAGE_DATA_DIRECTORY *dir;
39 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
41 if (!hmod) hmod = GetModuleHandleA( NULL );
42 else if (!HIWORD(hmod))
44 FIXME("Enumeration of 16-bit resources is not supported\n");
45 SetLastError(ERROR_INVALID_HANDLE);
46 return NULL;
48 dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
49 if (dir->Size && dir->VirtualAddress)
50 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress);
51 return ret;
55 /**********************************************************************
56 * find_entry_by_id
58 * Find an entry by id in a resource directory
60 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
61 WORD id, const void *root )
63 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
64 int min, max, pos;
66 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
67 min = dir->NumberOfNamedEntries;
68 max = min + dir->NumberOfIdEntries - 1;
69 while (min <= max)
71 pos = (min + max) / 2;
72 if (entry[pos].u1.Id == id)
73 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s.OffsetToDirectory);
74 if (entry[pos].u1.Id > id) max = pos - 1;
75 else min = pos + 1;
77 return NULL;
81 /**********************************************************************
82 * find_entry_by_nameW
84 * Find an entry by name in a resource directory
86 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
87 LPCWSTR name, const void *root )
89 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
90 const IMAGE_RESOURCE_DIR_STRING_U *str;
91 int min, max, res, pos, namelen;
93 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
94 if (name[0] == '#')
96 char buf[16];
97 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
98 return NULL;
99 return find_entry_by_id( dir, atoi(buf), root );
102 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
103 namelen = strlenW(name);
104 min = 0;
105 max = dir->NumberOfNamedEntries - 1;
106 while (min <= max)
108 pos = (min + max) / 2;
109 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s.NameOffset);
110 res = strncmpiW( name, str->NameString, str->Length );
111 if (!res && namelen == str->Length)
112 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s.OffsetToDirectory);
113 if (res < 0) max = pos - 1;
114 else min = pos + 1;
116 return NULL;
120 /**********************************************************************
121 * find_entry_by_nameA
123 * Find an entry by name in a resource directory
125 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
126 LPCSTR name, const void *root )
128 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
129 LPWSTR nameW;
131 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
132 if (name[0] == '#')
134 return find_entry_by_id( dir, atoi(name+1), root );
137 if ((nameW = HEAP_strdupAtoW( GetProcessHeap(), 0, name )))
139 ret = find_entry_by_nameW( dir, nameW, root );
140 HeapFree( GetProcessHeap(), 0, nameW );
142 return ret;
146 /**********************************************************************
147 * find_entry_default
149 * Find a default entry in a resource directory
151 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
152 const void *root )
154 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
156 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
157 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s.OffsetToDirectory);
161 /**********************************************************************
162 * PE_FindResourceExW
164 * FindResourceExA/W does search in the following order:
165 * 1. Exact specified language
166 * 2. Language with neutral sublanguage
167 * 3. Neutral language with neutral sublanguage
168 * 4. Neutral language with default sublanguage
170 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
172 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
173 const void *root;
174 HRSRC result;
176 if (!resdirptr) return 0;
178 root = resdirptr;
179 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
180 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
182 /* 1. Exact specified language */
183 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
185 /* 2. Language with neutral sublanguage */
186 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
187 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
189 /* 3. Neutral language with neutral sublanguage */
190 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
191 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
193 /* 4. Neutral language with default sublanguage */
194 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
195 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
197 found:
198 return result;
201 /**********************************************************************
202 * PE_FindResourceW
204 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
205 * FindResourceA/W does search in the following order:
206 * 1. Neutral language with neutral sublanguage
207 * 2. Neutral language with default sublanguage
208 * 3. Current locale lang id
209 * 4. Current locale lang id with neutral sublanguage
210 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
211 * 6. Return first in the list
213 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
215 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
216 const void *root;
217 HRSRC result;
218 WORD lang;
220 if (!resdirptr) return 0;
222 root = resdirptr;
223 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
224 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
226 /* 1. Neutral language with neutral sublanguage */
227 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
228 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
230 /* 2. Neutral language with default sublanguage */
231 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
232 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
234 /* 3. Current locale lang id */
235 lang = LANGIDFROMLCID(GetUserDefaultLCID());
236 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
238 /* 4. Current locale lang id with neutral sublanguage */
239 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
240 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
242 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
243 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
244 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
246 /* 6. Return first in the list */
247 result = (HRSRC)find_entry_default( resdirptr, root );
249 found:
250 return result;
254 /**********************************************************************
255 * PE_LoadResource
257 HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc )
259 if (!hRsrc) return 0;
260 return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
264 /**********************************************************************
265 * PE_SizeofResource
267 DWORD PE_SizeofResource( HANDLE hRsrc )
269 if (!hRsrc) return 0;
270 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
274 /**********************************************************************
275 * EnumResourceTypesA (KERNEL32.90)
277 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
279 int i;
280 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
281 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
282 BOOL ret;
284 if (!resdir) return FALSE;
286 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
287 ret = FALSE;
288 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
289 LPSTR type;
291 if (et[i].u1.s.NameIsString)
293 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s.NameOffset);
294 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
295 NULL, 0, NULL, NULL);
296 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
297 return FALSE;
298 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
299 type, len, NULL, NULL);
300 type[len] = '\0';
301 ret = lpfun(hmod,type,lparam);
302 HeapFree(GetProcessHeap(), 0, type);
304 else
306 type = (LPSTR)(int)et[i].u1.Id;
307 ret = lpfun(hmod,type,lparam);
309 if (!ret)
310 break;
312 return ret;
316 /**********************************************************************
317 * EnumResourceTypesW (KERNEL32.91)
319 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
321 int i;
322 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
323 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
324 BOOL ret;
326 if (!resdir) return FALSE;
328 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
329 ret = FALSE;
330 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
331 LPWSTR type;
333 if (et[i].u1.s.NameIsString)
335 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s.NameOffset);
336 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
337 return FALSE;
338 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
339 type[pResString->Length] = '\0';
340 ret = lpfun(hmod,type,lparam);
341 HeapFree(GetProcessHeap(), 0, type);
343 else
345 type = (LPWSTR)(int)et[i].u1.Id;
346 ret = lpfun(hmod,type,lparam);
348 if (!ret)
349 break;
351 return ret;
355 /**********************************************************************
356 * EnumResourceNamesA (KERNEL32.88)
358 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
360 int i;
361 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
362 const IMAGE_RESOURCE_DIRECTORY *resdir;
363 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
364 BOOL ret;
366 if (!basedir) return FALSE;
368 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
370 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
371 ret = FALSE;
372 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
373 LPSTR name;
375 if (et[i].u1.s.NameIsString)
377 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s.NameOffset);
378 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
379 NULL, 0, NULL, NULL);
380 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
381 return FALSE;
382 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
383 name, len, NULL, NULL );
384 name[len] = '\0';
385 ret = lpfun(hmod,type,name,lparam);
386 HeapFree( GetProcessHeap(), 0, name );
388 else
390 name = (LPSTR)(int)et[i].u1.Id;
391 ret = lpfun(hmod,type,name,lparam);
393 if (!ret)
394 break;
396 return ret;
400 /**********************************************************************
401 * EnumResourceNamesW (KERNEL32.89)
403 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
405 int i;
406 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
407 const IMAGE_RESOURCE_DIRECTORY *resdir;
408 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
409 BOOL ret;
411 if (!basedir) return FALSE;
413 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
415 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
416 ret = FALSE;
417 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
418 LPWSTR name;
420 if (et[i].u1.s.NameIsString)
422 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s.NameOffset);
423 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
424 return FALSE;
425 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
426 name[pResString->Length] = '\0';
427 ret = lpfun(hmod,type,name,lparam);
428 HeapFree(GetProcessHeap(), 0, name);
430 else
432 name = (LPWSTR)(int)et[i].u1.Id;
433 ret = lpfun(hmod,type,name,lparam);
435 if (!ret)
436 break;
438 return ret;
442 /**********************************************************************
443 * EnumResourceLanguagesA (KERNEL32.86)
445 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
446 ENUMRESLANGPROCA lpfun, LONG lparam )
448 int i;
449 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
450 const IMAGE_RESOURCE_DIRECTORY *resdir;
451 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
452 BOOL ret;
454 if (!basedir) return FALSE;
455 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
456 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
458 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
459 ret = FALSE;
460 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
461 /* languages are just ids... I hope */
462 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
463 if (!ret)
464 break;
466 return ret;
470 /**********************************************************************
471 * EnumResourceLanguagesW (KERNEL32.87)
473 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
474 ENUMRESLANGPROCW lpfun, LONG lparam )
476 int i;
477 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
478 const IMAGE_RESOURCE_DIRECTORY *resdir;
479 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
480 BOOL ret;
482 if (!basedir) return FALSE;
484 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
485 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
487 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
488 ret = FALSE;
489 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
490 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
491 if (!ret)
492 break;
494 return ret;