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