aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/reswutil.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 06:38:23 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:21:09 -0700
commit7f642e51670bc38a4ef782a363936850bc2b0ba9 (patch)
tree19684b2d94979f130c0935328f0d44cf006e45ef /src/libs/dutil/WixToolset.DUtil/reswutil.cpp
parentf39e7a3e164d0736e45049e5726d0da2013da3c9 (diff)
downloadwix-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.cpp386
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.
24typedef 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
33static HRESULT StringBlockInitialize(
34 __in_opt HINSTANCE hModule,
35 __in DWORD dwBlockId,
36 __in WORD wLangId,
37 __in RES_STRING_BLOCK* pStrBlock
38 );
39static void StringBlockUnitialize(
40 __in RES_STRING_BLOCK* pStrBlock
41 );
42static HRESULT StringBlockChangeString(
43 __in RES_STRING_BLOCK* pStrBlock,
44 __in DWORD dwStringId,
45 __in_z LPCWSTR szData
46 );
47static HRESULT StringBlockConvertToResourceData(
48 __in const RES_STRING_BLOCK* pStrBlock,
49 __deref_out_bcount(*pcbData) LPVOID* ppvData,
50 __out DWORD* pcbData
51 );
52static HRESULT StringBlockConvertFromResourceData(
53 __in RES_STRING_BLOCK* pStrBlock,
54 __in_bcount(cbData) LPCVOID pvData,
55 __in SIZE_T cbData
56 );
57
58
59/********************************************************************
60ResWriteString - sets the string into to the specified file's resource name
61
62********************************************************************/
63extern "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
113LExit:
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/********************************************************************
133ResWriteData - sets the data into to the specified file's resource name
134
135********************************************************************/
136extern "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
166LExit:
167 if (hUpdate)
168 {
169 ::EndUpdateResource(hUpdate, TRUE);
170 }
171
172 return hr;
173}
174
175
176/********************************************************************
177ResImportDataFromFile - reads a file and sets the data into to the specified file's resource name
178
179********************************************************************/
180extern "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
213LExit:
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
230static 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
264LExit:
265 return hr;
266}
267
268
269static 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
283static 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
307LExit:
308 ReleaseMem(pwzData);
309
310 return hr;
311}
312
313
314static 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
353LExit:
354 ReleaseMem(pvData);
355
356 return hr;
357}
358
359
360static 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
384LExit:
385 return hr;
386}