Use the locale id we created instead of the system or user default,
[wine/gsoc_dplay.git] / loader / pe_resource.c
bloba50ff04dbe00ce9d4b9d92c05ed64fd7bf3844ab
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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "config.h"
29 #include <stdlib.h>
30 #include <sys/types.h>
32 #include "wine/unicode.h"
33 #include "windef.h"
34 #include "winnls.h"
35 #include "winternl.h"
36 #include "winerror.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(resource);
42 /**********************************************************************
43 * is_data_file_module
45 * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
47 inline static int is_data_file_module( HMODULE hmod )
49 return (ULONG_PTR)hmod & 1;
53 /**********************************************************************
54 * get_resdir
56 * Get the resource directory of a PE module
58 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
60 DWORD size;
62 if (!hmod) hmod = GetModuleHandleA( NULL );
63 else if (!HIWORD(hmod))
65 FIXME("Enumeration of 16-bit resources is not supported\n");
66 SetLastError(ERROR_INVALID_HANDLE);
67 return NULL;
69 return RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
73 /**********************************************************************
74 * find_entry_by_id
76 * Find an entry by id in a resource directory
78 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
79 WORD id, const void *root )
81 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
82 int min, max, pos;
84 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
85 min = dir->NumberOfNamedEntries;
86 max = min + dir->NumberOfIdEntries - 1;
87 while (min <= max)
89 pos = (min + max) / 2;
90 if (entry[pos].u1.s2.Id == id)
91 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
92 if (entry[pos].u1.s2.Id > id) max = pos - 1;
93 else min = pos + 1;
95 return NULL;
99 /**********************************************************************
100 * find_entry_by_nameW
102 * Find an entry by name in a resource directory
104 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
105 LPCWSTR name, const void *root )
107 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
108 const IMAGE_RESOURCE_DIR_STRING_U *str;
109 int min, max, res, pos, namelen;
111 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
112 if (name[0] == '#')
114 char buf[16];
115 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
116 return NULL;
117 return find_entry_by_id( dir, atoi(buf), root );
120 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
121 namelen = strlenW(name);
122 min = 0;
123 max = dir->NumberOfNamedEntries - 1;
124 while (min <= max)
126 pos = (min + max) / 2;
127 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
128 res = strncmpiW( name, str->NameString, str->Length );
129 if (!res && namelen == str->Length)
130 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
131 if (res < 0) max = pos - 1;
132 else min = pos + 1;
134 return NULL;
138 /**********************************************************************
139 * find_entry_by_nameA
141 * Find an entry by name in a resource directory
143 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
144 LPCSTR name, const void *root )
146 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
147 LPWSTR nameW;
148 INT len;
150 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
151 if (name[0] == '#')
153 return find_entry_by_id( dir, atoi(name+1), root );
156 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
157 if ((nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
159 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
160 ret = find_entry_by_nameW( dir, nameW, root );
161 HeapFree( GetProcessHeap(), 0, nameW );
163 return ret;
167 /**********************************************************************
168 * find_entry_default
170 * Find a default entry in a resource directory
172 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
173 const void *root )
175 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
177 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
178 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
182 /**********************************************************************
183 * PE_FindResourceExW
185 * FindResourceExA/W does search in the following order:
186 * 1. Exact specified language
187 * 2. Language with neutral sublanguage
188 * 3. Neutral language with neutral sublanguage
189 * 4. Neutral language with default sublanguage
191 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
193 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
194 const void *root;
195 HRSRC result;
197 if (!resdirptr) return 0;
199 root = resdirptr;
200 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
201 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
203 /* 1. Exact specified language */
204 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
206 /* 2. Language with neutral sublanguage */
207 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
208 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
210 /* 3. Neutral language with neutral sublanguage */
211 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
212 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
214 /* 4. Neutral language with default sublanguage */
215 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
216 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
218 found:
219 return result;
222 /**********************************************************************
223 * PE_FindResourceW
225 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
226 * FindResourceA/W does search in the following order:
227 * 1. Neutral language with neutral sublanguage
228 * 2. Neutral language with default sublanguage
229 * 3. Current locale lang id
230 * 4. Current locale lang id with neutral sublanguage
231 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
232 * 6. Return first in the list
234 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
236 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
237 const void *root;
238 HRSRC result;
239 WORD lang;
241 if (!resdirptr) return 0;
243 root = resdirptr;
244 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
245 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
247 /* 1. Neutral language with neutral sublanguage */
248 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
249 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
251 /* 2. Neutral language with default sublanguage */
252 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
253 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
255 /* 3. Current locale lang id */
256 lang = LANGIDFROMLCID(GetUserDefaultLCID());
257 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
259 /* 4. Current locale lang id with neutral sublanguage */
260 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
261 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
263 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
264 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
265 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
267 /* 6. Return first in the list */
268 result = (HRSRC)find_entry_default( resdirptr, root );
270 found:
271 return result;
275 /**********************************************************************
276 * PE_LoadResource
278 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
280 DWORD offset;
282 if (!hRsrc) return 0;
283 if (!hmod) hmod = GetModuleHandleA( NULL );
285 offset = ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData;
287 if (is_data_file_module(hmod))
289 hmod = (HMODULE)((ULONG_PTR)hmod & ~1);
290 return (HGLOBAL)RtlImageRvaToVa( RtlImageNtHeader(hmod), hmod, offset, NULL );
292 else
293 return (HGLOBAL)((char *)hmod + offset);
297 /**********************************************************************
298 * PE_SizeofResource
300 DWORD PE_SizeofResource( HRSRC hRsrc )
302 if (!hRsrc) return 0;
303 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
307 /**********************************************************************
308 * EnumResourceTypesA (KERNEL32.@)
310 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
312 int i;
313 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
314 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
315 BOOL ret;
317 if (!resdir) return FALSE;
319 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
320 ret = FALSE;
321 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
322 LPSTR type;
324 if (et[i].u1.s1.NameIsString)
326 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
327 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
328 NULL, 0, NULL, NULL);
329 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
330 return FALSE;
331 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
332 type, len, NULL, NULL);
333 type[len] = '\0';
334 ret = lpfun(hmod,type,lparam);
335 HeapFree(GetProcessHeap(), 0, type);
337 else
339 type = (LPSTR)(int)et[i].u1.s2.Id;
340 ret = lpfun(hmod,type,lparam);
342 if (!ret)
343 break;
345 return ret;
349 /**********************************************************************
350 * EnumResourceTypesW (KERNEL32.@)
352 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
354 int i;
355 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
356 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
357 BOOL ret;
359 if (!resdir) return FALSE;
361 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
362 ret = FALSE;
363 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
364 LPWSTR type;
366 if (et[i].u1.s1.NameIsString)
368 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
369 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
370 return FALSE;
371 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
372 type[pResString->Length] = '\0';
373 ret = lpfun(hmod,type,lparam);
374 HeapFree(GetProcessHeap(), 0, type);
376 else
378 type = (LPWSTR)(int)et[i].u1.s2.Id;
379 ret = lpfun(hmod,type,lparam);
381 if (!ret)
382 break;
384 return ret;
388 /**********************************************************************
389 * EnumResourceNamesA (KERNEL32.@)
391 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
393 int i;
394 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
395 const IMAGE_RESOURCE_DIRECTORY *resdir;
396 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
397 BOOL ret;
399 if (!basedir) return FALSE;
401 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
403 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
404 ret = FALSE;
405 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
406 LPSTR name;
408 if (et[i].u1.s1.NameIsString)
410 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
411 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
412 NULL, 0, NULL, NULL);
413 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
414 return FALSE;
415 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
416 name, len, NULL, NULL );
417 name[len] = '\0';
418 ret = lpfun(hmod,type,name,lparam);
419 HeapFree( GetProcessHeap(), 0, name );
421 else
423 name = (LPSTR)(int)et[i].u1.s2.Id;
424 ret = lpfun(hmod,type,name,lparam);
426 if (!ret)
427 break;
429 return ret;
433 /**********************************************************************
434 * EnumResourceNamesW (KERNEL32.@)
436 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
438 int i;
439 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
440 const IMAGE_RESOURCE_DIRECTORY *resdir;
441 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
442 BOOL ret;
444 if (!basedir) return FALSE;
446 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
448 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
449 ret = FALSE;
450 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
451 LPWSTR name;
453 if (et[i].u1.s1.NameIsString)
455 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
456 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
457 return FALSE;
458 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
459 name[pResString->Length] = '\0';
460 ret = lpfun(hmod,type,name,lparam);
461 HeapFree(GetProcessHeap(), 0, name);
463 else
465 name = (LPWSTR)(int)et[i].u1.s2.Id;
466 ret = lpfun(hmod,type,name,lparam);
468 if (!ret)
469 break;
471 return ret;
475 /**********************************************************************
476 * EnumResourceLanguagesA (KERNEL32.@)
478 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
479 ENUMRESLANGPROCA lpfun, LONG lparam )
481 int i;
482 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
483 const IMAGE_RESOURCE_DIRECTORY *resdir;
484 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
485 BOOL ret;
487 if (!basedir) return FALSE;
488 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
489 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
491 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
492 ret = FALSE;
493 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
494 /* languages are just ids... I hope */
495 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
496 if (!ret)
497 break;
499 return ret;
503 /**********************************************************************
504 * EnumResourceLanguagesW (KERNEL32.@)
506 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
507 ENUMRESLANGPROCW lpfun, LONG lparam )
509 int i;
510 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
511 const IMAGE_RESOURCE_DIRECTORY *resdir;
512 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
513 BOOL ret;
515 if (!basedir) return FALSE;
517 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
518 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
520 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
521 ret = FALSE;
522 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
523 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
524 if (!ret)
525 break;
527 return ret;