Subversion Repositories filter_foundry

Rev

Rev 433 | 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
418 daniel-mar 535
        // Reported in https://bugs.winehq.org/show_bug.cgi?id=52121
406 daniel-mar 536
        // RtlUpcaseUnicodeString(str, str, FALSE);
537
        // For our implementation, this simple inplace function works:
538
        _InplaceRtlUpcaseUnicodeString(str);
539
 
402 daniel-mar 540
        return STATUS_SUCCESS;
541
    }
542
}
543
 
544
/*
545
HRSRC WINAPI WineFindResourceExA(HMODULE module, LPCSTR type, LPCSTR name, WORD lang)
546
{
547
    NTSTATUS status;
548
    UNICODE_STRING nameW, typeW;
549
    HRSRC ret = NULL;
550
 
551
    //TRACE("%p %s %s %04x\n", module, debugstr_a(type), debugstr_a(name), lang);
552
 
553
    if (!module) module = GetModuleHandleW(0);
554
    nameW.Buffer = NULL;
555
    typeW.Buffer = NULL;
556
 
557
    //__TRY
558
    //{
559
    if (!(status = get_res_nameA(name, &nameW)) && !(status = get_res_nameA(type, &typeW)))
560
        ret = WineFindResourceExW(module, typeW.Buffer, nameW.Buffer, lang);
561
    else
562
        SetLastError(1); // RtlNtStatusToDosError(status)
563
    //}
564
    //__EXCEPT_PAGE_FAULT
565
    //{
566
    //    SetLastError(ERROR_INVALID_PARAMETER);
567
    //}
568
    //__ENDTRY
569
 
570
    if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree(GetProcessHeap(), 0, nameW.Buffer);
571
    if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree(GetProcessHeap(), 0, typeW.Buffer);
572
    return ret;
573
}
574
 
575
HRSRC WINAPI WineFindResourceA(HMODULE hModule, LPCSTR name, LPCSTR type)
576
{
577
    return WineFindResourceExA(hModule, type, name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
578
}
579
 
580
BOOL WINAPI WineEnumResourceTypesA(HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG_PTR lparam)
581
{
582
    return WineEnumResourceTypesExA(hmod, lpfun, lparam, 0, 0);
583
}
584
 
585
BOOL WINAPI WineEnumResourceTypesW(HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG_PTR lparam)
586
{
587
    return WineEnumResourceTypesExW(hmod, lpfun, lparam, 0, 0);
588
}
589
 
590
BOOL WINAPI WineEnumResourceNamesA(HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG_PTR lparam)
591
{
592
    return WineEnumResourceNamesExA(hmod, type, lpfun, lparam, 0, 0);
593
}
594
 
595
BOOL WINAPI WineEnumResourceLanguagesA(HMODULE hmod, LPCSTR type, LPCSTR name,
596
    ENUMRESLANGPROCA lpfun, LONG_PTR lparam)
597
{
598
    return WineEnumResourceLanguagesExA(hmod, type, name, lpfun, lparam, 0, 0);
599
}
600
 
601
BOOL WINAPI WineEnumResourceLanguagesW(HMODULE hmod, LPCWSTR type, LPCWSTR name,
602
    ENUMRESLANGPROCW lpfun, LONG_PTR lparam)
603
{
604
    return WineEnumResourceLanguagesExW(hmod, type, name, lpfun, lparam, 0, 0);
605
}
606
*/
607
 
608
/*
609
 *  Data structure for updating resources.
610
 *  Type/Name/Language is a keyset for accessing resource data.
611
 *
612
 *  QUEUEDUPDATES (root) ->
613
 *    list of struct resource_dir_entry    (Type) ->
614
 *      list of struct resource_dir_entry  (Name)   ->
615
 *         list of struct resource_data    Language + Data
616
 */
617
 
618
typedef struct
619
{
620
    void* unknown[6];
621
    LPSTR pFileName;
622
    BOOL bDeleteExistingResources;
623
    struct list root;
624
} QUEUEDUPDATES;
625
 
626
/* this structure is shared for types and names */
627
struct resource_dir_entry {
628
    struct list entry;
629
    LPWSTR id;
630
    struct list children;
631
};
632
 
633
/* this structure is the leaf */
634
struct resource_data {
635
    struct list entry;
636
    LANGID lang;
637
    DWORD codepage;
638
    DWORD cbData;
639
    void* lpData;
640
};
641
 
642
static int resource_strcmp(LPCWSTR a, LPCWSTR b)
643
{
644
    if (a == b)
645
        return 0;
646
    if (!IS_INTRESOURCE(a) && !IS_INTRESOURCE(b))
647
        return wcscmp(a, b);
648
    /* strings come before ids */
649
    if (!IS_INTRESOURCE(a) && IS_INTRESOURCE(b))
650
        return -1;
651
    if (!IS_INTRESOURCE(b) && IS_INTRESOURCE(a))
652
        return 1;
653
    return (a < b) ? -1 : 1;
654
}
655
 
656
static struct resource_dir_entry* find_resource_dir_entry(struct list* dir, LPCWSTR id)
657
{
658
    struct resource_dir_entry* ent;
659
 
660
    /* match either IDs or strings */
661
    LIST_FOR_EACH_ENTRY(ent, dir, struct resource_dir_entry, entry)
662
        if (!resource_strcmp(id, ent->id))
663
            return ent;
664
 
665
    return NULL;
666
}
667
 
668
static struct resource_data* find_resource_data(struct list* dir, LANGID lang)
669
{
670
    struct resource_data* res_data;
671
 
672
    /* match only languages here */
673
    LIST_FOR_EACH_ENTRY(res_data, dir, struct resource_data, entry)
674
        if (lang == res_data->lang)
675
            return res_data;
676
 
677
    return NULL;
678
}
679
 
680
static void add_resource_dir_entry(struct list* dir, struct resource_dir_entry* resdir)
681
{
682
    struct resource_dir_entry* ent;
683
 
684
    LIST_FOR_EACH_ENTRY(ent, dir, struct resource_dir_entry, entry)
685
    {
686
        if (0 > resource_strcmp(ent->id, resdir->id))
687
            continue;
688
 
689
        list_add_before(&ent->entry, &resdir->entry);
690
        return;
691
    }
692
    list_add_tail(dir, &resdir->entry);
693
}
694
 
695
static void add_resource_data_entry(struct list* dir, struct resource_data* resdata)
696
{
697
    struct resource_data* ent;
698
 
699
    LIST_FOR_EACH_ENTRY(ent, dir, struct resource_data, entry)
700
    {
701
        if (ent->lang < resdata->lang)
702
            continue;
703
 
704
        list_add_before(&ent->entry, &resdata->entry);
705
        return;
706
    }
707
    list_add_tail(dir, &resdata->entry);
708
}
709
 
710
static LPWSTR res_strdupW(LPCWSTR str)
711
{
712
    LPWSTR ret;
713
    UINT len;
714
 
715
    if (IS_INTRESOURCE(str))
716
        return (LPWSTR)(UINT_PTR)LOWORD(str);
717
    len = (lstrlenW(str) + 1) * sizeof(WCHAR);
718
    ret = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len);
405 daniel-mar 719
    if (!ret) return NULL; // Added by Daniel Marschall
402 daniel-mar 720
    memcpy(ret, str, len);
