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