From 7f642e51670bc38a4ef782a363936850bc2b0ba9 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 06:38:23 -0700 Subject: Move dutil into libs/dutil --- src/libs/dutil/WixToolset.DUtil/reswutil.cpp | 386 +++++++++++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 src/libs/dutil/WixToolset.DUtil/reswutil.cpp (limited to 'src/libs/dutil/WixToolset.DUtil/reswutil.cpp') 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 @@ +// 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. + +#include "precomp.h" + + +// Exit macros +#define ReswExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) +#define ReswExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) +#define ReswExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) +#define ReswExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) +#define ReswExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) +#define ReswExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_RESWUTIL, x, s, __VA_ARGS__) +#define ReswExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_RESWUTIL, p, x, e, s, __VA_ARGS__) +#define ReswExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_RESWUTIL, p, x, s, __VA_ARGS__) +#define ReswExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_RESWUTIL, p, x, e, s, __VA_ARGS__) +#define ReswExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_RESWUTIL, p, x, s, __VA_ARGS__) +#define ReswExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_RESWUTIL, e, x, s, __VA_ARGS__) +#define ReswExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_RESWUTIL, g, x, s, __VA_ARGS__) + +#define RES_STRINGS_PER_BLOCK 16 + +// Internal data structure format for a string block in a resource table. +// Note: Strings are always stored as UNICODED. +typedef struct _RES_STRING_BLOCK +{ + DWORD dwBlockId; + WORD wLangId; + LPWSTR rgwz[RES_STRINGS_PER_BLOCK]; +} RES_STRING_BLOCK; + + +// private functions +static HRESULT StringBlockInitialize( + __in_opt HINSTANCE hModule, + __in DWORD dwBlockId, + __in WORD wLangId, + __in RES_STRING_BLOCK* pStrBlock + ); +static void StringBlockUnitialize( + __in RES_STRING_BLOCK* pStrBlock + ); +static HRESULT StringBlockChangeString( + __in RES_STRING_BLOCK* pStrBlock, + __in DWORD dwStringId, + __in_z LPCWSTR szData + ); +static HRESULT StringBlockConvertToResourceData( + __in const RES_STRING_BLOCK* pStrBlock, + __deref_out_bcount(*pcbData) LPVOID* ppvData, + __out DWORD* pcbData + ); +static HRESULT StringBlockConvertFromResourceData( + __in RES_STRING_BLOCK* pStrBlock, + __in_bcount(cbData) LPCVOID pvData, + __in SIZE_T cbData + ); + + +/******************************************************************** +ResWriteString - sets the string into to the specified file's resource name + +********************************************************************/ +extern "C" HRESULT DAPI ResWriteString( + __in_z LPCWSTR wzResourceFile, + __in DWORD dwDataId, + __in_z LPCWSTR wzData, + __in WORD wLangId + ) +{ + Assert(wzResourceFile); + Assert(wzData); + + HRESULT hr = S_OK; + HINSTANCE hModule = NULL; + HANDLE hUpdate = NULL; + RES_STRING_BLOCK StrBlock = { }; + LPVOID pvData = NULL; + DWORD cbData = 0; + + DWORD dwBlockId = (dwDataId / RES_STRINGS_PER_BLOCK) + 1; + DWORD dwStringId = (dwDataId % RES_STRINGS_PER_BLOCK); + + hModule = LoadLibraryExW(wzResourceFile, NULL, DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_AS_DATAFILE); + ReswExitOnNullWithLastError(hModule, hr, "Failed to load library: %ls", wzResourceFile); + + hr = StringBlockInitialize(hModule, dwBlockId, wLangId, &StrBlock); + ReswExitOnFailure(hr, "Failed to get string block to update."); + + hr = StringBlockChangeString(&StrBlock, dwStringId, wzData); + ReswExitOnFailure(hr, "Failed to update string block string."); + + hr = StringBlockConvertToResourceData(&StrBlock, &pvData, &cbData); + ReswExitOnFailure(hr, "Failed to convert string block to resource data."); + + ::FreeLibrary(hModule); + hModule = NULL; + + hUpdate = ::BeginUpdateResourceW(wzResourceFile, FALSE); + ReswExitOnNullWithLastError(hUpdate, hr, "Failed to ::BeginUpdateResourcesW."); + + if (!::UpdateResourceA(hUpdate, RT_STRING, MAKEINTRESOURCE(dwBlockId), wLangId, pvData, cbData)) + { + ReswExitWithLastError(hr, "Failed to ::UpdateResourceA."); + } + + if (!::EndUpdateResource(hUpdate, FALSE)) + { + ReswExitWithLastError(hr, "Failed to ::EndUpdateResourceW."); + } + + hUpdate = NULL; + +LExit: + ReleaseMem(pvData); + + StringBlockUnitialize(&StrBlock); + + if (hUpdate) + { + ::EndUpdateResource(hUpdate, TRUE); + } + + if (hModule) + { + ::FreeLibrary(hModule); + } + + return hr; +} + + +/******************************************************************** +ResWriteData - sets the data into to the specified file's resource name + +********************************************************************/ +extern "C" HRESULT DAPI ResWriteData( + __in_z LPCWSTR wzResourceFile, + __in_z LPCSTR szDataName, + __in PVOID pData, + __in DWORD cbData + ) +{ + Assert(wzResourceFile); + Assert(szDataName); + Assert(pData); + Assert(cbData); + + HRESULT hr = S_OK; + HANDLE hUpdate = NULL; + + hUpdate = ::BeginUpdateResourceW(wzResourceFile, FALSE); + ReswExitOnNullWithLastError(hUpdate, hr, "Failed to ::BeginUpdateResourcesW."); + + if (!::UpdateResourceA(hUpdate, RT_RCDATA, szDataName, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), pData, cbData)) + { + ReswExitWithLastError(hr, "Failed to ::UpdateResourceA."); + } + + if (!::EndUpdateResource(hUpdate, FALSE)) + { + ReswExitWithLastError(hr, "Failed to ::EndUpdateResourceW."); + } + + hUpdate = NULL; + +LExit: + if (hUpdate) + { + ::EndUpdateResource(hUpdate, TRUE); + } + + return hr; +} + + +/******************************************************************** +ResImportDataFromFile - reads a file and sets the data into to the specified file's resource name + +********************************************************************/ +extern "C" HRESULT DAPI ResImportDataFromFile( + __in_z LPCWSTR wzTargetFile, + __in_z LPCWSTR wzSourceFile, + __in_z LPCSTR szDataName + ) +{ + HRESULT hr = S_OK; + HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD cbFile = 0; + HANDLE hMap = NULL; + PVOID pv = NULL; + + hFile = ::CreateFileW(wzSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (INVALID_HANDLE_VALUE == hFile) + { + ReswExitWithLastError(hr, "Failed to CreateFileW for %ls.", wzSourceFile); + } + + cbFile = ::GetFileSize(hFile, NULL); + if (!cbFile) + { + ReswExitWithLastError(hr, "Failed to GetFileSize for %ls.", wzSourceFile); + } + + hMap = ::CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + ReswExitOnNullWithLastError(hMap, hr, "Failed to CreateFileMapping for %ls.", wzSourceFile); + + pv = ::MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, cbFile); + ReswExitOnNullWithLastError(pv, hr, "Failed to MapViewOfFile for %ls.", wzSourceFile); + + hr = ResWriteData(wzTargetFile, szDataName, pv, cbFile); + ReswExitOnFailure(hr, "Failed to ResSetData %s on file %ls.", szDataName, wzTargetFile); + +LExit: + if (pv) + { + ::UnmapViewOfFile(pv); + } + + if (hMap) + { + ::CloseHandle(hMap); + } + + ReleaseFile(hFile); + + return hr; +} + + +static HRESULT StringBlockInitialize( + __in_opt HINSTANCE hModule, + __in DWORD dwBlockId, + __in WORD wLangId, + __in RES_STRING_BLOCK* pStrBlock + ) +{ + HRESULT hr = S_OK; + HRSRC hRsrc = NULL; + HGLOBAL hData = NULL; + LPCVOID pvData = NULL; // does not need to be freed + DWORD cbData = 0; + + hRsrc = ::FindResourceExA(hModule, RT_STRING, MAKEINTRESOURCE(dwBlockId), wLangId); + ReswExitOnNullWithLastError(hRsrc, hr, "Failed to ::FindResourceExW."); + + hData = ::LoadResource(hModule, hRsrc); + ReswExitOnNullWithLastError(hData, hr, "Failed to ::LoadResource."); + + cbData = ::SizeofResource(hModule, hRsrc); + if (!cbData) + { + ReswExitWithLastError(hr, "Failed to ::SizeofResource."); + } + + pvData = ::LockResource(hData); + ReswExitOnNullWithLastError(pvData, hr, "Failed to lock data resource."); + + pStrBlock->dwBlockId = dwBlockId; + pStrBlock->wLangId = wLangId; + + hr = StringBlockConvertFromResourceData(pStrBlock, pvData, cbData); + ReswExitOnFailure(hr, "Failed to convert string block from resource data."); + +LExit: + return hr; +} + + +static void StringBlockUnitialize( + __in RES_STRING_BLOCK* pStrBlock + ) +{ + if (pStrBlock) + { + for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) + { + ReleaseNullMem(pStrBlock->rgwz[i]); + } + } +} + + +static HRESULT StringBlockChangeString( + __in RES_STRING_BLOCK* pStrBlock, + __in DWORD dwStringId, + __in_z LPCWSTR szData + ) +{ + HRESULT hr = S_OK; + LPWSTR pwzData = NULL; + size_t cchData = 0; + + hr = ::StringCchLengthW(szData, STRSAFE_MAX_LENGTH, &cchData); + ReswExitOnRootFailure(hr, "Failed to get block string length."); + + pwzData = static_cast(MemAlloc((cchData + 1) * sizeof(WCHAR), TRUE)); + ReswExitOnNull(pwzData, hr, E_OUTOFMEMORY, "Failed to allocate new block string."); + + hr = ::StringCchCopyW(pwzData, cchData + 1, szData); + ReswExitOnRootFailure(hr, "Failed to copy new block string."); + + ReleaseNullMem(pStrBlock->rgwz[dwStringId]); + + pStrBlock->rgwz[dwStringId] = pwzData; + pwzData = NULL; + +LExit: + ReleaseMem(pwzData); + + return hr; +} + + +static HRESULT StringBlockConvertToResourceData( + __in const RES_STRING_BLOCK* pStrBlock, + __deref_out_bcount(*pcbData) LPVOID* ppvData, + __out DWORD* pcbData + ) +{ + HRESULT hr = S_OK; + DWORD cbData = 0; + LPVOID pvData = NULL; + WCHAR* pwz = NULL; + + for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) + { + cbData += (lstrlenW(pStrBlock->rgwz[i]) + 1); + } + cbData *= sizeof(WCHAR); + + pvData = MemAlloc(cbData, TRUE); + ReswExitOnNull(pvData, hr, E_OUTOFMEMORY, "Failed to allocate buffer to convert string block."); + + pwz = static_cast(pvData); + for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) + { + DWORD cch = lstrlenW(pStrBlock->rgwz[i]); + + *pwz = static_cast(cch); + ++pwz; + + for (DWORD j = 0; j < cch; ++j) + { + *pwz = pStrBlock->rgwz[i][j]; + ++pwz; + } + } + + *pcbData = cbData; + *ppvData = pvData; + pvData = NULL; + +LExit: + ReleaseMem(pvData); + + return hr; +} + + +static HRESULT StringBlockConvertFromResourceData( + __in RES_STRING_BLOCK* pStrBlock, + __in_bcount(cbData) LPCVOID pvData, + __in SIZE_T cbData + ) +{ + UNREFERENCED_PARAMETER(cbData); + HRESULT hr = S_OK; + LPCWSTR pwzParse = static_cast(pvData); + + for (DWORD i = 0; i < RES_STRINGS_PER_BLOCK; ++i) + { + DWORD cchParse = static_cast(*pwzParse); + ++pwzParse; + + pStrBlock->rgwz[i] = static_cast(MemAlloc((cchParse + 1) * sizeof(WCHAR), TRUE)); + ReswExitOnNull(pStrBlock->rgwz[i], hr, E_OUTOFMEMORY, "Failed to populate pStrBlock."); + + hr = ::StringCchCopyNExW(pStrBlock->rgwz[i], cchParse + 1, pwzParse, cchParse, NULL, NULL, STRSAFE_FILL_BEHIND_NULL); + ReswExitOnFailure(hr, "Failed to copy parsed resource data into string block."); + + pwzParse += cchParse; + } + +LExit: + return hr; +} -- cgit v1.2.3-55-g6feb