diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/locutil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/locutil.cpp | 628 |
1 files changed, 628 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/locutil.cpp b/src/libs/dutil/WixToolset.DUtil/locutil.cpp new file mode 100644 index 00000000..c4567c03 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/locutil.cpp | |||
@@ -0,0 +1,628 @@ | |||
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 LocExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__) | ||
8 | #define LocExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__) | ||
9 | #define LocExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__) | ||
10 | #define LocExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__) | ||
11 | #define LocExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__) | ||
12 | #define LocExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_LOCUTIL, x, s, __VA_ARGS__) | ||
13 | #define LocExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_LOCUTIL, p, x, e, s, __VA_ARGS__) | ||
14 | #define LocExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_LOCUTIL, p, x, s, __VA_ARGS__) | ||
15 | #define LocExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_LOCUTIL, p, x, e, s, __VA_ARGS__) | ||
16 | #define LocExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_LOCUTIL, p, x, s, __VA_ARGS__) | ||
17 | #define LocExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_LOCUTIL, e, x, s, __VA_ARGS__) | ||
18 | #define LocExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_LOCUTIL, g, x, s, __VA_ARGS__) | ||
19 | |||
20 | // prototypes | ||
21 | static HRESULT ParseWxl( | ||
22 | __in IXMLDOMDocument* pixd, | ||
23 | __out WIX_LOCALIZATION** ppWixLoc | ||
24 | ); | ||
25 | static HRESULT ParseWxlStrings( | ||
26 | __in IXMLDOMElement* pElement, | ||
27 | __in WIX_LOCALIZATION* pWixLoc | ||
28 | ); | ||
29 | static HRESULT ParseWxlControls( | ||
30 | __in IXMLDOMElement* pElement, | ||
31 | __in WIX_LOCALIZATION* pWixLoc | ||
32 | ); | ||
33 | static HRESULT ParseWxlString( | ||
34 | __in IXMLDOMNode* pixn, | ||
35 | __in DWORD dwIdx, | ||
36 | __in WIX_LOCALIZATION* pWixLoc | ||
37 | ); | ||
38 | static HRESULT ParseWxlControl( | ||
39 | __in IXMLDOMNode* pixn, | ||
40 | __in DWORD dwIdx, | ||
41 | __in WIX_LOCALIZATION* pWixLoc | ||
42 | ); | ||
43 | |||
44 | // from Winnls.h | ||
45 | #ifndef MUI_LANGUAGE_ID | ||
46 | #define MUI_LANGUAGE_ID 0x4 // Use traditional language ID convention | ||
47 | #endif | ||
48 | #ifndef MUI_MERGE_USER_FALLBACK | ||
49 | #define MUI_MERGE_USER_FALLBACK 0x20 // GetThreadPreferredUILanguages merges in user preferred languages | ||
50 | #endif | ||
51 | #ifndef MUI_MERGE_SYSTEM_FALLBACK | ||
52 | #define MUI_MERGE_SYSTEM_FALLBACK 0x10 // GetThreadPreferredUILanguages merges in parent and base languages | ||
53 | #endif | ||
54 | typedef WINBASEAPI BOOL (WINAPI *GET_THREAD_PREFERRED_UI_LANGUAGES) ( | ||
55 | __in DWORD dwFlags, | ||
56 | __out PULONG pulNumLanguages, | ||
57 | __out_ecount_opt(*pcchLanguagesBuffer) PZZWSTR pwszLanguagesBuffer, | ||
58 | __inout PULONG pcchLanguagesBuffer | ||
59 | ); | ||
60 | |||
61 | extern "C" HRESULT DAPI LocProbeForFile( | ||
62 | __in_z LPCWSTR wzBasePath, | ||
63 | __in_z LPCWSTR wzLocFileName, | ||
64 | __in_z_opt LPCWSTR wzLanguage, | ||
65 | __inout LPWSTR* psczPath | ||
66 | ) | ||
67 | { | ||
68 | HRESULT hr = S_OK; | ||
69 | LPWSTR sczProbePath = NULL; | ||
70 | LANGID langid = 0; | ||
71 | LPWSTR sczLangIdFile = NULL; | ||
72 | LPWSTR sczLangsBuff = NULL; | ||
73 | GET_THREAD_PREFERRED_UI_LANGUAGES pvfnGetThreadPreferredUILanguages = | ||
74 | reinterpret_cast<GET_THREAD_PREFERRED_UI_LANGUAGES>( | ||
75 | GetProcAddress(GetModuleHandle("Kernel32.dll"), "GetThreadPreferredUILanguages")); | ||
76 | |||
77 | // If a language was specified, look for a loc file in that as a directory. | ||
78 | if (wzLanguage && *wzLanguage) | ||
79 | { | ||
80 | hr = PathConcat(wzBasePath, wzLanguage, &sczProbePath); | ||
81 | LocExitOnFailure(hr, "Failed to concat base path to language."); | ||
82 | |||
83 | hr = PathConcat(sczProbePath, wzLocFileName, &sczProbePath); | ||
84 | LocExitOnFailure(hr, "Failed to concat loc file name to probe path."); | ||
85 | |||
86 | if (FileExistsEx(sczProbePath, NULL)) | ||
87 | { | ||
88 | ExitFunction(); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | if (pvfnGetThreadPreferredUILanguages) | ||
93 | { | ||
94 | ULONG nLangs; | ||
95 | ULONG cchLangs = 0; | ||
96 | DWORD dwFlags = MUI_LANGUAGE_ID | MUI_MERGE_USER_FALLBACK | MUI_MERGE_SYSTEM_FALLBACK; | ||
97 | if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, NULL, &cchLangs)) | ||
98 | { | ||
99 | LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return buffer size."); | ||
100 | } | ||
101 | |||
102 | hr = StrAlloc(&sczLangsBuff, cchLangs); | ||
103 | LocExitOnFailure(hr, "Failed to allocate buffer for languages"); | ||
104 | |||
105 | nLangs = 0; | ||
106 | if (!(*pvfnGetThreadPreferredUILanguages)(dwFlags, &nLangs, sczLangsBuff, &cchLangs)) | ||
107 | { | ||
108 | LocExitWithLastError(hr, "GetThreadPreferredUILanguages failed to return language list."); | ||
109 | } | ||
110 | |||
111 | LPWSTR szLangs = sczLangsBuff; | ||
112 | for (ULONG i = 0; i < nLangs; ++i, szLangs += 5) | ||
113 | { | ||
114 | // StrHexDecode assumes low byte is first. We'll need to swap the bytes once we parse out the value. | ||
115 | hr = StrHexDecode(szLangs, reinterpret_cast<BYTE*>(&langid), sizeof(langid)); | ||
116 | LocExitOnFailure(hr, "Failed to parse langId."); | ||
117 | |||
118 | langid = MAKEWORD(HIBYTE(langid), LOBYTE(langid)); | ||
119 | hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); | ||
120 | LocExitOnFailure(hr, "Failed to format user preferred langid."); | ||
121 | |||
122 | hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); | ||
123 | LocExitOnFailure(hr, "Failed to concat user preferred langid file name to base path."); | ||
124 | |||
125 | if (FileExistsEx(sczProbePath, NULL)) | ||
126 | { | ||
127 | ExitFunction(); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | langid = ::GetUserDefaultUILanguage(); | ||
133 | |||
134 | hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); | ||
135 | LocExitOnFailure(hr, "Failed to format user langid."); | ||
136 | |||
137 | hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); | ||
138 | LocExitOnFailure(hr, "Failed to concat user langid file name to base path."); | ||
139 | |||
140 | if (FileExistsEx(sczProbePath, NULL)) | ||
141 | { | ||
142 | ExitFunction(); | ||
143 | } | ||
144 | |||
145 | if (MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT) != langid) | ||
146 | { | ||
147 | langid = MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT); | ||
148 | |||
149 | hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); | ||
150 | LocExitOnFailure(hr, "Failed to format user langid (default sublang)."); | ||
151 | |||
152 | hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); | ||
153 | LocExitOnFailure(hr, "Failed to concat user langid file name to base path (default sublang)."); | ||
154 | |||
155 | if (FileExistsEx(sczProbePath, NULL)) | ||
156 | { | ||
157 | ExitFunction(); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | langid = ::GetSystemDefaultUILanguage(); | ||
162 | |||
163 | hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); | ||
164 | LocExitOnFailure(hr, "Failed to format system langid."); | ||
165 | |||
166 | hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); | ||
167 | LocExitOnFailure(hr, "Failed to concat system langid file name to base path."); | ||
168 | |||
169 | if (FileExistsEx(sczProbePath, NULL)) | ||
170 | { | ||
171 | ExitFunction(); | ||
172 | } | ||
173 | |||
174 | if (MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT) != langid) | ||
175 | { | ||
176 | langid = MAKELANGID(langid & 0x3FF, SUBLANG_DEFAULT); | ||
177 | |||
178 | hr = StrAllocFormatted(&sczLangIdFile, L"%u\\%ls", langid, wzLocFileName); | ||
179 | LocExitOnFailure(hr, "Failed to format user langid (default sublang)."); | ||
180 | |||
181 | hr = PathConcat(wzBasePath, sczLangIdFile, &sczProbePath); | ||
182 | LocExitOnFailure(hr, "Failed to concat user langid file name to base path (default sublang)."); | ||
183 | |||
184 | if (FileExistsEx(sczProbePath, NULL)) | ||
185 | { | ||
186 | ExitFunction(); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | // Finally, look for the loc file in the base path. | ||
191 | hr = PathConcat(wzBasePath, wzLocFileName, &sczProbePath); | ||
192 | LocExitOnFailure(hr, "Failed to concat loc file name to base path."); | ||
193 | |||
194 | if (!FileExistsEx(sczProbePath, NULL)) | ||
195 | { | ||
196 | hr = E_FILENOTFOUND; | ||
197 | } | ||
198 | |||
199 | LExit: | ||
200 | if (SUCCEEDED(hr)) | ||
201 | { | ||
202 | hr = StrAllocString(psczPath, sczProbePath, 0); | ||
203 | } | ||
204 | |||
205 | ReleaseStr(sczLangIdFile); | ||
206 | ReleaseStr(sczProbePath); | ||
207 | ReleaseStr(sczLangsBuff); | ||
208 | |||
209 | return hr; | ||
210 | } | ||
211 | |||
212 | extern "C" HRESULT DAPI LocLoadFromFile( | ||
213 | __in_z LPCWSTR wzWxlFile, | ||
214 | __out WIX_LOCALIZATION** ppWixLoc | ||
215 | ) | ||
216 | { | ||
217 | HRESULT hr = S_OK; | ||
218 | IXMLDOMDocument* pixd = NULL; | ||
219 | |||
220 | hr = XmlLoadDocumentFromFile(wzWxlFile, &pixd); | ||
221 | LocExitOnFailure(hr, "Failed to load WXL file as XML document."); | ||
222 | |||
223 | hr = ParseWxl(pixd, ppWixLoc); | ||
224 | LocExitOnFailure(hr, "Failed to parse WXL."); | ||
225 | |||
226 | LExit: | ||
227 | ReleaseObject(pixd); | ||
228 | |||
229 | return hr; | ||
230 | } | ||
231 | |||
232 | extern "C" HRESULT DAPI LocLoadFromResource( | ||
233 | __in HMODULE hModule, | ||
234 | __in_z LPCSTR szResource, | ||
235 | __out WIX_LOCALIZATION** ppWixLoc | ||
236 | ) | ||
237 | { | ||
238 | HRESULT hr = S_OK; | ||
239 | LPVOID pvResource = NULL; | ||
240 | DWORD cbResource = 0; | ||
241 | LPWSTR sczXml = NULL; | ||
242 | IXMLDOMDocument* pixd = NULL; | ||
243 | |||
244 | hr = ResReadData(hModule, szResource, &pvResource, &cbResource); | ||
245 | LocExitOnFailure(hr, "Failed to read theme from resource."); | ||
246 | |||
247 | hr = StrAllocStringAnsi(&sczXml, reinterpret_cast<LPCSTR>(pvResource), cbResource, CP_UTF8); | ||
248 | LocExitOnFailure(hr, "Failed to convert XML document data from UTF-8 to unicode string."); | ||
249 | |||
250 | hr = XmlLoadDocument(sczXml, &pixd); | ||
251 | LocExitOnFailure(hr, "Failed to load theme resource as XML document."); | ||
252 | |||
253 | hr = ParseWxl(pixd, ppWixLoc); | ||
254 | LocExitOnFailure(hr, "Failed to parse WXL."); | ||
255 | |||
256 | LExit: | ||
257 | ReleaseObject(pixd); | ||
258 | ReleaseStr(sczXml); | ||
259 | |||
260 | return hr; | ||
261 | } | ||
262 | |||
263 | extern "C" void DAPI LocFree( | ||
264 | __in_opt WIX_LOCALIZATION* pWixLoc | ||
265 | ) | ||
266 | { | ||
267 | if (pWixLoc) | ||
268 | { | ||
269 | for (DWORD idx = 0; idx < pWixLoc->cLocStrings; ++idx) | ||
270 | { | ||
271 | ReleaseStr(pWixLoc->rgLocStrings[idx].wzId); | ||
272 | ReleaseStr(pWixLoc->rgLocStrings[idx].wzText); | ||
273 | } | ||
274 | |||
275 | for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx) | ||
276 | { | ||
277 | ReleaseStr(pWixLoc->rgLocControls[idx].wzControl); | ||
278 | ReleaseStr(pWixLoc->rgLocControls[idx].wzText); | ||
279 | } | ||
280 | |||
281 | ReleaseMem(pWixLoc->rgLocStrings); | ||
282 | ReleaseMem(pWixLoc->rgLocControls); | ||
283 | ReleaseMem(pWixLoc); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | extern "C" HRESULT DAPI LocLocalizeString( | ||
288 | __in const WIX_LOCALIZATION* pWixLoc, | ||
289 | __inout LPWSTR* ppsczInput | ||
290 | ) | ||
291 | { | ||
292 | Assert(ppsczInput && pWixLoc); | ||
293 | HRESULT hr = S_OK; | ||
294 | |||
295 | for (DWORD i = 0; i < pWixLoc->cLocStrings; ++i) | ||
296 | { | ||
297 | hr = StrReplaceStringAll(ppsczInput, pWixLoc->rgLocStrings[i].wzId, pWixLoc->rgLocStrings[i].wzText); | ||
298 | LocExitOnFailure(hr, "Localizing string failed."); | ||
299 | } | ||
300 | |||
301 | LExit: | ||
302 | return hr; | ||
303 | } | ||
304 | |||
305 | extern "C" HRESULT DAPI LocGetControl( | ||
306 | __in const WIX_LOCALIZATION* pWixLoc, | ||
307 | __in_z LPCWSTR wzId, | ||
308 | __out LOC_CONTROL** ppLocControl | ||
309 | ) | ||
310 | { | ||
311 | HRESULT hr = S_OK; | ||
312 | LOC_CONTROL* pLocControl = NULL; | ||
313 | |||
314 | for (DWORD i = 0; i < pWixLoc->cLocControls; ++i) | ||
315 | { | ||
316 | pLocControl = &pWixLoc->rgLocControls[i]; | ||
317 | |||
318 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pLocControl->wzControl, -1, wzId, -1)) | ||
319 | { | ||
320 | *ppLocControl = pLocControl; | ||
321 | ExitFunction1(hr = S_OK); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | hr = E_NOTFOUND; | ||
326 | |||
327 | LExit: | ||
328 | return hr; | ||
329 | } | ||
330 | |||
331 | extern "C" HRESULT DAPI LocGetString( | ||
332 | __in const WIX_LOCALIZATION* pWixLoc, | ||
333 | __in_z LPCWSTR wzId, | ||
334 | __out LOC_STRING** ppLocString | ||
335 | ) | ||
336 | { | ||
337 | HRESULT hr = E_NOTFOUND; | ||
338 | LOC_STRING* pLocString = NULL; | ||
339 | |||
340 | for (DWORD i = 0; i < pWixLoc->cLocStrings; ++i) | ||
341 | { | ||
342 | pLocString = pWixLoc->rgLocStrings + i; | ||
343 | |||
344 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pLocString->wzId, -1, wzId, -1)) | ||
345 | { | ||
346 | *ppLocString = pLocString; | ||
347 | hr = S_OK; | ||
348 | break; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | return hr; | ||
353 | } | ||
354 | |||
355 | extern "C" HRESULT DAPI LocAddString( | ||
356 | __in WIX_LOCALIZATION* pWixLoc, | ||
357 | __in_z LPCWSTR wzId, | ||
358 | __in_z LPCWSTR wzLocString, | ||
359 | __in BOOL bOverridable | ||
360 | ) | ||
361 | { | ||
362 | HRESULT hr = S_OK; | ||
363 | |||
364 | ++pWixLoc->cLocStrings; | ||
365 | pWixLoc->rgLocStrings = static_cast<LOC_STRING*>(MemReAlloc(pWixLoc->rgLocStrings, sizeof(LOC_STRING) * pWixLoc->cLocStrings, TRUE)); | ||
366 | LocExitOnNull(pWixLoc->rgLocStrings, hr, E_OUTOFMEMORY, "Failed to reallocate memory for localization strings."); | ||
367 | |||
368 | LOC_STRING* pLocString = pWixLoc->rgLocStrings + (pWixLoc->cLocStrings - 1); | ||
369 | |||
370 | hr = StrAllocFormatted(&pLocString->wzId, L"#(loc.%s)", wzId); | ||
371 | LocExitOnFailure(hr, "Failed to set localization string Id."); | ||
372 | |||
373 | hr = StrAllocString(&pLocString->wzText, wzLocString, 0); | ||
374 | LocExitOnFailure(hr, "Failed to set localization string Text."); | ||
375 | |||
376 | pLocString->bOverridable = bOverridable; | ||
377 | |||
378 | LExit: | ||
379 | return hr; | ||
380 | } | ||
381 | |||
382 | // helper functions | ||
383 | |||
384 | static HRESULT ParseWxl( | ||
385 | __in IXMLDOMDocument* pixd, | ||
386 | __out WIX_LOCALIZATION** ppWixLoc | ||
387 | ) | ||
388 | { | ||
389 | HRESULT hr = S_OK; | ||
390 | IXMLDOMElement *pWxlElement = NULL; | ||
391 | WIX_LOCALIZATION* pWixLoc = NULL; | ||
392 | |||
393 | pWixLoc = static_cast<WIX_LOCALIZATION*>(MemAlloc(sizeof(WIX_LOCALIZATION), TRUE)); | ||
394 | LocExitOnNull(pWixLoc, hr, E_OUTOFMEMORY, "Failed to allocate memory for Wxl file."); | ||
395 | |||
396 | // read the WixLocalization tag | ||
397 | hr = pixd->get_documentElement(&pWxlElement); | ||
398 | LocExitOnFailure(hr, "Failed to get localization element."); | ||
399 | |||
400 | // get the Language attribute if present | ||
401 | pWixLoc->dwLangId = WIX_LOCALIZATION_LANGUAGE_NOT_SET; | ||
402 | hr = XmlGetAttributeNumber(pWxlElement, L"Language", &pWixLoc->dwLangId); | ||
403 | if (S_FALSE == hr) | ||
404 | { | ||
405 | hr = S_OK; | ||
406 | } | ||
407 | LocExitOnFailure(hr, "Failed to get Language value."); | ||
408 | |||
409 | // store the strings and controls in a node list | ||
410 | hr = ParseWxlStrings(pWxlElement, pWixLoc); | ||
411 | LocExitOnFailure(hr, "Parsing localization strings failed."); | ||
412 | |||
413 | hr = ParseWxlControls(pWxlElement, pWixLoc); | ||
414 | LocExitOnFailure(hr, "Parsing localization controls failed."); | ||
415 | |||
416 | *ppWixLoc = pWixLoc; | ||
417 | pWixLoc = NULL; | ||
418 | |||
419 | LExit: | ||
420 | ReleaseObject(pWxlElement); | ||
421 | ReleaseMem(pWixLoc); | ||
422 | |||
423 | return hr; | ||
424 | } | ||
425 | |||
426 | |||
427 | static HRESULT ParseWxlStrings( | ||
428 | __in IXMLDOMElement* pElement, | ||
429 | __in WIX_LOCALIZATION* pWixLoc | ||
430 | ) | ||
431 | { | ||
432 | HRESULT hr = S_OK; | ||
433 | IXMLDOMNode* pixn = NULL; | ||
434 | IXMLDOMNodeList* pixnl = NULL; | ||
435 | DWORD dwIdx = 0; | ||
436 | |||
437 | hr = XmlSelectNodes(pElement, L"String", &pixnl); | ||
438 | LocExitOnLastError(hr, "Failed to get String child nodes of Wxl File."); | ||
439 | |||
440 | hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocStrings)); | ||
441 | LocExitOnLastError(hr, "Failed to get number of String child nodes in Wxl File."); | ||
442 | |||
443 | if (0 < pWixLoc->cLocStrings) | ||
444 | { | ||
445 | pWixLoc->rgLocStrings = static_cast<LOC_STRING*>(MemAlloc(sizeof(LOC_STRING) * pWixLoc->cLocStrings, TRUE)); | ||
446 | LocExitOnNull(pWixLoc->rgLocStrings, hr, E_OUTOFMEMORY, "Failed to allocate memory for localization strings."); | ||
447 | |||
448 | while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL))) | ||
449 | { | ||
450 | hr = ParseWxlString(pixn, dwIdx, pWixLoc); | ||
451 | LocExitOnFailure(hr, "Failed to parse localization string."); | ||
452 | |||
453 | ++dwIdx; | ||
454 | ReleaseNullObject(pixn); | ||
455 | } | ||
456 | |||
457 | hr = S_OK; | ||
458 | LocExitOnFailure(hr, "Failed to enumerate all localization strings."); | ||
459 | } | ||
460 | |||
461 | LExit: | ||
462 | if (FAILED(hr) && pWixLoc->rgLocStrings) | ||
463 | { | ||
464 | for (DWORD idx = 0; idx < pWixLoc->cLocStrings; ++idx) | ||
465 | { | ||
466 | ReleaseStr(pWixLoc->rgLocStrings[idx].wzId); | ||
467 | ReleaseStr(pWixLoc->rgLocStrings[idx].wzText); | ||
468 | } | ||
469 | |||
470 | ReleaseMem(pWixLoc->rgLocStrings); | ||
471 | } | ||
472 | |||
473 | ReleaseObject(pixn); | ||
474 | ReleaseObject(pixnl); | ||
475 | |||
476 | return hr; | ||
477 | } | ||
478 | |||
479 | static HRESULT ParseWxlControls( | ||
480 | __in IXMLDOMElement* pElement, | ||
481 | __in WIX_LOCALIZATION* pWixLoc | ||
482 | ) | ||
483 | { | ||
484 | HRESULT hr = S_OK; | ||
485 | IXMLDOMNode* pixn = NULL; | ||
486 | IXMLDOMNodeList* pixnl = NULL; | ||
487 | DWORD dwIdx = 0; | ||
488 | |||
489 | hr = XmlSelectNodes(pElement, L"UI|Control", &pixnl); | ||
490 | LocExitOnLastError(hr, "Failed to get UI child nodes of Wxl File."); | ||
491 | |||
492 | hr = pixnl->get_length(reinterpret_cast<long*>(&pWixLoc->cLocControls)); | ||
493 | LocExitOnLastError(hr, "Failed to get number of UI child nodes in Wxl File."); | ||
494 | |||
495 | if (0 < pWixLoc->cLocControls) | ||
496 | { | ||
497 | pWixLoc->rgLocControls = static_cast<LOC_CONTROL*>(MemAlloc(sizeof(LOC_CONTROL) * pWixLoc->cLocControls, TRUE)); | ||
498 | LocExitOnNull(pWixLoc->rgLocControls, hr, E_OUTOFMEMORY, "Failed to allocate memory for localized controls."); | ||
499 | |||
500 | while (S_OK == (hr = XmlNextElement(pixnl, &pixn, NULL))) | ||
501 | { | ||
502 | hr = ParseWxlControl(pixn, dwIdx, pWixLoc); | ||
503 | LocExitOnFailure(hr, "Failed to parse localized control."); | ||
504 | |||
505 | ++dwIdx; | ||
506 | ReleaseNullObject(pixn); | ||
507 | } | ||
508 | |||
509 | hr = S_OK; | ||
510 | LocExitOnFailure(hr, "Failed to enumerate all localized controls."); | ||
511 | } | ||
512 | |||
513 | LExit: | ||
514 | if (FAILED(hr) && pWixLoc->rgLocControls) | ||
515 | { | ||
516 | for (DWORD idx = 0; idx < pWixLoc->cLocControls; ++idx) | ||
517 | { | ||
518 | ReleaseStr(pWixLoc->rgLocControls[idx].wzControl); | ||
519 | ReleaseStr(pWixLoc->rgLocControls[idx].wzText); | ||
520 | } | ||
521 | |||
522 | ReleaseMem(pWixLoc->rgLocControls); | ||
523 | } | ||
524 | |||
525 | ReleaseObject(pixn); | ||
526 | ReleaseObject(pixnl); | ||
527 | |||
528 | return hr; | ||
529 | } | ||
530 | |||
531 | static HRESULT ParseWxlString( | ||
532 | __in IXMLDOMNode* pixn, | ||
533 | __in DWORD dwIdx, | ||
534 | __in WIX_LOCALIZATION* pWixLoc | ||
535 | ) | ||
536 | { | ||
537 | HRESULT hr = S_OK; | ||
538 | LOC_STRING* pLocString = NULL; | ||
539 | BSTR bstrText = NULL; | ||
540 | |||
541 | pLocString = pWixLoc->rgLocStrings + dwIdx; | ||
542 | |||
543 | // Id | ||
544 | hr = XmlGetAttribute(pixn, L"Id", &bstrText); | ||
545 | LocExitOnFailure(hr, "Failed to get Xml attribute Id in Wxl file."); | ||
546 | |||
547 | hr = StrAllocFormatted(&pLocString->wzId, L"#(loc.%s)", bstrText); | ||
548 | LocExitOnFailure(hr, "Failed to duplicate Xml attribute Id in Wxl file."); | ||
549 | |||
550 | ReleaseNullBSTR(bstrText); | ||
551 | |||
552 | // Overrideable | ||
553 | hr = XmlGetAttribute(pixn, L"Overridable", &bstrText); | ||
554 | LocExitOnFailure(hr, "Failed to get Xml attribute Overridable."); | ||
555 | |||
556 | if (S_OK == hr) | ||
557 | { | ||
558 | pLocString->bOverridable = CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrText, -1, L"yes", -1); | ||
559 | } | ||
560 | |||
561 | ReleaseNullBSTR(bstrText); | ||
562 | |||
563 | // Text | ||
564 | hr = XmlGetText(pixn, &bstrText); | ||
565 | LocExitOnFailure(hr, "Failed to get Xml text in Wxl file."); | ||
566 | |||
567 | hr = StrAllocString(&pLocString->wzText, bstrText, 0); | ||
568 | LocExitOnFailure(hr, "Failed to duplicate Xml text in Wxl file."); | ||
569 | |||
570 | LExit: | ||
571 | ReleaseBSTR(bstrText); | ||
572 | |||
573 | return hr; | ||
574 | } | ||
575 | |||
576 | static HRESULT ParseWxlControl( | ||
577 | __in IXMLDOMNode* pixn, | ||
578 | __in DWORD dwIdx, | ||
579 | __in WIX_LOCALIZATION* pWixLoc | ||
580 | ) | ||
581 | { | ||
582 | HRESULT hr = S_OK; | ||
583 | LOC_CONTROL* pLocControl = NULL; | ||
584 | BSTR bstrText = NULL; | ||
585 | |||
586 | pLocControl = pWixLoc->rgLocControls + dwIdx; | ||
587 | |||
588 | // Id | ||
589 | hr = XmlGetAttribute(pixn, L"Control", &bstrText); | ||
590 | LocExitOnFailure(hr, "Failed to get Xml attribute Control in Wxl file."); | ||
591 | |||
592 | hr = StrAllocString(&pLocControl->wzControl, bstrText, 0); | ||
593 | LocExitOnFailure(hr, "Failed to duplicate Xml attribute Control in Wxl file."); | ||
594 | |||
595 | ReleaseNullBSTR(bstrText); | ||
596 | |||
597 | // X | ||
598 | pLocControl->nX = LOC_CONTROL_NOT_SET; | ||
599 | hr = XmlGetAttributeNumber(pixn, L"X", reinterpret_cast<DWORD*>(&pLocControl->nX)); | ||
600 | LocExitOnFailure(hr, "Failed to get control X attribute."); | ||
601 | |||
602 | // Y | ||
603 | pLocControl->nY = LOC_CONTROL_NOT_SET; | ||
604 | hr = XmlGetAttributeNumber(pixn, L"Y", reinterpret_cast<DWORD*>(&pLocControl->nY)); | ||
605 | LocExitOnFailure(hr, "Failed to get control Y attribute."); | ||
606 | |||
607 | // Width | ||
608 | pLocControl->nWidth = LOC_CONTROL_NOT_SET; | ||
609 | hr = XmlGetAttributeNumber(pixn, L"Width", reinterpret_cast<DWORD*>(&pLocControl->nWidth)); | ||
610 | LocExitOnFailure(hr, "Failed to get control width attribute."); | ||
611 | |||
612 | // Height | ||
613 | pLocControl->nHeight = LOC_CONTROL_NOT_SET; | ||
614 | hr = XmlGetAttributeNumber(pixn, L"Height", reinterpret_cast<DWORD*>(&pLocControl->nHeight)); | ||
615 | LocExitOnFailure(hr, "Failed to get control height attribute."); | ||
616 | |||
617 | // Text | ||
618 | hr = XmlGetText(pixn, &bstrText); | ||
619 | LocExitOnFailure(hr, "Failed to get control text in Wxl file."); | ||
620 | |||
621 | hr = StrAllocString(&pLocControl->wzText, bstrText, 0); | ||
622 | LocExitOnFailure(hr, "Failed to duplicate control text in Wxl file."); | ||
623 | |||
624 | LExit: | ||
625 | ReleaseBSTR(bstrText); | ||
626 | |||
627 | return hr; | ||
628 | } | ||