The provider functions are WINAPI.
[wine] / loader / pe_resource.c
1 /*
2  * PE (Portable Execute) File Resources
3  *
4  * Copyright 1995 Thomas Sandford
5  * Copyright 1996 Martin von Loewis
6  *
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
11  *
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.
16  *
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.
21  *
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
25  */
26
27 #include "config.h"
28
29 #include <stdlib.h>
30 #include <sys/types.h>
31
32 #include "wine/unicode.h"
33 #include "windef.h"
34 #include "winnls.h"
35 #include "ntddk.h"
36 #include "winerror.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(resource);
40
41
42 /**********************************************************************
43  *  is_data_file_module
44  *
45  * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
46  */
47 inline static int is_data_file_module( HMODULE hmod )
48 {
49     return (ULONG_PTR)hmod & 1;
50 }
51
52
53 /**********************************************************************
54  *  get_resdir
55  *
56  * Get the resource directory of a PE module
57  */
58 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
59 {
60     DWORD size;
61
62     if (!hmod) hmod = GetModuleHandleA( NULL );
63     else if (!HIWORD(hmod))
64     {
65         FIXME("Enumeration of 16-bit resources is not supported\n");
66         SetLastError(ERROR_INVALID_HANDLE);
67         return NULL;
68     }
69     return RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
70 }
71
72
73 /**********************************************************************
74  *  find_entry_by_id
75  *
76  * Find an entry by id in a resource directory
77  */
78 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
79                                                          WORD id, const void *root )
80 {
81     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
82     int min, max, pos;
83
84     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
85     min = dir->NumberOfNamedEntries;
86     max = min + dir->NumberOfIdEntries - 1;
87     while (min <= max)
88     {
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;
94     }
95     return NULL;
96 }
97
98
99 /**********************************************************************
100  *  find_entry_by_nameW
101  *
102  * Find an entry by name in a resource directory
103  */
104 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
105                                                             LPCWSTR name, const void *root )
106 {
107     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
108     const IMAGE_RESOURCE_DIR_STRING_U *str;
109     int min, max, res, pos, namelen;
110
111     if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
112     if (name[0] == '#')
113     {
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 );
118     }
119
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)
125     {
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;
133     }
134     return NULL;
135 }
136
137
138 /**********************************************************************
139  *  find_entry_by_nameA
140  *
141  * Find an entry by name in a resource directory
142  */
143 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
144                                                             LPCSTR name, const void *root )
145 {
146     const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
147     LPWSTR nameW;
148     INT len;
149
150     if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
151     if (name[0] == '#')
152     {
153         return find_entry_by_id( dir, atoi(name+1), root );
154     }
155
156     len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
157     if ((nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
158     {
159         MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
160         ret = find_entry_by_nameW( dir, nameW, root );
161         HeapFree( GetProcessHeap(), 0, nameW );
162     }
163     return ret;
164 }
165
166
167 /**********************************************************************
168  *  find_entry_default
169  *
170  * Find a default entry in a resource directory
171  */
172 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
173                                                            const void *root )
174 {
175     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
176
177     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
178     return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
179 }
180
181
182 /**********************************************************************
183  *          PE_FindResourceExW
184  *
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
190  */
191 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
192 {
193     const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
194     const void *root;
195     HRSRC result;
196
197     if (!resdirptr) return 0;
198
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;
202
203     /* 1. Exact specified language */
204     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
205
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;
209
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;
213
214     /* 4. Neutral language with default sublanguage */
215     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
216     result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
217
218  found:
219     return result;
220 }
221
222 /**********************************************************************
223  *          PE_FindResourceW
224  *
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
233  */
234 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
235 {
236     const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
237     const void *root;
238     HRSRC result;
239     WORD lang;
240
241     if (!resdirptr) return 0;
242
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;
246
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;
250
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;
254
255     /* 3. Current locale lang id */
256     lang = LANGIDFROMLCID(GetUserDefaultLCID());
257     if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
258
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;
262
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;
266
267     /* 6. Return first in the list */
268     result = (HRSRC)find_entry_default( resdirptr, root );
269
270  found:
271     return result;
272 }
273
274
275 /**********************************************************************
276  *          PE_LoadResource
277  */
278 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
279 {
280     DWORD offset;
281
282     if (!hRsrc) return 0;
283     if (!hmod) hmod = GetModuleHandleA( NULL );
284
285     offset = ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData;
286
287     if (is_data_file_module(hmod))
288     {
289         hmod = (HMODULE)((ULONG_PTR)hmod & ~1);
290         return (HGLOBAL)RtlImageRvaToVa( RtlImageNtHeader(hmod), hmod, offset, NULL );
291     }
292     else
293         return (HGLOBAL)((char *)hmod + offset);
294 }
295
296
297 /**********************************************************************
298  *          PE_SizeofResource
299  */
300 DWORD PE_SizeofResource( HRSRC hRsrc )
301 {
302     if (!hRsrc) return 0;
303     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
304 }
305
306
307 /**********************************************************************
308  *      EnumResourceTypesA      (KERNEL32.@)
309  */
310 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
311 {
312     int         i;
313     const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
314     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
315     BOOL        ret;
316
317     if (!resdir) return FALSE;
318
319     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
320     ret = FALSE;
321     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
322         LPSTR type;
323
324         if (et[i].u1.s1.NameIsString)
325         {
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);
336         }
337         else
338         {
339             type = (LPSTR)(int)et[i].u1.s2.Id;
340             ret = lpfun(hmod,type,lparam);
341         }
342         if (!ret)
343                 break;
344     }
345     return ret;
346 }
347
348
349 /**********************************************************************
350  *      EnumResourceTypesW      (KERNEL32.@)
351  */
352 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
353 {
354     int         i;
355     const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
356     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
357     BOOL        ret;
358
359     if (!resdir) return FALSE;
360
361     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
362     ret = FALSE;
363     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
364         LPWSTR  type;
365
366         if (et[i].u1.s1.NameIsString)
367         {
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);
375         }
376         else
377         {
378             type = (LPWSTR)(int)et[i].u1.s2.Id;
379             ret = lpfun(hmod,type,lparam);
380         }
381         if (!ret)
382                 break;
383     }
384     return ret;
385 }
386
387
388 /**********************************************************************
389  *      EnumResourceNamesA      (KERNEL32.@)
390  */
391 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
392 {
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;
398
399     if (!basedir) return FALSE;
400
401     if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
402
403     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
404     ret = FALSE;
405     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
406         LPSTR name;
407
408         if (et[i].u1.s1.NameIsString)
409         {
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 );
420         }
421         else
422         {
423             name = (LPSTR)(int)et[i].u1.s2.Id;
424             ret = lpfun(hmod,type,name,lparam);
425         }
426         if (!ret)
427                 break;
428     }
429     return ret;
430 }
431
432
433 /**********************************************************************
434  *      EnumResourceNamesW      (KERNEL32.@)
435  */
436 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
437 {
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;
443
444     if (!basedir) return FALSE;
445
446     if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
447
448     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
449     ret = FALSE;
450     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
451         LPWSTR name;
452
453         if (et[i].u1.s1.NameIsString)
454         {
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);
462         }
463         else
464         {
465             name = (LPWSTR)(int)et[i].u1.s2.Id;
466             ret = lpfun(hmod,type,name,lparam);
467         }
468         if (!ret)
469                 break;
470     }
471     return ret;
472 }
473
474
475 /**********************************************************************
476  *      EnumResourceLanguagesA  (KERNEL32.@)
477  */
478 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
479                                     ENUMRESLANGPROCA lpfun, LONG lparam )
480 {
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;
486
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;
490
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;
498     }
499     return ret;
500 }
501
502
503 /**********************************************************************
504  *      EnumResourceLanguagesW  (KERNEL32.@)
505  */
506 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
507                                     ENUMRESLANGPROCW lpfun, LONG lparam )
508 {
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;
514
515     if (!basedir) return FALSE;
516
517     if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
518     if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
519
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;
526     }
527     return ret;
528 }