diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-04-22 06:38:23 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-04-29 16:21:09 -0700 |
| commit | 7f642e51670bc38a4ef782a363936850bc2b0ba9 (patch) | |
| tree | 19684b2d94979f130c0935328f0d44cf006e45ef /src/libs/dutil/WixToolset.DUtil/reswutil.cpp | |
| parent | f39e7a3e164d0736e45049e5726d0da2013da3c9 (diff) | |
| download | wix-7f642e51670bc38a4ef782a363936850bc2b0ba9.tar.gz wix-7f642e51670bc38a4ef782a363936850bc2b0ba9.tar.bz2 wix-7f642e51670bc38a4ef782a363936850bc2b0ba9.zip | |
Move dutil into libs/dutil
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/reswutil.cpp')
| -rw-r--r-- | src/libs/dutil/WixToolset.DUtil/reswutil.cpp | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/reswutil.cpp b/src/libs/dutil/WixToolset.DUtil/reswutil.cpp new file mode 100644 index 00000000..e78de84a --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/reswutil.cpp | |||
| @@ -0,0 +1,386 @@ | |||
| 1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
| 2 | |||
| 3 | #include "precomp.h" | ||
| 4 | |||
| 5 | |||
| 6 | // Exit macros | ||
| 7 | #define ReswExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) | ||
| 8 | #define ReswExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) | ||
| 9 | #define ReswExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) | ||
| 10 | #define ReswExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) | ||
| 11 | #define ReswExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) | ||
| 12 | #define ReswExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) | ||
| 13 | #define ReswExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_RESWUTIL, p, x, e, s, __VA_ARGS__) | ||
| 14 | #define ReswExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_RESWUTIL, p, x, s, __VA_ARGS__) | ||
| 15 | #define ReswExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_RESWUTIL, p, x, e, s, __VA_ARGS__) | ||
| 16 | #define ReswExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_RESWUTIL, p, x, s, __VA_ARGS__) | ||
| 17 | #define ReswExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_RESWUTIL, e, x, s, __VA_ARGS__) | ||
| 18 | #define ReswExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_RESWUTIL, g, x, s, __VA_ARGS__) | ||
| 19 | |||
| 20 | #define RES_STRINGS_PER_BLOCK 16 | ||
| 21 | |||
| 22 | // Internal data structure format for a string block in a resource table. | ||
| 23 | // Note: Strings are always stored as UNICODED. | ||
| 24 | typedef struct _RES_STRING_BLOCK | ||
| 25 | { | ||
| 26 | DWORD dwBlockId; | ||
| 27 | WORD wLangId; | ||
| 28 | LPWSTR rgwz[RES_STRINGS_PER_BLOCK]; | ||
| 29 | } RES_STRING_BLOCK; | ||
| 30 | |||
| 31 | |||
| 32 | // private functions | ||
| 33 | static HRESULT StringBlockInitialize( | ||
| 34 | __in_opt HINSTANCE hModule, | ||
| 35 | __in DWORD dwBlockId, | ||
| 36 | __in WORD wLangId, | ||
| 37 | __in RES_STRING_BLOCK* pStrBlock | ||
| 38 | ); | ||
| 39 | static void StringBlockUnitialize( | ||
| 40 | __in RES_STRING_BLOCK* pStrBlock | ||
| 41 | ); | ||
| 42 | static HRESULT StringBlockChangeString( | ||
| 43 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 44 | __in DWORD dwStringId, | ||
| 45 | __in_z LPCWSTR szData | ||
| 46 | ); | ||
| 47 | static HRESULT StringBlockConvertToResourceData( | ||
| 48 | __in const RES_STRING_BLOCK* pStrBlock, | ||
| 49 | __deref_out_bcount(*pcbData) LPVOID* ppvData, | ||
| 50 | __out DWORD* pcbData | ||
| 51 | ); | ||
| 52 | static HRESULT StringBlockConvertFromResourceData( | ||
| 53 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 54 | __in_bcount(cbData) LPCVOID pvData, | ||
| 55 | __in SIZE_T cbData | ||
| 56 | ); | ||
| 57 | |||
| 58 | |||
| 59 | /******************************************************************** | ||
| 60 | ResWriteString - sets the string into to the specified file's resource name | ||
| 61 | |||
| 62 | ********************************************************************/ | ||
| 63 | extern "C" HRESULT DAPI ResWriteString( | ||
| 64 | __in_z LPCWSTR wzResourceFile, | ||
| 65 | __in DWORD dwDataId, | ||
| 66 | __in_z LPCWSTR wzData, | ||
| 67 | __in WORD wLangId | ||
| 68 | ) | ||
| 69 | { | ||
| 70 | Assert(wzResourceFile); | ||
| 71 | Assert(wzData); | ||
| 72 | |||
| 73 | HRESULT hr = S_OK; | ||
| 74 | HINSTANCE hModule = NULL; | ||
| 75 | HANDLE hUpdate = NULL; | ||
| 76 | RES_STRING_BLOCK StrBlock = { }; | ||
| 77 | LPVOID pvData = NULL; | ||
| 78 | DWORD cbData = 0; | ||
| 79 | |||
| 80 | DWORD dwBlockId = (dwDataId / RES_STRINGS_PER_BLOCK) + 1; | ||
| 81 | DWORD dwStringId = (dwDataId % RES_STRINGS_PER_BLOCK); | ||
| 82 | |||
| 83 | hModule = LoadLibraryExW(wzResourceFile, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); | ||
| 84 | ReswExitOnNullWithLastError(hModule, hr, "Failed to load library: %ls", wzResourceFile); | ||
| 85 | |||
| 86 | hr = StringBlockInitialize(hModule, dwBlockId, wLangId, &StrBlock); | ||
| 87 | ReswExitOnFailure(hr, "Failed to get string block to update."); | ||
| 88 | |||
| 89 | hr = StringBlockChangeString(&StrBlock, dwStringId, wzData); | ||
| 90 | ReswExitOnFailure(hr, "Failed to update string block string."); | ||
| 91 | |||
| 92 | hr = StringBlockConvertToResourceData(&StrBlock, &pvData, &cbData); | ||
| 93 | ReswExitOnFailure(hr, "Failed to convert string block to resource data."); | ||
| 94 | |||
| 95 | ::FreeLibrary(hModule); | ||
| 96 | hModule = NULL; | ||
| 97 | |||
| 98 | hUpdate = ::BeginUpdateResourceW(wzResourceFile, FALSE); | ||
| 99 | ReswExitOnNullWithLastError(hUpdate, hr, "Failed to ::BeginUpdateResourcesW."); | ||
| 100 | |||
| 101 | if (!::UpdateResourceA(hUpdate, RT_STRING, MAKEINTRESOURCE(dwBlockId), wLangId, pvData, cbData)) | ||
| 102 | { | ||
| 103 | ReswExitWithLastError(hr, "Failed to ::UpdateResourceA."); | ||
| 104 | } | ||
| 105 | |||
| 106 | if (!::EndUpdateResource(hUpdate, FALSE)) | ||
| 107 | { | ||
| 108 | ReswExitWithLastError(hr, "Failed to ::EndUpdateResourceW."); | ||
| 109 | } | ||
| 110 | |||
| 111 | hUpdate = NULL; | ||
| 112 | |||
| 113 | LExit: | ||
| 114 | ReleaseMem(pvData); | ||
| 115 | |||
| 116 | StringBlockUnitialize(&StrBlock); | ||
| 117 | |||
| 118 | if (hUpdate) | ||
| 119 | { | ||
| 120 | ::EndUpdateResource(hUpdate, TRUE); | ||
| 121 | } | ||
| 122 | |||
| 123 | if (hModule) | ||
| 124 | { | ||
| 125 | ::FreeLibrary(hModule); | ||
| 126 | } | ||
| 127 | |||
| 128 | return hr; | ||
| 129 | } | ||
| 130 | |||
| 131 | |||
| 132 | /******************************************************************** | ||
| 133 | ResWriteData - sets the data into to the specified file's resource name | ||
| 134 | |||
| 135 | ********************************************************************/ | ||
| 136 | extern "C" HRESULT DAPI ResWriteData( | ||
| 137 | __in_z LPCWSTR wzResourceFile, | ||
| 138 | __in_z LPCSTR szDataName, | ||
| 139 | __in PVOID pData, | ||
| 140 | __in DWORD cbData | ||
| 141 | ) | ||
| 142 | { | ||
| 143 | Assert(wzResourceFile); | ||
| 144 | Assert(szDataName); | ||
| 145 | Assert(pData); | ||
| 146 | Assert(cbData); | ||
| 147 | |||
| 148 | HRESULT hr = S_OK; | ||
| 149 | HANDLE hUpdate = NULL; | ||
| 150 | |||
| 151 | hUpdate = ::BeginUpdateResourceW(wzResourceFile, FALSE); | ||
| 152 | ReswExitOnNullWithLastError(hUpdate, hr, "Failed to ::BeginUpdateResourcesW."); | ||
| 153 | |||
| 154 | if (!::UpdateResourceA(hUpdate, RT_RCDATA, szDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pData, cbData)) | ||
| 155 | { | ||
| 156 | ReswExitWithLastError(hr, "Failed to ::UpdateResourceA."); | ||
| 157 | } | ||
| 158 | |||
| 159 | if (!::EndUpdateResource(hUpdate, FALSE)) | ||
| 160 | { | ||
| 161 | ReswExitWithLastError(hr, "Failed to ::EndUpdateResourceW."); | ||
| 162 | } | ||
| 163 | |||
| 164 | hUpdate = NULL; | ||
| 165 | |||
| 166 | LExit: | ||
| 167 | if (hUpdate) | ||
| 168 | { | ||
| 169 | ::EndUpdateResource(hUpdate, TRUE); | ||
| 170 | } | ||
| 171 | |||
| 172 | return hr; | ||
| 173 | } | ||
| 174 | |||
| 175 | |||
| 176 | /******************************************************************** | ||
| 177 | ResImportDataFromFile - reads a file and sets the data into to the specified file's resource name | ||
| 178 | |||
| 179 | ********************************************************************/ | ||
| 180 | extern "C" HRESULT DAPI ResImportDataFromFile( | ||
| 181 | __in_z LPCWSTR wzTargetFile, | ||
| 182 | __in_z LPCWSTR wzSourceFile, | ||
| 183 | __in_z LPCSTR szDataName | ||
| 184 | ) | ||
| 185 | { | ||
| 186 | HRESULT hr = S_OK; | ||
| 187 | HANDLE hFile = INVALID_HANDLE_VALUE; | ||
| 188 | DWORD cbFile = 0; | ||
| 189 | HANDLE hMap = NULL; | ||
| 190 | PVOID pv = NULL; | ||
| 191 | |||
| 192 | hFile = ::CreateFileW(wzSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||
| 193 | if (INVALID_HANDLE_VALUE == hFile) | ||
| 194 | { | ||
| 195 | ReswExitWithLastError(hr, "Failed to CreateFileW for %ls.", wzSourceFile); | ||
| 196 | } | ||
| 197 | |||
| 198 | cbFile = ::GetFileSize(hFile, NULL); | ||
| 199 | if (!cbFile) | ||
| 200 | { | ||
| 201 | ReswExitWithLastError(hr, "Failed to GetFileSize for %ls.", wzSourceFile); | ||
| 202 | } | ||
| 203 | |||
| 204 | hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); | ||
| 205 | ReswExitOnNullWithLastError(hMap, hr, "Failed to CreateFileMapping for %ls.", wzSourceFile); | ||
| 206 | |||
| 207 | pv = ::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbFile); | ||
| 208 | ReswExitOnNullWithLastError(pv, hr, "Failed to MapViewOfFile for %ls.", wzSourceFile); | ||
| 209 | |||
| 210 | hr = ResWriteData(wzTargetFile, szDataName, pv, cbFile); | ||
| 211 | ReswExitOnFailure(hr, "Failed to ResSetData %s on file %ls.", szDataName, wzTargetFile); | ||
| 212 | |||
| 213 | LExit: | ||
| 214 | if (pv) | ||
| 215 | { | ||
| 216 | ::UnmapViewOfFile(pv); | ||
| 217 | } | ||
| 218 | |||
| 219 | if (hMap) | ||
| 220 | { | ||
| 221 | ::CloseHandle(hMap); | ||
| 222 | } | ||
| 223 | |||
| 224 | ReleaseFile(hFile); | ||
| 225 | |||
| 226 | return hr; | ||
| 227 | } | ||
| 228 | |||
| 229 | |||
| 230 | static HRESULT StringBlockInitialize( | ||
| 231 | __in_opt HINSTANCE hModule, | ||
| 232 | __in DWORD dwBlockId, | ||
| 233 | __in WORD wLangId, | ||
| 234 | __in RES_STRING_BLOCK* pStrBlock | ||
| 235 | ) | ||
| 236 | { | ||
| 237 | HRESULT hr = S_OK; | ||
| 238 | HRSRC hRsrc = NULL; | ||
| 239 | HGLOBAL hData = NULL; | ||
| 240 | LPCVOID pvData = NULL; // does not need to be freed | ||
| 241 | DWORD cbData = 0; | ||
| 242 | |||
| 243 | hRsrc = ::FindResourceExA(hModule, RT_STRING, MAKEINTRESOURCE(dwBlockId), wLangId); | ||
| 244 | ReswExitOnNullWithLastError(hRsrc, hr, "Failed to ::FindResourceExW."); | ||
| 245 | |||
| 246 | hData = ::LoadResource(hModule, hRsrc); | ||
| 247 | ReswExitOnNullWithLastError(hData, hr, "Failed to ::LoadResource."); | ||
| 248 | |||
| 249 | cbData = ::SizeofResource(hModule, hRsrc); | ||
| 250 | if (!cbData) | ||
| 251 | { | ||
| 252 | ReswExitWithLastError(hr, "Failed to ::SizeofResource."); | ||
| 253 | } | ||
| 254 | |||
| 255 | pvData = ::LockResource(hData); | ||
| 256 | ReswExitOnNullWithLastError(pvData, hr, "Failed to lock data resource."); | ||
| 257 | |||
| 258 | pStrBlock->dwBlockId = dwBlockId; | ||
| 259 | pStrBlock->wLangId = wLangId; | ||
| 260 | |||
| 261 | hr = StringBlockConvertFromResourceData(pStrBlock, pvData, cbData); | ||
| 262 | ReswExitOnFailure(hr, "Failed to convert string block from resource data."); | ||
| 263 | |||
| 264 | LExit: | ||
| 265 | return hr; | ||
| 266 | } | ||
| 267 | |||
| 268 | |||
| 269 | static void StringBlockUnitialize( | ||
| 270 | __in RES_STRING_BLOCK* pStrBlock | ||
| 271 | ) | ||
| 272 | { | ||
| 273 | if (pStrBlock) | ||
| 274 | { | ||
| 275 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 276 | { | ||
| 277 | ReleaseNullMem(pStrBlock->rgwz[i]); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 283 | static HRESULT StringBlockChangeString( | ||
| 284 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 285 | __in DWORD dwStringId, | ||
| 286 | __in_z LPCWSTR szData | ||
| 287 | ) | ||
| 288 | { | ||
| 289 | HRESULT hr = S_OK; | ||
| 290 | LPWSTR pwzData = NULL; | ||
| 291 | size_t cchData = 0; | ||
| 292 | |||
| 293 | hr = ::StringCchLengthW(szData, STRSAFE_MAX_LENGTH, &cchData); | ||
| 294 | ReswExitOnRootFailure(hr, "Failed to get block string length."); | ||
| 295 | |||
| 296 | pwzData = static_cast<LPWSTR>(MemAlloc((cchData + 1) * sizeof(WCHAR), TRUE)); | ||
| 297 | ReswExitOnNull(pwzData, hr, E_OUTOFMEMORY, "Failed to allocate new block string."); | ||
| 298 | |||
| 299 | hr = ::StringCchCopyW(pwzData, cchData + 1, szData); | ||
| 300 | ReswExitOnRootFailure(hr, "Failed to copy new block string."); | ||
| 301 | |||
| 302 | ReleaseNullMem(pStrBlock->rgwz[dwStringId]); | ||
| 303 | |||
| 304 | pStrBlock->rgwz[dwStringId] = pwzData; | ||
| 305 | pwzData = NULL; | ||
| 306 | |||
| 307 | LExit: | ||
| 308 | ReleaseMem(pwzData); | ||
| 309 | |||
| 310 | return hr; | ||
| 311 | } | ||
| 312 | |||
| 313 | |||
| 314 | static HRESULT StringBlockConvertToResourceData( | ||
| 315 | __in const RES_STRING_BLOCK* pStrBlock, | ||
| 316 | __deref_out_bcount(*pcbData) LPVOID* ppvData, | ||
| 317 | __out DWORD* pcbData | ||
| 318 | ) | ||
| 319 | { | ||
| 320 | HRESULT hr = S_OK; | ||
| 321 | DWORD cbData = 0; | ||
| 322 | LPVOID pvData = NULL; | ||
| 323 | WCHAR* pwz = NULL; | ||
| 324 | |||
| 325 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 326 | { | ||
| 327 | cbData += (lstrlenW(pStrBlock->rgwz[i]) + 1); | ||
| 328 | } | ||
| 329 | cbData *= sizeof(WCHAR); | ||
| 330 | |||
| 331 | pvData = MemAlloc(cbData, TRUE); | ||
| 332 | ReswExitOnNull(pvData, hr, E_OUTOFMEMORY, "Failed to allocate buffer to convert string block."); | ||
| 333 | |||
| 334 | pwz = static_cast<LPWSTR>(pvData); | ||
| 335 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 336 | { | ||
| 337 | DWORD cch = lstrlenW(pStrBlock->rgwz[i]); | ||
| 338 | |||
| 339 | *pwz = static_cast<WCHAR>(cch); | ||
| 340 | ++pwz; | ||
| 341 | |||
| 342 | for (DWORD j = 0; j < cch; ++j) | ||
| 343 | { | ||
| 344 | *pwz = pStrBlock->rgwz[i][j]; | ||
| 345 | ++pwz; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | *pcbData = cbData; | ||
| 350 | *ppvData = pvData; | ||
| 351 | pvData = NULL; | ||
| 352 | |||
| 353 | LExit: | ||
| 354 | ReleaseMem(pvData); | ||
| 355 | |||
| 356 | return hr; | ||
| 357 | } | ||
| 358 | |||
| 359 | |||
| 360 | static HRESULT StringBlockConvertFromResourceData( | ||
| 361 | __in RES_STRING_BLOCK* pStrBlock, | ||
| 362 | __in_bcount(cbData) LPCVOID pvData, | ||
| 363 | __in SIZE_T cbData | ||
| 364 | ) | ||
| 365 | { | ||
| 366 | UNREFERENCED_PARAMETER(cbData); | ||
| 367 | HRESULT hr = S_OK; | ||
| 368 | LPCWSTR pwzParse = static_cast<LPCWSTR>(pvData); | ||
| 369 | |||
| 370 | for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) | ||
| 371 | { | ||
| 372 | DWORD cchParse = static_cast<DWORD>(*pwzParse); | ||
| 373 | ++pwzParse; | ||
| 374 | |||
| 375 | pStrBlock->rgwz[i] = static_cast<LPWSTR>(MemAlloc((cchParse + 1) * sizeof(WCHAR), TRUE)); | ||
| 376 | ReswExitOnNull(pStrBlock->rgwz[i], hr, E_OUTOFMEMORY, "Failed to populate pStrBlock."); | ||
| 377 | |||
| 378 | hr = ::StringCchCopyNExW(pStrBlock->rgwz[i], cchParse + 1, pwzParse, cchParse, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); | ||
| 379 | ReswExitOnFailure(hr, "Failed to copy parsed resource data into string block."); | ||
| 380 | |||
| 381 | pwzParse += cchParse; | ||
| 382 | } | ||
| 383 | |||
| 384 | LExit: | ||
| 385 | return hr; | ||
| 386 | } | ||
