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