Added Korean resources.
[wine.git] / loader / pe_resource.c
blob0f06b621371612fbb6580f1f8eb0bb12de3134e4
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 "winerror.h"
36 #include "module.h"
37 #include "stackframe.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(resource);
43 /**********************************************************************
44 * get_module_base
46 * Get the base address of a module
48 static const void *get_module_base( HMODULE hmod )
50 if (!hmod) hmod = GetModuleHandleA( NULL );
51 else if (!HIWORD(hmod))
53 FIXME("Enumeration of 16-bit resources is not supported\n");
54 SetLastError(ERROR_INVALID_HANDLE);
55 return NULL;
58 /* clear low order bit in case of LOAD_LIBRARY_AS_DATAFILE module */
59 return (void *)((ULONG_PTR)hmod & ~1);
63 /**********************************************************************
64 * is_data_file_module
66 * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
68 inline static int is_data_file_module( HMODULE hmod )
70 return (ULONG_PTR)hmod & 1;
74 /**********************************************************************
75 * get_data_file_ptr
77 * Get a pointer to a given offset in a file mapped as data file.
79 static const void *get_data_file_ptr( const void *base, DWORD offset )
81 const IMAGE_NT_HEADERS *nt = PE_HEADER(base);
82 const IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader +
83 nt->FileHeader.SizeOfOptionalHeader);
84 int i;
86 /* find the section containing the virtual address */
87 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
89 if ((sec->VirtualAddress <= offset) && (sec->VirtualAddress + sec->SizeOfRawData > offset))
90 return (char *)base + sec->PointerToRawData + (offset - sec->VirtualAddress);
92 return NULL;
96 /**********************************************************************
97 * get_resdir
99 * Get the resource directory of a PE module
101 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
103 const IMAGE_DATA_DIRECTORY *dir;
104 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
105 const void *base = get_module_base( hmod );
107 if (base)
109 dir = &PE_HEADER(base)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
110 if (dir->Size && dir->VirtualAddress)
112 if (is_data_file_module(hmod)) ret = get_data_file_ptr( base, dir->VirtualAddress );
113 else ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)base + dir->VirtualAddress);
116 return ret;
120 /**********************************************************************
121 * find_entry_by_id
123 * Find an entry by id in a resource directory
125 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
126 WORD id, const void *root )
128 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
129 int min, max, pos;
131 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
132 min = dir->NumberOfNamedEntries;
133 max = min + dir->NumberOfIdEntries - 1;
134 while (min <= max)
136 pos = (min + max) / 2;
137 if (entry[pos].u1.s2.Id == id)
138 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
139 if (entry[pos].u1.s2.Id > id) max = pos - 1;
140 else min = pos + 1;
142 return NULL;
146 /**********************************************************************
147 * find_entry_by_nameW
149 * Find an entry by name in a resource directory
151 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
152 LPCWSTR name, const void *root )
154 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
155 const IMAGE_RESOURCE_DIR_STRING_U *str;
156 int min, max, res, pos, namelen;
158 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
159 if (name[0] == '#')
161 char buf[16];
162 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
163 return NULL;
164 return find_entry_by_id( dir, atoi(buf), root );
167 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
168 namelen = strlenW(name);
169 min = 0;
170 max = dir->NumberOfNamedEntries - 1;
171 while (min <= max)
173 pos = (min + max) / 2;
174 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
175 res = strncmpiW( name, str->NameString, str->Length );
176 if (!res && namelen == str->Length)
177 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
178 if (res < 0) max = pos - 1;
179 else min = pos + 1;
181 return NULL;
185 /**********************************************************************
186 * find_entry_by_nameA
188 * Find an entry by name in a resource directory
190 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
191 LPCSTR name, const void *root )
193 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
194 LPWSTR nameW;
195 INT len;
197 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
198 if (name[0] == '#')
200 return find_entry_by_id( dir, atoi(name+1), root );
203 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
204 if ((nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
206 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
207 ret = find_entry_by_nameW( dir, nameW, root );
208 HeapFree( GetProcessHeap(), 0, nameW );
210 return ret;
214 /**********************************************************************
215 * find_entry_default
217 * Find a default entry in a resource directory
219 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
220 const void *root )
222 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
224 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
225 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
229 /**********************************************************************
230 * PE_FindResourceExW
232 * FindResourceExA/W does search in the following order:
233 * 1. Exact specified language
234 * 2. Language with neutral sublanguage
235 * 3. Neutral language with neutral sublanguage
236 * 4. Neutral language with default sublanguage
238 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
240 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
241 const void *root;
242 HRSRC result;
244 if (!resdirptr) return 0;
246 root = resdirptr;
247 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
248 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
250 /* 1. Exact specified language */
251 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
253 /* 2. Language with neutral sublanguage */
254 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
255 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
257 /* 3. Neutral language with neutral sublanguage */
258 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
259 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
261 /* 4. Neutral language with default sublanguage */
262 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
263 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
265 found:
266 return result;
269 /**********************************************************************
270 * PE_FindResourceW
272 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
273 * FindResourceA/W does search in the following order:
274 * 1. Neutral language with neutral sublanguage
275 * 2. Neutral language with default sublanguage
276 * 3. Current locale lang id
277 * 4. Current locale lang id with neutral sublanguage
278 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
279 * 6. Return first in the list
281 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
283 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
284 const void *root;
285 HRSRC result;
286 WORD lang;
288 if (!resdirptr) return 0;
290 root = resdirptr;
291 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
292 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
294 /* 1. Neutral language with neutral sublanguage */
295 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
296 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
298 /* 2. Neutral language with default sublanguage */
299 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
300 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
302 /* 3. Current locale lang id */
303 lang = LANGIDFROMLCID(GetUserDefaultLCID());
304 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
306 /* 4. Current locale lang id with neutral sublanguage */
307 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
308 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
310 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
311 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
312 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
314 /* 6. Return first in the list */
315 result = (HRSRC)find_entry_default( resdirptr, root );
317 found:
318 return result;
322 /**********************************************************************
323 * PE_LoadResource
325 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
327 DWORD offset;
328 const void *base = get_module_base( hmod );
330 if (!hRsrc || !base) return 0;
332 offset = ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData;
334 if (is_data_file_module(hmod))
335 return (HANDLE)get_data_file_ptr( base, offset );
336 else
337 return (HANDLE)((char *)base + offset);
341 /**********************************************************************
342 * PE_SizeofResource
344 DWORD PE_SizeofResource( HRSRC hRsrc )
346 if (!hRsrc) return 0;
347 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
351 /**********************************************************************
352 * EnumResourceTypesA (KERNEL32.@)
354 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
356 int i;
357 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
358 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
359 BOOL ret;
361 if (!resdir) return FALSE;
363 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
364 ret = FALSE;
365 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
366 LPSTR type;
368 if (et[i].u1.s1.NameIsString)
370 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
371 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
372 NULL, 0, NULL, NULL);
373 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
374 return FALSE;
375 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
376 type, len, NULL, NULL);
377 type[len] = '\0';
378 ret = lpfun(hmod,type,lparam);
379 HeapFree(GetProcessHeap(), 0, type);
381 else
383 type = (LPSTR)(int)et[i].u1.s2.Id;
384 ret = lpfun(hmod,type,lparam);
386 if (!ret)
387 break;
389 return ret;
393 /**********************************************************************
394 * EnumResourceTypesW (KERNEL32.@)
396 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
398 int i;
399 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
400 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
401 BOOL ret;
403 if (!resdir) return FALSE;
405 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
406 ret = FALSE;
407 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
408 LPWSTR type;
410 if (et[i].u1.s1.NameIsString)
412 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
413 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
414 return FALSE;
415 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
416 type[pResString->Length] = '\0';
417 ret = lpfun(hmod,type,lparam);
418 HeapFree(GetProcessHeap(), 0, type);
420 else
422 type = (LPWSTR)(int)et[i].u1.s2.Id;
423 ret = lpfun(hmod,type,lparam);
425 if (!ret)
426 break;
428 return ret;
432 /**********************************************************************
433 * EnumResourceNamesA (KERNEL32.@)
435 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
437 int i;
438 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
439 const IMAGE_RESOURCE_DIRECTORY *resdir;
440 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
441 BOOL ret;
443 if (!basedir) return FALSE;
445 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
447 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
448 ret = FALSE;
449 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
450 LPSTR name;
452 if (et[i].u1.s1.NameIsString)
454 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
455 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
456 NULL, 0, NULL, NULL);
457 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
458 return FALSE;
459 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
460 name, len, NULL, NULL );
461 name[len] = '\0';
462 ret = lpfun(hmod,type,name,lparam);
463 HeapFree( GetProcessHeap(), 0, name );
465 else
467 name = (LPSTR)(int)et[i].u1.s2.Id;
468 ret = lpfun(hmod,type,name,lparam);
470 if (!ret)
471 break;
473 return ret;
477 /**********************************************************************
478 * EnumResourceNamesW (KERNEL32.@)
480 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
482 int i;
483 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
484 const IMAGE_RESOURCE_DIRECTORY *resdir;
485 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
486 BOOL ret;
488 if (!basedir) return FALSE;
490 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
492 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
493 ret = FALSE;
494 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
495 LPWSTR name;
497 if (et[i].u1.s1.NameIsString)
499 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
500 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
501 return FALSE;
502 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
503 name[pResString->Length] = '\0';
504 ret = lpfun(hmod,type,name,lparam);
505 HeapFree(GetProcessHeap(), 0, name);
507 else
509 name = (LPWSTR)(int)et[i].u1.s2.Id;
510 ret = lpfun(hmod,type,name,lparam);
512 if (!ret)
513 break;
515 return ret;
519 /**********************************************************************
520 * EnumResourceLanguagesA (KERNEL32.@)
522 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
523 ENUMRESLANGPROCA lpfun, LONG lparam )
525 int i;
526 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
527 const IMAGE_RESOURCE_DIRECTORY *resdir;
528 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
529 BOOL ret;
531 if (!basedir) return FALSE;
532 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
533 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
535 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
536 ret = FALSE;
537 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
538 /* languages are just ids... I hope */
539 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
540 if (!ret)
541 break;
543 return ret;
547 /**********************************************************************
548 * EnumResourceLanguagesW (KERNEL32.@)
550 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
551 ENUMRESLANGPROCW lpfun, LONG lparam )
553 int i;
554 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
555 const IMAGE_RESOURCE_DIRECTORY *resdir;
556 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
557 BOOL ret;
559 if (!basedir) return FALSE;
561 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
562 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
564 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
565 ret = FALSE;
566 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
567 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
568 if (!ret)
569 break;
571 return ret;