Subversion Repositories filter_foundry

Rev

Rev 433 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     32/64 bit "standalone" ASCII Resource Modification methods for Win9x compatibility
  3.     includes many fixes (marked with "Fix by Daniel Marschall" comment)
  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
  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?!
  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
  127. // Attention: These supplements are VERY simple and they ONLY accept ASCII!
  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.  
  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.  
  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.  
  514.  /* retrieve the resource name to pass to the ntdll functions */
  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);
  533.  
  534.         // Fix by Daniel Marschall: Added RtlUpcaseUnicodeString for get_res_nameA, like it was done for get_res_nameW
  535.         // Reported in https://bugs.winehq.org/show_bug.cgi?id=52121
  536.         // RtlUpcaseUnicodeString(str, str, FALSE);
  537.         // For our implementation, this simple inplace function works:
  538.         _InplaceRtlUpcaseUnicodeString(str);
  539.        
  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);
  719.     if (!ret) return NULL; // Added by Daniel Marschall
  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.  
  737.     //TRACE("%p %s %s %p %d\n", updates,
  738.     //      debugstr_w(Type), debugstr_w(Name), resdata, overwrite_existing );
  739.  
  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.  
  886.     UNREFERENCED_PARAMETER(updates);
  887.  
  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.  
  902.     //Fix by Daniel Marschall: Removed, because the variables are not used!
  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];
  907.     //TRACE("resources: %08x %08x\n",
  908.     //      dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
  909.     //      dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
  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.  
  996. /* this function is based on the code in winedump's pe.c */
  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.  
  1006.     //TRACE("version (%d.%d) %d named %d id entries\n",
  1007.     //      root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
  1008.  
  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.  
  1083.     //TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
  1084.  
  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.  
  1141.     // TODO: Which Windows version supports HEAP_ZERO_MEMORY? Can we safely use it, or is memset() safer?
  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.  
  1150.     // Fix by Daniel Marschall: Changed "0" to "FILE_SHARE_READ | (rw ? FILE_SHARE_WRITE : 0)"
  1151.     // Reported in https://bugs.winehq.org/show_bug.cgi?id=52121
  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.  
  1159.         if (map_file_into_memory(mi))
  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;
  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);
  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.  
  1255.     //TRACE("%p %p %p %08x\n", updates, base, si, rva );
  1256.  
  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.  
  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.  */
  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.  
  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
  1415.     // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
  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.  
  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.  
  1444.     //TRACE("size = %08x\n", sz);
  1445.  
  1446.     return sz;
  1447. }
  1448.  
  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
  1456.     // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
  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.  
  1473. }
  1474.  
  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
  1479.     // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
  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.  
  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;
  1503.     IMAGE_SECTION_HEADER* sec, *lastsec;
  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;
  1513.     if (!GetTempPathA(MAX_PATH, tempdir))
  1514.         return ret;
  1515.  
  1516.     if (!GetTempFileNameA(tempdir, "resu", 0, tempfile))
  1517.         return ret;
  1518.  
  1519.     if (!CopyFileA(updates->pFileName, tempfile, FALSE))
  1520.         goto done;
  1521.  
  1522.     //TRACE("tempfile %s\n", debugstr_w(tempfile));
  1523.  
  1524.     if (!updates->bDeleteExistingResources)
  1525.     {
  1526.         read_map = create_mapping(updates->pFileName, FALSE);
  1527.         if (!read_map)
  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);
  1539.     if (!write_map)
  1540.         goto done;
  1541.  
  1542.     nt = (IMAGE_NT_HEADERS32*)get_nt_header(write_map->base, write_map->size);
  1543.     if (!nt)
  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);
  1576.         if (!sec)
  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.  
  1594.     //TRACE("before .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
  1595.  
  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.  
  1602.     //TRACE("requires %08x (%08x) bytes\n", res_size.total_size, section_size );
  1603.  
  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.  
  1620.         //TRACE("file size %08x -> %08x\n", old_size, mapping_size);
  1621.  
  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);
  1637.             if (!sec)
  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);
  1674.             if (!sec)
  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) {
  1682.             ULONGLONG pEndOfLastSection, pEndOfLastSectionMem, uCalcSizeOfFile;
  1683.  
  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;
  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
  1696.             // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
  1697.             lastsec = get_last_section(write_map->base, mapping_size);
  1698.             pEndOfLastSection = (ULONGLONG)lastsec->VirtualAddress + (ULONGLONG)lastsec->Misc.VirtualSize + nt64->OptionalHeader.ImageBase;
  1699.             //NOTE: we are rounding to memory section alignment, not file
  1700.             pEndOfLastSectionMem = peRoundUpToAlignment64(nt64->OptionalHeader.SectionAlignment, pEndOfLastSection);
  1701.             uCalcSizeOfFile = pEndOfLastSectionMem - nt64->OptionalHeader.ImageBase;
  1702.             nt64->OptionalHeader.SizeOfImage = (DWORD)uCalcSizeOfFile;
  1703.         }
  1704.         else {
  1705.             DWORD pEndOfLastSection, pEndOfLastSectionMem, uCalcSizeOfFile;
  1706.  
  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;
  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
  1719.             // Reported Wine bug here: https://bugs.winehq.org/show_bug.cgi?id=52119
  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;
  1726.         }
  1727.     }
  1728.  
  1729.     res_base = (LPBYTE)write_map->base + sec->PointerToRawData;
  1730.  
  1731.     //TRACE("base = %p offset = %08x\n", write_map->base, sec->PointerToRawData);
  1732.  
  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.  
  1737.     //TRACE("after  .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
  1738.  
  1739. done:
  1740.     destroy_mapping(read_map);
  1741.     destroy_mapping(write_map);
  1742.  
  1743.     if (ret)
  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.  
  1758.     //TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
  1759.  
  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.  
  1774.             // Fix by Daniel Marschall: Changed "GENERIC_READ | GENERIC_WRITE, 0" to "GENERIC_READ, FILE_SHARE_READ"
  1775.             // Reported in https://bugs.winehq.org/show_bug.cgi?id=52121
  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.  
  1801.     // TRACE("%p %d\n", hUpdate, fDiscard);
  1802.  
  1803.     updates = (QUEUEDUPDATES*)GlobalLock(hUpdate);
  1804.     if (!updates)
  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.  
  1825.     //TRACE("%p %s %s %08x %p %d\n", hUpdate,
  1826.     //      debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
  1827.  
  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. }
  1855.