intl/icu/source/common/locid.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /*
michael@0 2 **********************************************************************
michael@0 3 * Copyright (C) 1997-2012, International Business Machines
michael@0 4 * Corporation and others. All Rights Reserved.
michael@0 5 **********************************************************************
michael@0 6 *
michael@0 7 * File locid.cpp
michael@0 8 *
michael@0 9 * Created by: Richard Gillam
michael@0 10 *
michael@0 11 * Modification History:
michael@0 12 *
michael@0 13 * Date Name Description
michael@0 14 * 02/11/97 aliu Changed gLocPath to fgDataDirectory and added
michael@0 15 * methods to get and set it.
michael@0 16 * 04/02/97 aliu Made operator!= inline; fixed return value
michael@0 17 * of getName().
michael@0 18 * 04/15/97 aliu Cleanup for AIX/Win32.
michael@0 19 * 04/24/97 aliu Numerous changes per code review.
michael@0 20 * 08/18/98 stephen Changed getDisplayName()
michael@0 21 * Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE
michael@0 22 * Added getISOCountries(), getISOLanguages(),
michael@0 23 * getLanguagesForCountry()
michael@0 24 * 03/16/99 bertrand rehaul.
michael@0 25 * 07/21/99 stephen Added U_CFUNC setDefault
michael@0 26 * 11/09/99 weiv Added const char * getName() const;
michael@0 27 * 04/12/00 srl removing unicodestring api's and cached hash code
michael@0 28 * 08/10/01 grhoten Change the static Locales to accessor functions
michael@0 29 ******************************************************************************
michael@0 30 */
michael@0 31
michael@0 32
michael@0 33 #include "unicode/locid.h"
michael@0 34 #include "unicode/uloc.h"
michael@0 35 #include "putilimp.h"
michael@0 36 #include "mutex.h"
michael@0 37 #include "umutex.h"
michael@0 38 #include "uassert.h"
michael@0 39 #include "cmemory.h"
michael@0 40 #include "cstring.h"
michael@0 41 #include "uhash.h"
michael@0 42 #include "ucln_cmn.h"
michael@0 43 #include "ustr_imp.h"
michael@0 44
michael@0 45 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
michael@0 46
michael@0 47 U_CDECL_BEGIN
michael@0 48 static UBool U_CALLCONV locale_cleanup(void);
michael@0 49 U_CDECL_END
michael@0 50
michael@0 51 U_NAMESPACE_BEGIN
michael@0 52
michael@0 53 static Locale *gLocaleCache = NULL;
michael@0 54
michael@0 55 // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
michael@0 56 static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER;
michael@0 57 static UHashtable *gDefaultLocalesHashT = NULL;
michael@0 58 static Locale *gDefaultLocale = NULL;
michael@0 59
michael@0 60 U_NAMESPACE_END
michael@0 61
michael@0 62 typedef enum ELocalePos {
michael@0 63 eENGLISH,
michael@0 64 eFRENCH,
michael@0 65 eGERMAN,
michael@0 66 eITALIAN,
michael@0 67 eJAPANESE,
michael@0 68 eKOREAN,
michael@0 69 eCHINESE,
michael@0 70
michael@0 71 eFRANCE,
michael@0 72 eGERMANY,
michael@0 73 eITALY,
michael@0 74 eJAPAN,
michael@0 75 eKOREA,
michael@0 76 eCHINA, /* Alias for PRC */
michael@0 77 eTAIWAN,
michael@0 78 eUK,
michael@0 79 eUS,
michael@0 80 eCANADA,
michael@0 81 eCANADA_FRENCH,
michael@0 82 eROOT,
michael@0 83
michael@0 84
michael@0 85 //eDEFAULT,
michael@0 86 eMAX_LOCALES
michael@0 87 } ELocalePos;
michael@0 88
michael@0 89 U_CFUNC int32_t locale_getKeywords(const char *localeID,
michael@0 90 char prev,
michael@0 91 char *keywords, int32_t keywordCapacity,
michael@0 92 char *values, int32_t valuesCapacity, int32_t *valLen,
michael@0 93 UBool valuesToo,
michael@0 94 UErrorCode *status);
michael@0 95
michael@0 96 U_CDECL_BEGIN
michael@0 97 //
michael@0 98 // Deleter function for Locales owned by the default Locale hash table/
michael@0 99 //
michael@0 100 static void U_CALLCONV
michael@0 101 deleteLocale(void *obj) {
michael@0 102 delete (icu::Locale *) obj;
michael@0 103 }
michael@0 104
michael@0 105 static UBool U_CALLCONV locale_cleanup(void)
michael@0 106 {
michael@0 107 U_NAMESPACE_USE
michael@0 108
michael@0 109 if (gLocaleCache) {
michael@0 110 delete [] gLocaleCache;
michael@0 111 gLocaleCache = NULL;
michael@0 112 }
michael@0 113
michael@0 114 if (gDefaultLocalesHashT) {
michael@0 115 uhash_close(gDefaultLocalesHashT); // Automatically deletes all elements, using deleter func.
michael@0 116 gDefaultLocalesHashT = NULL;
michael@0 117 gDefaultLocale = NULL;
michael@0 118 }
michael@0 119
michael@0 120 return TRUE;
michael@0 121 }
michael@0 122 U_CDECL_END
michael@0 123
michael@0 124 U_NAMESPACE_BEGIN
michael@0 125
michael@0 126 Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
michael@0 127 // Synchronize this entire function.
michael@0 128 Mutex lock(&gDefaultLocaleMutex);
michael@0 129
michael@0 130 UBool canonicalize = FALSE;
michael@0 131
michael@0 132 // If given a NULL string for the locale id, grab the default
michael@0 133 // name from the system.
michael@0 134 // (Different from most other locale APIs, where a null name means use
michael@0 135 // the current ICU default locale.)
michael@0 136 if (id == NULL) {
michael@0 137 id = uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify.
michael@0 138 canonicalize = TRUE; // always canonicalize host ID
michael@0 139 }
michael@0 140
michael@0 141 char localeNameBuf[512];
michael@0 142
michael@0 143 if (canonicalize) {
michael@0 144 uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
michael@0 145 } else {
michael@0 146 uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
michael@0 147 }
michael@0 148 localeNameBuf[sizeof(localeNameBuf)-1] = 0; // Force null termination in event of
michael@0 149 // a long name filling the buffer.
michael@0 150 // (long names are truncated.)
michael@0 151 //
michael@0 152 if (U_FAILURE(status)) {
michael@0 153 return gDefaultLocale;
michael@0 154 }
michael@0 155
michael@0 156 if (gDefaultLocalesHashT == NULL) {
michael@0 157 gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
michael@0 158 if (U_FAILURE(status)) {
michael@0 159 return gDefaultLocale;
michael@0 160 }
michael@0 161 uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale);
michael@0 162 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
michael@0 163 }
michael@0 164
michael@0 165 Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
michael@0 166 if (newDefault == NULL) {
michael@0 167 newDefault = new Locale(Locale::eBOGUS);
michael@0 168 if (newDefault == NULL) {
michael@0 169 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 170 return gDefaultLocale;
michael@0 171 }
michael@0 172 newDefault->init(localeNameBuf, FALSE);
michael@0 173 uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status);
michael@0 174 if (U_FAILURE(status)) {
michael@0 175 return gDefaultLocale;
michael@0 176 }
michael@0 177 }
michael@0 178 gDefaultLocale = newDefault;
michael@0 179 return gDefaultLocale;
michael@0 180 }
michael@0 181
michael@0 182 U_NAMESPACE_END
michael@0 183
michael@0 184 /* sfb 07/21/99 */
michael@0 185 U_CFUNC void
michael@0 186 locale_set_default(const char *id)
michael@0 187 {
michael@0 188 U_NAMESPACE_USE
michael@0 189 UErrorCode status = U_ZERO_ERROR;
michael@0 190 locale_set_default_internal(id, status);
michael@0 191 }
michael@0 192 /* end */
michael@0 193
michael@0 194 U_CFUNC const char *
michael@0 195 locale_get_default(void)
michael@0 196 {
michael@0 197 U_NAMESPACE_USE
michael@0 198 return Locale::getDefault().getName();
michael@0 199 }
michael@0 200
michael@0 201
michael@0 202 U_NAMESPACE_BEGIN
michael@0 203
michael@0 204 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
michael@0 205
michael@0 206 /*Character separating the posix id fields*/
michael@0 207 // '_'
michael@0 208 // In the platform codepage.
michael@0 209 #define SEP_CHAR '_'
michael@0 210
michael@0 211 Locale::~Locale()
michael@0 212 {
michael@0 213 /*if fullName is on the heap, we free it*/
michael@0 214 if (fullName != fullNameBuffer)
michael@0 215 {
michael@0 216 uprv_free(fullName);
michael@0 217 fullName = NULL;
michael@0 218 }
michael@0 219 if (baseName && baseName != baseNameBuffer) {
michael@0 220 uprv_free(baseName);
michael@0 221 baseName = NULL;
michael@0 222 }
michael@0 223 }
michael@0 224
michael@0 225 Locale::Locale()
michael@0 226 : UObject(), fullName(fullNameBuffer), baseName(NULL)
michael@0 227 {
michael@0 228 init(NULL, FALSE);
michael@0 229 }
michael@0 230
michael@0 231 /*
michael@0 232 * Internal constructor to allow construction of a locale object with
michael@0 233 * NO side effects. (Default constructor tries to get
michael@0 234 * the default locale.)
michael@0 235 */
michael@0 236 Locale::Locale(Locale::ELocaleType)
michael@0 237 : UObject(), fullName(fullNameBuffer), baseName(NULL)
michael@0 238 {
michael@0 239 setToBogus();
michael@0 240 }
michael@0 241
michael@0 242
michael@0 243 Locale::Locale( const char * newLanguage,
michael@0 244 const char * newCountry,
michael@0 245 const char * newVariant,
michael@0 246 const char * newKeywords)
michael@0 247 : UObject(), fullName(fullNameBuffer), baseName(NULL)
michael@0 248 {
michael@0 249 if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
michael@0 250 {
michael@0 251 init(NULL, FALSE); /* shortcut */
michael@0 252 }
michael@0 253 else
michael@0 254 {
michael@0 255 MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> togo;
michael@0 256 int32_t size = 0;
michael@0 257 int32_t lsize = 0;
michael@0 258 int32_t csize = 0;
michael@0 259 int32_t vsize = 0;
michael@0 260 int32_t ksize = 0;
michael@0 261 char *p;
michael@0 262
michael@0 263 // Calculate the size of the resulting string.
michael@0 264
michael@0 265 // Language
michael@0 266 if ( newLanguage != NULL )
michael@0 267 {
michael@0 268 lsize = (int32_t)uprv_strlen(newLanguage);
michael@0 269 size = lsize;
michael@0 270 }
michael@0 271
michael@0 272 // _Country
michael@0 273 if ( newCountry != NULL )
michael@0 274 {
michael@0 275 csize = (int32_t)uprv_strlen(newCountry);
michael@0 276 size += csize;
michael@0 277 }
michael@0 278
michael@0 279 // _Variant
michael@0 280 if ( newVariant != NULL )
michael@0 281 {
michael@0 282 // remove leading _'s
michael@0 283 while(newVariant[0] == SEP_CHAR)
michael@0 284 {
michael@0 285 newVariant++;
michael@0 286 }
michael@0 287
michael@0 288 // remove trailing _'s
michael@0 289 vsize = (int32_t)uprv_strlen(newVariant);
michael@0 290 while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
michael@0 291 {
michael@0 292 vsize--;
michael@0 293 }
michael@0 294 }
michael@0 295
michael@0 296 if( vsize > 0 )
michael@0 297 {
michael@0 298 size += vsize;
michael@0 299 }
michael@0 300
michael@0 301 // Separator rules:
michael@0 302 if ( vsize > 0 )
michael@0 303 {
michael@0 304 size += 2; // at least: __v
michael@0 305 }
michael@0 306 else if ( csize > 0 )
michael@0 307 {
michael@0 308 size += 1; // at least: _v
michael@0 309 }
michael@0 310
michael@0 311 if ( newKeywords != NULL)
michael@0 312 {
michael@0 313 ksize = (int32_t)uprv_strlen(newKeywords);
michael@0 314 size += ksize + 1;
michael@0 315 }
michael@0 316
michael@0 317
michael@0 318 // NOW we have the full locale string..
michael@0 319
michael@0 320 /*if the whole string is longer than our internal limit, we need
michael@0 321 to go to the heap for temporary buffers*/
michael@0 322 if (size >= togo.getCapacity())
michael@0 323 {
michael@0 324 // If togo_heap could not be created, initialize with default settings.
michael@0 325 if (togo.resize(size+1) == NULL) {
michael@0 326 init(NULL, FALSE);
michael@0 327 }
michael@0 328 }
michael@0 329
michael@0 330 togo[0] = 0;
michael@0 331
michael@0 332 // Now, copy it back.
michael@0 333 p = togo.getAlias();
michael@0 334 if ( lsize != 0 )
michael@0 335 {
michael@0 336 uprv_strcpy(p, newLanguage);
michael@0 337 p += lsize;
michael@0 338 }
michael@0 339
michael@0 340 if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v
michael@0 341 { // ^
michael@0 342 *p++ = SEP_CHAR;
michael@0 343 }
michael@0 344
michael@0 345 if ( csize != 0 )
michael@0 346 {
michael@0 347 uprv_strcpy(p, newCountry);
michael@0 348 p += csize;
michael@0 349 }
michael@0 350
michael@0 351 if ( vsize != 0)
michael@0 352 {
michael@0 353 *p++ = SEP_CHAR; // at least: __v
michael@0 354
michael@0 355 uprv_strncpy(p, newVariant, vsize); // Must use strncpy because
michael@0 356 p += vsize; // of trimming (above).
michael@0 357 *p = 0; // terminate
michael@0 358 }
michael@0 359
michael@0 360 if ( ksize != 0)
michael@0 361 {
michael@0 362 if (uprv_strchr(newKeywords, '=')) {
michael@0 363 *p++ = '@'; /* keyword parsing */
michael@0 364 }
michael@0 365 else {
michael@0 366 *p++ = '_'; /* Variant parsing with a script */
michael@0 367 if ( vsize == 0) {
michael@0 368 *p++ = '_'; /* No country found */
michael@0 369 }
michael@0 370 }
michael@0 371 uprv_strcpy(p, newKeywords);
michael@0 372 p += ksize;
michael@0 373 }
michael@0 374
michael@0 375 // Parse it, because for example 'language' might really be a complete
michael@0 376 // string.
michael@0 377 init(togo.getAlias(), FALSE);
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 Locale::Locale(const Locale &other)
michael@0 382 : UObject(other), fullName(fullNameBuffer), baseName(NULL)
michael@0 383 {
michael@0 384 *this = other;
michael@0 385 }
michael@0 386
michael@0 387 Locale &Locale::operator=(const Locale &other)
michael@0 388 {
michael@0 389 if (this == &other) {
michael@0 390 return *this;
michael@0 391 }
michael@0 392
michael@0 393 if (&other == NULL) {
michael@0 394 this->setToBogus();
michael@0 395 return *this;
michael@0 396 }
michael@0 397
michael@0 398 /* Free our current storage */
michael@0 399 if(fullName != fullNameBuffer) {
michael@0 400 uprv_free(fullName);
michael@0 401 fullName = fullNameBuffer;
michael@0 402 }
michael@0 403
michael@0 404 /* Allocate the full name if necessary */
michael@0 405 if(other.fullName != other.fullNameBuffer) {
michael@0 406 fullName = (char *)uprv_malloc(sizeof(char)*(uprv_strlen(other.fullName)+1));
michael@0 407 if (fullName == NULL) {
michael@0 408 return *this;
michael@0 409 }
michael@0 410 }
michael@0 411 /* Copy the full name */
michael@0 412 uprv_strcpy(fullName, other.fullName);
michael@0 413
michael@0 414 /* baseName is the cached result of getBaseName. if 'other' has a
michael@0 415 baseName and it fits in baseNameBuffer, then copy it. otherwise set
michael@0 416 it to NULL, and let the user lazy-create it (in getBaseName) if they
michael@0 417 want it. */
michael@0 418 if(baseName && baseName != baseNameBuffer) {
michael@0 419 uprv_free(baseName);
michael@0 420 }
michael@0 421 baseName = NULL;
michael@0 422
michael@0 423 if(other.baseName == other.baseNameBuffer) {
michael@0 424 uprv_strcpy(baseNameBuffer, other.baseNameBuffer);
michael@0 425 baseName = baseNameBuffer;
michael@0 426 }
michael@0 427
michael@0 428 /* Copy the language and country fields */
michael@0 429 uprv_strcpy(language, other.language);
michael@0 430 uprv_strcpy(script, other.script);
michael@0 431 uprv_strcpy(country, other.country);
michael@0 432
michael@0 433 /* The variantBegin is an offset, just copy it */
michael@0 434 variantBegin = other.variantBegin;
michael@0 435 fIsBogus = other.fIsBogus;
michael@0 436 return *this;
michael@0 437 }
michael@0 438
michael@0 439 Locale *
michael@0 440 Locale::clone() const {
michael@0 441 return new Locale(*this);
michael@0 442 }
michael@0 443
michael@0 444 UBool
michael@0 445 Locale::operator==( const Locale& other) const
michael@0 446 {
michael@0 447 return (uprv_strcmp(other.fullName, fullName) == 0);
michael@0 448 }
michael@0 449
michael@0 450 #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
michael@0 451
michael@0 452 /*This function initializes a Locale from a C locale ID*/
michael@0 453 Locale& Locale::init(const char* localeID, UBool canonicalize)
michael@0 454 {
michael@0 455 fIsBogus = FALSE;
michael@0 456 /* Free our current storage */
michael@0 457 if(fullName != fullNameBuffer) {
michael@0 458 uprv_free(fullName);
michael@0 459 fullName = fullNameBuffer;
michael@0 460 }
michael@0 461
michael@0 462 if(baseName && baseName != baseNameBuffer) {
michael@0 463 uprv_free(baseName);
michael@0 464 baseName = NULL;
michael@0 465 }
michael@0 466
michael@0 467 // not a loop:
michael@0 468 // just an easy way to have a common error-exit
michael@0 469 // without goto and without another function
michael@0 470 do {
michael@0 471 char *separator;
michael@0 472 char *field[5] = {0};
michael@0 473 int32_t fieldLen[5] = {0};
michael@0 474 int32_t fieldIdx;
michael@0 475 int32_t variantField;
michael@0 476 int32_t length;
michael@0 477 UErrorCode err;
michael@0 478
michael@0 479 if(localeID == NULL) {
michael@0 480 // not an error, just set the default locale
michael@0 481 return *this = getDefault();
michael@0 482 }
michael@0 483
michael@0 484 /* preset all fields to empty */
michael@0 485 language[0] = script[0] = country[0] = 0;
michael@0 486
michael@0 487 // "canonicalize" the locale ID to ICU/Java format
michael@0 488 err = U_ZERO_ERROR;
michael@0 489 length = canonicalize ?
michael@0 490 uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
michael@0 491 uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
michael@0 492
michael@0 493 if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
michael@0 494 /*Go to heap for the fullName if necessary*/
michael@0 495 fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
michael@0 496 if(fullName == 0) {
michael@0 497 fullName = fullNameBuffer;
michael@0 498 break; // error: out of memory
michael@0 499 }
michael@0 500 err = U_ZERO_ERROR;
michael@0 501 length = canonicalize ?
michael@0 502 uloc_canonicalize(localeID, fullName, length+1, &err) :
michael@0 503 uloc_getName(localeID, fullName, length+1, &err);
michael@0 504 }
michael@0 505 if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
michael@0 506 /* should never occur */
michael@0 507 break;
michael@0 508 }
michael@0 509
michael@0 510 variantBegin = length;
michael@0 511
michael@0 512 /* after uloc_getName/canonicalize() we know that only '_' are separators */
michael@0 513 separator = field[0] = fullName;
michael@0 514 fieldIdx = 1;
michael@0 515 while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) && fieldIdx < (int32_t)(sizeof(field)/sizeof(field[0]))-1) {
michael@0 516 field[fieldIdx] = separator + 1;
michael@0 517 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
michael@0 518 fieldIdx++;
michael@0 519 }
michael@0 520 // variant may contain @foo or .foo POSIX cruft; remove it
michael@0 521 separator = uprv_strchr(field[fieldIdx-1], '@');
michael@0 522 char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
michael@0 523 if (separator!=NULL || sep2!=NULL) {
michael@0 524 if (separator==NULL || (sep2!=NULL && separator > sep2)) {
michael@0 525 separator = sep2;
michael@0 526 }
michael@0 527 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
michael@0 528 } else {
michael@0 529 fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
michael@0 530 }
michael@0 531
michael@0 532 if (fieldLen[0] >= (int32_t)(sizeof(language)))
michael@0 533 {
michael@0 534 break; // error: the language field is too long
michael@0 535 }
michael@0 536
michael@0 537 variantField = 1; /* Usually the 2nd one, except when a script or country is also used. */
michael@0 538 if (fieldLen[0] > 0) {
michael@0 539 /* We have a language */
michael@0 540 uprv_memcpy(language, fullName, fieldLen[0]);
michael@0 541 language[fieldLen[0]] = 0;
michael@0 542 }
michael@0 543 if (fieldLen[1] == 4 && ISASCIIALPHA(field[1][0]) &&
michael@0 544 ISASCIIALPHA(field[1][1]) && ISASCIIALPHA(field[1][2]) &&
michael@0 545 ISASCIIALPHA(field[1][3])) {
michael@0 546 /* We have at least a script */
michael@0 547 uprv_memcpy(script, field[1], fieldLen[1]);
michael@0 548 script[fieldLen[1]] = 0;
michael@0 549 variantField++;
michael@0 550 }
michael@0 551
michael@0 552 if (fieldLen[variantField] == 2 || fieldLen[variantField] == 3) {
michael@0 553 /* We have a country */
michael@0 554 uprv_memcpy(country, field[variantField], fieldLen[variantField]);
michael@0 555 country[fieldLen[variantField]] = 0;
michael@0 556 variantField++;
michael@0 557 } else if (fieldLen[variantField] == 0) {
michael@0 558 variantField++; /* script or country empty but variant in next field (i.e. en__POSIX) */
michael@0 559 }
michael@0 560
michael@0 561 if (fieldLen[variantField] > 0) {
michael@0 562 /* We have a variant */
michael@0 563 variantBegin = (int32_t)(field[variantField] - fullName);
michael@0 564 }
michael@0 565
michael@0 566 // successful end of init()
michael@0 567 return *this;
michael@0 568 } while(0); /*loop doesn't iterate*/
michael@0 569
michael@0 570 // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
michael@0 571 setToBogus();
michael@0 572
michael@0 573 return *this;
michael@0 574 }
michael@0 575
michael@0 576 int32_t
michael@0 577 Locale::hashCode() const
michael@0 578 {
michael@0 579 return ustr_hashCharsN(fullName, uprv_strlen(fullName));
michael@0 580 }
michael@0 581
michael@0 582 void
michael@0 583 Locale::setToBogus() {
michael@0 584 /* Free our current storage */
michael@0 585 if(fullName != fullNameBuffer) {
michael@0 586 uprv_free(fullName);
michael@0 587 fullName = fullNameBuffer;
michael@0 588 }
michael@0 589 if(baseName && baseName != baseNameBuffer) {
michael@0 590 uprv_free(baseName);
michael@0 591 baseName = NULL;
michael@0 592 }
michael@0 593 *fullNameBuffer = 0;
michael@0 594 *language = 0;
michael@0 595 *script = 0;
michael@0 596 *country = 0;
michael@0 597 fIsBogus = TRUE;
michael@0 598 }
michael@0 599
michael@0 600 const Locale& U_EXPORT2
michael@0 601 Locale::getDefault()
michael@0 602 {
michael@0 603 {
michael@0 604 Mutex lock(&gDefaultLocaleMutex);
michael@0 605 if (gDefaultLocale != NULL) {
michael@0 606 return *gDefaultLocale;
michael@0 607 }
michael@0 608 }
michael@0 609 UErrorCode status = U_ZERO_ERROR;
michael@0 610 return *locale_set_default_internal(NULL, status);
michael@0 611 }
michael@0 612
michael@0 613
michael@0 614
michael@0 615 void U_EXPORT2
michael@0 616 Locale::setDefault( const Locale& newLocale,
michael@0 617 UErrorCode& status)
michael@0 618 {
michael@0 619 if (U_FAILURE(status)) {
michael@0 620 return;
michael@0 621 }
michael@0 622
michael@0 623 /* Set the default from the full name string of the supplied locale.
michael@0 624 * This is a convenient way to access the default locale caching mechanisms.
michael@0 625 */
michael@0 626 const char *localeID = newLocale.getName();
michael@0 627 locale_set_default_internal(localeID, status);
michael@0 628 }
michael@0 629
michael@0 630 Locale U_EXPORT2
michael@0 631 Locale::createFromName (const char *name)
michael@0 632 {
michael@0 633 if (name) {
michael@0 634 Locale l("");
michael@0 635 l.init(name, FALSE);
michael@0 636 return l;
michael@0 637 }
michael@0 638 else {
michael@0 639 return getDefault();
michael@0 640 }
michael@0 641 }
michael@0 642
michael@0 643 Locale U_EXPORT2
michael@0 644 Locale::createCanonical(const char* name) {
michael@0 645 Locale loc("");
michael@0 646 loc.init(name, TRUE);
michael@0 647 return loc;
michael@0 648 }
michael@0 649
michael@0 650 const char *
michael@0 651 Locale::getISO3Language() const
michael@0 652 {
michael@0 653 return uloc_getISO3Language(fullName);
michael@0 654 }
michael@0 655
michael@0 656
michael@0 657 const char *
michael@0 658 Locale::getISO3Country() const
michael@0 659 {
michael@0 660 return uloc_getISO3Country(fullName);
michael@0 661 }
michael@0 662
michael@0 663 /**
michael@0 664 * Return the LCID value as specified in the "LocaleID" resource for this
michael@0 665 * locale. The LocaleID must be expressed as a hexadecimal number, from
michael@0 666 * one to four digits. If the LocaleID resource is not present, or is
michael@0 667 * in an incorrect format, 0 is returned. The LocaleID is for use in
michael@0 668 * Windows (it is an LCID), but is available on all platforms.
michael@0 669 */
michael@0 670 uint32_t
michael@0 671 Locale::getLCID() const
michael@0 672 {
michael@0 673 return uloc_getLCID(fullName);
michael@0 674 }
michael@0 675
michael@0 676 const char* const* U_EXPORT2 Locale::getISOCountries()
michael@0 677 {
michael@0 678 return uloc_getISOCountries();
michael@0 679 }
michael@0 680
michael@0 681 const char* const* U_EXPORT2 Locale::getISOLanguages()
michael@0 682 {
michael@0 683 return uloc_getISOLanguages();
michael@0 684 }
michael@0 685
michael@0 686 // Set the locale's data based on a posix id.
michael@0 687 void Locale::setFromPOSIXID(const char *posixID)
michael@0 688 {
michael@0 689 init(posixID, TRUE);
michael@0 690 }
michael@0 691
michael@0 692 const Locale & U_EXPORT2
michael@0 693 Locale::getRoot(void)
michael@0 694 {
michael@0 695 return getLocale(eROOT);
michael@0 696 }
michael@0 697
michael@0 698 const Locale & U_EXPORT2
michael@0 699 Locale::getEnglish(void)
michael@0 700 {
michael@0 701 return getLocale(eENGLISH);
michael@0 702 }
michael@0 703
michael@0 704 const Locale & U_EXPORT2
michael@0 705 Locale::getFrench(void)
michael@0 706 {
michael@0 707 return getLocale(eFRENCH);
michael@0 708 }
michael@0 709
michael@0 710 const Locale & U_EXPORT2
michael@0 711 Locale::getGerman(void)
michael@0 712 {
michael@0 713 return getLocale(eGERMAN);
michael@0 714 }
michael@0 715
michael@0 716 const Locale & U_EXPORT2
michael@0 717 Locale::getItalian(void)
michael@0 718 {
michael@0 719 return getLocale(eITALIAN);
michael@0 720 }
michael@0 721
michael@0 722 const Locale & U_EXPORT2
michael@0 723 Locale::getJapanese(void)
michael@0 724 {
michael@0 725 return getLocale(eJAPANESE);
michael@0 726 }
michael@0 727
michael@0 728 const Locale & U_EXPORT2
michael@0 729 Locale::getKorean(void)
michael@0 730 {
michael@0 731 return getLocale(eKOREAN);
michael@0 732 }
michael@0 733
michael@0 734 const Locale & U_EXPORT2
michael@0 735 Locale::getChinese(void)
michael@0 736 {
michael@0 737 return getLocale(eCHINESE);
michael@0 738 }
michael@0 739
michael@0 740 const Locale & U_EXPORT2
michael@0 741 Locale::getSimplifiedChinese(void)
michael@0 742 {
michael@0 743 return getLocale(eCHINA);
michael@0 744 }
michael@0 745
michael@0 746 const Locale & U_EXPORT2
michael@0 747 Locale::getTraditionalChinese(void)
michael@0 748 {
michael@0 749 return getLocale(eTAIWAN);
michael@0 750 }
michael@0 751
michael@0 752
michael@0 753 const Locale & U_EXPORT2
michael@0 754 Locale::getFrance(void)
michael@0 755 {
michael@0 756 return getLocale(eFRANCE);
michael@0 757 }
michael@0 758
michael@0 759 const Locale & U_EXPORT2
michael@0 760 Locale::getGermany(void)
michael@0 761 {
michael@0 762 return getLocale(eGERMANY);
michael@0 763 }
michael@0 764
michael@0 765 const Locale & U_EXPORT2
michael@0 766 Locale::getItaly(void)
michael@0 767 {
michael@0 768 return getLocale(eITALY);
michael@0 769 }
michael@0 770
michael@0 771 const Locale & U_EXPORT2
michael@0 772 Locale::getJapan(void)
michael@0 773 {
michael@0 774 return getLocale(eJAPAN);
michael@0 775 }
michael@0 776
michael@0 777 const Locale & U_EXPORT2
michael@0 778 Locale::getKorea(void)
michael@0 779 {
michael@0 780 return getLocale(eKOREA);
michael@0 781 }
michael@0 782
michael@0 783 const Locale & U_EXPORT2
michael@0 784 Locale::getChina(void)
michael@0 785 {
michael@0 786 return getLocale(eCHINA);
michael@0 787 }
michael@0 788
michael@0 789 const Locale & U_EXPORT2
michael@0 790 Locale::getPRC(void)
michael@0 791 {
michael@0 792 return getLocale(eCHINA);
michael@0 793 }
michael@0 794
michael@0 795 const Locale & U_EXPORT2
michael@0 796 Locale::getTaiwan(void)
michael@0 797 {
michael@0 798 return getLocale(eTAIWAN);
michael@0 799 }
michael@0 800
michael@0 801 const Locale & U_EXPORT2
michael@0 802 Locale::getUK(void)
michael@0 803 {
michael@0 804 return getLocale(eUK);
michael@0 805 }
michael@0 806
michael@0 807 const Locale & U_EXPORT2
michael@0 808 Locale::getUS(void)
michael@0 809 {
michael@0 810 return getLocale(eUS);
michael@0 811 }
michael@0 812
michael@0 813 const Locale & U_EXPORT2
michael@0 814 Locale::getCanada(void)
michael@0 815 {
michael@0 816 return getLocale(eCANADA);
michael@0 817 }
michael@0 818
michael@0 819 const Locale & U_EXPORT2
michael@0 820 Locale::getCanadaFrench(void)
michael@0 821 {
michael@0 822 return getLocale(eCANADA_FRENCH);
michael@0 823 }
michael@0 824
michael@0 825 const Locale &
michael@0 826 Locale::getLocale(int locid)
michael@0 827 {
michael@0 828 Locale *localeCache = getLocaleCache();
michael@0 829 U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
michael@0 830 if (localeCache == NULL) {
michael@0 831 // Failure allocating the locale cache.
michael@0 832 // The best we can do is return a NULL reference.
michael@0 833 locid = 0;
michael@0 834 }
michael@0 835 return localeCache[locid]; /*operating on NULL*/
michael@0 836 }
michael@0 837
michael@0 838 /*
michael@0 839 This function is defined this way in order to get around static
michael@0 840 initialization and static destruction.
michael@0 841 */
michael@0 842 Locale *
michael@0 843 Locale::getLocaleCache(void)
michael@0 844 {
michael@0 845 umtx_lock(NULL);
michael@0 846 UBool needInit = (gLocaleCache == NULL);
michael@0 847 umtx_unlock(NULL);
michael@0 848
michael@0 849 if (needInit) {
michael@0 850 Locale *tLocaleCache = new Locale[(int)eMAX_LOCALES];
michael@0 851 if (tLocaleCache == NULL) {
michael@0 852 return NULL;
michael@0 853 }
michael@0 854 tLocaleCache[eROOT] = Locale("");
michael@0 855 tLocaleCache[eENGLISH] = Locale("en");
michael@0 856 tLocaleCache[eFRENCH] = Locale("fr");
michael@0 857 tLocaleCache[eGERMAN] = Locale("de");
michael@0 858 tLocaleCache[eITALIAN] = Locale("it");
michael@0 859 tLocaleCache[eJAPANESE] = Locale("ja");
michael@0 860 tLocaleCache[eKOREAN] = Locale("ko");
michael@0 861 tLocaleCache[eCHINESE] = Locale("zh");
michael@0 862 tLocaleCache[eFRANCE] = Locale("fr", "FR");
michael@0 863 tLocaleCache[eGERMANY] = Locale("de", "DE");
michael@0 864 tLocaleCache[eITALY] = Locale("it", "IT");
michael@0 865 tLocaleCache[eJAPAN] = Locale("ja", "JP");
michael@0 866 tLocaleCache[eKOREA] = Locale("ko", "KR");
michael@0 867 tLocaleCache[eCHINA] = Locale("zh", "CN");
michael@0 868 tLocaleCache[eTAIWAN] = Locale("zh", "TW");
michael@0 869 tLocaleCache[eUK] = Locale("en", "GB");
michael@0 870 tLocaleCache[eUS] = Locale("en", "US");
michael@0 871 tLocaleCache[eCANADA] = Locale("en", "CA");
michael@0 872 tLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
michael@0 873
michael@0 874 umtx_lock(NULL);
michael@0 875 if (gLocaleCache == NULL) {
michael@0 876 gLocaleCache = tLocaleCache;
michael@0 877 tLocaleCache = NULL;
michael@0 878 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
michael@0 879 }
michael@0 880 umtx_unlock(NULL);
michael@0 881 if (tLocaleCache) {
michael@0 882 delete [] tLocaleCache; // Fancy array delete will destruct each member.
michael@0 883 }
michael@0 884 }
michael@0 885 return gLocaleCache;
michael@0 886 }
michael@0 887
michael@0 888 class KeywordEnumeration : public StringEnumeration {
michael@0 889 private:
michael@0 890 char *keywords;
michael@0 891 char *current;
michael@0 892 int32_t length;
michael@0 893 UnicodeString currUSKey;
michael@0 894 static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
michael@0 895
michael@0 896 public:
michael@0 897 static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
michael@0 898 virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
michael@0 899 public:
michael@0 900 KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
michael@0 901 : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
michael@0 902 if(U_SUCCESS(status) && keywordLen != 0) {
michael@0 903 if(keys == NULL || keywordLen < 0) {
michael@0 904 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 905 } else {
michael@0 906 keywords = (char *)uprv_malloc(keywordLen+1);
michael@0 907 if (keywords == NULL) {
michael@0 908 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 909 }
michael@0 910 else {
michael@0 911 uprv_memcpy(keywords, keys, keywordLen);
michael@0 912 keywords[keywordLen] = 0;
michael@0 913 current = keywords + currentIndex;
michael@0 914 length = keywordLen;
michael@0 915 }
michael@0 916 }
michael@0 917 }
michael@0 918 }
michael@0 919
michael@0 920 virtual ~KeywordEnumeration();
michael@0 921
michael@0 922 virtual StringEnumeration * clone() const
michael@0 923 {
michael@0 924 UErrorCode status = U_ZERO_ERROR;
michael@0 925 return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
michael@0 926 }
michael@0 927
michael@0 928 virtual int32_t count(UErrorCode &/*status*/) const {
michael@0 929 char *kw = keywords;
michael@0 930 int32_t result = 0;
michael@0 931 while(*kw) {
michael@0 932 result++;
michael@0 933 kw += uprv_strlen(kw)+1;
michael@0 934 }
michael@0 935 return result;
michael@0 936 }
michael@0 937
michael@0 938 virtual const char* next(int32_t* resultLength, UErrorCode& status) {
michael@0 939 const char* result;
michael@0 940 int32_t len;
michael@0 941 if(U_SUCCESS(status) && *current != 0) {
michael@0 942 result = current;
michael@0 943 len = (int32_t)uprv_strlen(current);
michael@0 944 current += len+1;
michael@0 945 if(resultLength != NULL) {
michael@0 946 *resultLength = len;
michael@0 947 }
michael@0 948 } else {
michael@0 949 if(resultLength != NULL) {
michael@0 950 *resultLength = 0;
michael@0 951 }
michael@0 952 result = NULL;
michael@0 953 }
michael@0 954 return result;
michael@0 955 }
michael@0 956
michael@0 957 virtual const UnicodeString* snext(UErrorCode& status) {
michael@0 958 int32_t resultLength = 0;
michael@0 959 const char *s = next(&resultLength, status);
michael@0 960 return setChars(s, resultLength, status);
michael@0 961 }
michael@0 962
michael@0 963 virtual void reset(UErrorCode& /*status*/) {
michael@0 964 current = keywords;
michael@0 965 }
michael@0 966 };
michael@0 967
michael@0 968 const char KeywordEnumeration::fgClassID = '\0';
michael@0 969
michael@0 970 KeywordEnumeration::~KeywordEnumeration() {
michael@0 971 uprv_free(keywords);
michael@0 972 }
michael@0 973
michael@0 974 StringEnumeration *
michael@0 975 Locale::createKeywords(UErrorCode &status) const
michael@0 976 {
michael@0 977 char keywords[256];
michael@0 978 int32_t keywordCapacity = 256;
michael@0 979 StringEnumeration *result = NULL;
michael@0 980
michael@0 981 const char* variantStart = uprv_strchr(fullName, '@');
michael@0 982 const char* assignment = uprv_strchr(fullName, '=');
michael@0 983 if(variantStart) {
michael@0 984 if(assignment > variantStart) {
michael@0 985 int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
michael@0 986 if(keyLen) {
michael@0 987 result = new KeywordEnumeration(keywords, keyLen, 0, status);
michael@0 988 }
michael@0 989 } else {
michael@0 990 status = U_INVALID_FORMAT_ERROR;
michael@0 991 }
michael@0 992 }
michael@0 993 return result;
michael@0 994 }
michael@0 995
michael@0 996 int32_t
michael@0 997 Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
michael@0 998 {
michael@0 999 return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
michael@0 1000 }
michael@0 1001
michael@0 1002 void
michael@0 1003 Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status)
michael@0 1004 {
michael@0 1005 uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status);
michael@0 1006 }
michael@0 1007
michael@0 1008 const char *
michael@0 1009 Locale::getBaseName() const
michael@0 1010 {
michael@0 1011 // lazy init
michael@0 1012 UErrorCode status = U_ZERO_ERROR;
michael@0 1013 // semantically const
michael@0 1014 if(baseName == 0) {
michael@0 1015 ((Locale *)this)->baseName = ((Locale *)this)->baseNameBuffer;
michael@0 1016 int32_t baseNameSize = uloc_getBaseName(fullName, baseName, ULOC_FULLNAME_CAPACITY, &status);
michael@0 1017 if(baseNameSize >= ULOC_FULLNAME_CAPACITY) {
michael@0 1018 ((Locale *)this)->baseName = (char *)uprv_malloc(sizeof(char) * baseNameSize + 1);
michael@0 1019 if (baseName == NULL) {
michael@0 1020 return baseName;
michael@0 1021 }
michael@0 1022 uloc_getBaseName(fullName, baseName, baseNameSize+1, &status);
michael@0 1023 }
michael@0 1024 baseName[baseNameSize] = 0;
michael@0 1025
michael@0 1026 // the computation of variantBegin leaves it equal to the length
michael@0 1027 // of fullName if there is no variant. It should instead be
michael@0 1028 // the length of the baseName. Patch around this for now.
michael@0 1029 if (variantBegin == (int32_t)uprv_strlen(fullName)) {
michael@0 1030 ((Locale*)this)->variantBegin = baseNameSize;
michael@0 1031 }
michael@0 1032 }
michael@0 1033 return baseName;
michael@0 1034 }
michael@0 1035
michael@0 1036 //eof
michael@0 1037 U_NAMESPACE_END

mercurial