ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

res.c
Go to the documentation of this file.
00001 /*
00002  * Resources
00003  *
00004  * Copyright 1993 Robert J. Amstadt
00005  * Copyright 1995, 2003 Alexandre Julliard
00006  * Copyright 2006 Mike McCormack
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 //#include "config.h"
00024 //#include "wine/port.h"
00025 
00026 #include <stdarg.h>
00027 
00028 #define NONAMELESSUNION
00029 #define NONAMELESSSTRUCT
00030 #include "ntstatus.h"
00031 #define WIN32_NO_STATUS
00032 #include "windef.h"
00033 #include "winbase.h"
00034 #include "winternl.h"
00035 #include "wine/debug.h"
00036 #include "wine/exception.h"
00037 #include "wine/unicode.h"
00038 #include "wine/list.h"
00039 
00040 #define HeapAlloc RtlAllocateHeap
00041 #define HeapReAlloc RtlReAllocateHeap
00042 #define HeapFree RtlFreeHeap
00043 WINE_DEFAULT_DEBUG_CHANNEL(resource);
00044 
00045 /* we don't want to include winuser.h just for this */
00046 #define IS_INTRESOURCE(x)   (((ULONG_PTR)(x) >> 16) == 0)
00047 
00048 /* retrieve the resource name to pass to the ntdll functions */
00049 static NTSTATUS get_res_nameA( LPCSTR name, UNICODE_STRING *str )
00050 {
00051     if (IS_INTRESOURCE(name))
00052     {
00053         str->Buffer = ULongToPtr(LOWORD(name));
00054         return STATUS_SUCCESS;
00055     }
00056     if (name[0] == '#')
00057     {
00058         ULONG value;
00059         if (RtlCharToInteger( name + 1, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
00060             return STATUS_INVALID_PARAMETER;
00061         str->Buffer = ULongToPtr(value);
00062         return STATUS_SUCCESS;
00063     }
00064     RtlCreateUnicodeStringFromAsciiz( str, name );
00065     RtlUpcaseUnicodeString( str, str, FALSE );
00066     return STATUS_SUCCESS;
00067 }
00068 
00069 /* retrieve the resource name to pass to the ntdll functions */
00070 static NTSTATUS get_res_nameW( LPCWSTR name, UNICODE_STRING *str )
00071 {
00072     if (IS_INTRESOURCE(name))
00073     {
00074         str->Buffer = ULongToPtr(LOWORD(name));
00075         return STATUS_SUCCESS;
00076     }
00077     if (name[0] == '#')
00078     {
00079         ULONG value;
00080         RtlInitUnicodeString( str, name + 1 );
00081         if (RtlUnicodeStringToInteger( str, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
00082             return STATUS_INVALID_PARAMETER;
00083         str->Buffer = ULongToPtr(value);
00084         return STATUS_SUCCESS;
00085     }
00086     RtlCreateUnicodeString( str, name );
00087     RtlUpcaseUnicodeString( str, str, FALSE );
00088     return STATUS_SUCCESS;
00089 }
00090 
00091 /* implementation of FindResourceExA */
00092 static HRSRC find_resourceA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
00093 {
00094     NTSTATUS status;
00095     UNICODE_STRING nameW, typeW;
00096     LDR_RESOURCE_INFO info;
00097     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
00098 
00099     nameW.Buffer = NULL;
00100     typeW.Buffer = NULL;
00101 
00102     __TRY
00103     {
00104         if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS) goto done;
00105         if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS) goto done;
00106         info.Type = (ULONG_PTR)typeW.Buffer;
00107         info.Name = (ULONG_PTR)nameW.Buffer;
00108         info.Language = lang;
00109         status = LdrFindResource_U( hModule, &info, 3, &entry );
00110     done:
00111         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00112     }
00113     __EXCEPT_PAGE_FAULT
00114     {
00115         SetLastError( ERROR_INVALID_PARAMETER );
00116     }
00117     __ENDTRY
00118 
00119     if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
00120     if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
00121     return (HRSRC)entry;
00122 }
00123 
00124 
00125 /* implementation of FindResourceExW */
00126 static HRSRC find_resourceW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
00127 {
00128     NTSTATUS status;
00129     UNICODE_STRING nameW, typeW;
00130     LDR_RESOURCE_INFO info;
00131     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
00132 
00133     nameW.Buffer = typeW.Buffer = NULL;
00134 
00135     __TRY
00136     {
00137         if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS) goto done;
00138         if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS) goto done;
00139         info.Type = (ULONG_PTR)typeW.Buffer;
00140         info.Name = (ULONG_PTR)nameW.Buffer;
00141         info.Language = lang;
00142         status = LdrFindResource_U( hModule, &info, 3, &entry );
00143     done:
00144         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00145     }
00146     __EXCEPT_PAGE_FAULT
00147     {
00148         SetLastError( ERROR_INVALID_PARAMETER );
00149     }
00150     __ENDTRY
00151 
00152     if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
00153     if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
00154     return (HRSRC)entry;
00155 }
00156 
00157 /**********************************************************************
00158  *      FindResourceExA  (KERNEL32.@)
00159  */
00160 HRSRC WINAPI FindResourceExA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
00161 {
00162     TRACE( "%p %s %s %04x\n", hModule, debugstr_a(type), debugstr_a(name), lang );
00163 
00164     if (!hModule) hModule = GetModuleHandleW(0);
00165     return find_resourceA( hModule, type, name, lang );
00166 }
00167 
00168 
00169 /**********************************************************************
00170  *      FindResourceA    (KERNEL32.@)
00171  */
00172 HRSRC WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
00173 {
00174     return FindResourceExA( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
00175 }
00176 
00177 
00178 /**********************************************************************
00179  *      FindResourceExW  (KERNEL32.@)
00180  */
00181 HRSRC WINAPI FindResourceExW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
00182 {
00183     TRACE( "%p %s %s %04x\n", hModule, debugstr_w(type), debugstr_w(name), lang );
00184 
00185     if (!hModule) hModule = GetModuleHandleW(0);
00186     return find_resourceW( hModule, type, name, lang );
00187 }
00188 
00189 
00190 /**********************************************************************
00191  *      FindResourceW    (KERNEL32.@)
00192  */
00193 HRSRC WINAPI FindResourceW( HINSTANCE hModule, LPCWSTR name, LPCWSTR type )
00194 {
00195     return FindResourceExW( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
00196 }
00197 
00198 
00199 /**********************************************************************
00200  *  EnumResourceTypesA  (KERNEL32.@)
00201  */
00202 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG_PTR lparam )
00203 {
00204     int i;
00205     BOOL ret = FALSE;
00206     LPSTR type = NULL;
00207     DWORD len = 0, newlen;
00208     NTSTATUS status;
00209     const IMAGE_RESOURCE_DIRECTORY *resdir;
00210     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
00211     const IMAGE_RESOURCE_DIR_STRING_U *str;
00212 
00213     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
00214 
00215     if (!hmod) hmod = GetModuleHandleA( NULL );
00216 
00217     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
00218     {
00219         SetLastError( RtlNtStatusToDosError(status) );
00220         return FALSE;
00221     }
00222     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
00223     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
00224     {
00225         if (et[i].u1.s1.NameIsString)
00226         {
00227             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
00228             newlen = WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
00229             if (newlen + 1 > len)
00230             {
00231                 len = newlen + 1;
00232                 HeapFree( GetProcessHeap(), 0, type );
00233                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
00234             }
00235             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, type, len, NULL, NULL);
00236             type[newlen] = 0;
00237             ret = lpfun(hmod,type,lparam);
00238         }
00239         else
00240         {
00241             ret = lpfun( hmod, UIntToPtr(et[i].u1.Id), lparam );
00242         }
00243         if (!ret) break;
00244     }
00245     HeapFree( GetProcessHeap(), 0, type );
00246     return ret;
00247 }
00248 
00249 
00250 /**********************************************************************
00251  *  EnumResourceTypesW  (KERNEL32.@)
00252  */
00253 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG_PTR lparam )
00254 {
00255     int i, len = 0;
00256     BOOL ret = FALSE;
00257     LPWSTR type = NULL;
00258     NTSTATUS status;
00259     const IMAGE_RESOURCE_DIRECTORY *resdir;
00260     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
00261     const IMAGE_RESOURCE_DIR_STRING_U *str;
00262 
00263     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
00264 
00265     if (!hmod) hmod = GetModuleHandleW( NULL );
00266 
00267     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
00268     {
00269         SetLastError( RtlNtStatusToDosError(status) );
00270         return FALSE;
00271     }
00272     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
00273     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
00274     {
00275         if (et[i].u1.s1.NameIsString)
00276         {
00277             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
00278             if (str->Length + 1 > len)
00279             {
00280                 len = str->Length + 1;
00281                 HeapFree( GetProcessHeap(), 0, type );
00282                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
00283             }
00284             memcpy(type, str->NameString, str->Length * sizeof (WCHAR));
00285             type[str->Length] = 0;
00286             ret = lpfun(hmod,type,lparam);
00287         }
00288         else
00289         {
00290             ret = lpfun( hmod, UIntToPtr(et[i].u1.Id), lparam );
00291         }
00292         if (!ret) break;
00293     }
00294     HeapFree( GetProcessHeap(), 0, type );
00295     return ret;
00296 }
00297 
00298 
00299 /**********************************************************************
00300  *  EnumResourceNamesA  (KERNEL32.@)
00301  */
00302 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG_PTR lparam )
00303 {
00304     int i;
00305     BOOL ret = FALSE;
00306     DWORD len = 0, newlen;
00307     LPSTR name = NULL;
00308     NTSTATUS status;
00309     UNICODE_STRING typeW;
00310     LDR_RESOURCE_INFO info;
00311     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
00312     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
00313     const IMAGE_RESOURCE_DIR_STRING_U *str;
00314 
00315     TRACE( "%p %s %p %lx\n", hmod, debugstr_a(type), lpfun, lparam );
00316 
00317     if (!hmod) hmod = GetModuleHandleA( NULL );
00318     typeW.Buffer = NULL;
00319     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
00320         goto done;
00321     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
00322         goto done;
00323     info.Type = (ULONG_PTR)typeW.Buffer;
00324     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
00325         goto done;
00326 
00327     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
00328     __TRY
00329     {
00330         for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
00331         {
00332             if (et[i].u1.s1.NameIsString)
00333             {
00334                 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
00335                 newlen = WideCharToMultiByte(CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
00336                 if (newlen + 1 > len)
00337                 {
00338                     len = newlen + 1;
00339                     HeapFree( GetProcessHeap(), 0, name );
00340                     if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
00341                     {
00342                         ret = FALSE;
00343                         break;
00344                     }
00345                 }
00346                 WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, name, len, NULL, NULL );
00347                 name[newlen] = 0;
00348                 ret = lpfun(hmod,type,name,lparam);
00349             }
00350             else
00351             {
00352                 ret = lpfun( hmod, type, UIntToPtr(et[i].u1.Id), lparam );
00353             }
00354             if (!ret) break;
00355         }
00356     }
00357     __EXCEPT_PAGE_FAULT
00358     {
00359         ret = FALSE;
00360         status = STATUS_ACCESS_VIOLATION;
00361     }
00362     __ENDTRY;
00363 
00364 done:
00365     HeapFree( GetProcessHeap(), 0, name );
00366     if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
00367     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00368     return ret;
00369 }
00370 
00371 
00372 /**********************************************************************
00373  *  EnumResourceNamesW  (KERNEL32.@)
00374  */
00375 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG_PTR lparam )
00376 {
00377     int i, len = 0;
00378     BOOL ret = FALSE;
00379     LPWSTR name = NULL;
00380     NTSTATUS status;
00381     UNICODE_STRING typeW;
00382     LDR_RESOURCE_INFO info;
00383     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
00384     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
00385     const IMAGE_RESOURCE_DIR_STRING_U *str;
00386 
00387     TRACE( "%p %s %p %lx\n", hmod, debugstr_w(type), lpfun, lparam );
00388 
00389     if (!hmod) hmod = GetModuleHandleW( NULL );
00390     typeW.Buffer = NULL;
00391     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
00392         goto done;
00393     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
00394         goto done;
00395     info.Type = (ULONG_PTR)typeW.Buffer;
00396     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
00397         goto done;
00398 
00399     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
00400     __TRY
00401     {
00402         for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
00403         {
00404             if (et[i].u1.s1.NameIsString)
00405             {
00406                 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
00407                 if (str->Length + 1 > len)
00408                 {
00409                     len = str->Length + 1;
00410                     HeapFree( GetProcessHeap(), 0, name );
00411                     if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
00412                     {
00413                         ret = FALSE;
00414                         break;
00415                     }
00416                 }
00417                 memcpy(name, str->NameString, str->Length * sizeof (WCHAR));
00418                 name[str->Length] = 0;
00419                 ret = lpfun(hmod,type,name,lparam);
00420             }
00421             else
00422             {
00423                 ret = lpfun( hmod, type, UIntToPtr(et[i].u1.Id), lparam );
00424             }
00425             if (!ret) break;
00426         }
00427     }
00428     __EXCEPT_PAGE_FAULT
00429     {
00430         ret = FALSE;
00431         status = STATUS_ACCESS_VIOLATION;
00432     }
00433     __ENDTRY
00434 done:
00435     HeapFree( GetProcessHeap(), 0, name );
00436     if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
00437     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00438     return ret;
00439 }
00440 
00441 
00442 /**********************************************************************
00443  *  EnumResourceLanguagesA  (KERNEL32.@)
00444  */
00445 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
00446                                     ENUMRESLANGPROCA lpfun, LONG_PTR lparam )
00447 {
00448     int i;
00449     BOOL ret = FALSE;
00450     NTSTATUS status;
00451     UNICODE_STRING typeW, nameW;
00452     LDR_RESOURCE_INFO info;
00453     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
00454     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
00455 
00456     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_a(type), debugstr_a(name), lpfun, lparam );
00457 
00458     if (!hmod) hmod = GetModuleHandleA( NULL );
00459     typeW.Buffer = nameW.Buffer = NULL;
00460     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
00461         goto done;
00462     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
00463         goto done;
00464     if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS)
00465         goto done;
00466     info.Type = (ULONG_PTR)typeW.Buffer;
00467     info.Name = (ULONG_PTR)nameW.Buffer;
00468     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
00469         goto done;
00470 
00471     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
00472     __TRY
00473     {
00474         for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
00475         {
00476             ret = lpfun( hmod, type, name, et[i].u1.Id, lparam );
00477             if (!ret) break;
00478         }
00479     }
00480     __EXCEPT_PAGE_FAULT
00481     {
00482         ret = FALSE;
00483         status = STATUS_ACCESS_VIOLATION;
00484     }
00485     __ENDTRY
00486 done:
00487     if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
00488     if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
00489     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00490     return ret;
00491 }
00492 
00493 
00494 /**********************************************************************
00495  *  EnumResourceLanguagesW  (KERNEL32.@)
00496  */
00497 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
00498                                     ENUMRESLANGPROCW lpfun, LONG_PTR lparam )
00499 {
00500     int i;
00501     BOOL ret = FALSE;
00502     NTSTATUS status;
00503     UNICODE_STRING typeW, nameW;
00504     LDR_RESOURCE_INFO info;
00505     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
00506     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
00507 
00508     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_w(type), debugstr_w(name), lpfun, lparam );
00509 
00510     if (!hmod) hmod = GetModuleHandleW( NULL );
00511     typeW.Buffer = nameW.Buffer = NULL;
00512     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
00513         goto done;
00514     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
00515         goto done;
00516     if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS)
00517         goto done;
00518     info.Type = (ULONG_PTR)typeW.Buffer;
00519     info.Name = (ULONG_PTR)nameW.Buffer;
00520     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
00521         goto done;
00522 
00523     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
00524     __TRY
00525     {
00526         for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
00527         {
00528             ret = lpfun( hmod, type, name, et[i].u1.Id, lparam );
00529             if (!ret) break;
00530         }
00531     }
00532     __EXCEPT_PAGE_FAULT
00533     {
00534         ret = FALSE;
00535         status = STATUS_ACCESS_VIOLATION;
00536     }
00537     __ENDTRY
00538 done:
00539     if (!IS_INTRESOURCE(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
00540     if (!IS_INTRESOURCE(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
00541     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00542     return ret;
00543 }
00544 
00545 
00546 /**********************************************************************
00547  *      LoadResource     (KERNEL32.@)
00548  */
00549 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
00550 {
00551     NTSTATUS status;
00552     void *ret = NULL;
00553 
00554     TRACE( "%p %p\n", hModule, hRsrc );
00555 
00556     if (!hRsrc) return 0;
00557     if (!hModule) hModule = GetModuleHandleA( NULL );
00558     status = LdrAccessResource( hModule, (IMAGE_RESOURCE_DATA_ENTRY *)hRsrc, &ret, NULL );
00559     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
00560     return ret;
00561 }
00562 
00563 
00564 /**********************************************************************
00565  *      LockResource     (KERNEL32.@)
00566  */
00567 LPVOID WINAPI LockResource( HGLOBAL handle )
00568 {
00569     return handle;
00570 }
00571 
00572 
00573 /**********************************************************************
00574  *      FreeResource     (KERNEL32.@)
00575  */
00576 BOOL WINAPI FreeResource( HGLOBAL handle )
00577 {
00578     return 0;
00579 }
00580 
00581 
00582 /**********************************************************************
00583  *      SizeofResource   (KERNEL32.@)
00584  */
00585 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
00586 {
00587     if (!hRsrc) return 0;
00588     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
00589 }
00590 
00591 /*
00592  *  Data structure for updating resources.
00593  *  Type/Name/Language is a keyset for accessing resource data.
00594  *
00595  *  QUEUEDUPDATES (root) ->
00596  *    list of struct resource_dir_entry    (Type) ->
00597  *      list of struct resource_dir_entry  (Name)   ->
00598  *         list of struct resource_data    Language + Data
00599  */
00600 
00601 typedef struct
00602 {
00603     LPWSTR pFileName;
00604     BOOL bDeleteExistingResources;
00605     struct list root;
00606 } QUEUEDUPDATES;
00607 
00608 /* this structure is shared for types and names */
00609 struct resource_dir_entry {
00610     struct list entry;
00611     LPWSTR id;
00612     struct list children;
00613 };
00614 
00615 /* this structure is the leaf */
00616 struct resource_data {
00617     struct list entry;
00618     LANGID lang;
00619     DWORD codepage;
00620     DWORD cbData;
00621     void *lpData;
00622 };
00623 
00624 static int resource_strcmp( LPCWSTR a, LPCWSTR b )
00625 {
00626     if ( a == b )
00627         return 0;
00628     if (!IS_INTRESOURCE( a ) && !IS_INTRESOURCE( b ) )
00629         return lstrcmpW( a, b );
00630     /* strings come before ids */
00631     if (!IS_INTRESOURCE( a ) && IS_INTRESOURCE( b ))
00632         return -1;
00633     if (!IS_INTRESOURCE( b ) && IS_INTRESOURCE( a ))
00634         return 1;
00635     return ( a < b ) ? -1 : 1;
00636 }
00637 
00638 static struct resource_dir_entry *find_resource_dir_entry( struct list *dir, LPCWSTR id )
00639 {
00640     struct resource_dir_entry *ent;
00641 
00642     /* match either IDs or strings */
00643     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
00644         if (!resource_strcmp( id, ent->id ))
00645             return ent;
00646 
00647     return NULL;
00648 }
00649 
00650 static struct resource_data *find_resource_data( struct list *dir, LANGID lang )
00651 {
00652     struct resource_data *res_data;
00653 
00654     /* match only languages here */
00655     LIST_FOR_EACH_ENTRY( res_data, dir, struct resource_data, entry )
00656         if ( lang == res_data->lang )
00657              return res_data;
00658 
00659     return NULL;
00660 }
00661 
00662 static void add_resource_dir_entry( struct list *dir, struct resource_dir_entry *resdir )
00663 {
00664     struct resource_dir_entry *ent;
00665 
00666     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
00667     {
00668         if (0>resource_strcmp( ent->id, resdir->id ))
00669             continue;
00670 
00671         list_add_before( &ent->entry, &resdir->entry );
00672         return;
00673     }
00674     list_add_tail( dir, &resdir->entry );
00675 }
00676 
00677 static void add_resource_data_entry( struct list *dir, struct resource_data *resdata )
00678 {
00679     struct resource_data *ent;
00680 
00681     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_data, entry )
00682     {
00683         if (ent->lang < resdata->lang)
00684             continue;
00685 
00686         list_add_before( &ent->entry, &resdata->entry );
00687         return;
00688     }
00689     list_add_tail( dir, &resdata->entry );
00690 }
00691 
00692 static LPWSTR res_strdupW( LPCWSTR str )
00693 {
00694     LPWSTR ret;
00695     UINT len;
00696 
00697     if (IS_INTRESOURCE(str))
00698         return (LPWSTR) (UINT_PTR) LOWORD(str);
00699     len = (lstrlenW( str ) + 1) * sizeof (WCHAR);
00700     ret = HeapAlloc( GetProcessHeap(), 0, len );
00701     memcpy( ret, str, len );
00702     return ret;
00703 }
00704 
00705 static void res_free_str( LPWSTR str )
00706 {
00707     if (!IS_INTRESOURCE(str))
00708         HeapFree( GetProcessHeap(), 0, str );
00709 }
00710 
00711 static BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
00712                                  LANGID Lang, struct resource_data *resdata,
00713                                  BOOL overwrite_existing )
00714 {
00715     struct resource_dir_entry *restype, *resname;
00716     struct resource_data *existing;
00717 
00718     TRACE("%p %s %s %p %d\n", updates,
00719           debugstr_w(Type), debugstr_w(Name), resdata, overwrite_existing );
00720 
00721     restype = find_resource_dir_entry( &updates->root, Type );
00722     if (!restype)
00723     {
00724         restype = HeapAlloc( GetProcessHeap(), 0, sizeof *restype );
00725         restype->id = res_strdupW( Type );
00726         list_init( &restype->children );
00727         add_resource_dir_entry( &updates->root, restype );
00728     }
00729 
00730     resname = find_resource_dir_entry( &restype->children, Name );
00731     if (!resname)
00732     {
00733         resname = HeapAlloc( GetProcessHeap(), 0, sizeof *resname );
00734         resname->id = res_strdupW( Name );
00735         list_init( &resname->children );
00736         add_resource_dir_entry( &restype->children, resname );
00737     }
00738 
00739     /*
00740      * If there's an existing resource entry with matching (Type,Name,Language)
00741      *  it needs to be removed before adding the new data.
00742      */
00743     existing = find_resource_data( &resname->children, Lang );
00744     if (existing)
00745     {
00746         if (!overwrite_existing)
00747             return FALSE;
00748         list_remove( &existing->entry );
00749         HeapFree( GetProcessHeap(), 0, existing );
00750     }
00751 
00752     if (resdata)
00753         add_resource_data_entry( &resname->children, resdata );
00754 
00755     return TRUE;
00756 }
00757 
00758 static struct resource_data *allocate_resource_data( WORD Language, DWORD codepage,
00759                                                      LPVOID lpData, DWORD cbData, BOOL copy_data )
00760 {
00761     struct resource_data *resdata;
00762 
00763     if (!lpData || !cbData)
00764         return NULL;
00765 
00766     resdata = HeapAlloc( GetProcessHeap(), 0, sizeof *resdata + (copy_data ? cbData : 0) );
00767     if (resdata)
00768     {
00769         resdata->lang = Language;
00770         resdata->codepage = codepage;
00771         resdata->cbData = cbData;
00772         if (copy_data)
00773         {
00774             resdata->lpData = &resdata[1];
00775             memcpy( resdata->lpData, lpData, cbData );
00776         }
00777         else
00778             resdata->lpData = lpData;
00779     }
00780 
00781     return resdata;
00782 }
00783 
00784 static void free_resource_directory( struct list *head, int level )
00785 {
00786     struct list *ptr = NULL;
00787 
00788     while ((ptr = list_head( head )))
00789     {
00790         list_remove( ptr );
00791         if (level)
00792         {
00793             struct resource_dir_entry *ent;
00794 
00795             ent = LIST_ENTRY( ptr, struct resource_dir_entry, entry );
00796             res_free_str( ent->id );
00797             free_resource_directory( &ent->children, level - 1 );
00798             HeapFree(GetProcessHeap(), 0, ent);
00799         }
00800         else
00801         {
00802             struct resource_data *data;
00803 
00804             data = LIST_ENTRY( ptr, struct resource_data, entry );
00805             HeapFree( GetProcessHeap(), 0, data );
00806         }
00807     }
00808 }
00809 
00810 static IMAGE_NT_HEADERS *get_nt_header( void *base, DWORD mapping_size )
00811 {
00812     IMAGE_NT_HEADERS *nt;
00813     IMAGE_DOS_HEADER *dos;
00814 
00815     if (mapping_size<sizeof (*dos))
00816         return NULL;
00817 
00818     dos = base;
00819     if (dos->e_magic != IMAGE_DOS_SIGNATURE)
00820         return NULL;
00821 
00822     if ((dos->e_lfanew + sizeof (*nt)) > mapping_size)
00823         return NULL;
00824 
00825     nt = (void*) ((BYTE*)base + dos->e_lfanew);
00826 
00827     if (nt->Signature != IMAGE_NT_SIGNATURE)
00828         return NULL;
00829 
00830     return nt;
00831 }
00832 
00833 static IMAGE_SECTION_HEADER *get_section_header( void *base, DWORD mapping_size, DWORD *num_sections )
00834 {
00835     IMAGE_NT_HEADERS *nt;
00836     IMAGE_SECTION_HEADER *sec;
00837     DWORD section_ofs;
00838 
00839     nt = get_nt_header( base, mapping_size );
00840     if (!nt)
00841         return NULL;
00842 
00843     /* check that we don't go over the end of the file accessing the sections */
00844     section_ofs = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + nt->FileHeader.SizeOfOptionalHeader;
00845     if ((nt->FileHeader.NumberOfSections * sizeof (*sec) + section_ofs) > mapping_size)
00846         return NULL;
00847 
00848     if (num_sections)
00849         *num_sections = nt->FileHeader.NumberOfSections;
00850 
00851     /* from here we have a valid PE exe to update */
00852     return (void*) ((BYTE*)nt + section_ofs);
00853 }
00854 
00855 static BOOL check_pe_exe( HANDLE file, QUEUEDUPDATES *updates )
00856 {
00857     const IMAGE_NT_HEADERS *nt;
00858     const IMAGE_SECTION_HEADER *sec;
00859     BOOL ret = FALSE;
00860     HANDLE mapping;
00861     DWORD mapping_size, num_sections = 0;
00862     void *base = NULL;
00863 
00864     mapping_size = GetFileSize( file, NULL );
00865 
00866     mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
00867     if (!mapping)
00868         goto done;
00869 
00870     base = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, mapping_size );
00871     if (!base)
00872         goto done;
00873 
00874     nt = get_nt_header( base, mapping_size );
00875     if (!nt)
00876         goto done;
00877 
00878     TRACE("resources: %08x %08x\n",
00879           nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
00880           nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
00881 
00882     sec = get_section_header( base, mapping_size, &num_sections );
00883     if (!sec)
00884         goto done;
00885 
00886     ret = TRUE;
00887 
00888 done:
00889     if (base)
00890         UnmapViewOfFile( base );
00891     if (mapping)
00892         CloseHandle( mapping );
00893 
00894     return ret;
00895 }
00896 
00897 struct resource_size_info {
00898     DWORD types_ofs;
00899     DWORD names_ofs;
00900     DWORD langs_ofs;
00901     DWORD data_entry_ofs;
00902     DWORD strings_ofs;
00903     DWORD data_ofs;
00904     DWORD total_size;
00905 };
00906 
00907 struct mapping_info {
00908     HANDLE file;
00909     void *base;
00910     DWORD size;
00911     BOOL read_write;
00912 };
00913 
00914 static const IMAGE_SECTION_HEADER *section_from_rva( void *base, DWORD mapping_size, DWORD rva )
00915 {
00916     const IMAGE_SECTION_HEADER *sec;
00917     DWORD num_sections = 0;
00918     int i;
00919 
00920     sec = get_section_header( base, mapping_size, &num_sections );
00921     if (!sec)
00922         return NULL;
00923 
00924     for (i=num_sections-1; i>=0; i--)
00925     {
00926         if (sec[i].VirtualAddress <= rva &&
00927             rva <= (DWORD)sec[i].VirtualAddress + sec[i].SizeOfRawData)
00928         {
00929             return &sec[i];
00930         }
00931     }
00932 
00933     return NULL;
00934 }
00935 
00936 static void *address_from_rva( void *base, DWORD mapping_size, DWORD rva, DWORD len )
00937 {
00938     const IMAGE_SECTION_HEADER *sec;
00939 
00940     sec = section_from_rva( base, mapping_size, rva );
00941     if (!sec)
00942         return NULL;
00943 
00944     if (rva + len <= (DWORD)sec->VirtualAddress + sec->SizeOfRawData)
00945         return (void*)((LPBYTE) base + (sec->PointerToRawData + rva - sec->VirtualAddress));
00946 
00947     return NULL;
00948 }
00949 
00950 static LPWSTR resource_dup_string( const IMAGE_RESOURCE_DIRECTORY *root, const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry )
00951 {
00952     const IMAGE_RESOURCE_DIR_STRING_U* string;
00953     LPWSTR s;
00954 
00955     if (!entry->u1.s1.NameIsString)
00956         return UIntToPtr(entry->u1.Id);
00957 
00958     string = (const IMAGE_RESOURCE_DIR_STRING_U*) (((const char *)root) + entry->u1.s1.NameOffset);
00959     s = HeapAlloc(GetProcessHeap(), 0, (string->Length + 1)*sizeof (WCHAR) );
00960     memcpy( s, string->NameString, (string->Length + 1)*sizeof (WCHAR) );
00961     s[string->Length] = 0;
00962 
00963     return s;
00964 }
00965 
00966 /* this function is based on the code in winedump's pe.c */
00967 static BOOL enumerate_mapped_resources( QUEUEDUPDATES *updates,
00968                              void *base, DWORD mapping_size,
00969                              const IMAGE_RESOURCE_DIRECTORY *root )
00970 {
00971     const IMAGE_RESOURCE_DIRECTORY *namedir, *langdir;
00972     const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
00973     const IMAGE_RESOURCE_DATA_ENTRY *data;
00974     DWORD i, j, k;
00975 
00976     TRACE("version (%d.%d) %d named %d id entries\n",
00977           root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
00978 
00979     for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
00980     {
00981         LPWSTR Type;
00982 
00983         e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
00984 
00985         Type = resource_dup_string( root, e1 );
00986 
00987         namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
00988         for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
00989         {
00990             LPWSTR Name;
00991 
00992             e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
00993 
00994             Name = resource_dup_string( root, e2 );
00995 
00996             langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
00997             for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
00998             {
00999                 LANGID Lang;
01000                 void *p;
01001                 struct resource_data *resdata;
01002 
01003                 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
01004 
01005                 Lang = e3->u1.Id;
01006 
01007                 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
01008 
01009                 p = address_from_rva( base, mapping_size, data->OffsetToData, data->Size );
01010 
01011                 resdata = allocate_resource_data( Lang, data->CodePage, p, data->Size, FALSE );
01012                 if (resdata)
01013                 {
01014                     if (!update_add_resource( updates, Type, Name, Lang, resdata, FALSE ))
01015                         HeapFree( GetProcessHeap(), 0, resdata );
01016                 }
01017             }
01018             res_free_str( Name );
01019         }
01020         res_free_str( Type );
01021     }
01022 
01023     return TRUE;
01024 }
01025 
01026 static BOOL read_mapped_resources( QUEUEDUPDATES *updates, void *base, DWORD mapping_size )
01027 {
01028     const IMAGE_RESOURCE_DIRECTORY *root;
01029     const IMAGE_NT_HEADERS *nt;
01030     const IMAGE_SECTION_HEADER *sec;
01031     DWORD num_sections = 0, i;
01032 
01033     nt = get_nt_header( base, mapping_size );
01034     if (!nt)
01035         return FALSE;
01036 
01037     sec = get_section_header( base, mapping_size, &num_sections );
01038     if (!sec)
01039         return FALSE;
01040 
01041     for (i=0; i<num_sections; i++)
01042         if (!memcmp(sec[i].Name, ".rsrc", 6))
01043             break;
01044 
01045     if (i == num_sections)
01046         return TRUE;
01047 
01048     /* check the resource data is inside the mapping */
01049     if (sec[i].PointerToRawData > mapping_size ||
01050         (sec[i].PointerToRawData + sec[i].SizeOfRawData) > mapping_size)
01051         return TRUE;
01052 
01053     TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
01054 
01055     if (!sec[i].PointerToRawData || sec[i].SizeOfRawData < sizeof(IMAGE_RESOURCE_DIRECTORY))
01056         return TRUE;
01057 
01058     root = (void*) ((BYTE*)base + sec[i].PointerToRawData);
01059     enumerate_mapped_resources( updates, base, mapping_size, root );
01060 
01061     return TRUE;
01062 }
01063 
01064 static BOOL map_file_into_memory( struct mapping_info *mi )
01065 {
01066     DWORD page_attr, perm;
01067     HANDLE mapping;
01068 
01069     if (mi->read_write)
01070     {
01071         page_attr = PAGE_READWRITE;
01072         perm = FILE_MAP_WRITE | FILE_MAP_READ;
01073     }
01074     else
01075     {
01076         page_attr = PAGE_READONLY;
01077         perm = FILE_MAP_READ;
01078     }
01079 
01080     mapping = CreateFileMappingW( mi->file, NULL, page_attr, 0, 0, NULL );
01081     if (!mapping) return FALSE;
01082 
01083     mi->base = MapViewOfFile( mapping, perm, 0, 0, mi->size );
01084     CloseHandle( mapping );
01085 
01086     return mi->base != NULL;
01087 }
01088 
01089 static BOOL unmap_file_from_memory( struct mapping_info *mi )
01090 {
01091     if (mi->base)
01092         UnmapViewOfFile( mi->base );
01093     mi->base = NULL;
01094     return TRUE;
01095 }
01096 
01097 static void destroy_mapping( struct mapping_info *mi )
01098 {
01099     if (!mi)
01100         return;
01101     unmap_file_from_memory( mi );
01102     if (mi->file)
01103         CloseHandle( mi->file );
01104     HeapFree( GetProcessHeap(), 0, mi );
01105 }
01106 
01107 static struct mapping_info *create_mapping( LPCWSTR name, BOOL rw )
01108 {
01109     struct mapping_info *mi;
01110 
01111     mi = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *mi );
01112     if (!mi)
01113         return NULL;
01114 
01115     mi->read_write = rw;
01116 
01117     mi->file = CreateFileW( name, GENERIC_READ | (rw ? GENERIC_WRITE : 0),
01118                             0, NULL, OPEN_EXISTING, 0, 0 );
01119 
01120     if (mi->file != INVALID_HANDLE_VALUE)
01121     {
01122         mi->size = GetFileSize( mi->file, NULL );
01123 
01124         if (map_file_into_memory( mi ))
01125             return mi;
01126     }
01127     destroy_mapping( mi );
01128     return NULL;
01129 }
01130 
01131 static BOOL resize_mapping( struct mapping_info *mi, DWORD new_size )
01132 {
01133     if (!unmap_file_from_memory( mi ))
01134         return FALSE;
01135 
01136     /* change the file size */
01137     SetFilePointer( mi->file, new_size, NULL, FILE_BEGIN );
01138     if (!SetEndOfFile( mi->file ))
01139     {
01140         ERR("failed to set file size to %08x\n", new_size );
01141         return FALSE;
01142     }
01143 
01144     mi->size = new_size;
01145 
01146     return map_file_into_memory( mi );
01147 }
01148 
01149 static void get_resource_sizes( QUEUEDUPDATES *updates, struct resource_size_info *si )
01150 {
01151     struct resource_dir_entry *types, *names;
01152     struct resource_data *data;
01153     DWORD num_types = 0, num_names = 0, num_langs = 0, strings_size = 0, data_size = 0;
01154 
01155     memset( si, 0, sizeof *si );
01156 
01157     LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
01158     {
01159         num_types++;
01160         if (!IS_INTRESOURCE( types->id ))
01161             strings_size += sizeof (WORD) + lstrlenW( types->id )*sizeof (WCHAR);
01162 
01163         LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
01164         {
01165             num_names++;
01166 
01167             if (!IS_INTRESOURCE( names->id ))
01168                 strings_size += sizeof (WORD) + lstrlenW( names->id )*sizeof (WCHAR);
01169 
01170             LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
01171             {
01172                 num_langs++;
01173                 data_size += (data->cbData + 3) & ~3;
01174             }
01175         }
01176     }
01177 
01178     /* names are at the end of the types */
01179     si->names_ofs = sizeof (IMAGE_RESOURCE_DIRECTORY) +
01180             num_types * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
01181 
01182     /* language directories are at the end of the names */
01183     si->langs_ofs = si->names_ofs +
01184             num_types * sizeof (IMAGE_RESOURCE_DIRECTORY) +
01185             num_names * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
01186 
01187     si->data_entry_ofs = si->langs_ofs +
01188             num_names * sizeof (IMAGE_RESOURCE_DIRECTORY) +
01189             num_langs * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
01190 
01191     si->strings_ofs = si->data_entry_ofs +
01192             num_langs * sizeof (IMAGE_RESOURCE_DATA_ENTRY);
01193 
01194     si->data_ofs = si->strings_ofs + ((strings_size + 3) & ~3);
01195 
01196     si->total_size = si->data_ofs + data_size;
01197 
01198     TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
01199           si->names_ofs, si->langs_ofs, si->data_entry_ofs,
01200           si->strings_ofs, si->data_ofs, si->total_size);
01201 }
01202 
01203 static void res_write_padding( BYTE *res_base, DWORD size )
01204 {
01205     static const BYTE pad[] = {
01206         'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
01207     DWORD i;
01208 
01209     for ( i = 0; i < size / sizeof pad; i++ )
01210         memcpy( &res_base[i*sizeof pad], pad, sizeof pad );
01211     memcpy( &res_base[i*sizeof pad], pad, size%sizeof pad );
01212 }
01213 
01214 static BOOL write_resources( QUEUEDUPDATES *updates, LPBYTE base, struct resource_size_info *si, DWORD rva )
01215 {
01216     struct resource_dir_entry *types, *names;
01217     struct resource_data *data;
01218     IMAGE_RESOURCE_DIRECTORY *root;
01219 
01220     TRACE("%p %p %p %08x\n", updates, base, si, rva );
01221 
01222     memset( base, 0, si->total_size );
01223 
01224     /* the root entry always exists */
01225     root = (IMAGE_RESOURCE_DIRECTORY*) base;
01226     memset( root, 0, sizeof *root );
01227     root->MajorVersion = 4;
01228     si->types_ofs = sizeof *root;
01229     LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
01230     {
01231         IMAGE_RESOURCE_DIRECTORY_ENTRY *e1;
01232         IMAGE_RESOURCE_DIRECTORY *namedir;
01233 
01234         e1 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->types_ofs];
01235         memset( e1, 0, sizeof *e1 );
01236         if (!IS_INTRESOURCE( types->id ))
01237         {
01238             WCHAR *strings;
01239             DWORD len;
01240 
01241             root->NumberOfNamedEntries++;
01242             e1->u1.s1.NameIsString = 1;
01243             e1->u1.s1.NameOffset = si->strings_ofs;
01244 
01245             strings = (WCHAR*) &base[si->strings_ofs];
01246             len = lstrlenW( types->id );
01247             strings[0] = len;
01248             memcpy( &strings[1], types->id, len * sizeof (WCHAR) );
01249             si->strings_ofs += (len + 1) * sizeof (WCHAR);
01250         }
01251         else
01252         {
01253             root->NumberOfIdEntries++;
01254             e1->u1.Id = LOWORD( types->id );
01255         }
01256         e1->u2.s3.OffsetToDirectory = si->names_ofs;
01257         e1->u2.s3.DataIsDirectory = TRUE;
01258         si->types_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
01259 
01260         namedir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->names_ofs];
01261         memset( namedir, 0, sizeof *namedir );
01262         namedir->MajorVersion = 4;
01263         si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
01264 
01265         LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
01266         {
01267             IMAGE_RESOURCE_DIRECTORY_ENTRY *e2;
01268             IMAGE_RESOURCE_DIRECTORY *langdir;
01269 
01270             e2 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->names_ofs];
01271             memset( e2, 0, sizeof *e2 );
01272             if (!IS_INTRESOURCE( names->id ))
01273             {
01274                 WCHAR *strings;
01275                 DWORD len;
01276 
01277                 namedir->NumberOfNamedEntries++;
01278                 e2->u1.s1.NameIsString = 1;
01279                 e2->u1.s1.NameOffset = si->strings_ofs;
01280 
01281                 strings = (WCHAR*) &base[si->strings_ofs];
01282                 len = lstrlenW( names->id );
01283                 strings[0] = len;
01284                 memcpy( &strings[1], names->id, len * sizeof (WCHAR) );
01285                 si->strings_ofs += (len + 1) * sizeof (WCHAR);
01286             }
01287             else
01288             {
01289                 namedir->NumberOfIdEntries++;
01290                 e2->u1.Id = LOWORD( names->id );
01291             }
01292             e2->u2.s3.OffsetToDirectory = si->langs_ofs;
01293             e2->u2.s3.DataIsDirectory = TRUE;
01294             si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
01295 
01296             langdir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->langs_ofs];
01297             memset( langdir, 0, sizeof *langdir );
01298             langdir->MajorVersion = 4;
01299             si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
01300 
01301             LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
01302             {
01303                 IMAGE_RESOURCE_DIRECTORY_ENTRY *e3;
01304                 IMAGE_RESOURCE_DATA_ENTRY *de;
01305                 int pad_size;
01306 
01307                 e3 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->langs_ofs];
01308                 memset( e3, 0, sizeof *e3 );
01309                 langdir->NumberOfIdEntries++;
01310                 e3->u1.Id = LOWORD( data->lang );
01311                 e3->u2.OffsetToData = si->data_entry_ofs;
01312 
01313                 si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
01314 
01315                 /* write out all the data entries */
01316                 de = (IMAGE_RESOURCE_DATA_ENTRY*) &base[si->data_entry_ofs];
01317                 memset( de, 0, sizeof *de );
01318                 de->OffsetToData = si->data_ofs + rva;
01319                 de->Size = data->cbData;
01320                 de->CodePage = data->codepage;
01321                 si->data_entry_ofs += sizeof (IMAGE_RESOURCE_DATA_ENTRY);
01322 
01323                 /* write out the resource data */
01324                 memcpy( &base[si->data_ofs], data->lpData, data->cbData );
01325                 si->data_ofs += data->cbData;
01326 
01327                 pad_size = (-si->data_ofs)&3;
01328                 res_write_padding( &base[si->data_ofs], pad_size );
01329                 si->data_ofs += pad_size;
01330             }
01331         }
01332     }
01333 
01334     return TRUE;
01335 }
01336 
01337 /*
01338  *  FIXME:
01339  *  Assumes that the resources are in .rsrc
01340  *   and .rsrc is the last section in the file.
01341  *  Not sure whether updating resources will other cases on Windows.
01342  *  If the resources lie in a section containing other data,
01343  *   resizing that section could possibly cause trouble.
01344  *  If the section with the resources isn't last, the remaining
01345  *   sections need to be moved down in the file, and the section header
01346  *   would need to be adjusted.
01347  *  If we needed to add a section, what would we name it?
01348  *  If we needed to add a section and there wasn't space in the file
01349  *   header, how would that work?
01350  *  Seems that at least some of these cases can't be handled properly.
01351  */
01352 static IMAGE_SECTION_HEADER *get_resource_section( void *base, DWORD mapping_size )
01353 {
01354     IMAGE_SECTION_HEADER *sec;
01355     IMAGE_NT_HEADERS *nt;
01356     DWORD i, num_sections = 0;
01357 
01358     nt = get_nt_header( base, mapping_size );
01359     if (!nt)
01360         return NULL;
01361 
01362     sec = get_section_header( base, mapping_size, &num_sections );
01363     if (!sec)
01364         return NULL;
01365 
01366     /* find the resources section */
01367     for (i=0; i<num_sections; i++)
01368         if (!memcmp(sec[i].Name, ".rsrc", 6))
01369             break;
01370 
01371     if (i == num_sections)
01372         return NULL;
01373 
01374     return &sec[i];
01375 }
01376 
01377 static DWORD get_init_data_size( void *base, DWORD mapping_size )
01378 {
01379     DWORD i, sz = 0, num_sections = 0;
01380     IMAGE_SECTION_HEADER *s;
01381 
01382     s = get_section_header( base, mapping_size, &num_sections );
01383 
01384     for (i=0; i<num_sections; i++)
01385         if (s[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
01386             sz += s[i].SizeOfRawData;
01387 
01388     TRACE("size = %08x\n", sz);
01389 
01390     return sz;
01391 }
01392 
01393 static BOOL write_raw_resources( QUEUEDUPDATES *updates )
01394 {
01395     static const WCHAR prefix[] = { 'r','e','s','u',0 };
01396     WCHAR tempdir[MAX_PATH], tempfile[MAX_PATH];
01397     DWORD section_size;
01398     BOOL ret = FALSE;
01399     IMAGE_SECTION_HEADER *sec;
01400     IMAGE_NT_HEADERS *nt;
01401     struct resource_size_info res_size;
01402     BYTE *res_base;
01403     struct mapping_info *read_map = NULL, *write_map = NULL;
01404 
01405     /* copy the exe to a temp file then update the temp file... */
01406     tempdir[0] = 0;
01407     if (!GetTempPathW( MAX_PATH, tempdir ))
01408         return ret;
01409 
01410     if (!GetTempFileNameW( tempdir, prefix, 0, tempfile ))
01411         return ret;
01412 
01413     if (!CopyFileW( updates->pFileName, tempfile, FALSE ))
01414         goto done;
01415 
01416     TRACE("tempfile %s\n", debugstr_w(tempfile));
01417 
01418     if (!updates->bDeleteExistingResources)
01419     {
01420         read_map = create_mapping( updates->pFileName, FALSE );
01421         if (!read_map)
01422             goto done;
01423 
01424         ret = read_mapped_resources( updates, read_map->base, read_map->size );
01425         if (!ret)
01426         {
01427             ERR("failed to read existing resources\n");
01428             goto done;
01429         }
01430     }
01431 
01432     write_map = create_mapping( tempfile, TRUE );
01433     if (!write_map)
01434         goto done;
01435 
01436     nt = get_nt_header( write_map->base, write_map->size );
01437     if (!nt)
01438         goto done;
01439 
01440     if (nt->OptionalHeader.SectionAlignment <= 0)
01441     {
01442         ERR("invalid section alignment %04x\n", nt->OptionalHeader.SectionAlignment);
01443         goto done;
01444     }
01445 
01446     if (nt->OptionalHeader.FileAlignment <= 0)
01447     {
01448         ERR("invalid file alignment %04x\n", nt->OptionalHeader.FileAlignment);
01449         goto done;
01450     }
01451 
01452     sec = get_resource_section( write_map->base, write_map->size );
01453     if (!sec) /* no section, add one */
01454     {
01455         DWORD num_sections;
01456 
01457         sec = get_section_header( write_map->base, write_map->size, &num_sections );
01458         if (!sec)
01459             goto done;
01460 
01461         sec += num_sections;
01462         nt->FileHeader.NumberOfSections++;
01463 
01464         memset( sec, 0, sizeof *sec );
01465         memcpy( sec->Name, ".rsrc", 5 );
01466         sec->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
01467         sec->VirtualAddress = nt->OptionalHeader.SizeOfImage;
01468     }
01469 
01470     if (!sec->PointerToRawData)  /* empty section */
01471     {
01472         sec->PointerToRawData = write_map->size + (-write_map->size) % nt->OptionalHeader.FileAlignment;
01473         sec->SizeOfRawData = 0;
01474     }
01475 
01476     TRACE("before .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
01477 
01478     get_resource_sizes( updates, &res_size );
01479 
01480     /* round up the section size */
01481     section_size = res_size.total_size;
01482     section_size += (-section_size) % nt->OptionalHeader.FileAlignment;
01483 
01484     TRACE("requires %08x (%08x) bytes\n", res_size.total_size, section_size );
01485 
01486     /* check if the file size needs to be changed */
01487     if (section_size != sec->SizeOfRawData)
01488     {
01489         DWORD old_size = write_map->size;
01490         DWORD virtual_section_size = res_size.total_size + (-res_size.total_size) % nt->OptionalHeader.SectionAlignment;
01491         int delta = section_size - (sec->SizeOfRawData + (-sec->SizeOfRawData) % nt->OptionalHeader.FileAlignment);
01492         int rva_delta = virtual_section_size -
01493             (sec->Misc.VirtualSize + (-sec->Misc.VirtualSize) % nt->OptionalHeader.SectionAlignment);
01494         BOOL rsrc_is_last = sec->PointerToRawData + sec->SizeOfRawData == old_size;
01495     /* align .rsrc size when possible */
01496         DWORD mapping_size = rsrc_is_last ? sec->PointerToRawData + section_size : old_size + delta;
01497 
01498         /* postpone file truncation if there are some data to be moved down from file end */
01499         BOOL resize_after = mapping_size < old_size && !rsrc_is_last;
01500 
01501         TRACE("file size %08x -> %08x\n", old_size, mapping_size);
01502 
01503         if (!resize_after)
01504         {
01505             /* unmap the file before changing the file size */
01506             ret = resize_mapping( write_map, mapping_size );
01507 
01508             /* get the pointers again - they might be different after remapping */
01509             nt = get_nt_header( write_map->base, mapping_size );
01510             if (!nt)
01511             {
01512                 ERR("couldn't get NT header\n");
01513                 goto done;
01514             }
01515 
01516             sec = get_resource_section( write_map->base, mapping_size );
01517             if (!sec)
01518                  goto done;
01519         }
01520 
01521         if (!rsrc_is_last) /* not last section, relocate trailing sections */
01522         {
01523             IMAGE_SECTION_HEADER *s;
01524             DWORD tail_start = sec->PointerToRawData + sec->SizeOfRawData;
01525             DWORD i, num_sections = 0;
01526 
01527             memmove( (char*)write_map->base + tail_start + delta, (char*)write_map->base + tail_start, old_size - tail_start );
01528 
01529             s = get_section_header( write_map->base, mapping_size, &num_sections );
01530 
01531             for (i=0; i<num_sections; i++)
01532             {
01533                 if (s[i].PointerToRawData > sec->PointerToRawData)
01534                 {
01535                     s[i].PointerToRawData += delta;
01536                     s[i].VirtualAddress += rva_delta;
01537                 }
01538             }
01539         }
01540 
01541         if (resize_after)
01542         {
01543             ret = resize_mapping( write_map, mapping_size );
01544 
01545             nt = get_nt_header( write_map->base, mapping_size );
01546             if (!nt)
01547             {
01548                 ERR("couldn't get NT header\n");
01549                 goto done;
01550             }
01551 
01552             sec = get_resource_section( write_map->base, mapping_size );
01553             if (!sec)
01554                  goto done;
01555         }
01556 
01557         /* adjust the PE header information */
01558         sec->SizeOfRawData = section_size;
01559         sec->Misc.VirtualSize = virtual_section_size;
01560         nt->OptionalHeader.SizeOfImage += rva_delta;
01561         nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = res_size.total_size;
01562         nt->OptionalHeader.SizeOfInitializedData = get_init_data_size( write_map->base, mapping_size );
01563     }
01564 
01565     res_base = (LPBYTE) write_map->base + sec->PointerToRawData;
01566 
01567     TRACE("base = %p offset = %08x\n", write_map->base, sec->PointerToRawData);
01568 
01569     ret = write_resources( updates, res_base, &res_size, sec->VirtualAddress );
01570 
01571     res_write_padding( res_base + res_size.total_size, section_size - res_size.total_size );
01572 
01573     TRACE("after  .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
01574 
01575 done:
01576     destroy_mapping( read_map );
01577     destroy_mapping( write_map );
01578 
01579     if (ret)
01580         ret = CopyFileW( tempfile, updates->pFileName, FALSE );
01581 
01582     DeleteFileW( tempfile );
01583 
01584     return ret;
01585 }
01586 
01587 /***********************************************************************
01588  *          BeginUpdateResourceW                 (KERNEL32.@)
01589  */
01590 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
01591 {
01592     QUEUEDUPDATES *updates = NULL;
01593     HANDLE hUpdate, file, ret = NULL;
01594 
01595     TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
01596 
01597     hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES));
01598     if (!hUpdate)
01599         return ret;
01600 
01601     updates = GlobalLock(hUpdate);
01602     if (updates)
01603     {
01604         list_init( &updates->root );
01605         updates->bDeleteExistingResources = bDeleteExistingResources;
01606         updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
01607         if (updates->pFileName)
01608         {
01609             lstrcpyW(updates->pFileName, pFileName);
01610 
01611             file = CreateFileW( pFileName, GENERIC_READ | GENERIC_WRITE,
01612                                 0, NULL, OPEN_EXISTING, 0, 0 );
01613 
01614             /* if resources are deleted, only the file's presence is checked */
01615             if (file != INVALID_HANDLE_VALUE &&
01616                 (bDeleteExistingResources || check_pe_exe( file, updates )))
01617                 ret = hUpdate;
01618             else
01619                 HeapFree( GetProcessHeap(), 0, updates->pFileName );
01620 
01621             CloseHandle( file );
01622         }
01623         GlobalUnlock(hUpdate);
01624     }
01625 
01626     if (!ret)
01627         GlobalFree(hUpdate);
01628 
01629     return ret;
01630 }
01631 
01632 
01633 /***********************************************************************
01634  *          BeginUpdateResourceA                 (KERNEL32.@)
01635  */
01636 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
01637 {
01638     UNICODE_STRING FileNameW;
01639     HANDLE ret;
01640     RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
01641     ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
01642     RtlFreeUnicodeString(&FileNameW);
01643     return ret;
01644 }
01645 
01646 
01647 /***********************************************************************
01648  *          EndUpdateResourceW                 (KERNEL32.@)
01649  */
01650 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
01651 {
01652     QUEUEDUPDATES *updates;
01653     BOOL ret;
01654 
01655     TRACE("%p %d\n", hUpdate, fDiscard);
01656 
01657     updates = GlobalLock(hUpdate);
01658     if (!updates)
01659         return FALSE;
01660 
01661     ret = fDiscard || write_raw_resources( updates );
01662 
01663     free_resource_directory( &updates->root, 2 );
01664 
01665     HeapFree( GetProcessHeap(), 0, updates->pFileName );
01666     GlobalUnlock( hUpdate );
01667     GlobalFree( hUpdate );
01668 
01669     return ret;
01670 }
01671 
01672 
01673 /***********************************************************************
01674  *          EndUpdateResourceA                 (KERNEL32.@)
01675  */
01676 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
01677 {
01678     return EndUpdateResourceW(hUpdate, fDiscard);
01679 }
01680 
01681 
01682 /***********************************************************************
01683  *           UpdateResourceW                 (KERNEL32.@)
01684  */
01685 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
01686                              WORD wLanguage, LPVOID lpData, DWORD cbData)
01687 {
01688     QUEUEDUPDATES *updates;
01689     BOOL ret = FALSE;
01690 
01691     TRACE("%p %s %s %08x %p %d\n", hUpdate,
01692           debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
01693 
01694     updates = GlobalLock(hUpdate);
01695     if (updates)
01696     {
01697         if (lpData == NULL && cbData == 0)  /* remove resource */
01698         {
01699             ret = update_add_resource( updates, lpType, lpName, wLanguage, NULL, TRUE );
01700         }
01701         else
01702         {
01703             struct resource_data *data;
01704             data = allocate_resource_data( wLanguage, 0, lpData, cbData, TRUE );
01705             if (data)
01706                 ret = update_add_resource( updates, lpType, lpName, wLanguage, data, TRUE );
01707         }
01708         GlobalUnlock(hUpdate);
01709     }
01710     return ret;
01711 }
01712 
01713 
01714 /***********************************************************************
01715  *           UpdateResourceA                 (KERNEL32.@)
01716  */
01717 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
01718                              WORD wLanguage, LPVOID lpData, DWORD cbData)
01719 {
01720     BOOL ret;
01721     UNICODE_STRING TypeW;
01722     UNICODE_STRING NameW;
01723     if(IS_INTRESOURCE(lpType))
01724         TypeW.Buffer = ULongToPtr(LOWORD(lpType));
01725     else
01726         RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
01727     if(IS_INTRESOURCE(lpName))
01728         NameW.Buffer = ULongToPtr(LOWORD(lpName));
01729     else
01730         RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
01731     ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
01732     if(!IS_INTRESOURCE(lpType)) RtlFreeUnicodeString(&TypeW);
01733     if(!IS_INTRESOURCE(lpName)) RtlFreeUnicodeString(&NameW);
01734     return ret;
01735 }

Generated on Thu May 24 2012 04:24:50 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.