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