1 krisbash 1.1 /*
2 **==============================================================================
3 **
4 ** Open Management Infrastructure (OMI)
5 **
6 ** Copyright (c) Microsoft Corporation
7 **
|
8 krisbash 1.2 ** Licensed under the Apache License, Version 2.0 (the "License"); you may not
9 ** use this file except in compliance with the License. You may obtain a copy
10 ** of the License at
11 **
12 ** http://www.apache.org/licenses/LICENSE-2.0
|
13 krisbash 1.1 **
14 ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15 krisbash 1.2 ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 ** MERCHANTABLITY OR NON-INFRINGEMENT.
|
18 krisbash 1.1 **
|
19 krisbash 1.2 ** See the Apache 2 License for the specific language governing permissions
|
20 krisbash 1.1 ** and limitations under the License.
21 **
22 **==============================================================================
23 */
24
25 #include "intlstr.h"
26
27 #include <assert.h>
|
28 krisbash 1.2 #include <pal/intsafe.h>
|
29 krisbash 1.1
30 #if defined(_MSC_VER)
31
32 #include <windows.h>
33
34 _Use_decl_annotations_
35 const PAL_Char* _Intlstr_GetString_LoadString(HINSTANCE hInstance, UINT uID)
36 {
37 int err;
38 LPTSTR lpBuffer;
39
40 err = LoadString(hInstance, uID, (LPTSTR)&lpBuffer, 0);
41 if (err == 0)
42 {
43 /* TODO/FIXME - OI diagnostics */
44 return NULL;
45 }
46
47 return lpBuffer;
48 }
49
50 krisbash 1.1 _Use_decl_annotations_
51 PAL_Char* _Intlstr_FormatString_FormatMessage(HINSTANCE hInstance, UINT uID, ...)
52 {
53 DWORD result;
54 int err;
55 LPTSTR lpTemplate;
56 LPTSTR lpFormattedString;
|
57 krisbash 1.2 va_list ap;
|
58 krisbash 1.1
59 err = LoadString(hInstance, uID, (LPTSTR)&lpTemplate, 0);
60 if (err == 0)
61 {
62 /* TODO/FIXME - OI diagnostics */
63 return NULL;
64 }
65
|
66 krisbash 1.2 va_start(ap, uID);
|
67 krisbash 1.1 result = FormatMessage(
68 /* TODO/FIXME - FORMAT_MESSAGE_FROM_HMODULE can in theory help avoid the LoadString above, but I couldn't get it to work... */
|
69 krisbash 1.2 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
70 lpTemplate,
|
71 krisbash 1.1 0, /* dwMessageId; ignored when FORMAT_MESSAGE_FROM_STRING is used */
72 0, /* dwLanguageId; ignored when FORMAT_MESSAGE_FROM_STRING is used */
73 (LPTSTR)&lpFormattedString,
74 0, /* nSize - maximum size of buffer to allocate; 0 means no limit */
75 &ap);
|
76 krisbash 1.2 va_end(ap);
|
77 krisbash 1.1 if (result == 0)
78 {
79 /* TODO/FIXME - OI diagnostics */
80 return NULL;
81 }
82
83 return lpFormattedString;
84 }
85
86 #else /* !defined(_MSC_VER) */
87
88 #include <pal/format.h>
89 #include <pal/strings.h>
90
91 #if defined(CONFIG_ENABLE_GETTEXT)
92
93 #include <libintl.h>
94 #include <stdarg.h>
95 #include <pal/hashmap.h>
96 #include <pal/once.h>
97 #include <pal/lock.h>
98 krisbash 1.1
99 #if defined(CONFIG_ENABLE_WCHAR)
100
101 typedef struct _IntlstrBucket {
102 HashBucket bucket;
103 int id;
104 const char* domain_name;
105 PAL_Char text[1];
106 } IntlstrBucket;
107
108 static size_t Intlstr_HashMapHashProc(const HashBucket* untypedBucket)
109 {
110 IntlstrBucket* bucket = (IntlstrBucket*)untypedBucket;
111 return (size_t)bucket->id ^ HashMap_HashProc_AnsiString(bucket->domain_name);
112 }
113
114 static int Intlstr_HashMapEqualProc(_In_ const HashBucket* untypedBucket1, _In_ const HashBucket* untypedBucket2)
115 {
116 IntlstrBucket* bucket1 = (IntlstrBucket*)untypedBucket1;
117 IntlstrBucket* bucket2 = (IntlstrBucket*)untypedBucket2;
118 return (bucket1->id == bucket2->id) &&
119 krisbash 1.1 (0 == strcmp(bucket1->domain_name, bucket2->domain_name));
120 }
121
122 static void Intlstr_HashMapReleaseProc(_In_ HashBucket* untypedBucket)
123 {
124 PAL_UNUSED(untypedBucket);
125 }
126
127 static Once g_intlStr_once = ONCE_INITIALIZER;
128 static HashMap g_intlStr_hashmap;
129 static ReadWriteLock g_intlStr_lock;
130
131 static void ATEXIT_API _Intlstr_OnceCleanup(void)
132 {
133 HashMap_Destroy(&g_intlStr_hashmap);
134 }
135
136 _Success_(return == 0) int _Intlstr_OnceInit(void* data, _Outptr_result_maybenull_ void** value)
137 {
138 int result = 0;
139
140 krisbash 1.1 *value = NULL;
141
142 ReadWriteLock_Init(&g_intlStr_lock);
143
144 result = HashMap_Init(
|
145 krisbash 1.2 &g_intlStr_hashmap,
|
146 krisbash 1.1 32, /* initial number of buckets */
147 Intlstr_HashMapHashProc,
148 Intlstr_HashMapEqualProc,
149 Intlstr_HashMapReleaseProc);
150
151 if (result == 0)
152 {
153 result = PAL_Atexit(_Intlstr_OnceCleanup);
154 }
155
156 return result;
157 }
158
159 #endif /* ?defined(CONFIG_ENABLE_WCHAR) */
160
161 _Use_decl_annotations_
162 const PAL_Char* _Intlstr_GetString_GetText(const char* domain_name, int id, const char* msgid)
163 {
164 #if defined(CONFIG_ENABLE_WCHAR)
165 IntlstrBucket* bucket;
166
167 krisbash 1.1 if (0 != Once_Invoke(&g_intlStr_once, _Intlstr_OnceInit, NULL))
168 {
169 /* TODO/FIXME - OI diagnostics */
170 return NULL;
171 }
172
173 {
174 IntlstrBucket referenceBucket;
175 referenceBucket.id = id;
176 referenceBucket.domain_name = domain_name;
177 ReadWriteLock_AcquireRead(&g_intlStr_lock);
178 bucket = (IntlstrBucket*) HashMap_Find(&g_intlStr_hashmap, (HashBucket*) &referenceBucket);
179 ReadWriteLock_ReleaseRead(&g_intlStr_lock);
180 }
181
182 if (bucket == NULL)
183 {
184 size_t wcharCount;
185 size_t copiedCount;
186 int insertResult;
187
188 krisbash 1.1 char* localizedString = dgettext(domain_name, msgid);
189 if (localizedString == NULL)
190 {
191 /* TODO/FIXME - OI diagnostics */
192 return NULL;
193 }
194
195 wcharCount = mbstowcs(NULL, localizedString, 0);
196 if (wcharCount == ((size_t)-1))
197 {
198 /* TODO/FIXME - OI diagnostics */
199 return NULL;
200 }
201 if ((((size_t)(-1)) - sizeof(IntlstrBucket) / 2) < wcharCount)
202 {
203 /* TODO/FIXME - OI diagnostics */
204 return NULL;
205 }
206
|
207 krisbash 1.2 size_t allocSize = 0;
208 if (SizeTMult(sizeof(wchar_t), wcharCount, &allocSize) != S_OK ||
209 SizeTAdd(allocSize, sizeof(IntlstrBucket), &allocSize != S_OK))
210 {
211 return NULL;
212 }
213
214 bucket = (IntlstrBucket*) PAL_Malloc(allocSize);
|
215 krisbash 1.1 if (!bucket)
216 {
217 /* TODO/FIXME - OI diagnostics */
218 return NULL;
219 }
220 bucket->id = id;
221 bucket->domain_name = domain_name;
222
223 copiedCount = mbstowcs(bucket->text, localizedString, wcharCount + 1);
224 assert(copiedCount == wcharCount);
225
226 ReadWriteLock_AcquireWrite(&g_intlStr_lock);
227 insertResult = HashMap_Insert(&g_intlStr_hashmap, (HashBucket*) bucket);
228 if (insertResult == 1) /* already exists? => use the old one / discard the new one */
229 {
230 IntlstrBucket* oldBucket = (IntlstrBucket*) HashMap_Find(&g_intlStr_hashmap, (HashBucket*) bucket);
231 assert(oldBucket != NULL);
232 PAL_Free(bucket);
233 bucket = oldBucket;
234 }
235 ReadWriteLock_ReleaseWrite(&g_intlStr_lock);
236 krisbash 1.1 }
237
238 return bucket->text;
239 #else /* !defined(CONFIG_ENABLE_WCHAR) */
240 char* localizedString;
|
241 krisbash 1.2
|
242 krisbash 1.1 PAL_UNUSED(id);
243
244 localizedString = dgettext(domain_name, msgid);
245 if (localizedString == NULL)
246 {
247 /* TODO/FIXME - OI diagnostics */
248 return NULL;
249 }
250
251 return localizedString;
252 #endif /* ?defined(CONFIG_ENABLE_WCHAR) */
253 }
254
255 PAL_Char* _Intlstr_FormatString_gettext_and_snprintf(const char* domain_name, int id, const char* msgid, ...)
256 {
257 PAL_Char* templateString = NULL;
258 PAL_Char* resultString = NULL;
|
259 krisbash 1.2 va_list ap;
|
260 krisbash 1.1
|
261 krisbash 1.2 va_start(ap, msgid);
|
262 krisbash 1.1
263 templateString = _Intlstr_GetString_GetText(domain_name, id, msgid);
264 if (!templateString)
265 {
266 /* TODO/FIXME - OI diagnostics */
267 goto CleanUp;
268 }
269
270 resultString = Vstprintf_StrDup(templateString, ap);
271 if (!resultString)
272 {
273 /* TODO/FIXME - OI diagnostics */
274 goto CleanUp;
275 }
276
277 CleanUp:
|
278 krisbash 1.2 va_end(ap);
|
279 krisbash 1.1 return resultString;
280 }
281
282 #endif /* ?defined(CONFIG_ENABLE_GETTEXT) */
283
284 #endif /* ?defined(_MSC_VER) */
|