Subversion Repositories filter_foundry

Rev

Rev 405 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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