721
    return ret;
722
}
723
 
724
static void res_free_str(LPWSTR str)
725
{
726
    if (!IS_INTRESOURCE(str))
727
        HeapFree(GetProcessHeap(), 0, str);
728
}
729
 
730
static BOOL update_add_resource(QUEUEDUPDATES* updates, LPCWSTR Type, LPCWSTR Name,
731
    LANGID Lang, struct resource_data* resdata,
732
    BOOL overwrite_existing)
733
{
734
    struct resource_dir_entry* restype, * resname;
735
    struct resource_data* existing;
736
 
405 daniel-mar 737
    //TRACE("%p %s %s %p %d\n", updates,
738
    //      debugstr_w(Type), debugstr_w(Name), resdata, overwrite_existing );
739
 
402 daniel-mar 740
    restype = find_resource_dir_entry(&updates->root, Type);
741
    if (!restype)
742
    {
743
        restype = (struct resource_dir_entry*)HeapAlloc(GetProcessHeap(), 0, sizeof(struct resource_dir_entry));
744
        if (!restype) return FALSE;
745
        restype->id = res_strdupW(Type);
746
        list_init(&restype->children);
747
        add_resource_dir_entry(&updates->root, restype);
748
    }
749
 
750
    resname = find_resource_dir_entry(&restype->children, Name);
751
    if (!resname)
752
    {
753
        resname = (struct resource_dir_entry*)HeapAlloc(GetProcessHeap(), 0, sizeof(struct resource_dir_entry));
754
        if (!resname) return FALSE;
755
        resname->id = res_strdupW(Name);
756
        list_init(&resname->children);
757
        add_resource_dir_entry(&restype->children, resname);
758
    }
759
 
760
    /*
761
     * If there's an existing resource entry with matching (Type,Name,Language)
762
     *  it needs to be removed before adding the new data.
763
     */
764
    existing = find_resource_data(&resname->children, Lang);
765
    if (existing)
766
    {
767
        if (!overwrite_existing)
768
            return FALSE;
769
        list_remove(&existing->entry);
770
        HeapFree(GetProcessHeap(), 0, existing);
771
    }
772
 
773
    if (resdata)
774
        add_resource_data_entry(&resname->children, resdata);
775
 
776
    return TRUE;
777
}
778
 
779
static struct resource_data* allocate_resource_data(WORD Language, DWORD codepage,
780
    LPVOID lpData, DWORD cbData, BOOL copy_data)
781
{
782
    struct resource_data* resdata;
783
 
784
    if (!lpData || !cbData)
785
        return NULL;
786
 
787
    resdata = (struct resource_data*)HeapAlloc(GetProcessHeap(), 0, sizeof * resdata + (copy_data ? cbData : 0));
788
    if (resdata)
789
    {
790
        resdata->lang = Language;
791
        resdata->codepage = codepage;
792
        resdata->cbData = cbData;
793
        if (copy_data)
794
        {
795
            resdata->lpData = &resdata[1];
796
            memcpy(resdata->lpData, lpData, cbData);
797
        }
798
        else
799
            resdata->lpData = lpData;
800
    }
801
 
802
    return resdata;
803
}
804
 
805
static void free_resource_directory(struct list* head, int level)
806
{
807
    struct list* ptr = NULL;
808
 
809
    while ((ptr = list_head(head)))
810
    {
811
        list_remove(ptr);
812
        if (level)
813
        {
814
            struct resource_dir_entry* ent;
815
 
816
            ent = LIST_ENTRY(ptr, struct resource_dir_entry, entry);
817
            res_free_str(ent->id);
818
            free_resource_directory(&ent->children, level - 1);
819
            HeapFree(GetProcessHeap(), 0, ent);
820
        }
821
        else
822
        {
823
            struct resource_data* data;
824
 
825
            data = LIST_ENTRY(ptr, struct resource_data, entry);
826
            HeapFree(GetProcessHeap(), 0, data);
827
        }
828
    }
829
}
830
 
831
static IMAGE_NT_HEADERS* get_nt_header(void* base, DWORD mapping_size)
832
{
833
    IMAGE_NT_HEADERS* nt;
834
    IMAGE_DOS_HEADER* dos;
835
 
836
    if (mapping_size < sizeof(*dos))
837
        return NULL;
838
 
839
    dos = (IMAGE_DOS_HEADER*)base;
840
    if (dos->e_magic != IMAGE_DOS_SIGNATURE)
841
        return NULL;
842
 
843
    if ((dos->e_lfanew + sizeof(*nt)) > mapping_size)
844
        return NULL;
845
 
846
    nt = (IMAGE_NT_HEADERS*)((BYTE*)base + dos->e_lfanew);
847
 
848
    if (nt->Signature != IMAGE_NT_SIGNATURE)
849
        return NULL;
850
 
851
    return nt;
852
}
853
 
854
static IMAGE_SECTION_HEADER* get_section_header(void* base, DWORD mapping_size, DWORD* num_sections)
855
{
856
    IMAGE_NT_HEADERS* nt;
857
    DWORD section_ofs;
858
 
859
    nt = get_nt_header(base, mapping_size);
860
    if (!nt)
861
        return NULL;
862
 
863
    /* check that we don't go over the end of the file accessing the sections */
864
    section_ofs = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + nt->FileHeader.SizeOfOptionalHeader;
865
    if ((nt->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + section_ofs) > mapping_size)
866
        return NULL;
867
 
868
    if (num_sections)
869
        *num_sections = nt->FileHeader.NumberOfSections;
870
 
871
    /* from here we have a valid PE exe to update */
872
    return (IMAGE_SECTION_HEADER*)((BYTE*)nt + section_ofs);
873
}
874
 
875
static BOOL check_pe_exe(HANDLE file, QUEUEDUPDATES* updates)
876
{
877
    const IMAGE_NT_HEADERS32* nt;
878
    //const IMAGE_NT_HEADERS64* nt64;
879
    const IMAGE_SECTION_HEADER* sec;
880
    //const IMAGE_DATA_DIRECTORY* dd;
881
    BOOL ret = FALSE;
882
    HANDLE mapping;
883
    DWORD mapping_size, num_sections = 0;
884
    void* base = NULL;
885
 
433 daniel-mar 886
    UNREFERENCED_PARAMETER(updates);
887
 
402 daniel-mar 888
    mapping_size = GetFileSize(file, NULL);
889
 
890
    mapping = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL);
891
    if (!mapping)
892
        goto done;
893
 
894
    base = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, mapping_size);
895
    if (!base)
896
        goto done;
897
 
898
    nt = (IMAGE_NT_HEADERS32*)get_nt_header(base, mapping_size);
899
    if (!nt)
900
        goto done;
901
 
405 daniel-mar 902
    //Fix by Daniel Marschall: Removed, because the variables are not used!
402 daniel-mar 903
    //nt64 = (IMAGE_NT_HEADERS64*)nt;
904
    //dd = &nt->OptionalHeader.DataDirectory[0];
905
    //if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
906
    //    dd = &nt64->OptionalHeader.DataDirectory[0];
405 daniel-mar 907
    //TRACE("resources: %08x %08x\n",
908
    //      dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
909
    //      dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
402 daniel-mar 910
 
911
    sec = get_section_header(base, mapping_size, &num_sections);
912
    if (!sec)
913
        goto done;
