Subversion Repositories filter_foundry

Rev

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