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 */ 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 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 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 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 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 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 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 */ 226 static void rtl_locale_once_init (void) 227 { 228 OSL_ASSERT(g_pLocaleTable == 0); 229 rtl_hashtable_init(&g_pLocaleTable, 1); 230 } 231 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 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 */ 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 */ 304 rtl_Locale * SAL_CALL rtl_locale_getDefault() 305 { 306 return g_pDefaultLocale; 307 } 308 309 /************************************************************************* 310 * rtl_locale_setDefault 311 */ 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 */ 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 */ 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 */ 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 */ 347 sal_Int32 SAL_CALL rtl_locale_hashCode( rtl_Locale * This ) 348 { 349 return This->HashCode; 350 } 351 352 /************************************************************************* 353 * rtl_locale_equals 354 */ 355 sal_Int32 SAL_CALL rtl_locale_equals( rtl_Locale * This, rtl_Locale * obj ) 356 { 357 return This == obj; 358 } 359