wininet: Allow a NULL value to be passed into HTTP_ProcessHeader
[wine] / dlls / kernel32 / resource.c
1 /*
2  * Resources
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995, 2003 Alexandre Julliard
6  * Copyright 2006 Mike McCormack
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winternl.h"
35 #include "wownt32.h"
36 #include "wine/winbase16.h"
37 #include "wine/debug.h"
38 #include "excpt.h"
39 #include "wine/exception.h"
40 #include "wine/unicode.h"
41 #include "wine/list.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(resource);
44
45 /* handle conversions */
46 #define HRSRC_32(h16)   ((HRSRC)(ULONG_PTR)(h16))
47 #define HRSRC_16(h32)   (LOWORD(h32))
48 #define HGLOBAL_32(h16) ((HGLOBAL)(ULONG_PTR)(h16))
49 #define HGLOBAL_16(h32) (LOWORD(h32))
50 #define HMODULE_16(h32) (LOWORD(h32))
51
52 /* retrieve the resource name to pass to the ntdll functions */
53 static NTSTATUS get_res_nameA( LPCSTR name, UNICODE_STRING *str )
54 {
55     if (!HIWORD(name))
56     {
57         str->Buffer = (LPWSTR)name;
58         return STATUS_SUCCESS;
59     }
60     if (name[0] == '#')
61     {
62         ULONG value;
63         if (RtlCharToInteger( name + 1, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
64             return STATUS_INVALID_PARAMETER;
65         str->Buffer = (LPWSTR)value;
66         return STATUS_SUCCESS;
67     }
68     RtlCreateUnicodeStringFromAsciiz( str, name );
69     RtlUpcaseUnicodeString( str, str, FALSE );
70     return STATUS_SUCCESS;
71 }
72
73 /* retrieve the resource name to pass to the ntdll functions */
74 static NTSTATUS get_res_nameW( LPCWSTR name, UNICODE_STRING *str )
75 {
76     if (!HIWORD(name))
77     {
78         str->Buffer = (LPWSTR)name;
79         return STATUS_SUCCESS;
80     }
81     if (name[0] == '#')
82     {
83         ULONG value;
84         RtlInitUnicodeString( str, name + 1 );
85         if (RtlUnicodeStringToInteger( str, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
86             return STATUS_INVALID_PARAMETER;
87         str->Buffer = (LPWSTR)value;
88         return STATUS_SUCCESS;
89     }
90     RtlCreateUnicodeString( str, name );
91     RtlUpcaseUnicodeString( str, str, FALSE );
92     return STATUS_SUCCESS;
93 }
94
95 /* retrieve the resource names for the 16-bit FindResource function */
96 static BOOL get_res_name_type_WtoA( LPCWSTR name, LPCWSTR type, LPSTR *nameA, LPSTR *typeA )
97 {
98     *nameA = *typeA = NULL;
99
100     __TRY
101     {
102         if (HIWORD(name))
103         {
104             DWORD len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
105             *nameA = HeapAlloc( GetProcessHeap(), 0, len );
106             if (*nameA) WideCharToMultiByte( CP_ACP, 0, name, -1, *nameA, len, NULL, NULL );
107         }
108         else *nameA = (LPSTR)name;
109
110         if (HIWORD(type))
111         {
112             DWORD len = WideCharToMultiByte( CP_ACP, 0, type, -1, NULL, 0, NULL, NULL );
113             *typeA = HeapAlloc( GetProcessHeap(), 0, len );
114             if (*typeA) WideCharToMultiByte( CP_ACP, 0, type, -1, *typeA, len, NULL, NULL );
115         }
116         else *typeA = (LPSTR)type;
117     }
118     __EXCEPT_PAGE_FAULT
119     {
120         if (HIWORD(*nameA)) HeapFree( GetProcessHeap(), 0, *nameA );
121         if (HIWORD(*typeA)) HeapFree( GetProcessHeap(), 0, *typeA );
122         SetLastError( ERROR_INVALID_PARAMETER );
123         return FALSE;
124     }
125     __ENDTRY
126     return TRUE;
127 }
128
129 /* implementation of FindResourceExA */
130 static HRSRC find_resourceA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
131 {
132     NTSTATUS status;
133     UNICODE_STRING nameW, typeW;
134     LDR_RESOURCE_INFO info;
135     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
136
137     __TRY
138     {
139         if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS) goto done;
140         if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS) goto done;
141         info.Type = (ULONG_PTR)typeW.Buffer;
142         info.Name = (ULONG_PTR)nameW.Buffer;
143         info.Language = lang;
144         status = LdrFindResource_U( hModule, &info, 3, &entry );
145     done:
146         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
147     }
148     __EXCEPT_PAGE_FAULT
149     {
150         SetLastError( ERROR_INVALID_PARAMETER );
151     }
152     __ENDTRY
153
154     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
155     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
156     return (HRSRC)entry;
157 }
158
159
160 /* implementation of FindResourceExW */
161 static HRSRC find_resourceW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
162 {
163     NTSTATUS status;
164     UNICODE_STRING nameW, typeW;
165     LDR_RESOURCE_INFO info;
166     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
167
168     nameW.Buffer = typeW.Buffer = NULL;
169
170     __TRY
171     {
172         if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS) goto done;
173         if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS) goto done;
174         info.Type = (ULONG_PTR)typeW.Buffer;
175         info.Name = (ULONG_PTR)nameW.Buffer;
176         info.Language = lang;
177         status = LdrFindResource_U( hModule, &info, 3, &entry );
178     done:
179         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
180     }
181     __EXCEPT_PAGE_FAULT
182     {
183         SetLastError( ERROR_INVALID_PARAMETER );
184     }
185     __ENDTRY
186
187     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
188     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
189     return (HRSRC)entry;
190 }
191
192 /**********************************************************************
193  *          FindResourceExA  (KERNEL32.@)
194  */
195 HRSRC WINAPI FindResourceExA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
196 {
197     TRACE( "%p %s %s %04x\n", hModule, debugstr_a(type), debugstr_a(name), lang );
198
199     if (!hModule) hModule = GetModuleHandleW(0);
200     else if (!HIWORD(hModule))
201     {
202         return HRSRC_32( FindResource16( HMODULE_16(hModule), name, type ) );
203     }
204     return find_resourceA( hModule, type, name, lang );
205 }
206
207
208 /**********************************************************************
209  *          FindResourceA    (KERNEL32.@)
210  */
211 HRSRC WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
212 {
213     return FindResourceExA( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
214 }
215
216
217 /**********************************************************************
218  *          FindResourceExW  (KERNEL32.@)
219  */
220 HRSRC WINAPI FindResourceExW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
221 {
222     TRACE( "%p %s %s %04x\n", hModule, debugstr_w(type), debugstr_w(name), lang );
223
224     if (!hModule) hModule = GetModuleHandleW(0);
225     else if (!HIWORD(hModule))
226     {
227         LPSTR nameA, typeA;
228         HRSRC16 ret;
229
230         if (!get_res_name_type_WtoA( name, type, &nameA, &typeA )) return NULL;
231
232         ret = FindResource16( HMODULE_16(hModule), nameA, typeA );
233         if (HIWORD(nameA)) HeapFree( GetProcessHeap(), 0, nameA );
234         if (HIWORD(typeA)) HeapFree( GetProcessHeap(), 0, typeA );
235         return HRSRC_32(ret);
236     }
237
238     return find_resourceW( hModule, type, name, lang );
239 }
240
241
242 /**********************************************************************
243  *          FindResourceW    (KERNEL32.@)
244  */
245 HRSRC WINAPI FindResourceW( HINSTANCE hModule, LPCWSTR name, LPCWSTR type )
246 {
247     return FindResourceExW( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
248 }
249
250
251 /**********************************************************************
252  *      EnumResourceTypesA      (KERNEL32.@)
253  */
254 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG_PTR lparam )
255 {
256     int i;
257     BOOL ret = FALSE;
258     LPSTR type = NULL;
259     DWORD len = 0, newlen;
260     NTSTATUS status;
261     const IMAGE_RESOURCE_DIRECTORY *resdir;
262     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
263     const IMAGE_RESOURCE_DIR_STRING_U *str;
264
265     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
266
267     if (!hmod) hmod = GetModuleHandleA( NULL );
268
269     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
270     {
271         SetLastError( RtlNtStatusToDosError(status) );
272         return FALSE;
273     }
274     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
275     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
276     {
277         if (et[i].u1.s1.NameIsString)
278         {
279             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
280             newlen = WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
281             if (newlen + 1 > len)
282             {
283                 len = newlen + 1;
284                 HeapFree( GetProcessHeap(), 0, type );
285                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
286             }
287             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, type, len, NULL, NULL);
288             type[newlen] = 0;
289             ret = lpfun(hmod,type,lparam);
290         }
291         else
292         {
293             ret = lpfun( hmod, (LPSTR)(int)et[i].u1.s2.Id, lparam );
294         }
295         if (!ret) break;
296     }
297     HeapFree( GetProcessHeap(), 0, type );
298     return ret;
299 }
300
301
302 /**********************************************************************
303  *      EnumResourceTypesW      (KERNEL32.@)
304  */
305 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG_PTR lparam )
306 {
307     int i, len = 0;
308     BOOL ret = FALSE;
309     LPWSTR type = NULL;
310     NTSTATUS status;
311     const IMAGE_RESOURCE_DIRECTORY *resdir;
312     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
313     const IMAGE_RESOURCE_DIR_STRING_U *str;
314
315     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
316
317     if (!hmod) hmod = GetModuleHandleW( NULL );
318
319     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
320     {
321         SetLastError( RtlNtStatusToDosError(status) );
322         return FALSE;
323     }
324     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
325     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
326     {
327         if (et[i].u1.s1.NameIsString)
328         {
329             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
330             if (str->Length + 1 > len)
331             {
332                 len = str->Length + 1;
333                 HeapFree( GetProcessHeap(), 0, type );
334                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
335             }
336             memcpy(type, str->NameString, str->Length * sizeof (WCHAR));
337             type[str->Length] = 0;
338             ret = lpfun(hmod,type,lparam);
339         }
340         else
341         {
342             ret = lpfun( hmod, (LPWSTR)(int)et[i].u1.s2.Id, lparam );
343         }
344         if (!ret) break;
345     }
346     HeapFree( GetProcessHeap(), 0, type );
347     return ret;
348 }
349
350
351 /**********************************************************************
352  *      EnumResourceNamesA      (KERNEL32.@)
353  */
354 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG_PTR lparam )
355 {
356     int i;
357     BOOL ret = FALSE;
358     DWORD len = 0, newlen;
359     LPSTR name = NULL;
360     NTSTATUS status;
361     UNICODE_STRING typeW;
362     LDR_RESOURCE_INFO info;
363     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
364     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
365     const IMAGE_RESOURCE_DIR_STRING_U *str;
366
367     TRACE( "%p %s %p %lx\n", hmod, debugstr_a(type), lpfun, lparam );
368
369     if (!hmod) hmod = GetModuleHandleA( NULL );
370     typeW.Buffer = NULL;
371     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
372         goto done;
373     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
374         goto done;
375     info.Type = (ULONG)typeW.Buffer;
376     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
377         goto done;
378
379     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
380     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
381     {
382         if (et[i].u1.s1.NameIsString)
383         {
384             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
385             newlen = WideCharToMultiByte(CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
386             if (newlen + 1 > len)
387             {
388                 len = newlen + 1;
389                 HeapFree( GetProcessHeap(), 0, name );
390                 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
391                 {
392                     ret = FALSE;
393                     break;
394                 }
395             }
396             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, name, len, NULL, NULL );
397             name[newlen] = 0;
398             ret = lpfun(hmod,type,name,lparam);
399         }
400         else
401         {
402             ret = lpfun( hmod, type, (LPSTR)(int)et[i].u1.s2.Id, lparam );
403         }
404         if (!ret) break;
405     }
406 done:
407     HeapFree( GetProcessHeap(), 0, name );
408     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
409     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
410     return ret;
411 }
412
413
414 /**********************************************************************
415  *      EnumResourceNamesW      (KERNEL32.@)
416  */
417 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG_PTR lparam )
418 {
419     int i, len = 0;
420     BOOL ret = FALSE;
421     LPWSTR name = NULL;
422     NTSTATUS status;
423     UNICODE_STRING typeW;
424     LDR_RESOURCE_INFO info;
425     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
426     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
427     const IMAGE_RESOURCE_DIR_STRING_U *str;
428
429     TRACE( "%p %s %p %lx\n", hmod, debugstr_w(type), lpfun, lparam );
430
431     if (!hmod) hmod = GetModuleHandleW( NULL );
432     typeW.Buffer = NULL;
433     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
434         goto done;
435     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
436         goto done;
437     info.Type = (ULONG)typeW.Buffer;
438     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
439         goto done;
440
441     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
442     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
443     {
444         if (et[i].u1.s1.NameIsString)
445         {
446             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
447             if (str->Length + 1 > len)
448             {
449                 len = str->Length + 1;
450                 HeapFree( GetProcessHeap(), 0, name );
451                 if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
452                 {
453                     ret = FALSE;
454                     break;
455                 }
456             }
457             memcpy(name, str->NameString, str->Length * sizeof (WCHAR));
458             name[str->Length] = 0;
459             ret = lpfun(hmod,type,name,lparam);
460         }
461         else
462         {
463             ret = lpfun( hmod, type, (LPWSTR)(int)et[i].u1.s2.Id, lparam );
464         }
465         if (!ret) break;
466     }
467 done:
468     HeapFree( GetProcessHeap(), 0, name );
469     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
470     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
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_PTR lparam )
480 {
481     int i;
482     BOOL ret = FALSE;
483     NTSTATUS status;
484     UNICODE_STRING typeW, nameW;
485     LDR_RESOURCE_INFO info;
486     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
487     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
488
489     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_a(type), debugstr_a(name), lpfun, lparam );
490
491     if (!hmod) hmod = GetModuleHandleA( NULL );
492     typeW.Buffer = nameW.Buffer = NULL;
493     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
494         goto done;
495     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
496         goto done;
497     if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS)
498         goto done;
499     info.Type = (ULONG_PTR)typeW.Buffer;
500     info.Name = (ULONG_PTR)nameW.Buffer;
501     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
502         goto done;
503
504     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
505     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
506     {
507         ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
508         if (!ret) break;
509     }
510 done:
511     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
512     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
513     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
514     return ret;
515 }
516
517
518 /**********************************************************************
519  *      EnumResourceLanguagesW  (KERNEL32.@)
520  */
521 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
522                                     ENUMRESLANGPROCW lpfun, LONG_PTR lparam )
523 {
524     int i;
525     BOOL ret = FALSE;
526     NTSTATUS status;
527     UNICODE_STRING typeW, nameW;
528     LDR_RESOURCE_INFO info;
529     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
530     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
531
532     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_w(type), debugstr_w(name), lpfun, lparam );
533
534     if (!hmod) hmod = GetModuleHandleW( NULL );
535     typeW.Buffer = nameW.Buffer = NULL;
536     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
537         goto done;
538     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
539         goto done;
540     if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS)
541         goto done;
542     info.Type = (ULONG_PTR)typeW.Buffer;
543     info.Name = (ULONG_PTR)nameW.Buffer;
544     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
545         goto done;
546
547     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
548     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
549     {
550         ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
551         if (!ret) break;
552     }
553 done:
554     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
555     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
556     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
557     return ret;
558 }
559
560
561 /**********************************************************************
562  *          LoadResource     (KERNEL32.@)
563  */
564 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
565 {
566     NTSTATUS status;
567     void *ret = NULL;
568
569     TRACE( "%p %p\n", hModule, hRsrc );
570
571     if (hModule && !HIWORD(hModule))
572         /* FIXME: should convert return to 32-bit resource */
573         return HGLOBAL_32( LoadResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) ) );
574
575     if (!hRsrc) return 0;
576     if (!hModule) hModule = GetModuleHandleA( NULL );
577     status = LdrAccessResource( hModule, (IMAGE_RESOURCE_DATA_ENTRY *)hRsrc, &ret, NULL );
578     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
579     return ret;
580 }
581
582
583 /**********************************************************************
584  *          LockResource     (KERNEL32.@)
585  */
586 LPVOID WINAPI LockResource( HGLOBAL handle )
587 {
588     TRACE("(%p)\n", handle );
589
590     if (HIWORD( handle ))  /* 32-bit memory handle */
591         return (LPVOID)handle;
592
593     /* 16-bit memory handle */
594     return LockResource16( HGLOBAL_16(handle) );
595 }
596
597
598 /**********************************************************************
599  *          FreeResource     (KERNEL32.@)
600  */
601 BOOL WINAPI FreeResource( HGLOBAL handle )
602 {
603     if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
604     return FreeResource16( HGLOBAL_16(handle) );
605 }
606
607
608 /**********************************************************************
609  *          SizeofResource   (KERNEL32.@)
610  */
611 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
612 {
613     if (hModule && !HIWORD(hModule))
614         return SizeofResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) );
615
616     if (!hRsrc) return 0;
617     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
618 }
619
620 /*
621  *  Data structure for updating resources.
622  *  Type/Name/Language is a keyset for accessing resource data.
623  *
624  *  QUEUEDUPDATES (root) ->
625  *    list of struct resource_dir_entry    (Type) ->
626  *      list of struct resource_dir_entry  (Name)   ->
627  *         list of struct resource_data    Language + Data
628  */
629
630 typedef struct
631 {
632     LPWSTR pFileName;
633     BOOL bDeleteExistingResources;
634     struct list root;
635 } QUEUEDUPDATES;
636
637 /* this structure is shared for types and names */
638 struct resource_dir_entry {
639     struct list entry;
640     LPWSTR id;
641     struct list children;
642 };
643
644 /* this structure is the leaf */
645 struct resource_data {
646     struct list entry;
647     LANGID lang;
648     DWORD codepage;
649     DWORD cbData;
650     void *lpData;
651 };
652
653 static int resource_strcmp( LPCWSTR a, LPCWSTR b )
654 {
655     if ( a == b )
656         return 0;
657     if (HIWORD( a ) && HIWORD( b ) )
658         return lstrcmpW( a, b );
659     /* strings come before ids */
660     if (HIWORD( a ) && !HIWORD( b ))
661         return -1;
662     if (HIWORD( b ) && !HIWORD( a ))
663         return 1;
664     return ( a < b ) ? -1 : 1;
665 }
666
667 static struct resource_dir_entry *find_resource_dir_entry( struct list *dir, LPCWSTR id )
668 {
669     struct resource_dir_entry *ent;
670
671     /* match either IDs or strings */
672     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
673         if (!resource_strcmp( id, ent->id ))
674             return ent;
675
676     return NULL;
677 }
678
679 static struct resource_data *find_resource_data( struct list *dir, LANGID lang )
680 {
681     struct resource_data *res_data;
682
683     /* match only languages here */
684     LIST_FOR_EACH_ENTRY( res_data, dir, struct resource_data, entry )
685         if ( lang == res_data->lang )
686              return res_data;
687
688     return NULL;
689 }
690
691 static void add_resource_dir_entry( struct list *dir, struct resource_dir_entry *resdir )
692 {
693     struct resource_dir_entry *ent;
694
695     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
696     {
697         if (0>resource_strcmp( ent->id, resdir->id ))
698             continue;
699
700         list_add_before( &ent->entry, &resdir->entry );
701         return;
702     }
703     list_add_tail( dir, &resdir->entry );
704 }
705
706 static void add_resource_data_entry( struct list *dir, struct resource_data *resdata )
707 {
708     struct resource_data *ent;
709
710     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_data, entry )
711     {
712         if (ent->lang < resdata->lang)
713             continue;
714
715         list_add_before( &ent->entry, &resdata->entry );
716         return;
717     }
718     list_add_tail( dir, &resdata->entry );
719 }
720
721 static LPWSTR res_strdupW( LPCWSTR str )
722 {
723     LPWSTR ret;
724     UINT len;
725
726     if (HIWORD(str) == 0)
727         return (LPWSTR) (UINT_PTR) LOWORD(str);
728     len = (lstrlenW( str ) + 1) * sizeof (WCHAR);
729     ret = HeapAlloc( GetProcessHeap(), 0, len );
730     memcpy( ret, str, len );
731     return ret;
732 }
733
734 static void res_free_str( LPWSTR str )
735 {
736     if (HIWORD(str))
737         HeapFree( GetProcessHeap(), 0, str );
738 }
739
740 static BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
741                                  struct resource_data *resdata, BOOL overwrite_existing )
742 {
743     struct resource_dir_entry *restype, *resname;
744     struct resource_data *existing;
745
746     TRACE("%p %s %s %p %d\n", updates,
747           debugstr_w(Type), debugstr_w(Name), resdata, overwrite_existing );
748
749     restype = find_resource_dir_entry( &updates->root, Type );
750     if (!restype)
751     {
752         restype = HeapAlloc( GetProcessHeap(), 0, sizeof *restype );
753         restype->id = res_strdupW( Type );
754         list_init( &restype->children );
755         add_resource_dir_entry( &updates->root, restype );
756     }
757
758     resname = find_resource_dir_entry( &restype->children, Name );
759     if (!resname)
760     {
761         resname = HeapAlloc( GetProcessHeap(), 0, sizeof *resname );
762         resname->id = res_strdupW( Name );
763         list_init( &resname->children );
764         add_resource_dir_entry( &restype->children, resname );
765     }
766
767     /*
768      * If there's an existing resource entry with matching (Type,Name,Language)
769      *  it needs to be removed before adding the new data.
770      */
771     existing = find_resource_data( &resname->children, resdata->lang );
772     if (existing)
773     {
774         if (!overwrite_existing)
775             return TRUE;
776         list_remove( &existing->entry );
777         HeapFree( GetProcessHeap(), 0, existing );
778     }
779
780     add_resource_data_entry( &resname->children, resdata );
781
782     return TRUE;
783 }
784
785 static struct resource_data *allocate_resource_data( WORD Language, DWORD codepage,
786                                                      LPVOID lpData, DWORD cbData, BOOL copy_data )
787 {
788     struct resource_data *resdata;
789
790     if (!lpData || !cbData)
791         return NULL;
792
793     resdata = HeapAlloc( GetProcessHeap(), 0, sizeof *resdata + (copy_data ? cbData : 0) );
794     if (resdata)
795     {
796         resdata->lang = Language;
797         resdata->codepage = codepage;
798         resdata->cbData = cbData;
799         if (copy_data)
800         {
801             resdata->lpData = &resdata[1];
802             memcpy( resdata->lpData, lpData, cbData );
803         }
804         else
805             resdata->lpData = lpData;
806     }
807
808     return resdata;
809 }
810
811 static void free_resource_directory( struct list *head, int level )
812 {
813     struct list *ptr = NULL;
814
815     while ((ptr = list_head( head )))
816     {
817         list_remove( ptr );
818         if (level)
819         {
820             struct resource_dir_entry *ent;
821
822             ent = LIST_ENTRY( ptr, struct resource_dir_entry, entry );
823             res_free_str( ent->id );
824             free_resource_directory( &ent->children, level - 1 );
825             HeapFree(GetProcessHeap(), 0, ent);
826         }
827         else
828         {
829             struct resource_data *data;
830
831             data = LIST_ENTRY( ptr, struct resource_data, entry );
832             HeapFree( GetProcessHeap(), 0, data );
833         }
834     }
835 }
836
837 static IMAGE_NT_HEADERS *get_nt_header( void *base, DWORD mapping_size )
838 {
839     IMAGE_NT_HEADERS *nt;
840     IMAGE_DOS_HEADER *dos;
841
842     if (mapping_size<sizeof (*dos))
843         return NULL;
844
845     dos = base;
846     if (dos->e_magic != IMAGE_DOS_SIGNATURE)
847         return NULL;
848
849     if ((dos->e_lfanew + sizeof (*nt)) > mapping_size)
850         return NULL;
851
852     nt = (void*) ((BYTE*)base + dos->e_lfanew);
853
854     if (nt->Signature != IMAGE_NT_SIGNATURE)
855         return NULL;
856
857     return nt;
858 }
859
860 static IMAGE_SECTION_HEADER *get_section_header( void *base, DWORD mapping_size, DWORD *num_sections )
861 {
862     IMAGE_NT_HEADERS *nt;
863     IMAGE_SECTION_HEADER *sec;
864     DWORD section_ofs;
865
866     nt = get_nt_header( base, mapping_size );
867     if (!nt)
868         return NULL;
869
870     /* check that we don't go over the end of the file accessing the sections */
871     section_ofs = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + nt->FileHeader.SizeOfOptionalHeader;
872     if ((nt->FileHeader.NumberOfSections * sizeof (*sec) + section_ofs) > mapping_size)
873         return NULL;
874
875     if (num_sections)
876         *num_sections = nt->FileHeader.NumberOfSections;
877
878     /* from here we have a valid PE exe to update */
879     return (void*) ((BYTE*)nt + section_ofs);
880 }
881
882 static BOOL check_pe_exe( HANDLE file, QUEUEDUPDATES *updates )
883 {
884     const IMAGE_NT_HEADERS *nt;
885     const IMAGE_SECTION_HEADER *sec;
886     BOOL ret = FALSE;
887     HANDLE mapping;
888     DWORD mapping_size, num_sections = 0;
889     void *base = NULL;
890
891     mapping_size = GetFileSize( file, NULL );
892
893     mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
894     if (!mapping)
895         goto done;
896
897     base = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, mapping_size );
898     if (!base)
899         goto done;
900
901     nt = get_nt_header( base, mapping_size );
902     if (!nt)
903         goto done;
904
905     TRACE("resources: %08x %08x\n",
906           nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
907           nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
908
909     sec = get_section_header( base, mapping_size, &num_sections );
910     if (!sec)
911         goto done;
912
913     ret = TRUE;
914
915 done:
916     if (base)
917         UnmapViewOfFile( base );
918     if (mapping)
919         CloseHandle( mapping );
920
921     return ret;
922 }
923
924 struct resource_size_info {
925     DWORD types_ofs;
926     DWORD names_ofs;
927     DWORD langs_ofs;
928     DWORD data_entry_ofs;
929     DWORD strings_ofs;
930     DWORD data_ofs;
931     DWORD total_size;
932 };
933
934 struct mapping_info {
935     HANDLE file;
936     HANDLE mapping;
937     void *base;
938     DWORD size;
939     BOOL read_write;
940 };
941
942 static const IMAGE_SECTION_HEADER *section_from_rva( void *base, DWORD mapping_size, DWORD rva )
943 {
944     const IMAGE_SECTION_HEADER *sec;
945     DWORD num_sections = 0;
946     int i;
947
948     sec = get_section_header( base, mapping_size, &num_sections );
949     if (!sec)
950         return NULL;
951
952     for (i=num_sections-1; i>=0; i--)
953     {
954         if (sec[i].VirtualAddress <= rva &&
955             rva <= (DWORD)sec[i].VirtualAddress + sec[i].SizeOfRawData)
956         {
957             return &sec[i];
958         }
959     }
960
961     return NULL;
962 }
963
964 static void *address_from_rva( void *base, DWORD mapping_size, DWORD rva, DWORD len )
965 {
966     const IMAGE_SECTION_HEADER *sec;
967
968     sec = section_from_rva( base, mapping_size, rva );
969     if (!sec)
970         return NULL;
971
972     if (rva + len <= (DWORD)sec->VirtualAddress + sec->SizeOfRawData)
973         return (void*)((const BYTE*) base + (sec->PointerToRawData + rva - sec->VirtualAddress));
974
975     return NULL;
976 }
977
978 static LPWSTR resource_dup_string( const IMAGE_RESOURCE_DIRECTORY *root, const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry )
979 {
980     const IMAGE_RESOURCE_DIR_STRING_U* string;
981     LPWSTR s;
982
983     if (!entry->u1.s1.NameIsString)
984         return (LPWSTR) (DWORD) entry->u1.s2.Id;
985
986     string = (const IMAGE_RESOURCE_DIR_STRING_U*) (((const char *)root) + entry->u1.s1.NameOffset);
987     s = HeapAlloc(GetProcessHeap(), 0, (string->Length + 1)*sizeof (WCHAR) );
988     memcpy( s, string->NameString, (string->Length + 1)*sizeof (WCHAR) );
989     s[string->Length] = 0;
990
991     return s;
992 }
993
994 /* this function is based on the code in winedump's pe.c */
995 static BOOL enumerate_mapped_resources( QUEUEDUPDATES *updates,
996                              void *base, DWORD mapping_size,
997                              const IMAGE_RESOURCE_DIRECTORY *root )
998 {
999     const IMAGE_RESOURCE_DIRECTORY *namedir, *langdir;
1000     const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
1001     const IMAGE_RESOURCE_DATA_ENTRY *data;
1002     DWORD i, j, k;
1003
1004     TRACE("version (%d.%d) %d named %d id entries\n",
1005           root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
1006
1007     for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
1008     {
1009         LPWSTR Type;
1010
1011         e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
1012
1013         Type = resource_dup_string( root, e1 );
1014
1015         namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
1016         for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
1017         {
1018             LPWSTR Name;
1019
1020             e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
1021
1022             Name = resource_dup_string( root, e2 );
1023
1024             langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
1025             for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
1026             {
1027                 LANGID Lang;
1028                 void *p;
1029                 struct resource_data *resdata;
1030
1031                 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
1032
1033                 Lang = e3->u1.s2.Id;
1034
1035                 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
1036
1037                 p = address_from_rva( base, mapping_size, data->OffsetToData, data->Size );
1038
1039                 resdata = allocate_resource_data( Lang, data->CodePage, p, data->Size, FALSE );
1040                 if (resdata)
1041                     update_add_resource( updates, Type, Name, resdata, FALSE );
1042             }
1043             res_free_str( Name );
1044         }
1045         res_free_str( Type );
1046     }
1047
1048     return TRUE;
1049 }
1050
1051 static BOOL read_mapped_resources( QUEUEDUPDATES *updates, void *base, DWORD mapping_size )
1052 {
1053     const IMAGE_RESOURCE_DIRECTORY *root;
1054     const IMAGE_NT_HEADERS *nt;
1055     const IMAGE_SECTION_HEADER *sec;
1056     DWORD num_sections = 0, i;
1057
1058     nt = get_nt_header( base, mapping_size );
1059     if (!nt)
1060         return FALSE;
1061
1062     sec = get_section_header( base, mapping_size, &num_sections );
1063     if (!sec)
1064         return FALSE;
1065
1066     for (i=0; i<num_sections; i++)
1067         if (!memcmp(sec[i].Name, ".rsrc", 6))
1068             break;
1069
1070     if (i == num_sections)
1071         return TRUE;
1072
1073     /* check the resource data is inside the mapping */
1074     if (sec[i].PointerToRawData > mapping_size ||
1075         (sec[i].PointerToRawData + sec[i].SizeOfRawData) > mapping_size)
1076         return TRUE;
1077
1078     TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
1079
1080     root = (void*) ((BYTE*)base + sec[i].PointerToRawData);
1081     enumerate_mapped_resources( updates, base, mapping_size, root );
1082
1083     return TRUE;
1084 }
1085
1086 static BOOL map_file_into_memory( struct mapping_info *mi )
1087 {
1088     DWORD page_attr, perm;
1089
1090     if (mi->read_write)
1091     {
1092         page_attr = PAGE_READWRITE;
1093         perm = FILE_MAP_WRITE | FILE_MAP_READ;
1094     }
1095     else
1096     {
1097         page_attr = PAGE_READONLY;
1098         perm = FILE_MAP_READ;
1099     }
1100
1101     mi->mapping = CreateFileMappingW( mi->file, NULL, page_attr, 0, 0, NULL );
1102     if (!mi->mapping)
1103         return FALSE;
1104
1105     mi->base = MapViewOfFile( mi->mapping, perm, 0, 0, mi->size );
1106     if (!mi->base)
1107         return FALSE;
1108
1109     return TRUE;
1110 }
1111
1112 static BOOL unmap_file_from_memory( struct mapping_info *mi )
1113 {
1114     if (mi->base)
1115         UnmapViewOfFile( mi->base );
1116     mi->base = NULL;
1117     if (mi->mapping)
1118         CloseHandle( mi->mapping );
1119     mi->mapping = NULL;
1120     return TRUE;
1121 }
1122
1123 static void destroy_mapping( struct mapping_info *mi )
1124 {
1125     if (!mi)
1126         return;
1127     unmap_file_from_memory( mi );
1128     if (mi->file)
1129         CloseHandle( mi->file );
1130     HeapFree( GetProcessHeap(), 0, mi );
1131 }
1132
1133 static struct mapping_info *create_mapping( LPCWSTR name, BOOL rw )
1134 {
1135     struct mapping_info *mi;
1136
1137     mi = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *mi );
1138     if (!mi)
1139         return NULL;
1140
1141     mi->read_write = rw;
1142
1143     mi->file = CreateFileW( name, GENERIC_READ | (rw ? GENERIC_WRITE : 0),
1144                             0, NULL, OPEN_EXISTING, 0, 0 );
1145
1146     if (mi->file != INVALID_HANDLE_VALUE)
1147     {
1148         mi->size = GetFileSize( mi->file, NULL );
1149
1150         if (map_file_into_memory( mi ))
1151             return mi;
1152     }
1153
1154     unmap_file_from_memory( mi );
1155
1156     return NULL;
1157 }
1158
1159 static BOOL resize_mapping( struct mapping_info *mi, DWORD new_size )
1160 {
1161     if (!unmap_file_from_memory( mi ))
1162         return FALSE;
1163
1164     /* change the file size */
1165     SetFilePointer( mi->file, new_size, NULL, FILE_BEGIN );
1166     if (!SetEndOfFile( mi->file ))
1167     {
1168         ERR("failed to set file size to %08x\n", new_size );
1169         return FALSE;
1170     }
1171
1172     mi->size = new_size;
1173
1174     return map_file_into_memory( mi );
1175 }
1176
1177 static void get_resource_sizes( QUEUEDUPDATES *updates, struct resource_size_info *si )
1178 {
1179     struct resource_dir_entry *types, *names;
1180     struct resource_data *data;
1181     DWORD num_types = 0, num_names = 0, num_langs = 0, strings_size = 0, data_size = 0;
1182
1183     memset( si, 0, sizeof *si );
1184
1185     LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
1186     {
1187         num_types++;
1188         if (HIWORD( types->id ))
1189             strings_size += sizeof (WORD) + lstrlenW( types->id )*sizeof (WCHAR);
1190
1191         LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
1192         {
1193             num_names++;
1194
1195             if (HIWORD( names->id ))
1196                 strings_size += sizeof (WORD) + lstrlenW( names->id )*sizeof (WCHAR);
1197
1198             LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
1199             {
1200                 num_langs++;
1201                 data_size += (data->cbData + 3) & ~3;
1202             }
1203         }
1204     }
1205
1206     /* names are at the end of the types */
1207     si->names_ofs = sizeof (IMAGE_RESOURCE_DIRECTORY) +
1208             num_types * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1209
1210     /* language directories are at the end of the names */
1211     si->langs_ofs = si->names_ofs +
1212             num_types * sizeof (IMAGE_RESOURCE_DIRECTORY) +
1213             num_names * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1214
1215     si->data_entry_ofs = si->langs_ofs +
1216             num_names * sizeof (IMAGE_RESOURCE_DIRECTORY) +
1217             num_langs * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1218
1219     si->strings_ofs = si->data_entry_ofs +
1220             num_langs * sizeof (IMAGE_RESOURCE_DATA_ENTRY);
1221
1222     si->data_ofs = si->strings_ofs + ((strings_size + 3) & ~3);
1223
1224     si->total_size = si->data_ofs + data_size;
1225
1226     TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
1227           si->names_ofs, si->langs_ofs, si->data_entry_ofs,
1228           si->strings_ofs, si->data_ofs, si->total_size);
1229 }
1230
1231 static void res_write_padding( BYTE *res_base, DWORD size )
1232 {
1233     static const BYTE pad[] = {
1234         'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
1235     DWORD i;
1236
1237     for ( i = 0; i < size / sizeof pad; i++ )
1238         memcpy( &res_base[i*sizeof pad], pad, sizeof pad );
1239     memcpy( &res_base[i*sizeof pad], pad, size%sizeof pad );
1240 }
1241
1242 static BOOL write_resources( QUEUEDUPDATES *updates, LPBYTE base, struct resource_size_info *si, DWORD rva )
1243 {
1244     struct resource_dir_entry *types, *names;
1245     struct resource_data *data;
1246     IMAGE_RESOURCE_DIRECTORY *root;
1247
1248     TRACE("%p %p %p %08x\n", updates, base, si, rva );
1249
1250     memset( base, 0, si->total_size );
1251
1252     /* the root entry always exists */
1253     root = (IMAGE_RESOURCE_DIRECTORY*) base;
1254     memset( root, 0, sizeof *root );
1255     root->MajorVersion = 4;
1256     si->types_ofs = sizeof *root;
1257     LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
1258     {
1259         IMAGE_RESOURCE_DIRECTORY_ENTRY *e1;
1260         IMAGE_RESOURCE_DIRECTORY *namedir;
1261
1262         e1 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->types_ofs];
1263         memset( e1, 0, sizeof *e1 );
1264         if (HIWORD( types->id ))
1265         {
1266             WCHAR *strings;
1267             DWORD len;
1268
1269             root->NumberOfNamedEntries++;
1270             e1->u1.s1.NameIsString = 1;
1271             e1->u1.s1.NameOffset = si->strings_ofs;
1272
1273             strings = (WCHAR*) &base[si->strings_ofs];
1274             len = lstrlenW( types->id );
1275             strings[0] = len;
1276             memcpy( &strings[1], types->id, len * sizeof (WCHAR) );
1277             si->strings_ofs += (len + 1) * sizeof (WCHAR);
1278         }
1279         else
1280         {
1281             root->NumberOfIdEntries++;
1282             e1->u1.s2.Id = LOWORD( types->id );
1283         }
1284         e1->u2.s3.OffsetToDirectory = si->names_ofs;
1285         e1->u2.s3.DataIsDirectory = TRUE;
1286         si->types_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1287
1288         namedir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->names_ofs];
1289         memset( namedir, 0, sizeof *namedir );
1290         namedir->MajorVersion = 4;
1291         si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
1292
1293         LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
1294         {
1295             IMAGE_RESOURCE_DIRECTORY_ENTRY *e2;
1296             IMAGE_RESOURCE_DIRECTORY *langdir;
1297
1298             e2 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->names_ofs];
1299             memset( e2, 0, sizeof *e2 );
1300             if (HIWORD( names->id ))
1301             {
1302                 WCHAR *strings;
1303                 DWORD len;
1304
1305                 namedir->NumberOfNamedEntries++;
1306                 e2->u1.s1.NameIsString = 1;
1307                 e2->u1.s1.NameOffset = si->strings_ofs;
1308
1309                 strings = (WCHAR*) &base[si->strings_ofs];
1310                 len = lstrlenW( names->id );
1311                 strings[0] = len;
1312                 memcpy( &strings[1], names->id, len * sizeof (WCHAR) );
1313                 si->strings_ofs += (len + 1) * sizeof (WCHAR);
1314             }
1315             else
1316             {
1317                 namedir->NumberOfIdEntries++;
1318                 e2->u1.s2.Id = LOWORD( names->id );
1319             }
1320             e2->u2.s3.OffsetToDirectory = si->langs_ofs;
1321             e2->u2.s3.DataIsDirectory = TRUE;
1322             si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1323
1324             langdir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->langs_ofs];
1325             memset( langdir, 0, sizeof *langdir );
1326             langdir->MajorVersion = 4;
1327             si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
1328
1329             LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
1330             {
1331                 IMAGE_RESOURCE_DIRECTORY_ENTRY *e3;
1332                 IMAGE_RESOURCE_DATA_ENTRY *de;
1333                 int pad_size;
1334
1335                 e3 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->langs_ofs];
1336                 memset( e3, 0, sizeof *e3 );
1337                 langdir->NumberOfIdEntries++;
1338                 e3->u1.s2.Id = LOWORD( data->lang );
1339                 e3->u2.OffsetToData = si->data_entry_ofs;
1340
1341                 si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1342
1343                 /* write out all the data entries */
1344                 de = (IMAGE_RESOURCE_DATA_ENTRY*) &base[si->data_entry_ofs];
1345                 memset( de, 0, sizeof *de );
1346                 de->OffsetToData = si->data_ofs + rva;
1347                 de->Size = data->cbData;
1348                 de->CodePage = data->codepage;
1349                 si->data_entry_ofs += sizeof (IMAGE_RESOURCE_DATA_ENTRY);
1350
1351                 /* write out the resource data */
1352                 memcpy( &base[si->data_ofs], data->lpData, data->cbData );
1353                 si->data_ofs += data->cbData;
1354
1355                 pad_size = (-si->data_ofs)&3;
1356                 res_write_padding( &base[si->data_ofs], pad_size );
1357                 si->data_ofs += pad_size;
1358             }
1359         }
1360     }
1361
1362     return TRUE;
1363 }
1364
1365 /*
1366  *  FIXME:
1367  *  Assumes that the resources are in .rsrc
1368  *   and .rsrc is the last section in the file.
1369  *  Not sure whether updating resources will other cases on Windows.
1370  *  If the resources lie in a section containing other data,
1371  *   resizing that section could possibly cause trouble.
1372  *  If the section with the resources isn't last, the remaining
1373  *   sections need to be moved down in the file, and the section header
1374  *   would need to be adjusted.
1375  *  If we needed to add a section, what would we name it?
1376  *  If we needed to add a section and there wasn't space in the file
1377  *   header, how would that work?
1378  *  Seems that at least some of these cases can't be handled properly.
1379  */
1380 static IMAGE_SECTION_HEADER *get_resource_section( void *base, DWORD mapping_size )
1381 {
1382     IMAGE_SECTION_HEADER *sec;
1383     IMAGE_NT_HEADERS *nt;
1384     DWORD i, num_sections = 0;
1385
1386     nt = get_nt_header( base, mapping_size );
1387     if (!nt)
1388         return NULL;
1389
1390     sec = get_section_header( base, mapping_size, &num_sections );
1391     if (!sec)
1392         return NULL;
1393
1394     /* find the resources section */
1395     for (i=0; i<num_sections; i++)
1396         if (!memcmp(sec[i].Name, ".rsrc", 6))
1397             break;
1398
1399     if (i == num_sections)
1400     {
1401         FIXME(".rsrc doesn't exist\n");
1402         return NULL;
1403     }
1404
1405     /* check that the resources section is last */
1406     if (i != num_sections - 1)
1407     {
1408         FIXME(".rsrc isn't the last section\n");
1409         return NULL;
1410     }
1411
1412     return &sec[i];
1413 }
1414
1415 static DWORD get_init_data_size( void *base, DWORD mapping_size )
1416 {
1417     DWORD i, sz = 0, num_sections = 0;
1418     IMAGE_SECTION_HEADER *s;
1419
1420     s = get_section_header( base, mapping_size, &num_sections );
1421
1422     for (i=0; i<num_sections; i++)
1423         if (s[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
1424             sz += s[i].SizeOfRawData;
1425
1426     TRACE("size = %08x\n", sz);
1427
1428     return sz;
1429 }
1430
1431 static BOOL write_raw_resources( QUEUEDUPDATES *updates )
1432 {
1433     static const WCHAR prefix[] = { 'r','e','s','u',0 };
1434     WCHAR tempdir[MAX_PATH], tempfile[MAX_PATH];
1435     DWORD mapping_size, section_size, old_size;
1436     BOOL ret = FALSE;
1437     IMAGE_SECTION_HEADER *sec;
1438     IMAGE_NT_HEADERS *nt;
1439     struct resource_size_info res_size;
1440     BYTE *res_base;
1441     struct mapping_info *read_map = NULL, *write_map = NULL;
1442
1443     /* copy the exe to a temp file then update the temp file... */
1444     tempdir[0] = 0;
1445     if (!GetTempPathW( MAX_PATH, tempdir ))
1446         return ret;
1447
1448     if (!GetTempFileNameW( tempdir, prefix, 0, tempfile ))
1449         return ret;
1450
1451     if (!CopyFileW( updates->pFileName, tempfile, FALSE ))
1452         goto done;
1453
1454     TRACE("tempfile %s\n", debugstr_w(tempfile));
1455
1456     if (!updates->bDeleteExistingResources)
1457     {
1458         read_map = create_mapping( updates->pFileName, FALSE );
1459         if (!read_map)
1460             goto done;
1461
1462         ret = read_mapped_resources( updates, read_map->base, read_map->size );
1463         if (!ret)
1464         {
1465             ERR("failed to read existing resources\n");
1466             goto done;
1467         }
1468     }
1469
1470     write_map = create_mapping( tempfile, TRUE );
1471     if (!write_map)
1472         goto done;
1473
1474     nt = get_nt_header( write_map->base, write_map->size );
1475     if (!nt)
1476         goto done;
1477
1478     if (nt->OptionalHeader.SectionAlignment <= 0)
1479     {
1480         ERR("invalid section alignment %04x\n", nt->OptionalHeader.SectionAlignment);
1481         goto done;
1482     }
1483
1484     sec = get_resource_section( write_map->base, write_map->size );
1485     if (!sec)
1486         goto done;
1487
1488     if ((sec->SizeOfRawData + sec->PointerToRawData) != write_map->size)
1489     {
1490         FIXME(".rsrc isn't at the end of the image %08x + %08x != %08x\n",
1491             sec->SizeOfRawData, sec->PointerToRawData, write_map->size);
1492         goto done;
1493     }
1494
1495     TRACE("before .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1496
1497     get_resource_sizes( updates, &res_size );
1498
1499     /* round up the section size */
1500     section_size = res_size.total_size;
1501     section_size += (-section_size) % nt->OptionalHeader.SectionAlignment;
1502
1503     mapping_size = sec->PointerToRawData + section_size;
1504
1505     TRACE("requires %08x (%08x) bytes\n", res_size.total_size, section_size );
1506
1507     /* check if the file size needs to be changed */
1508     if (section_size != sec->SizeOfRawData)
1509     {
1510         old_size = write_map->size;
1511
1512         TRACE("file size %08x -> %08x\n", old_size, mapping_size);
1513
1514         /* unmap the file before changing the file size */
1515         ret = resize_mapping( write_map, mapping_size );
1516
1517         /* get the pointers again - they might be different after remapping */
1518         nt = get_nt_header( write_map->base, mapping_size );
1519         if (!nt)
1520         {
1521             ERR("couldn't get NT header\n");
1522             goto done;
1523         }
1524
1525         sec = get_resource_section( write_map->base, mapping_size );
1526         if (!sec)
1527              goto done;
1528
1529         /* adjust the PE header information */
1530         nt->OptionalHeader.SizeOfImage += (mapping_size - old_size);
1531         sec->SizeOfRawData = section_size;
1532         sec->Misc.VirtualSize = section_size;
1533         nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = res_size.total_size;
1534         nt->OptionalHeader.SizeOfInitializedData = get_init_data_size( write_map->base, mapping_size );
1535     }
1536
1537     res_base = (LPBYTE) write_map->base + sec->PointerToRawData;
1538
1539     TRACE("base = %p offset = %08x\n", write_map->base, sec->PointerToRawData);
1540
1541     ret = write_resources( updates, res_base, &res_size, sec->VirtualAddress );
1542
1543     res_write_padding( res_base + res_size.total_size, section_size - res_size.total_size );
1544
1545     TRACE("after  .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1546
1547 done:
1548     destroy_mapping( read_map );
1549     destroy_mapping( write_map );
1550
1551     if (ret)
1552         ret = CopyFileW( tempfile, updates->pFileName, FALSE );
1553
1554     DeleteFileW( tempfile );
1555
1556     return ret;
1557 }
1558
1559 /***********************************************************************
1560  *          BeginUpdateResourceW                 (KERNEL32.@)
1561  */
1562 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
1563 {
1564     QUEUEDUPDATES *updates = NULL;
1565     HANDLE hUpdate, file, ret = NULL;
1566
1567     TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
1568
1569     hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES));
1570     if (!hUpdate)
1571         return ret;
1572
1573     updates = GlobalLock(hUpdate);
1574     if (updates)
1575     {
1576         list_init( &updates->root );
1577         updates->bDeleteExistingResources = bDeleteExistingResources;
1578         updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
1579         if (updates->pFileName)
1580         {
1581             lstrcpyW(updates->pFileName, pFileName);
1582
1583             file = CreateFileW( pFileName, GENERIC_READ | GENERIC_WRITE,
1584                                 0, NULL, OPEN_EXISTING, 0, 0 );
1585
1586             /* if resources are deleted, only the file's presence is checked */
1587             if (file != INVALID_HANDLE_VALUE &&
1588                 (bDeleteExistingResources || check_pe_exe( file, updates )))
1589                 ret = hUpdate;
1590             else
1591                 HeapFree( GetProcessHeap(), 0, updates->pFileName );
1592
1593             CloseHandle( file );
1594         }
1595         GlobalUnlock(hUpdate);
1596     }
1597
1598     if (!ret)
1599         GlobalFree(hUpdate);
1600
1601     return ret;
1602 }
1603
1604
1605 /***********************************************************************
1606  *          BeginUpdateResourceA                 (KERNEL32.@)
1607  */
1608 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
1609 {
1610     UNICODE_STRING FileNameW;
1611     HANDLE ret;
1612     RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
1613     ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
1614     RtlFreeUnicodeString(&FileNameW);
1615     return ret;
1616 }
1617
1618
1619 /***********************************************************************
1620  *          EndUpdateResourceW                 (KERNEL32.@)
1621  */
1622 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
1623 {
1624     QUEUEDUPDATES *updates;
1625     BOOL ret;
1626
1627     TRACE("%p %d\n", hUpdate, fDiscard);
1628
1629     updates = GlobalLock(hUpdate);
1630     if (!updates)
1631         return FALSE;
1632
1633     ret = fDiscard || write_raw_resources( updates );
1634
1635     free_resource_directory( &updates->root, 2 );
1636
1637     HeapFree( GetProcessHeap(), 0, updates->pFileName );
1638     GlobalUnlock( hUpdate );
1639     GlobalFree( hUpdate );
1640
1641     return ret;
1642 }
1643
1644
1645 /***********************************************************************
1646  *          EndUpdateResourceA                 (KERNEL32.@)
1647  */
1648 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
1649 {
1650     return EndUpdateResourceW(hUpdate, fDiscard);
1651 }
1652
1653
1654 /***********************************************************************
1655  *           UpdateResourceW                 (KERNEL32.@)
1656  */
1657 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
1658                              WORD wLanguage, LPVOID lpData, DWORD cbData)
1659 {
1660     QUEUEDUPDATES *updates;
1661     BOOL ret = FALSE;
1662
1663     TRACE("%p %s %s %08x %p %d\n", hUpdate,
1664           debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
1665
1666     updates = GlobalLock(hUpdate);
1667     if (updates)
1668     {
1669         struct resource_data *data;
1670         data = allocate_resource_data( wLanguage, 0, lpData, cbData, TRUE );
1671         if (data)
1672             ret = update_add_resource( updates, lpType, lpName, data, TRUE );
1673         GlobalUnlock(hUpdate);
1674     }
1675     return ret;
1676 }
1677
1678
1679 /***********************************************************************
1680  *           UpdateResourceA                 (KERNEL32.@)
1681  */
1682 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
1683                              WORD wLanguage, LPVOID lpData, DWORD cbData)
1684 {
1685     BOOL ret;
1686     UNICODE_STRING TypeW;
1687     UNICODE_STRING NameW;
1688     if(!HIWORD(lpType))
1689         TypeW.Buffer = (LPWSTR)lpType;
1690     else
1691         RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
1692     if(!HIWORD(lpName))
1693         NameW.Buffer = (LPWSTR)lpName;
1694     else
1695         RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
1696     ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
1697     if(HIWORD(lpType)) RtlFreeUnicodeString(&TypeW);
1698     if(HIWORD(lpName)) RtlFreeUnicodeString(&NameW);
1699     return ret;
1700 }