914
 
915
    ret = TRUE;
916
 
917
done:
918
    if (base)
919
        UnmapViewOfFile(base);
920
    if (mapping)
921
        CloseHandle(mapping);
922
 
923
    return ret;
924
}
925
 
926
struct resource_size_info {
927
    DWORD types_ofs;
928
    DWORD names_ofs;
929
    DWORD langs_ofs;
930
    DWORD data_entry_ofs;
931
    DWORD strings_ofs;
932
    DWORD data_ofs;
933
    DWORD total_size;
934
};
935
 
936
struct mapping_info {
937
    HANDLE file;
938
    void* base;
939
    DWORD size;
940
    BOOL read_write;
941
};
942
 
943
static const IMAGE_SECTION_HEADER* section_from_rva(void* base, DWORD mapping_size, DWORD rva)
944
{
945
    const IMAGE_SECTION_HEADER* sec;
946
    DWORD num_sections = 0;
947
    int i;
948
 
949
    sec = get_section_header(base, mapping_size, &num_sections);
950
    if (!sec)
951
        return NULL;
952
 
953
    for (i = num_sections - 1; i >= 0; i--)
954
    {
955
        if (sec[i].VirtualAddress <= rva &&
956
            rva <= (DWORD)sec[i].VirtualAddress + sec[i].SizeOfRawData)
957
        {
958
            return &sec[i];
959
        }
960
    }
961
 
962
    return NULL;
963
}
964
 
965
static void* address_from_rva(void* base, DWORD mapping_size, DWORD rva, DWORD len)
966
{
967
    const IMAGE_SECTION_HEADER* sec;
968
 
969
    sec = section_from_rva(base, mapping_size, rva);
970
    if (!sec)
971
        return NULL;
972
 
973
    if (rva + len <= (DWORD)sec->VirtualAddress + sec->SizeOfRawData)
974
        return (void*)((LPBYTE)base + (sec->PointerToRawData + rva - sec->VirtualAddress));
975
 
976
    return NULL;
977
}
978
 
979
static LPWSTR resource_dup_string(const IMAGE_RESOURCE_DIRECTORY* root, const MyIMAGE_RESOURCE_DIRECTORY_ENTRY* entry)
980
{
981
    const IMAGE_RESOURCE_DIR_STRING_U* string;
982
    LPWSTR s;
983
 
984
    if (!entry->u.s.NameIsString)
985
        return (LPWSTR)UIntToPtr(entry->u.Id);
986
 
987
    string = (const IMAGE_RESOURCE_DIR_STRING_U*)(((const char*)root) + entry->u.s.NameOffset);
988
    s = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (string->Length + 1) * sizeof(WCHAR));
989
    if (!s) return NULL;
990
    memcpy(s, string->NameString, (string->Length + 1) * sizeof(WCHAR));
991
    s[string->Length] = 0;
992
 
993
    return s;
994
}
995
 
405 daniel-mar 996
/* this function is based on the code in winedump's pe.c */
402 daniel-mar 997
static BOOL enumerate_mapped_resources(QUEUEDUPDATES* updates,
998
    void* base, DWORD mapping_size,
999
    const IMAGE_RESOURCE_DIRECTORY* root)
