diff options
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 | } | ||