Backed out FindResource language patch.
[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
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include "wine/winestring.h"
16 #include "wine/unicode.h"
17 #include "windef.h"
18 #include "winnls.h"
19 #include "pe_image.h"
20 #include "module.h"
21 #include "heap.h"
22 #include "task.h"
23 #include "process.h"
24 #include "stackframe.h"
25 #include "neexe.h"
26 #include "debugtools.h"
27
28 /**********************************************************************
29  *  HMODULE32toPE_MODREF 
30  *
31  * small helper function to get a PE_MODREF from a passed HMODULE32
32  */
33 static PE_MODREF*
34 HMODULE32toPE_MODREF(HMODULE hmod) {
35         WINE_MODREF     *wm;
36
37         wm = MODULE32_LookupHMODULE( hmod );
38         if (!wm || wm->type!=MODULE32_PE)
39                 return NULL;
40         return &(wm->binfmt.pe);
41 }
42
43 /**********************************************************************
44  *          GetResDirEntryW
45  *
46  *      Helper function - goes down one level of PE resource tree
47  *
48  */
49 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr,
50                                            LPCWSTR name,DWORD root,
51                                            BOOL allowdefault)
52 {
53     int entrynum;
54     PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable;
55     int namelen;
56
57     if (HIWORD(name)) {
58         if (name[0]=='#') {
59                 char    buf[10];
60
61                 lstrcpynWtoA(buf,name+1,10);
62                 return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault);
63         }
64         entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
65                         (BYTE *) resdirptr + 
66                         sizeof(IMAGE_RESOURCE_DIRECTORY));
67         namelen = lstrlenW(name);
68         for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++)
69         {
70                 PIMAGE_RESOURCE_DIR_STRING_U str =
71                 (PIMAGE_RESOURCE_DIR_STRING_U) (root + 
72                         entryTable[entrynum].u1.s.NameOffset);
73                 if(namelen != str->Length)
74                         continue;
75                 if(strncmpiW(name,str->NameString,str->Length)==0)
76                         return (PIMAGE_RESOURCE_DIRECTORY) (
77                                 root +
78                                 entryTable[entrynum].u2.s.OffsetToDirectory);
79         }
80         return NULL;
81     } else {
82         entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
83                         (BYTE *) resdirptr + 
84                         sizeof(IMAGE_RESOURCE_DIRECTORY) +
85                         resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
86         for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++)
87             if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name)
88                 return (PIMAGE_RESOURCE_DIRECTORY) (
89                         root +
90                         entryTable[entrynum].u2.s.OffsetToDirectory);
91         /* just use first entry if no default can be found */
92         if (allowdefault && !name && resdirptr->NumberOfIdEntries)
93                 return (PIMAGE_RESOURCE_DIRECTORY) (
94                         root +
95                         entryTable[0].u2.s.OffsetToDirectory);
96         return NULL;
97     }
98 }
99
100 /**********************************************************************
101  *          GetResDirEntryA
102  */
103 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr,
104                                            LPCSTR name, DWORD root,
105                                            BOOL allowdefault )
106 {
107     PIMAGE_RESOURCE_DIRECTORY retv;
108     LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name ) 
109                                : (LPWSTR)name;
110
111     retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault );
112
113     if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW );
114
115     return retv;
116 }
117
118 /**********************************************************************
119  *          PE_FindResourceEx32W
120  */
121 HANDLE PE_FindResourceExW(
122         WINE_MODREF *wm,LPCWSTR name,LPCWSTR type,WORD lang
123 ) {
124     PIMAGE_RESOURCE_DIRECTORY resdirptr;
125     DWORD root;
126     HANDLE result;
127     PE_MODREF   *pem = &(wm->binfmt.pe);
128
129     if (!pem || !pem->pe_resource)
130         return 0;
131
132     resdirptr = pem->pe_resource;
133     root = (DWORD) resdirptr;
134     if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
135         return 0;
136     if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
137         return 0;
138     result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
139
140     /* Try with only the primary language set */
141     if (!result)
142     {
143         lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_DEFAULT);
144         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
145     }
146         /* Try LANG_NEUTRAL, too */
147     if(!result)
148         return (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)0, root, TRUE);
149     return result;
150 }
151
152
153 /**********************************************************************
154  *          PE_LoadResource32
155  */
156 HANDLE PE_LoadResource( WINE_MODREF *wm, HANDLE hRsrc )
157 {
158     if (!hRsrc || !wm || wm->type!=MODULE32_PE)
159         return 0;
160     return (HANDLE) (wm->module + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
161 }
162
163
164 /**********************************************************************
165  *          PE_SizeofResource32
166  */
167 DWORD PE_SizeofResource( HINSTANCE hModule, HANDLE hRsrc )
168 {
169     /* we don't need hModule */
170     if (!hRsrc)
171          return 0;
172     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
173 }
174
175 /**********************************************************************
176  *          PE_EnumResourceTypes32A
177  */
178 BOOL
179 PE_EnumResourceTypesA(HMODULE hmod,ENUMRESTYPEPROCA lpfun,LONG lparam) {
180     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
181     int         i;
182     PIMAGE_RESOURCE_DIRECTORY           resdir;
183     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
184     BOOL        ret;
185     HANDLE      heap = GetProcessHeap();        
186
187     if (!pem || !pem->pe_resource)
188         return FALSE;
189
190     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
191     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
192     ret = FALSE;
193     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
194         LPSTR   name;
195
196         if (et[i].u1.s.NameIsString)
197                 name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset));
198         else
199                 name = (LPSTR)(int)et[i].u1.Id;
200         ret = lpfun(hmod,name,lparam);
201         if (HIWORD(name))
202                 HeapFree(heap,0,name);
203         if (!ret)
204                 break;
205     }
206     return ret;
207 }
208
209 /**********************************************************************
210  *          PE_EnumResourceTypes32W
211  */
212 BOOL
213 PE_EnumResourceTypesW(HMODULE hmod,ENUMRESTYPEPROCW lpfun,LONG lparam) {
214     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
215     int         i;
216     PIMAGE_RESOURCE_DIRECTORY           resdir;
217     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
218     BOOL        ret;
219
220     if (!pem || !pem->pe_resource)
221         return FALSE;
222
223     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
224     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
225     ret = FALSE;
226     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
227         LPWSTR  type;
228         if (et[i].u1.s.NameIsString)
229                 type = (LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset);
230         else
231                 type = (LPWSTR)(int)et[i].u1.Id;
232
233         ret = lpfun(hmod,type,lparam);
234         if (!ret)
235                 break;
236     }
237     return ret;
238 }
239
240 /**********************************************************************
241  *          PE_EnumResourceNames32A
242  */
243 BOOL
244 PE_EnumResourceNamesA(
245         HMODULE hmod,LPCSTR type,ENUMRESNAMEPROCA lpfun,LONG lparam
246 ) {
247     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
248     int         i;
249     PIMAGE_RESOURCE_DIRECTORY           resdir;
250     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
251     BOOL        ret;
252     HANDLE      heap = GetProcessHeap();        
253     LPWSTR      typeW;
254
255     if (!pem || !pem->pe_resource)
256         return FALSE;
257     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
258     if (HIWORD(type))
259         typeW = HEAP_strdupAtoW(heap,0,type);
260     else
261         typeW = (LPWSTR)type;
262     resdir = GetResDirEntryW(resdir,typeW,(DWORD)pem->pe_resource,FALSE);
263     if (HIWORD(typeW))
264         HeapFree(heap,0,typeW);
265     if (!resdir)
266         return FALSE;
267     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
268     ret = FALSE;
269     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
270         LPSTR   name;
271
272         if (et[i].u1.s.NameIsString)
273             name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset));
274         else
275             name = (LPSTR)(int)et[i].u1.Id;
276         ret = lpfun(hmod,type,name,lparam);
277         if (HIWORD(name)) HeapFree(heap,0,name);
278         if (!ret)
279                 break;
280     }
281     return ret;
282 }
283
284 /**********************************************************************
285  *          PE_EnumResourceNames32W
286  */
287 BOOL
288 PE_EnumResourceNamesW(
289         HMODULE hmod,LPCWSTR type,ENUMRESNAMEPROCW lpfun,LONG lparam
290 ) {
291     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
292     int         i;
293     PIMAGE_RESOURCE_DIRECTORY           resdir;
294     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
295     BOOL        ret;
296
297     if (!pem || !pem->pe_resource)
298         return FALSE;
299
300     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
301     resdir = GetResDirEntryW(resdir,type,(DWORD)pem->pe_resource,FALSE);
302     if (!resdir)
303         return FALSE;
304     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
305     ret = FALSE;
306     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
307         LPWSTR  name;
308         if (et[i].u1.s.NameIsString)
309                 name = (LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.s.NameOffset);
310         else
311                 name = (LPWSTR)(int)et[i].u1.Id;
312         ret = lpfun(hmod,type,name,lparam);
313         if (!ret)
314                 break;
315     }
316     return ret;
317 }
318
319 /**********************************************************************
320  *          PE_EnumResourceNames32A
321  */
322 BOOL
323 PE_EnumResourceLanguagesA(
324         HMODULE hmod,LPCSTR name,LPCSTR type,ENUMRESLANGPROCA lpfun,
325         LONG lparam
326 ) {
327     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
328     int         i;
329     PIMAGE_RESOURCE_DIRECTORY           resdir;
330     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
331     BOOL        ret;
332     HANDLE      heap = GetProcessHeap();        
333     LPWSTR      nameW,typeW;
334
335     if (!pem || !pem->pe_resource)
336         return FALSE;
337
338     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
339     if (HIWORD(name))
340         nameW = HEAP_strdupAtoW(heap,0,name);
341     else
342         nameW = (LPWSTR)name;
343     resdir = GetResDirEntryW(resdir,nameW,(DWORD)pem->pe_resource,FALSE);
344     if (HIWORD(nameW))
345         HeapFree(heap,0,nameW);
346     if (!resdir)
347         return FALSE;
348     if (HIWORD(type))
349         typeW = HEAP_strdupAtoW(heap,0,type);
350     else
351         typeW = (LPWSTR)type;
352     resdir = GetResDirEntryW(resdir,typeW,(DWORD)pem->pe_resource,FALSE);
353     if (HIWORD(typeW))
354         HeapFree(heap,0,typeW);
355     if (!resdir)
356         return FALSE;
357     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
358     ret = FALSE;
359     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
360         /* languages are just ids... I hopem */
361         ret = lpfun(hmod,name,type,et[i].u1.Id,lparam);
362         if (!ret)
363                 break;
364     }
365     return ret;
366 }
367
368 /**********************************************************************
369  *          PE_EnumResourceLanguages32W
370  */
371 BOOL
372 PE_EnumResourceLanguagesW(
373         HMODULE hmod,LPCWSTR name,LPCWSTR type,ENUMRESLANGPROCW lpfun,
374         LONG lparam
375 ) {
376     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
377     int         i;
378     PIMAGE_RESOURCE_DIRECTORY           resdir;
379     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
380     BOOL        ret;
381
382     if (!pem || !pem->pe_resource)
383         return FALSE;
384
385     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
386     resdir = GetResDirEntryW(resdir,name,(DWORD)pem->pe_resource,FALSE);
387     if (!resdir)
388         return FALSE;
389     resdir = GetResDirEntryW(resdir,type,(DWORD)pem->pe_resource,FALSE);
390     if (!resdir)
391         return FALSE;
392     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
393     ret = FALSE;
394     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
395         ret = lpfun(hmod,name,type,et[i].u1.Id,lparam);
396         if (!ret)
397                 break;
398     }
399     return ret;
400 }