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