1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "rtl/locale.h"
25
26 #include "osl/diagnose.h"
27 #include "rtl/alloc.h"
28
29 #include "internal/once.h"
30
31 static sal_Int32 RTL_HASHTABLE_SIZE[] =
32 {
33 7, 31, 127, 251, 509, 1021, 2039, 4093
34 };
35
36 typedef struct rtl_hashentry RTL_HASHENTRY;
37
38 struct rtl_hashentry
39 {
40 rtl_Locale* Entry;
41 RTL_HASHENTRY* Next;
42 };
43
44 typedef struct rtl_hashtable
45 {
46 sal_Int8 iSize;
47 sal_Int32 Size;
48 sal_Int32 Elements;
49 RTL_HASHENTRY** Table;
50 } RTL_HASHTABLE;
51
52 static RTL_HASHTABLE* g_pLocaleTable = NULL;
53
54 static rtl_Locale* g_pDefaultLocale = NULL;
55
56 static int rtl_locale_init (void);
57
58 /*************************************************************************
59 */
rtl_hashentry_destroy(RTL_HASHENTRY * entry)60 void rtl_hashentry_destroy(RTL_HASHENTRY* entry)
61 {
62 rtl_uString_release(entry->Entry->Language);
63 rtl_uString_release(entry->Entry->Country);
64 rtl_uString_release(entry->Entry->Variant);
65 if (entry->Next)
66 rtl_hashentry_destroy(entry->Next);
67
68 rtl_freeMemory(entry->Entry);
69 rtl_freeMemory(entry);
70 }
71
rtl_hashtable_destroy(RTL_HASHTABLE * table)72 void rtl_hashtable_destroy(RTL_HASHTABLE* table)
73 {
74 sal_Int32 size = 0;
75
76 if (!table)
77 return;
78
79 size = table->Size;
80
81 while (size)
82 {
83 if (table->Table[size - 1])
84 rtl_hashentry_destroy(table->Table[size - 1]);
85 size--;
86 }
87
88 rtl_freeMemory(table->Table);
89 rtl_freeMemory(table);
90 }
91
rtl_hashtable_init(RTL_HASHTABLE ** table,sal_Int8 sizeIndex)92 void rtl_hashtable_init(RTL_HASHTABLE** table, sal_Int8 sizeIndex)
93 {
94 sal_Int32 nSize = RTL_HASHTABLE_SIZE[sizeIndex];
95
96 if (*table)
97 rtl_hashtable_destroy(*table);
98
99 *table = (RTL_HASHTABLE*)rtl_allocateMemory( sizeof(RTL_HASHTABLE) );
100
101 (*table)->iSize = sizeIndex;
102 (*table)->Size = nSize;
103 (*table)->Elements = 0;
104 (*table)->Table = (RTL_HASHENTRY**)rtl_allocateMemory( (*table)->Size * sizeof(RTL_HASHENTRY*) );
105
106 while (nSize)
107 {
108 (*table)->Table[nSize - 1] = NULL;
109 nSize--;
110 }
111 }
112
rtl_hashfunc(RTL_HASHTABLE * table,sal_Int32 key)113 sal_Int32 rtl_hashfunc(RTL_HASHTABLE* table, sal_Int32 key)
114 {
115 return ( (sal_uInt32) key % table->Size);
116 }
117
118 sal_Bool rtl_hashtable_grow(RTL_HASHTABLE** table);
119
rtl_hashtable_add(RTL_HASHTABLE ** table,rtl_Locale * value)120 rtl_Locale* rtl_hashtable_add(RTL_HASHTABLE** table, rtl_Locale* value)
121 {
122 sal_Int32 key = 0;
123
124 if (!(*table))
125 return NULL;
126
127 if ((*table)->Elements > ((*table)->Size / 2))
128 rtl_hashtable_grow(table);
129
130 key = rtl_hashfunc(*table, value->HashCode);
131
132 if (!(*table)->Table[key])
133 {
134 RTL_HASHENTRY *newEntry = (RTL_HASHENTRY*)rtl_allocateMemory( sizeof(RTL_HASHENTRY) );
135 newEntry->Entry = value;
136 newEntry->Next = NULL;
137 (*table)->Table[key] = newEntry;
138 (*table)->Elements++;
139 return NULL;
140 } else
141 {
142 RTL_HASHENTRY *pEntry = (*table)->Table[key];
143 RTL_HASHENTRY *newEntry = NULL;
144
145 while (pEntry)
146 {
147 if (value->HashCode == pEntry->Entry->HashCode)
148 return pEntry->Entry;
149
150 if (!pEntry->Next)
151 break;
152
153 pEntry = pEntry->Next;
154 }
155
156 newEntry = (RTL_HASHENTRY*)rtl_allocateMemory( sizeof(RTL_HASHENTRY) );
157 newEntry->Entry = value;
158 newEntry->Next = NULL;
159 pEntry->Next = newEntry;
160 (*table)->Elements++;
161 return NULL;
162 }
163 }
164
rtl_hashtable_grow(RTL_HASHTABLE ** table)165 sal_Bool rtl_hashtable_grow(RTL_HASHTABLE** table)
166 {
167 RTL_HASHTABLE* pNewTable = NULL;
168 sal_Int32 i = 0;
169
170 rtl_hashtable_init(&pNewTable, (sal_Int8)((*table)->iSize + 1));
171
172 while (i < (*table)->Size)
173 {
174 if ((*table)->Table[i])
175 {
176 RTL_HASHENTRY *pNext;
177 RTL_HASHENTRY *pEntry = (*table)->Table[i];
178
179 rtl_hashtable_add(&pNewTable, pEntry->Entry);
180
181 while (pEntry->Next)
182 {
183 rtl_hashtable_add(&pNewTable, pEntry->Next->Entry);
184 pNext = pEntry->Next;
185 rtl_freeMemory(pEntry);
186 pEntry = pNext;
187 }
188
189 rtl_freeMemory(pEntry);
190 }
191 i++;
192 }
193
194 rtl_freeMemory((*table)->Table);
195 rtl_freeMemory((*table));
196 (*table) = pNewTable;
197
198 return sal_True;
199 }
200
rtl_hashtable_find(RTL_HASHTABLE * table,sal_Int32 key,sal_Int32 hashCode,rtl_Locale ** pValue)201 sal_Bool rtl_hashtable_find(RTL_HASHTABLE * table, sal_Int32 key, sal_Int32 hashCode, rtl_Locale** pValue)
202 {
203 if (!table)
204 return sal_False;
205
206 if (table->Table[key])
207 {
208 RTL_HASHENTRY *pEntry = table->Table[key];
209
210 while (pEntry && hashCode != pEntry->Entry->HashCode)
211 pEntry = pEntry->Next;
212
213 if (pEntry)
214 *pValue = pEntry->Entry;
215 else
216 return sal_False;
217 } else
218 return sal_False;
219
220 return sal_True;
221 }
222
223 /*************************************************************************
224 * rtl_locale_init
225 */
rtl_locale_once_init(void)226 static void rtl_locale_once_init (void)
227 {
228 OSL_ASSERT(g_pLocaleTable == 0);
229 rtl_hashtable_init(&g_pLocaleTable, 1);
230 }
231
rtl_locale_init(void)232 static int rtl_locale_init (void)
233 {
234 static sal_once_type g_once = SAL_ONCE_INIT;
235 SAL_ONCE(&g_once, rtl_locale_once_init);
236 return (g_pLocaleTable != 0);
237 }
238
239 /*************************************************************************
240 * rtl_locale_fini
241 */
242 #if defined(__GNUC__)
243 static void rtl_locale_fini (void) __attribute__((destructor));
244 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
245 #pragma fini(rtl_locale_fini)
246 static void rtl_locale_fini (void);
247 #endif /* __GNUC__ || __SUNPRO_C */
248
rtl_locale_fini(void)249 void rtl_locale_fini (void)
250 {
251 if (g_pLocaleTable != 0)
252 {
253 rtl_hashtable_destroy (g_pLocaleTable);
254 g_pLocaleTable = 0;
255 }
256 }
257
258 /*************************************************************************
259 * rtl_locale_register
260 */
rtl_locale_register(const sal_Unicode * language,const sal_Unicode * country,const sal_Unicode * variant)261 rtl_Locale * SAL_CALL rtl_locale_register( const sal_Unicode * language, const sal_Unicode * country, const sal_Unicode * variant )
262 {
263 sal_Unicode c = 0;
264 rtl_uString* sLanguage = NULL;
265 rtl_uString* sCountry = NULL;
266 rtl_uString* sVariant = NULL;
267 rtl_Locale *newLocale = NULL;
268 sal_Int32 hashCode = -1;
269 sal_Int32 key = 0;
270
271 if ( !country )
272 country = &c;
273 if ( !variant )
274 variant = &c;
275
276 if (!rtl_locale_init())
277 return NULL;
278
279 hashCode = rtl_ustr_hashCode(language) ^ rtl_ustr_hashCode(country) ^ rtl_ustr_hashCode(variant);
280 key = rtl_hashfunc(g_pLocaleTable, hashCode);
281
282 if (rtl_hashtable_find(g_pLocaleTable, key, hashCode, &newLocale))
283 return newLocale;
284
285 rtl_uString_newFromStr(&sLanguage, language);
286 rtl_uString_newFromStr(&sCountry, country);
287 rtl_uString_newFromStr(&sVariant, variant);
288
289 newLocale = (rtl_Locale*)rtl_allocateMemory( sizeof(rtl_Locale) );
290
291 newLocale->Language = sLanguage;
292 newLocale->Country = sCountry;
293 newLocale->Variant = sVariant;
294 newLocale->HashCode = hashCode;
295
296 rtl_hashtable_add(&g_pLocaleTable, newLocale);
297
298 return newLocale;
299 }
300
301 /*************************************************************************
302 * rtl_locale_getDefault
303 */
rtl_locale_getDefault()304 rtl_Locale * SAL_CALL rtl_locale_getDefault()
305 {
306 return g_pDefaultLocale;
307 }
308
309 /*************************************************************************
310 * rtl_locale_setDefault
311 */
rtl_locale_setDefault(const sal_Unicode * language,const sal_Unicode * country,const sal_Unicode * variant)312 void SAL_CALL rtl_locale_setDefault( const sal_Unicode * language, const sal_Unicode * country, const sal_Unicode * variant )
313 {
314 g_pDefaultLocale = rtl_locale_register(language, country, variant);
315 }
316
317 /*************************************************************************
318 * rtl_locale_getLanguage
319 */
rtl_locale_getLanguage(rtl_Locale * This)320 rtl_uString * SAL_CALL rtl_locale_getLanguage( rtl_Locale * This )
321 {
322 rtl_uString_acquire(This->Language);
323 return This->Language;
324 }
325
326 /*************************************************************************
327 * rtl_locale_getCountry
328 */
rtl_locale_getCountry(rtl_Locale * This)329 rtl_uString * SAL_CALL rtl_locale_getCountry( rtl_Locale * This )
330 {
331 rtl_uString_acquire(This->Country);
332 return This->Country;
333 }
334
335 /*************************************************************************
336 * rtl_locale_getVariant
337 */
rtl_locale_getVariant(rtl_Locale * This)338 rtl_uString * SAL_CALL rtl_locale_getVariant( rtl_Locale * This )
339 {
340 rtl_uString_acquire(This->Variant);
341 return This->Variant;
342 }
343
344 /*************************************************************************
345 * rtl_locale_hashCode
346 */
rtl_locale_hashCode(rtl_Locale * This)347 sal_Int32 SAL_CALL rtl_locale_hashCode( rtl_Locale * This )
348 {
349 return This->HashCode;
350 }
351
352 /*************************************************************************
353 * rtl_locale_equals
354 */
rtl_locale_equals(rtl_Locale * This,rtl_Locale * obj)355 sal_Int32 SAL_CALL rtl_locale_equals( rtl_Locale * This, rtl_Locale * obj )
356 {
357 return This == obj;
358 }
359