1000
{
1001
    const IMAGE_RESOURCE_DIRECTORY* namedir, * langdir;
1002
    const MyIMAGE_RESOURCE_DIRECTORY_ENTRY* e1, * e2, * e3;
1003
    const IMAGE_RESOURCE_DATA_ENTRY* data;
1004
    DWORD i, j, k;
1005
 
405 daniel-mar 1006
    //TRACE("version (%d.%d) %d named %d id entries\n",
1007
    //      root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
1008
 
402 daniel-mar 1009
    for (i = 0; i < (DWORD)root->NumberOfNamedEntries + (DWORD)root->NumberOfIdEntries; i++)
1010
    {
1011
        LPWSTR Type;
1012
 
1013
        e1 = (const MyIMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
1014
 
1015
        Type = resource_dup_string(root, e1);
1016
 
1017
        namedir = (const IMAGE_RESOURCE_DIRECTORY*)((const char*)root + e1->u2.s2.OffsetToDirectory);
1018
        for (j = 0; j < (DWORD)namedir->NumberOfNamedEntries + (DWORD)namedir->NumberOfIdEntries; j++)
1019
        {
1020
            LPWSTR Name;
1021
 
1022
            e2 = (const MyIMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
1023
 
1024
            Name = resource_dup_string(root, e2);
1025
 
1026
            langdir = (const IMAGE_RESOURCE_DIRECTORY*)((const char*)root + e2->u2.s2.OffsetToDirectory);
1027
            for (k = 0; k < (DWORD)langdir->NumberOfNamedEntries + (DWORD)langdir->NumberOfIdEntries; k++)
1028
            {
1029
                LANGID Lang;
1030
                void* p;
1031
                struct resource_data* resdata;
1032
 
1033
                e3 = (const MyIMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
1034
 
1035
                Lang = e3->u.Id;
1036
 
1037
                data = (const IMAGE_RESOURCE_DATA_ENTRY*)((const char*)root + e3->u2.OffsetToData);
1038
 
1039
                p = address_from_rva(base, mapping_size, data->OffsetToData, data->Size);
1040
 
1041
                resdata = allocate_resource_data(Lang, data->CodePage, p, data->Size, FALSE);
1042
                if (resdata)
1043
                {
1044
                    if (!update_add_resource(updates, Type, Name, Lang, resdata, FALSE))
1045
                        HeapFree(GetProcessHeap(), 0, resdata);
1046
                }
1047
            }
1048
            res_free_str(Name);
1049
        }
1050
        res_free_str(Type);
1051
    }
1052
 
1053
    return TRUE;
1054
}
1055
 
1056
static BOOL read_mapped_resources(QUEUEDUPDATES* updates, void* base, DWORD mapping_size)
1057
{
1058
    const IMAGE_RESOURCE_DIRECTORY* root;
1059
    const IMAGE_NT_HEADERS* nt;
1060
    const IMAGE_SECTION_HEADER* sec;
1061
    DWORD num_sections = 0, i;
1062
 
1063
    nt = get_nt_header(base, mapping_size);
1064
    if (!nt)
1065
        return FALSE;
1066
 
1067
    sec = get_section_header(base, mapping_size, &num_sections);
1068
    if (!sec)
1069
        return FALSE;
1070
 
1071
    for (i = 0; i < num_sections; i++)
1072
        if (!memcmp(sec[i].Name, ".rsrc", 6))
1073
            break;
1074
 
1075
    if (i == num_sections)
1076
        return TRUE;
1077
 
1078
    /* check the resource data is inside the mapping */
1079
    if (sec[i].PointerToRawData > mapping_size ||
1080
        (sec[i].PointerToRawData + sec[i].SizeOfRawData) > mapping_size)
1081
        return TRUE;
1082
 
405 daniel-mar 1083
    //TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
1084
 
402 daniel-mar 1085
    if (!sec[i].PointerToRawData || sec[i].SizeOfRawData < sizeof(IMAGE_RESOURCE_DIRECTORY))
1086
        return TRUE;
1087
 
1088
    root = (IMAGE_RESOURCE_DIRECTORY*)((BYTE*)base + sec[i].PointerToRawData);
1089
    enumerate_mapped_resources(updates, base, mapping_size, root);
1090
 
1091
    return TRUE;
1092
}
1093
 
1094
static BOOL map_file_into_memory(struct mapping_info* mi)
1095
{
1096
    DWORD page_attr, perm;
1097
    HANDLE mapping;
1098
 
1099
    if (mi->read_write)
1100
    {
1101
        page_attr = PAGE_READWRITE;
1102
        perm = FILE_MAP_WRITE | FILE_MAP_READ;
1103
    }
1104
    else
1105
    {
1106
        page_attr = PAGE_READONLY;
1107
        perm = FILE_MAP_READ;
1108
    }
1109
 
1110
    mapping = CreateFileMappingA(mi->file, NULL, page_attr, 0, 0, NULL);
1111
    if (!mapping) return FALSE;
1112
 
1113
    mi->base = MapViewOfFile(mapping, perm, 0, 0, mi->size);
1114
    CloseHandle(mapping);
1115
 
1116
    return mi->base != NULL;
1117
}
1118
 
1119
static BOOL unmap_file_from_memory(struct mapping_info* mi)
1120
{
1121
    if (mi->base)
1122
        UnmapViewOfFile(mi->base);
1123
    mi->base = NULL;
1124
    return TRUE;
1125
}
1126
 
1127
static void destroy_mapping(struct mapping_info* mi)
1128
{
1129
    if (!mi)
1130
        return;
1131
    unmap_file_from_memory(mi);
1132
    if (mi->file)
1133
        CloseHandle(mi->file);
1134
    HeapFree(GetProcessHeap(), 0, mi);
1135
}
1136
 
1137
static struct mapping_info* create_mapping(LPCSTR filename, BOOL rw)
1138
{
1139
    struct mapping_info* mi;
1140
 
405 daniel-mar 1141
    // TODO: Which Windows version supports HEAP_ZERO_MEMORY? Can we safely use it, or is memset() safer?
402 daniel-mar 1142
    mi = (struct mapping_info*)HeapAlloc(GetProcessHeap(), 0/*HEAP_ZERO_MEMORY*/, sizeof * mi);
1143
    if (!mi) {
1144
        return NULL;
1145
    }
1146
    memset(mi, 0, sizeof * mi);
1147
 
1148
    mi->read_write = rw;
1149
 
405 daniel-mar 1150
    // Fix by Daniel Marschall: Changed "0" to "FILE_SHARE_READ | (rw ? FILE_SHARE_WRITE : 0)"
418 daniel-mar 1151
    // Reported in https://bugs.winehq.org/show_bug.cgi?id=52121
402 daniel-mar 1152
    mi->file = CreateFileA(filename, GENERIC_READ | (rw ? GENERIC_WRITE : 0),
1153
        FILE_SHARE_READ | (rw ? FILE_SHARE_WRITE : 0), NULL, OPEN_EXISTING, 0, 0);
1154
 
1155
    if (mi->file != INVALID_HANDLE_VALUE)
1156
    {
1157
        mi->size = GetFileSize(mi->file, NULL);
1158
 
405 daniel-mar 1159
        if (map_file_into_memory(mi))
402 daniel-mar 1160
            return mi;
1161
    }
1162
    destroy_mapping(mi);
1163
    return NULL;
1164
}
1165
 
1166
static BOOL resize_mapping(struct mapping_info* mi, DWORD new_size)
1167
{
1168
    if (!unmap_file_from_memory(mi))
1169
        return FALSE;
1170
 
1171
    /* change the file size */
1172
    SetFilePointer(mi->file, new_size, NULL, FILE_BEGIN);
1173
    if (!SetEndOfFile(mi->file))
1174
    {
1175
        //ERR("failed to set file size to %08x\n", new_size);
1176
        return FALSE;
1177
    }
1178
 
1179
    mi->size = new_size;
1180
 
1181
    return map_file_into_memory(mi);
1182
}
1183
 
1184
static void get_resource_sizes(QUEUEDUPDATES* updates, struct resource_size_info* si)
1185
{
1186
    struct resource_dir_entry* types, * names;
1187
    struct resource_data* data;
1188
    DWORD num_types = 0, num_names = 0, num_langs = 0, strings_size = 0, data_size = 0;
1189
 
1190
    memset(si, 0, sizeof * si);
1191
 
1192
    LIST_FOR_EACH_ENTRY(types, &updates->root, struct resource_dir_entry, entry)
1193
    {
1194
        num_types++;
1195
        if (!IS_INTRESOURCE(types->id))
1196
            strings_size += sizeof(WORD) + lstrlenW(types->id) * sizeof(WCHAR);
1197
 
1198
        LIST_FOR_EACH_ENTRY(names, &types->children, struct resource_dir_entry, entry)
1199
        {
1200
            num_names++;
1201
 
1202
            if (!IS_INTRESOURCE(names->id))
1203
                strings_size += sizeof(WORD) + lstrlenW(names->id) * sizeof(WCHAR);
1204
 
1205
            LIST_FOR_EACH_ENTRY(data, &names->children, struct resource_data, entry)
1206
            {
1207
                num_langs++;
1208
                data_size += (data->cbData + 3) & ~3;
1209
            }
1210
        }
1211
    }
1212
 
1213
    /* names are at the end of the types */
1214
    si->names_ofs = sizeof(IMAGE_RESOURCE_DIRECTORY) +
1215
        num_types * sizeof(MyIMAGE_RESOURCE_DIRECTORY_ENTRY);
1216
 
1217
    /* language directories are at the end of the names */
1218
    si->langs_ofs = si->names_ofs +
1219
        num_types * sizeof(IMAGE_RESOURCE_DIRECTORY) +
1220
        num_names * sizeof(MyIMAGE_RESOURCE_DIRECTORY_ENTRY);
1221
 
1222
    si->data_entry_ofs = si->langs_ofs +
1223
        num_names * sizeof(IMAGE_RESOURCE_DIRECTORY) +
1224
        num_langs * sizeof(MyIMAGE_RESOURCE_DIRECTORY_ENTRY);
1225
 
1226
    si->strings_ofs = si->data_entry_ofs +
1227
        num_langs * sizeof(IMAGE_RESOURCE_DATA_ENTRY);
1228
 
1229
    si->data_ofs = si->strings_ofs + ((strings_size + 3) & ~3);
1230
 
1231
    si->total_size = si->data_ofs + data_size;
405 daniel-mar 1232
 
1233
    //TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
1234
    //      si->names_ofs, si->langs_ofs, si->data_entry_ofs,
1235
    //      si->strings_ofs, si->data_ofs, si->total_size);
402 daniel-mar 1236
}
1237
 
1238
static void res_write_padding(BYTE* res_base, DWORD size)
1239
{
1240
    static const BYTE pad[] = {
1241
        'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
1242
    DWORD i;
1243
 
1244
    for (i = 0; i < size / sizeof pad; i++)
1245
        memcpy(&res_base[i * sizeof pad], pad, sizeof pad);
1246
    memcpy(&res_base[i * sizeof pad], pad, size % sizeof pad);
1247
}
1248
 
1249
static BOOL write_resources(QUEUEDUPDATES* updates, LPBYTE base, struct resource_size_info* si, DWORD rva)
1250
{
1251
    struct resource_dir_entry* types, * names;
1252
    struct resource_data* data;
1253
    IMAGE_RESOURCE_DIRECTORY* root;
1254
 
405 daniel-mar 1255
    //TRACE("%p %p %p %08x\n", updates, base, si, rva );
1256
 
402 daniel-mar 1257
    memset(base, 0, si->total_size);
1258
 
1259
    /* the root entry always exists */
1260
    root = (IMAGE_RESOURCE_DIRECTORY*)base;
1261
    memset(root, 0, sizeof * root);
1262
    root->MajorVersion = 4;
1263
    si->types_ofs = sizeof * root;
1264
    LIST_FOR_EACH_ENTRY(types, &updates->root, struct resource_dir_entry, entry)
1265
    {
1266
        MyIMAGE_RESOURCE_DIRECTORY_ENTRY* e1;
1267
        IMAGE_RESOURCE_DIRECTORY* namedir;
1268
 
1269
        e1 = (MyIMAGE_RESOURCE_DIRECTORY_ENTRY*)&base[si->types_ofs];
1270
        memset(e1, 0, sizeof * e1);
1271
        if (!IS_INTRESOURCE(types->id))
1272
        {
1273
            WCHAR* strings;
1274
            DWORD len;
1275
 
1276
            root->NumberOfNamedEntries++;
1277
            e1->u.s.NameIsString = 1;
1278
            e1->u.s.NameOffset = si->strings_ofs;
1279
 
1280
            strings = (WCHAR*)&base[si->strings_ofs];
1281
            len = lstrlenW(types->id);
1282
            strings[0] = (WCHAR)len;
1283
            memcpy(&strings[1], types->id, len * sizeof(WCHAR));
1284
            si->strings_ofs += (len + 1) * sizeof(WCHAR);
1285
        }
1286
        else
1287
        {
1288
            root->NumberOfIdEntries++;
1289
            e1->u.Id = LOWORD(types->id);
1290
        }
1291
        e1->u2.s2.OffsetToDirectory = si->names_ofs;
1292
        e1->u2.s2.DataIsDirectory = TRUE;
1293
        si->types_ofs += sizeof(MyIMAGE_RESOURCE_DIRECTORY_ENTRY);
1294
 
1295
        namedir = (IMAGE_RESOURCE_DIRECTORY*)&base[si->names_ofs];
1296
        memset(namedir, 0, sizeof * namedir);
1297
        namedir->MajorVersion = 4;
1298
        si->names_ofs += sizeof(IMAGE_RESOURCE_DIRECTORY);
1299
 
1300
        LIST_FOR_EACH_ENTRY(names, &types->children, struct resource_dir_entry, entry)
1301
        {
1302
            MyIMAGE_RESOURCE_DIRECTORY_ENTRY* e2;
1303
            IMAGE_RESOURCE_DIRECTORY* langdir;
1304
 
1305
            e2 = (MyIMAGE_RESOURCE_DIRECTORY_ENTRY*)&base[si->names_ofs];
1306
            memset(e2, 0, sizeof * e2);
1307
            if (!IS_INTRESOURCE(names->id))
1308
            {
1309
                WCHAR* strings;
1310
                DWORD len;
1311
 
1312
                namedir->NumberOfNamedEntries++;
1313
                e2->u.s.NameIsString = 1;
1314
                e2->u.s.NameOffset = si->strings_ofs;
1315
 
1316
                strings = (WCHAR*)&base[si->strings_ofs];
1317
                len = lstrlenW(names->id);
1318
                strings[0] = (WCHAR)len;
1319
                memcpy(&strings[1], names->id, len * sizeof(WCHAR));
1320
                si->strings_ofs += (len + 1) * sizeof(WCHAR);
1321
            }
1322
            else
1323
            {
1324
                namedir->NumberOfIdEntries++;
1325
                e2->u.Id = LOWORD(names->id);
1326
            }
1327
            e2->u2.s2.OffsetToDirectory = si->langs_ofs;
1328
            e2->u2.s2.DataIsDirectory = TRUE;
1329
            si->names_ofs += sizeof(MyIMAGE_RESOURCE_DIRECTORY_ENTRY);
1330
 
1331
            langdir = (IMAGE_RESOURCE_DIRECTORY*)&base[si->langs_ofs];
1332
            memset(langdir, 0, sizeof * langdir);
1333
            langdir->MajorVersion = 4;
1334
            si->langs_ofs += sizeof(IMAGE_RESOURCE_DIRECTORY);
1335
 
1336
            LIST_FOR_EACH_ENTRY(data, &names->children, struct resource_data, entry)
1337
            {
1338
                MyIMAGE_RESOURCE_DIRECTORY_ENTRY* e3;
1339
                IMAGE_RESOURCE_DATA_ENTRY* de;
1340
                int pad_size;
1341
 
1342
                e3 = (MyIMAGE_RESOURCE_DIRECTORY_ENTRY*)&base[si->langs_ofs];
1343
                memset(e3, 0, sizeof * e3);
1344
                langdir->NumberOfIdEntries++;
1345
                e3->u.Id = LOWORD(data->lang);
1346
                e3->u2.OffsetToData = si->data_entry_ofs;
1347
 
1348
                si->langs_ofs += sizeof(MyIMAGE_RESOURCE_DIRECTORY_ENTRY);
1349
 
1350
                /* write out all the data entries */
1351
                de = (IMAGE_RESOURCE_DATA_ENTRY*)&base[si->data_entry_ofs];
1352
                memset(de, 0, sizeof * de);
1353
                de->OffsetToData = si->data_ofs + rva;
1354
                de->Size = data->cbData;
1355
                de->CodePage = data->codepage;
1356
                si->data_entry_ofs += sizeof(IMAGE_RESOURCE_DATA_ENTRY);
1357
 
1358
                /* write out the resource data */
1359
                memcpy(&base[si->data_ofs], data->lpData, data->cbData);
1360
                si->data_ofs += data->cbData;
1361
 
1362
                pad_size = (-(int)si->data_ofs) & 3;
1363
                res_write_padding(&base[si->data_ofs], pad_size);
1364
                si->data_ofs += pad_size;
1365
            }
1366
        }
1367
    }
1368
 
1369
    return TRUE;
1370
}
1371
 
405 daniel-mar 1372
/*
1373
 *  FIXME:
1374
 *  Assumes that the resources are in .rsrc
1375
 *   and .rsrc is the last section in the file.
1376
 *  Not sure whether updating resources will other cases on Windows.
1377
 *  If the resources lie in a section containing other data,
1378
 *   resizing that section could possibly cause trouble.
1379
 *  If the section with the resources isn't last, the remaining
1380
 *   sections need to be moved down in the file, and the section header
1381
 *   would need to be adjusted.
1382
 *  If we needed to add a section, what would we name it?
1383
 *  If we needed to add a section and there wasn't space in the file
1384
 *   header, how would that work?
1385
 *  Seems that at least some of these cases can't be handled properly.
1386
 */
402 daniel-mar 1387
static IMAGE_SECTION_HEADER* get_resource_section(void* base, DWORD mapping_size)
1388
{
1389
    IMAGE_SECTION_HEADER* sec;
1390
    IMAGE_NT_HEADERS* nt;
1391
    DWORD i, num_sections = 0;
1392
 
1393
    nt = get_nt_header(base, mapping_size);
1394
    if (!nt)
1395
        return NULL;
1396
 
1397
    sec = get_section_header(base, mapping_size, &num_sections);
1398
    if (!sec)
1399
        return NULL;
1400
 
1401
    /* find the resources section */
1402
    for (i = 0; i < num_sections; i++)
1403
        if (!memcmp(sec[i].Name, ".rsrc", 6))
1404
            break;
1405
 
1406
    if (i == num_sections)
1407
        return NULL;
1408
 
1409
    return &sec[i];
1410
}
1411
 
415 daniel-mar 1412
static IMAGE_SECTION_HEADER* get_last_section(void* base, DWORD mapping_size)
1413
{
1414
    // Fix by Fix by Daniel Marschall: Added this function which is required by the "SizeOfImage" field calculation
418 daniel-mar 1415
    // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
415 daniel-mar 1416
 
1417
    IMAGE_SECTION_HEADER* sec;
1418
    IMAGE_NT_HEADERS* nt;
1419
    DWORD num_sections = 0;
1420
 
1421
    nt = get_nt_header(base, mapping_size);
1422
    if (!nt)
1423
        return NULL;
1424
 
1425
    sec = get_section_header(base, mapping_size, &num_sections);
1426
    if (!sec)
1427
        return NULL;
1428
 
1429
    /* find the resources section */
1430
    return &sec[num_sections - 1];
1431
}
1432
 
402 daniel-mar 1433
static DWORD get_init_data_size(void* base, DWORD mapping_size)
1434
{
1435
    DWORD i, sz = 0, num_sections = 0;
1436
    IMAGE_SECTION_HEADER* s;
1437
 
1438
    s = get_section_header(base, mapping_size, &num_sections);
1439
 
1440
    for (i = 0; i < num_sections; i++)
1441
        if (s[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
1442
            sz += s[i].SizeOfRawData;
1443
 
405 daniel-mar 1444
    //TRACE("size = %08x\n", sz);
1445
 
402 daniel-mar 1446
    return sz;
1447
}
1448
 
415 daniel-mar 1449
//
1450
// peRoundUpToAlignment() - rounds dwValue up to nearest dwAlign
1451
//
1452
DWORD peRoundUpToAlignment(DWORD dwAlign, DWORD dwVal)
1453
{
1454
    // Fix by Fix by Daniel Marschall: Added this function, based on
1455
    // https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
418 daniel-mar 1456
    // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
415 daniel-mar 1457
    if (dwAlign)
1458
    {
1459
        //do the rounding with bitwise operations...
1460
 
1461
        //create bit mask of bits to keep
1462
        //  e.g. if section alignment is 0x1000                        1000000000000
1463
        //       we want the following bitmask      11111111111111111111000000000000
1464
        DWORD dwMask = ~(dwAlign - 1);
1465
 
1466
        //round up by adding full alignment (dwAlign-1 since if already aligned we don't want anything to change),
1467
        //  then mask off any lower bits
1468
        dwVal = (dwVal + dwAlign - 1) & dwMask;
1469
    }
1470
 
1471
    return(dwVal);
1472
 
416 daniel-mar 1473
}
415 daniel-mar 1474
 
416 daniel-mar 1475
ULONGLONG peRoundUpToAlignment64(ULONGLONG dwAlign, ULONGLONG dwVal)
1476
{
1477
    // Fix by Fix by Daniel Marschall: Added this function, based on
1478
    // https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
418 daniel-mar 1479
    // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
416 daniel-mar 1480
    if (dwAlign)
1481
    {
1482
        //do the rounding with bitwise operations...
1483
 
1484
        //create bit mask of bits to keep
1485
        //  e.g. if section alignment is 0x1000                        1000000000000
1486
        //       we want the following bitmask      11111111111111111111000000000000
1487
        ULONGLONG dwMask = ~(dwAlign - 1);
1488
 
1489
        //round up by adding full alignment (dwAlign-1 since if already aligned we don't want anything to change),
1490
        //  then mask off any lower bits
1491
        dwVal = (dwVal + dwAlign - 1) & dwMask;
1492
    }
1493
 
1494
    return(dwVal);
1495
 
1496
}
1497
 
402 daniel-mar 1498
static BOOL write_raw_resources(QUEUEDUPDATES* updates)
1499
{
1500
    CHAR tempdir[MAX_PATH], tempfile[MAX_PATH];
1501
    DWORD i, section_size;
1502
    BOOL ret = FALSE;
415 daniel-mar 1503
    IMAGE_SECTION_HEADER* sec, *lastsec;
402 daniel-mar 1504
    IMAGE_NT_HEADERS32* nt;
1505
    IMAGE_NT_HEADERS64* nt64;
1506
    struct resource_size_info res_size;
1507
    BYTE* res_base;
1508
    struct mapping_info* read_map = NULL, * write_map = NULL;
1509
    DWORD PeSectionAlignment, PeFileAlignment, PeSizeOfImage;
1510
 
1511
    /* copy the exe to a temp file then update the temp file... */
1512
    tempdir[0] = 0;
405 daniel-mar 1513
    if (!GetTempPathA(MAX_PATH, tempdir))
402 daniel-mar 1514
        return ret;
1515
 
405 daniel-mar 1516
    if (!GetTempFileNameA(tempdir, "resu", 0, tempfile))
402 daniel-mar 1517
        return ret;
1518
 
405 daniel-mar 1519
    if (!CopyFileA(updates->pFileName, tempfile, FALSE))
402 daniel-mar 1520
        goto done;
1521
 
405 daniel-mar 1522
    //TRACE("tempfile %s\n", debugstr_w(tempfile));
1523
 
402 daniel-mar 1524
    if (!updates->bDeleteExistingResources)
1525
    {
1526
        read_map = create_mapping(updates->pFileName, FALSE);
405 daniel-mar 1527
        if (!read_map)
402 daniel-mar 1528
            goto done;
1529
 
1530
        ret = read_mapped_resources(updates, read_map->base, read_map->size);
1531
        if (!ret)
1532
        {
1533
            //ERR("failed to read existing resources\n");
1534
            goto done;
1535
        }
1536
    }
1537
 
1538
    write_map = create_mapping(tempfile, TRUE);
405 daniel-mar 1539
    if (!write_map)
402 daniel-mar 1540
        goto done;
1541
 
1542
    nt = (IMAGE_NT_HEADERS32*)get_nt_header(write_map->base, write_map->size);
405 daniel-mar 1543
    if (!nt)
402 daniel-mar 1544
        goto done;
1545
 
1546
    nt64 = (IMAGE_NT_HEADERS64*)nt;
1547
    if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
1548
        PeSectionAlignment = nt64->OptionalHeader.SectionAlignment;
1549
        PeFileAlignment = nt64->OptionalHeader.FileAlignment;
1550
        PeSizeOfImage = nt64->OptionalHeader.SizeOfImage;
1551
    }
1552
    else {
1553
        PeSectionAlignment = nt->OptionalHeader.SectionAlignment;
1554
        PeFileAlignment = nt->OptionalHeader.FileAlignment;
1555
        PeSizeOfImage = nt->OptionalHeader.SizeOfImage;
1556
    }
1557
 
1558
    if ((LONG)PeSectionAlignment <= 0)
1559
    {
1560
        //ERR("invalid section alignment %08x\n", PeSectionAlignment);
1561
        goto done;
1562
    }
1563
 
1564
    if ((LONG)PeFileAlignment <= 0)
1565
    {
1566
        //ERR("invalid file alignment %08x\n", PeFileAlignment);
1567
        goto done;
1568
    }
1569
 
1570
    sec = get_resource_section(write_map->base, write_map->size);
1571
    if (!sec) /* no section, add one */
1572
    {
1573
        DWORD num_sections;
1574
 
1575
        sec = get_section_header(write_map->base, write_map->size, &num_sections);
405 daniel-mar 1576
        if (!sec)
402 daniel-mar 1577
            goto done;
1578
 
1579
        sec += num_sections;
1580
        nt->FileHeader.NumberOfSections++;
1581
 
1582
        memset(sec, 0, sizeof * sec);
1583
        memcpy(sec->Name, ".rsrc", 5);
1584
        sec->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
1585
        sec->VirtualAddress = PeSizeOfImage;
1586
    }
1587
 
1588
    if (!sec->PointerToRawData)  /* empty section */
1589
    {
1590
        sec->PointerToRawData = write_map->size + (-(int)write_map->size) % PeFileAlignment;
1591
        sec->SizeOfRawData = 0;
1592
    }
1593
 
405 daniel-mar 1594
    //TRACE("before .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1595
 
402 daniel-mar 1596
    get_resource_sizes(updates, &res_size);
1597
 
1598
    /* round up the section size */
1599
    section_size = res_size.total_size;
1600
    section_size += (-(int)section_size) % PeFileAlignment;
1601
 
405 daniel-mar 1602
    //TRACE("requires %08x (%08x) bytes\n", res_size.total_size, section_size );
1603
 
402 daniel-mar 1604
    /* check if the file size needs to be changed */
1605
    if (section_size != sec->SizeOfRawData)
1606
    {
1607
        DWORD old_size = write_map->size;
1608
        DWORD virtual_section_size = res_size.total_size + (-(int)res_size.total_size) % PeSectionAlignment;
1609
        int delta = section_size - (sec->SizeOfRawData + (-(int)sec->SizeOfRawData) % PeFileAlignment);
1610
        int rva_delta = virtual_section_size -
1611
            (sec->Misc.VirtualSize + (-(int)sec->Misc.VirtualSize) % PeSectionAlignment);
1612
        /* when new section is added it could end past current mapping size */
1613
        BOOL rsrc_is_last = sec->PointerToRawData + sec->SizeOfRawData >= old_size;
1614
        /* align .rsrc size when possible */
1615
        DWORD mapping_size = rsrc_is_last ? sec->PointerToRawData + section_size : old_size + delta;
1616
 
1617
        /* postpone file truncation if there are some data to be moved down from file end */
1618
        BOOL resize_after = mapping_size < old_size && !rsrc_is_last;
1619
 
405 daniel-mar 1620
        //TRACE("file size %08x -> %08x\n", old_size, mapping_size);
1621
 
402 daniel-mar 1622
        if (!resize_after)
1623
        {
1624
            /* unmap the file before changing the file size */
1625
            ret = resize_mapping(write_map, mapping_size);
1626
 
1627
            /* get the pointers again - they might be different after remapping */
1628
            nt = (IMAGE_NT_HEADERS32*)get_nt_header(write_map->base, mapping_size);
1629
            if (!nt)
1630
            {
1631
                //ERR("couldn't get NT header\n");
1632
                goto done;
1633
            }
1634
            nt64 = (IMAGE_NT_HEADERS64*)nt;
1635
 
1636
            sec = get_resource_section(write_map->base, mapping_size);
405 daniel-mar 1637
            if (!sec)
402 daniel-mar 1638
                goto done;
1639
        }
1640
 
1641
        if (!rsrc_is_last) /* not last section, relocate trailing sections */
1642
        {
1643
            IMAGE_SECTION_HEADER* s;
1644
            DWORD tail_start = sec->PointerToRawData + sec->SizeOfRawData;
1645
            DWORD i, num_sections = 0;
1646
 
1647
            memmove((char*)write_map->base + tail_start + delta, (char*)write_map->base + tail_start, old_size - tail_start);
1648
 
1649
            s = get_section_header(write_map->base, mapping_size, &num_sections);
1650
 
1651
            for (i = 0; i < num_sections; i++)
1652
            {
1653
                if (s[i].PointerToRawData > sec->PointerToRawData)
1654
                {
1655
                    s[i].PointerToRawData += delta;
1656
                    s[i].VirtualAddress += rva_delta;
1657
                }
1658
            }
1659
        }
1660
 
1661
        if (resize_after)
1662
        {
1663
            ret = resize_mapping(write_map, mapping_size);
1664
 
1665
            nt = (IMAGE_NT_HEADERS32*)get_nt_header(write_map->base, mapping_size);
1666
            if (!nt)
1667
            {
1668
                //ERR("couldn't get NT header\n");
1669
                goto done;
1670
            }
1671
            nt64 = (IMAGE_NT_HEADERS64*)nt;
1672
 
1673
            sec = get_resource_section(write_map->base, mapping_size);
405 daniel-mar 1674
            if (!sec)
402 daniel-mar 1675
                goto done;
1676
        }
1677
 
1678
        /* adjust the PE header information */
1679
        sec->SizeOfRawData = section_size;
1680
        sec->Misc.VirtualSize = virtual_section_size;
1681
        if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
416 daniel-mar 1682
            ULONGLONG pEndOfLastSection, pEndOfLastSectionMem, uCalcSizeOfFile;
415 daniel-mar 1683
 
402 daniel-mar 1684
            nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = sec->VirtualAddress;
1685
            nt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = res_size.total_size;
1686
            nt64->OptionalHeader.SizeOfInitializedData = get_init_data_size(write_map->base, mapping_size);
1687
 
1688
            for (i = 0; i < nt64->OptionalHeader.NumberOfRvaAndSizes; i++)
1689
                if (nt64->OptionalHeader.DataDirectory[i].VirtualAddress > sec->VirtualAddress)
1690
                    nt64->OptionalHeader.DataDirectory[i].VirtualAddress += rva_delta;
415 daniel-mar 1691
 
1692
            //nt64->OptionalHeader.SizeOfImage += rva_delta;
1693
            // Fix by Daniel Marschall: Added this calculation of "SizeOfImage".
1694
            // With the original implementation, Windows won't load some images!
1695
            // https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
418 daniel-mar 1696
            // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
415 daniel-mar 1697
            lastsec = get_last_section(write_map->base, mapping_size);
444 daniel-mar 1698
            pEndOfLastSection = (ULONGLONG)lastsec->VirtualAddress + (ULONGLONG)lastsec->Misc.VirtualSize + nt64->OptionalHeader.ImageBase;
415 daniel-mar 1699
            //NOTE: we are rounding to memory section alignment, not file
416 daniel-mar 1700
            pEndOfLastSectionMem = peRoundUpToAlignment64(nt64->OptionalHeader.SectionAlignment, pEndOfLastSection);
415 daniel-mar 1701
            uCalcSizeOfFile = pEndOfLastSectionMem - nt64->OptionalHeader.ImageBase;
416 daniel-mar 1702
            nt64->OptionalHeader.SizeOfImage = (DWORD)uCalcSizeOfFile;
402 daniel-mar 1703
        }
1704
        else {
415 daniel-mar 1705
            DWORD pEndOfLastSection, pEndOfLastSectionMem, uCalcSizeOfFile;
1706
 
402 daniel-mar 1707
            nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = sec->VirtualAddress;
1708
            nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = res_size.total_size;
1709
            nt->OptionalHeader.SizeOfInitializedData = get_init_data_size(write_map->base, mapping_size);
1710
 
1711
            for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
1712
                if (nt->OptionalHeader.DataDirectory[i].VirtualAddress > sec->VirtualAddress)
1713
                    nt->OptionalHeader.DataDirectory[i].VirtualAddress += rva_delta;
415 daniel-mar 1714
 
1715
            //nt->OptionalHeader.SizeOfImage += rva_delta;
1716
            // Fix by Daniel Marschall: Added this calculation of "SizeOfImage".
1717
            // With the original implementation, Windows won't load some images!
1718
            // https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
418 daniel-mar 1719
            // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
415 daniel-mar 1720
            lastsec = get_last_section(write_map->base, mapping_size);
1721
            pEndOfLastSection = lastsec->VirtualAddress + lastsec->Misc.VirtualSize + nt->OptionalHeader.ImageBase;
1722
            //NOTE: we are rounding to memory section alignment, not file
1723
            pEndOfLastSectionMem = peRoundUpToAlignment(nt->OptionalHeader.SectionAlignment, pEndOfLastSection);
1724
            uCalcSizeOfFile = pEndOfLastSectionMem - nt->OptionalHeader.ImageBase;
1725
            nt->OptionalHeader.SizeOfImage = uCalcSizeOfFile;
402 daniel-mar 1726
        }
1727
    }
1728
 
1729
    res_base = (LPBYTE)write_map->base + sec->PointerToRawData;
1730
 
405 daniel-mar 1731
    //TRACE("base = %p offset = %08x\n", write_map->base, sec->PointerToRawData);
1732
 
402 daniel-mar 1733
    ret = write_resources(updates, res_base, &res_size, sec->VirtualAddress);
1734
 
1735
    res_write_padding(res_base + res_size.total_size, section_size - res_size.total_size);
1736
 
405 daniel-mar 1737
    //TRACE("after  .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1738
 
402 daniel-mar 1739
done:
1740
    destroy_mapping(read_map);
1741
    destroy_mapping(write_map);
1742
 
405 daniel-mar 1743
    if (ret)
402 daniel-mar 1744
        ret = CopyFileA(tempfile, updates->pFileName, FALSE);
1745
 
1746
    DeleteFileA(tempfile);
1747
 
1748
    return ret;
1749
}
1750
 
1751
// ------------------------------------------------------------------------------------------------------------------------
1752
 
1753
HANDLE WINAPI WineBeginUpdateResourceA(LPCSTR pFileName, BOOL bDeleteExistingResources)
1754
{
1755
    QUEUEDUPDATES* updates = NULL;
1756
    HANDLE hUpdate, file, ret = NULL;
1757
 
405 daniel-mar 1758
    //TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
1759
 
402 daniel-mar 1760
    hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES));
1761
    if (!hUpdate)
1762
        return ret;
1763
 
1764
    updates = (QUEUEDUPDATES*)GlobalLock(hUpdate);
1765
    if (updates)
1766
    {
1767
        list_init(&updates->root);
1768
        updates->bDeleteExistingResources = bDeleteExistingResources;
1769
        updates->pFileName = (LPSTR)HeapAlloc(GetProcessHeap(), 0, (lstrlenA(pFileName) + 1) * sizeof(CHAR));
1770
        if (updates->pFileName)
1771
        {
1772
            lstrcpyA(updates->pFileName, pFileName);
1773
 
405 daniel-mar 1774
            // Fix by Daniel Marschall: Changed "GENERIC_READ | GENERIC_WRITE, 0" to "GENERIC_READ, FILE_SHARE_READ"
418 daniel-mar 1775
            // Reported in https://bugs.winehq.org/show_bug.cgi?id=52121
402 daniel-mar 1776
            file = CreateFileA(pFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
1777
 
1778
            /* if resources are deleted, only the file's presence is checked */
1779
            if (file != INVALID_HANDLE_VALUE &&
1780
                (bDeleteExistingResources || check_pe_exe(file, updates)))
1781
                ret = hUpdate;
1782
            else
1783
                HeapFree(GetProcessHeap(), 0, updates->pFileName);
1784
 
1785
            CloseHandle(file);
1786
        }
1787
        GlobalUnlock(hUpdate);
1788
    }
1789
 
1790
    if (!ret)
1791
        GlobalFree(hUpdate);
1792
 
1793
    return ret;
1794
}
1795
 
1796
BOOL WINAPI WineEndUpdateResourceA(HANDLE hUpdate, BOOL fDiscard)
1797
{
1798
    QUEUEDUPDATES* updates;
1799
    BOOL ret;
1800
 
405 daniel-mar 1801
    // TRACE("%p %d\n", hUpdate, fDiscard);
1802
 
402 daniel-mar 1803
    updates = (QUEUEDUPDATES*)GlobalLock(hUpdate);
405 daniel-mar 1804
    if (!updates)
402 daniel-mar 1805
        return FALSE;
1806
 
1807
    ret = fDiscard || write_raw_resources(updates);
1808
 
1809
    free_resource_directory(&updates->root, 2);
1810
 
1811
    HeapFree(GetProcessHeap(), 0, updates->pFileName);
1812
    GlobalUnlock(hUpdate);
1813
    GlobalFree(hUpdate);
1814
 
1815
    return ret;
1816
}
1817
 
1818
BOOL WINAPI WineUpdateResourceA(HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
1819
    WORD wLanguage, LPVOID lpData, DWORD cbData)
1820
{
1821
    QUEUEDUPDATES* updates;
1822
    UNICODE_STRING nameW, typeW;
1823
    BOOL ret = FALSE;
1824
 
405 daniel-mar 1825
    //TRACE("%p %s %s %08x %p %d\n", hUpdate,
1826
    //      debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
1827
 
402 daniel-mar 1828
    nameW.Buffer = typeW.Buffer = NULL;
1829
    updates = (QUEUEDUPDATES*)GlobalLock(hUpdate);
1830
    if (updates)
1831
    {
1832
        if (!set_ntstatus(get_res_nameA(lpName, &nameW))) goto done;
1833
        if (!set_ntstatus(get_res_nameA(lpType, &typeW))) goto done;
1834
 
1835
        if (lpData == NULL && cbData == 0)  /* remove resource */
1836
        {
1837
            ret = update_add_resource(updates, typeW.Buffer, nameW.Buffer, wLanguage, NULL, TRUE);
1838
        }
1839
        else
1840
        {
1841
            struct resource_data* data;
1842
            data = allocate_resource_data(wLanguage, 0, lpData, cbData, TRUE);
1843
            if (data)
1844
                ret = update_add_resource(updates, typeW.Buffer, nameW.Buffer, wLanguage, data, TRUE);
1845
        }
1846
 
1847
    done:
1848
        GlobalUnlock(hUpdate);
1849
    }
1850
 
1851
    if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree(GetProcessHeap(), 0, nameW.Buffer);
1852
    if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree(GetProcessHeap(), 0, typeW.Buffer);
1853
    return ret;
1854
}