LCOV - code coverage report
Current view: top level - intl/icu/source/common - locutil.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 98 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             :  *******************************************************************************
       5             :  * Copyright (C) 2002-2014, International Business Machines Corporation and
       6             :  * others. All Rights Reserved.
       7             :  *******************************************************************************
       8             :  */
       9             : #include "unicode/utypes.h"
      10             : 
      11             : #if !UCONFIG_NO_SERVICE || !UCONFIG_NO_TRANSLITERATION
      12             : 
      13             : #include "unicode/resbund.h"
      14             : #include "cmemory.h"
      15             : #include "ustrfmt.h"
      16             : #include "locutil.h"
      17             : #include "charstr.h"
      18             : #include "ucln_cmn.h"
      19             : #include "uassert.h"
      20             : #include "umutex.h"
      21             : 
      22             : // see LocaleUtility::getAvailableLocaleNames
      23             : static icu::UInitOnce   LocaleUtilityInitOnce = U_INITONCE_INITIALIZER;
      24             : static icu::Hashtable * LocaleUtility_cache = NULL;
      25             : 
      26             : #define UNDERSCORE_CHAR ((UChar)0x005f)
      27             : #define AT_SIGN_CHAR    ((UChar)64)
      28             : #define PERIOD_CHAR     ((UChar)46)
      29             : 
      30             : /*
      31             :  ******************************************************************
      32             :  */
      33             : 
      34             : /**
      35             :  * Release all static memory held by Locale Utility.  
      36             :  */
      37             : U_CDECL_BEGIN
      38           0 : static UBool U_CALLCONV service_cleanup(void) {
      39           0 :     if (LocaleUtility_cache) {
      40           0 :         delete LocaleUtility_cache;
      41           0 :         LocaleUtility_cache = NULL;
      42             :     }
      43           0 :     return TRUE;
      44             : }
      45             : 
      46             : 
      47           0 : static void U_CALLCONV locale_utility_init(UErrorCode &status) {
      48             :     using namespace icu;
      49           0 :     U_ASSERT(LocaleUtility_cache == NULL);
      50           0 :     ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup);
      51           0 :     LocaleUtility_cache = new Hashtable(status);
      52           0 :     if (U_FAILURE(status)) {
      53           0 :         delete LocaleUtility_cache;
      54           0 :         LocaleUtility_cache = NULL;
      55           0 :         return;
      56             :     }
      57           0 :     if (LocaleUtility_cache == NULL) {
      58           0 :         status = U_MEMORY_ALLOCATION_ERROR;
      59           0 :         return;
      60             :     }
      61           0 :     LocaleUtility_cache->setValueDeleter(uhash_deleteHashtable);
      62             : }
      63             : 
      64             : U_CDECL_END
      65             : 
      66             : U_NAMESPACE_BEGIN
      67             : 
      68             : UnicodeString&
      69           0 : LocaleUtility::canonicalLocaleString(const UnicodeString* id, UnicodeString& result)
      70             : {
      71           0 :   if (id == NULL) {
      72           0 :     result.setToBogus();
      73             :   } else {
      74             :     // Fix case only (no other changes) up to the first '@' or '.' or
      75             :     // end of string, whichever comes first.  In 3.0 I changed this to
      76             :     // stop at first '@' or '.'.  It used to run out to the end of
      77             :     // string.  My fix makes the tests pass but is probably
      78             :     // structurally incorrect.  See below.  [alan 3.0]
      79             : 
      80             :     // TODO: Doug, you might want to revise this...
      81           0 :     result = *id;
      82           0 :     int32_t i = 0;
      83           0 :     int32_t end = result.indexOf(AT_SIGN_CHAR);
      84           0 :     int32_t n = result.indexOf(PERIOD_CHAR);
      85           0 :     if (n >= 0 && n < end) {
      86           0 :         end = n;
      87             :     }
      88           0 :     if (end < 0) {
      89           0 :         end = result.length();
      90             :     }
      91           0 :     n = result.indexOf(UNDERSCORE_CHAR);
      92           0 :     if (n < 0) {
      93           0 :       n = end;
      94             :     }
      95           0 :     for (; i < n; ++i) {
      96           0 :       UChar c = result.charAt(i);
      97           0 :       if (c >= 0x0041 && c <= 0x005a) {
      98           0 :         c += 0x20;
      99           0 :         result.setCharAt(i, c);
     100             :       }
     101             :     }
     102           0 :     for (n = end; i < n; ++i) {
     103           0 :       UChar c = result.charAt(i);
     104           0 :       if (c >= 0x0061 && c <= 0x007a) {
     105           0 :         c -= 0x20;
     106           0 :         result.setCharAt(i, c);
     107             :       }
     108             :     }
     109             :   }
     110           0 :   return result;
     111             : 
     112             : #if 0
     113             :     // This code does a proper full level 2 canonicalization of id.
     114             :     // It's nasty to go from UChar to char to char to UChar -- but
     115             :     // that's what you have to do to use the uloc_canonicalize
     116             :     // function on UnicodeStrings.
     117             : 
     118             :     // I ended up doing the alternate fix (see above) not for
     119             :     // performance reasons, although performance will certainly be
     120             :     // better, but because doing a full level 2 canonicalization
     121             :     // causes some tests to fail.  [alan 3.0]
     122             : 
     123             :     // TODO: Doug, you might want to revisit this...
     124             :     result.setToBogus();
     125             :     if (id != 0) {
     126             :         int32_t buflen = id->length() + 8; // space for NUL
     127             :         char* buf = (char*) uprv_malloc(buflen);
     128             :         char* canon = (buf == 0) ? 0 : (char*) uprv_malloc(buflen);
     129             :         if (buf != 0 && canon != 0) {
     130             :             U_ASSERT(id->extract(0, INT32_MAX, buf, buflen) < buflen);
     131             :             UErrorCode ec = U_ZERO_ERROR;
     132             :             uloc_canonicalize(buf, canon, buflen, &ec);
     133             :             if (U_SUCCESS(ec)) {
     134             :                 result = UnicodeString(canon);
     135             :             }
     136             :         }
     137             :         uprv_free(buf);
     138             :         uprv_free(canon);
     139             :     }
     140             :     return result;
     141             : #endif
     142             : }
     143             : 
     144             : Locale&
     145           0 : LocaleUtility::initLocaleFromName(const UnicodeString& id, Locale& result)
     146             : {
     147             :     enum { BUFLEN = 128 }; // larger than ever needed
     148             : 
     149           0 :     if (id.isBogus() || id.length() >= BUFLEN) {
     150           0 :         result.setToBogus();
     151             :     } else {
     152             :         /*
     153             :          * We need to convert from a UnicodeString to char * in order to
     154             :          * create a Locale.
     155             :          *
     156             :          * Problem: Locale ID strings may contain '@' which is a variant
     157             :          * character and cannot be handled by invariant-character conversion.
     158             :          *
     159             :          * Hack: Since ICU code can handle locale IDs with multiple encodings
     160             :          * of '@' (at least for EBCDIC; it's not known to be a problem for
     161             :          * ASCII-based systems),
     162             :          * we use regular invariant-character conversion for everything else
     163             :          * and manually convert U+0040 into a compiler-char-constant '@'.
     164             :          * While this compilation-time constant may not match the runtime
     165             :          * encoding of '@', it should be one of the encodings which ICU
     166             :          * recognizes.
     167             :          *
     168             :          * There should be only at most one '@' in a locale ID.
     169             :          */
     170             :         char buffer[BUFLEN];
     171             :         int32_t prev, i;
     172           0 :         prev = 0;
     173             :         for(;;) {
     174           0 :             i = id.indexOf((UChar)0x40, prev);
     175           0 :             if(i < 0) {
     176             :                 // no @ between prev and the rest of the string
     177           0 :                 id.extract(prev, INT32_MAX, buffer + prev, BUFLEN - prev, US_INV);
     178           0 :                 break; // done
     179             :             } else {
     180             :                 // normal invariant-character conversion for text between @s
     181           0 :                 id.extract(prev, i - prev, buffer + prev, BUFLEN - prev, US_INV);
     182             :                 // manually "convert" U+0040 at id[i] into '@' at buffer[i]
     183           0 :                 buffer[i] = '@';
     184           0 :                 prev = i + 1;
     185             :             }
     186             :         }
     187           0 :         result = Locale::createFromName(buffer);
     188             :     }
     189           0 :     return result;
     190             : }
     191             : 
     192             : UnicodeString&
     193           0 : LocaleUtility::initNameFromLocale(const Locale& locale, UnicodeString& result)
     194             : {
     195           0 :     if (locale.isBogus()) {
     196           0 :         result.setToBogus();
     197             :     } else {
     198           0 :         result.append(UnicodeString(locale.getName(), -1, US_INV));
     199             :     }
     200           0 :     return result;
     201             : }
     202             : 
     203             : const Hashtable*
     204           0 : LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
     205             : {
     206             :     // LocaleUtility_cache is a hash-of-hashes.  The top-level keys
     207             :     // are path strings ('bundleID') passed to
     208             :     // ures_openAvailableLocales.  The top-level values are
     209             :     // second-level hashes.  The second-level keys are result strings
     210             :     // from ures_openAvailableLocales.  The second-level values are
     211             :     // garbage ((void*)1 or other random pointer).
     212             : 
     213           0 :     UErrorCode status = U_ZERO_ERROR;
     214           0 :     umtx_initOnce(LocaleUtilityInitOnce, locale_utility_init, status);
     215           0 :     Hashtable *cache = LocaleUtility_cache;
     216           0 :     if (cache == NULL) {
     217             :         // Catastrophic failure.
     218           0 :         return NULL;
     219             :     }
     220             : 
     221             :     Hashtable* htp;
     222           0 :     umtx_lock(NULL);
     223           0 :     htp = (Hashtable*) cache->get(bundleID);
     224           0 :     umtx_unlock(NULL);
     225             : 
     226           0 :     if (htp == NULL) {
     227           0 :         htp = new Hashtable(status);
     228           0 :         if (htp && U_SUCCESS(status)) {
     229           0 :             CharString cbundleID;
     230           0 :             cbundleID.appendInvariantChars(bundleID, status);
     231           0 :             const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data();
     232           0 :             UEnumeration *uenum = ures_openAvailableLocales(path, &status);
     233             :             for (;;) {
     234           0 :                 const UChar* id = uenum_unext(uenum, NULL, &status);
     235           0 :                 if (id == NULL) {
     236           0 :                     break;
     237             :                 }
     238           0 :                 htp->put(UnicodeString(id), (void*)htp, status);
     239           0 :             }
     240           0 :             uenum_close(uenum);
     241           0 :             if (U_FAILURE(status)) {
     242           0 :                 delete htp;
     243           0 :                 return NULL;
     244             :             }
     245           0 :             umtx_lock(NULL);
     246           0 :             Hashtable *t = static_cast<Hashtable *>(cache->get(bundleID));
     247           0 :             if (t != NULL) {
     248             :                 // Another thread raced through this code, creating the cache entry first.
     249             :                 // Discard ours and return theirs.
     250           0 :                 umtx_unlock(NULL);
     251           0 :                 delete htp;
     252           0 :                 htp = t;
     253             :             } else {
     254           0 :                 cache->put(bundleID, (void*)htp, status);
     255           0 :                 umtx_unlock(NULL);
     256             :             }
     257             :         }
     258             :     }
     259           0 :     return htp;
     260             : }
     261             : 
     262             : UBool
     263           0 : LocaleUtility::isFallbackOf(const UnicodeString& root, const UnicodeString& child)
     264             : {
     265           0 :     return child.indexOf(root) == 0 &&
     266           0 :       (child.length() == root.length() ||
     267           0 :        child.charAt(root.length()) == UNDERSCORE_CHAR);
     268             : }
     269             : 
     270             : U_NAMESPACE_END
     271             : 
     272             : /* !UCONFIG_NO_SERVICE */
     273             : #endif
     274             : 
     275             : 

Generated by: LCOV version 1.13