intl/icu/source/common/serv.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.

     1 /**
     2 *******************************************************************************
     3 * Copyright (C) 2001-2012, International Business Machines Corporation.
     4 * All Rights Reserved.
     5 *******************************************************************************
     6 */
     8 #include "unicode/utypes.h"
    10 #if !UCONFIG_NO_SERVICE
    12 #include "serv.h"
    13 #include "umutex.h"
    15 #undef SERVICE_REFCOUNT
    17 // in case we use the refcount stuff
    19 U_NAMESPACE_BEGIN
    21 /*
    22 ******************************************************************
    23 */
    25 const UChar ICUServiceKey::PREFIX_DELIMITER = 0x002F;   /* '/' */
    27 ICUServiceKey::ICUServiceKey(const UnicodeString& id) 
    28 : _id(id) {
    29 }
    31 ICUServiceKey::~ICUServiceKey() 
    32 {
    33 }
    35 const UnicodeString& 
    36 ICUServiceKey::getID() const 
    37 {
    38     return _id;
    39 }
    41 UnicodeString& 
    42 ICUServiceKey::canonicalID(UnicodeString& result) const 
    43 {
    44     return result.append(_id);
    45 }
    47 UnicodeString& 
    48 ICUServiceKey::currentID(UnicodeString& result) const 
    49 {
    50     return canonicalID(result);
    51 }
    53 UnicodeString& 
    54 ICUServiceKey::currentDescriptor(UnicodeString& result) const 
    55 {
    56     prefix(result);
    57     result.append(PREFIX_DELIMITER);
    58     return currentID(result);
    59 }
    61 UBool 
    62 ICUServiceKey::fallback() 
    63 {
    64     return FALSE;
    65 }
    67 UBool 
    68 ICUServiceKey::isFallbackOf(const UnicodeString& id) const 
    69 {
    70     return id == _id;
    71 }
    73 UnicodeString& 
    74 ICUServiceKey::prefix(UnicodeString& result) const 
    75 {
    76     return result;
    77 }
    79 UnicodeString& 
    80 ICUServiceKey::parsePrefix(UnicodeString& result) 
    81 {
    82     int32_t n = result.indexOf(PREFIX_DELIMITER);
    83     if (n < 0) {
    84         n = 0;
    85     }
    86     result.remove(n);
    87     return result;
    88 }
    90 UnicodeString& 
    91 ICUServiceKey::parseSuffix(UnicodeString& result) 
    92 {
    93     int32_t n = result.indexOf(PREFIX_DELIMITER);
    94     if (n >= 0) {
    95         result.remove(0, n+1);
    96     }
    97     return result;
    98 }
   100 #ifdef SERVICE_DEBUG
   101 UnicodeString& 
   102 ICUServiceKey::debug(UnicodeString& result) const 
   103 {
   104     debugClass(result);
   105     result.append(" id: ");
   106     result.append(_id);
   107     return result;
   108 }
   110 UnicodeString& 
   111 ICUServiceKey::debugClass(UnicodeString& result) const 
   112 {
   113     return result.append("ICUServiceKey");
   114 }
   115 #endif
   117 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ICUServiceKey)
   119 /*
   120 ******************************************************************
   121 */
   123 ICUServiceFactory::~ICUServiceFactory() {}
   125 SimpleFactory::SimpleFactory(UObject* instanceToAdopt, const UnicodeString& id, UBool visible) 
   126 : _instance(instanceToAdopt), _id(id), _visible(visible)
   127 {
   128 }
   130 SimpleFactory::~SimpleFactory() 
   131 {
   132     delete _instance;
   133 }
   135 UObject* 
   136 SimpleFactory::create(const ICUServiceKey& key, const ICUService* service, UErrorCode& status) const 
   137 {
   138     if (U_SUCCESS(status)) {
   139         UnicodeString temp;
   140         if (_id == key.currentID(temp)) {
   141             return service->cloneInstance(_instance); 
   142         }
   143     }
   144     return NULL;
   145 }
   147 void 
   148 SimpleFactory::updateVisibleIDs(Hashtable& result, UErrorCode& status) const 
   149 {
   150     if (_visible) {
   151         result.put(_id, (void*)this, status); // cast away const
   152     } else {
   153         result.remove(_id);
   154     }
   155 }
   157 UnicodeString& 
   158 SimpleFactory::getDisplayName(const UnicodeString& id, const Locale& /* locale */, UnicodeString& result) const 
   159 {
   160     if (_visible && _id == id) {
   161         result = _id;
   162     } else {
   163         result.setToBogus();
   164     }
   165     return result;
   166 }
   168 #ifdef SERVICE_DEBUG
   169 UnicodeString& 
   170 SimpleFactory::debug(UnicodeString& toAppendTo) const 
   171 {
   172     debugClass(toAppendTo);
   173     toAppendTo.append(" id: ");
   174     toAppendTo.append(_id);
   175     toAppendTo.append(", visible: ");
   176     toAppendTo.append(_visible ? "T" : "F");
   177     return toAppendTo;
   178 }
   180 UnicodeString& 
   181 SimpleFactory::debugClass(UnicodeString& toAppendTo) const 
   182 {
   183     return toAppendTo.append("SimpleFactory");
   184 }
   185 #endif
   187 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleFactory)
   189 /*
   190 ******************************************************************
   191 */
   193 ServiceListener::~ServiceListener() {}
   195 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ServiceListener)
   197 /*
   198 ******************************************************************
   199 */
   201 // Record the actual id for this service in the cache, so we can return it
   202 // even if we succeed later with a different id.
   203 class CacheEntry : public UMemory {
   204 private:
   205     int32_t refcount;
   207 public:
   208     UnicodeString actualDescriptor;
   209     UObject* service;
   211     /**
   212     * Releases a reference to the shared resource.
   213     */
   214     ~CacheEntry() {
   215         delete service;
   216     }
   218     CacheEntry(const UnicodeString& _actualDescriptor, UObject* _service) 
   219         : refcount(1), actualDescriptor(_actualDescriptor), service(_service) {
   220     }
   222     /**
   223     * Instantiation creates an initial reference, so don't call this
   224     * unless you're creating a new pointer to this.  Management of
   225     * that pointer will have to know how to deal with refcounts.  
   226     * Return true if the resource has not already been released.
   227     */
   228     CacheEntry* ref() {
   229         ++refcount;
   230         return this;
   231     }
   233     /**
   234     * Destructions removes a reference, so don't call this unless
   235     * you're removing pointer to this somewhere.  Management of that
   236     * pointer will have to know how to deal with refcounts.  Once
   237     * the refcount drops to zero, the resource is released.  Return
   238     * false if the resouce has been released.
   239     */
   240     CacheEntry* unref() {
   241         if ((--refcount) == 0) {
   242             delete this;
   243             return NULL;
   244         }
   245         return this;
   246     }
   248     /**
   249     * Return TRUE if there is at least one reference to this and the
   250     * resource has not been released.
   251     */
   252     UBool isShared() const {
   253         return refcount > 1;
   254     }
   255 };
   257 // UObjectDeleter for serviceCache
   258 U_CDECL_BEGIN
   259 static void U_CALLCONV
   260 cacheDeleter(void* obj) {
   261     U_NAMESPACE_USE ((CacheEntry*)obj)->unref();
   262 }
   264 /**
   265 * Deleter for UObjects
   266 */
   267 static void U_CALLCONV
   268 deleteUObject(void *obj) {
   269     U_NAMESPACE_USE delete (UObject*) obj;
   270 }
   271 U_CDECL_END
   273 /*
   274 ******************************************************************
   275 */
   277 class DNCache : public UMemory {
   278 public:
   279     Hashtable cache;
   280     const Locale locale;
   282     DNCache(const Locale& _locale) 
   283         : cache(), locale(_locale) 
   284     {
   285         // cache.setKeyDeleter(uprv_deleteUObject);
   286     }
   287 };
   290 /*
   291 ******************************************************************
   292 */
   294 StringPair* 
   295 StringPair::create(const UnicodeString& displayName, 
   296                    const UnicodeString& id,
   297                    UErrorCode& status)
   298 {
   299     if (U_SUCCESS(status)) {
   300         StringPair* sp = new StringPair(displayName, id);
   301         if (sp == NULL || sp->isBogus()) {
   302             status = U_MEMORY_ALLOCATION_ERROR;
   303             delete sp;
   304             return NULL;
   305         }
   306         return sp;
   307     }
   308     return NULL;
   309 }
   311 UBool 
   312 StringPair::isBogus() const {
   313     return displayName.isBogus() || id.isBogus();
   314 }
   316 StringPair::StringPair(const UnicodeString& _displayName, 
   317                        const UnicodeString& _id)
   318 : displayName(_displayName)
   319 , id(_id)
   320 {
   321 }
   323 U_CDECL_BEGIN
   324 static void U_CALLCONV
   325 userv_deleteStringPair(void *obj) {
   326     U_NAMESPACE_USE delete (StringPair*) obj;
   327 }
   328 U_CDECL_END
   330 /*
   331 ******************************************************************
   332 */
   334 static UMutex lock = U_MUTEX_INITIALIZER;
   336 ICUService::ICUService()
   337 : name()
   338 , timestamp(0)
   339 , factories(NULL)
   340 , serviceCache(NULL)
   341 , idCache(NULL)
   342 , dnCache(NULL)
   343 {
   344 }
   346 ICUService::ICUService(const UnicodeString& newName) 
   347 : name(newName)
   348 , timestamp(0)
   349 , factories(NULL)
   350 , serviceCache(NULL)
   351 , idCache(NULL)
   352 , dnCache(NULL)
   353 {
   354 }
   356 ICUService::~ICUService()
   357 {
   358     {
   359         Mutex mutex(&lock);
   360         clearCaches();
   361         delete factories;
   362         factories = NULL;
   363     }
   364 }
   366 UObject* 
   367 ICUService::get(const UnicodeString& descriptor, UErrorCode& status) const 
   368 {
   369     return get(descriptor, NULL, status);
   370 }
   372 UObject* 
   373 ICUService::get(const UnicodeString& descriptor, UnicodeString* actualReturn, UErrorCode& status) const 
   374 {
   375     UObject* result = NULL;
   376     ICUServiceKey* key = createKey(&descriptor, status);
   377     if (key) {
   378         result = getKey(*key, actualReturn, status);
   379         delete key;
   380     }
   381     return result;
   382 }
   384 UObject* 
   385 ICUService::getKey(ICUServiceKey& key, UErrorCode& status) const 
   386 {
   387     return getKey(key, NULL, status);
   388 }
   390 // this is a vector that subclasses of ICUService can override to further customize the result object
   391 // before returning it.  All other public get functions should call this one.
   393 UObject* 
   394 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& status) const 
   395 {
   396     return getKey(key, actualReturn, NULL, status);
   397 }
   399 // make it possible to call reentrantly on systems that don't have reentrant mutexes.
   400 // we can use this simple approach since we know the situation where we're calling
   401 // reentrantly even without knowing the thread.
   402 class XMutex : public UMemory {
   403 public:
   404     inline XMutex(UMutex *mutex, UBool reentering) 
   405         : fMutex(mutex)
   406         , fActive(!reentering) 
   407     {
   408         if (fActive) umtx_lock(fMutex);
   409     }
   410     inline ~XMutex() {
   411         if (fActive) umtx_unlock(fMutex);
   412     }
   414 private:
   415     UMutex  *fMutex;
   416     UBool fActive;
   417 };
   419 struct UVectorDeleter {
   420     UVector* _obj;
   421     UVectorDeleter() : _obj(NULL) {}
   422     ~UVectorDeleter() { delete _obj; }
   423 };
   425 // called only by factories, treat as private
   426 UObject* 
   427 ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, const ICUServiceFactory* factory, UErrorCode& status) const 
   428 {
   429     if (U_FAILURE(status)) {
   430         return NULL;
   431     }
   433     if (isDefault()) {
   434         return handleDefault(key, actualReturn, status);
   435     }
   437     ICUService* ncthis = (ICUService*)this; // cast away semantic const
   439     CacheEntry* result = NULL;
   440     {
   441         // The factory list can't be modified until we're done, 
   442         // otherwise we might update the cache with an invalid result.
   443         // The cache has to stay in synch with the factory list.
   444         // ICU doesn't have monitors so we can't use rw locks, so 
   445         // we single-thread everything using this service, for now.
   447         // if factory is not null, we're calling from within the mutex,
   448         // and since some unix machines don't have reentrant mutexes we
   449         // need to make sure not to try to lock it again.
   450         XMutex mutex(&lock, factory != NULL);
   452         if (serviceCache == NULL) {
   453             ncthis->serviceCache = new Hashtable(status);
   454             if (ncthis->serviceCache == NULL) {
   455                 return NULL;
   456             }
   457             if (U_FAILURE(status)) {
   458                 delete serviceCache;
   459                 return NULL;
   460             }
   461             serviceCache->setValueDeleter(cacheDeleter);
   462         }
   464         UnicodeString currentDescriptor;
   465         UVectorDeleter cacheDescriptorList;
   466         UBool putInCache = FALSE;
   468         int32_t startIndex = 0;
   469         int32_t limit = factories->size();
   470         UBool cacheResult = TRUE;
   472         if (factory != NULL) {
   473             for (int32_t i = 0; i < limit; ++i) {
   474                 if (factory == (const ICUServiceFactory*)factories->elementAt(i)) {
   475                     startIndex = i + 1;
   476                     break;
   477                 }
   478             }
   479             if (startIndex == 0) {
   480                 // throw new InternalError("Factory " + factory + "not registered with service: " + this);
   481                 status = U_ILLEGAL_ARGUMENT_ERROR;
   482                 return NULL;
   483             }
   484             cacheResult = FALSE;
   485         }
   487         do {
   488             currentDescriptor.remove();
   489             key.currentDescriptor(currentDescriptor);
   490             result = (CacheEntry*)serviceCache->get(currentDescriptor);
   491             if (result != NULL) {
   492                 break;
   493             }
   495             // first test of cache failed, so we'll have to update
   496             // the cache if we eventually succeed-- that is, if we're 
   497             // going to update the cache at all.
   498             putInCache = TRUE;
   500             int32_t index = startIndex;
   501             while (index < limit) {
   502                 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(index++);
   503                 UObject* service = f->create(key, this, status);
   504                 if (U_FAILURE(status)) {
   505                     delete service;
   506                     return NULL;
   507                 }
   508                 if (service != NULL) {
   509                     result = new CacheEntry(currentDescriptor, service);
   510                     if (result == NULL) {
   511                         delete service;
   512                         status = U_MEMORY_ALLOCATION_ERROR;
   513                         return NULL;
   514                     }
   516                     goto outerEnd;
   517                 }
   518             }
   520             // prepare to load the cache with all additional ids that 
   521             // will resolve to result, assuming we'll succeed.  We
   522             // don't want to keep querying on an id that's going to
   523             // fallback to the one that succeeded, we want to hit the
   524             // cache the first time next goaround.
   525             if (cacheDescriptorList._obj == NULL) {
   526                 cacheDescriptorList._obj = new UVector(uprv_deleteUObject, NULL, 5, status);
   527                 if (U_FAILURE(status)) {
   528                     return NULL;
   529                 }
   530             }
   531             UnicodeString* idToCache = new UnicodeString(currentDescriptor);
   532             if (idToCache == NULL || idToCache->isBogus()) {
   533                 status = U_MEMORY_ALLOCATION_ERROR;
   534                 return NULL;
   535             }
   537             cacheDescriptorList._obj->addElement(idToCache, status);
   538             if (U_FAILURE(status)) {
   539                 return NULL;
   540             }
   541         } while (key.fallback());
   542 outerEnd:
   544         if (result != NULL) {
   545             if (putInCache && cacheResult) {
   546                 serviceCache->put(result->actualDescriptor, result, status);
   547                 if (U_FAILURE(status)) {
   548                     delete result;
   549                     return NULL;
   550                 }
   552                 if (cacheDescriptorList._obj != NULL) {
   553                     for (int32_t i = cacheDescriptorList._obj->size(); --i >= 0;) {
   554                         UnicodeString* desc = (UnicodeString*)cacheDescriptorList._obj->elementAt(i);
   555                         serviceCache->put(*desc, result, status);
   556                         if (U_FAILURE(status)) {
   557                             delete result;
   558                             return NULL;
   559                         }
   561                         result->ref();
   562                         cacheDescriptorList._obj->removeElementAt(i);
   563                     }
   564                 }
   565             }
   567             if (actualReturn != NULL) {
   568                 // strip null prefix
   569                 if (result->actualDescriptor.indexOf((UChar)0x2f) == 0) { // U+002f=slash (/)
   570                     actualReturn->remove();
   571                     actualReturn->append(result->actualDescriptor, 
   572                         1, 
   573                         result->actualDescriptor.length() - 1);
   574                 } else {
   575                     *actualReturn = result->actualDescriptor;
   576                 }
   578                 if (actualReturn->isBogus()) {
   579                     status = U_MEMORY_ALLOCATION_ERROR;
   580                     delete result;
   581                     return NULL;
   582                 }
   583             }
   585             UObject* service = cloneInstance(result->service);
   586             if (putInCache && !cacheResult) {
   587                 delete result;
   588             }
   589             return service;
   590         }
   591     }
   593     return handleDefault(key, actualReturn, status);
   594 }
   596 UObject* 
   597 ICUService::handleDefault(const ICUServiceKey& /* key */, UnicodeString* /* actualIDReturn */, UErrorCode& /* status */) const 
   598 {
   599     return NULL;
   600 }
   602 UVector& 
   603 ICUService::getVisibleIDs(UVector& result, UErrorCode& status) const {
   604     return getVisibleIDs(result, NULL, status);
   605 }
   607 UVector& 
   608 ICUService::getVisibleIDs(UVector& result, const UnicodeString* matchID, UErrorCode& status) const 
   609 {
   610     result.removeAllElements();
   612     if (U_FAILURE(status)) {
   613         return result;
   614     }
   616     {
   617         Mutex mutex(&lock);
   618         const Hashtable* map = getVisibleIDMap(status);
   619         if (map != NULL) {
   620             ICUServiceKey* fallbackKey = createKey(matchID, status);
   622             for (int32_t pos = -1;;) {
   623                 const UHashElement* e = map->nextElement(pos);
   624                 if (e == NULL) {
   625                     break;
   626                 }
   628                 const UnicodeString* id = (const UnicodeString*)e->key.pointer;
   629                 if (fallbackKey != NULL) {
   630                     if (!fallbackKey->isFallbackOf(*id)) {
   631                         continue;
   632                     }
   633                 }
   635                 UnicodeString* idClone = new UnicodeString(*id);
   636                 if (idClone == NULL || idClone->isBogus()) {
   637                     delete idClone;
   638                     status = U_MEMORY_ALLOCATION_ERROR;
   639                     break;
   640                 }
   641                 result.addElement(idClone, status);
   642                 if (U_FAILURE(status)) {
   643                     delete idClone;
   644                     break;
   645                 }
   646             }
   647             delete fallbackKey;
   648         }
   649     }
   650     if (U_FAILURE(status)) {
   651         result.removeAllElements();
   652     }
   653     return result;
   654 }
   656 const Hashtable* 
   657 ICUService::getVisibleIDMap(UErrorCode& status) const {
   658     if (U_FAILURE(status)) return NULL;
   660     // must only be called when lock is already held
   662     ICUService* ncthis = (ICUService*)this; // cast away semantic const
   663     if (idCache == NULL) {
   664         ncthis->idCache = new Hashtable(status);
   665         if (idCache == NULL) {
   666             status = U_MEMORY_ALLOCATION_ERROR;
   667         } else if (factories != NULL) {
   668             for (int32_t pos = factories->size(); --pos >= 0;) {
   669                 ICUServiceFactory* f = (ICUServiceFactory*)factories->elementAt(pos);
   670                 f->updateVisibleIDs(*idCache, status);
   671             }
   672             if (U_FAILURE(status)) {
   673                 delete idCache;
   674                 ncthis->idCache = NULL;
   675             }
   676         }
   677     }
   679     return idCache;
   680 }
   683 UnicodeString& 
   684 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result) const 
   685 {
   686     return getDisplayName(id, result, Locale::getDefault());
   687 }
   689 UnicodeString& 
   690 ICUService::getDisplayName(const UnicodeString& id, UnicodeString& result, const Locale& locale) const 
   691 {
   692     {
   693         UErrorCode status = U_ZERO_ERROR;
   694         Mutex mutex(&lock);
   695         const Hashtable* map = getVisibleIDMap(status);
   696         if (map != NULL) {
   697             ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
   698             if (f != NULL) {
   699                 f->getDisplayName(id, locale, result);
   700                 return result;
   701             }
   703             // fallback
   704             UErrorCode status = U_ZERO_ERROR;
   705             ICUServiceKey* fallbackKey = createKey(&id, status);
   706             while (fallbackKey->fallback()) {
   707                 UnicodeString us;
   708                 fallbackKey->currentID(us);
   709                 f = (ICUServiceFactory*)map->get(us);
   710                 if (f != NULL) {
   711                     f->getDisplayName(id, locale, result);
   712                     delete fallbackKey;
   713                     return result;
   714                 }
   715             }
   716             delete fallbackKey;
   717         }
   718     }
   719     result.setToBogus();
   720     return result;
   721 }
   723 UVector& 
   724 ICUService::getDisplayNames(UVector& result, UErrorCode& status) const 
   725 {
   726     return getDisplayNames(result, Locale::getDefault(), NULL, status);
   727 }
   730 UVector& 
   731 ICUService::getDisplayNames(UVector& result, const Locale& locale, UErrorCode& status) const 
   732 {
   733     return getDisplayNames(result, locale, NULL, status);
   734 }
   736 UVector& 
   737 ICUService::getDisplayNames(UVector& result, 
   738                             const Locale& locale, 
   739                             const UnicodeString* matchID, 
   740                             UErrorCode& status) const 
   741 {
   742     result.removeAllElements();
   743     result.setDeleter(userv_deleteStringPair);
   744     if (U_SUCCESS(status)) {
   745         ICUService* ncthis = (ICUService*)this; // cast away semantic const
   746         Mutex mutex(&lock);
   748         if (dnCache != NULL && dnCache->locale != locale) {
   749             delete dnCache;
   750             ncthis->dnCache = NULL;
   751         }
   753         if (dnCache == NULL) {
   754             const Hashtable* m = getVisibleIDMap(status);
   755             if (U_FAILURE(status)) {
   756                 return result;
   757             }
   758             ncthis->dnCache = new DNCache(locale); 
   759             if (dnCache == NULL) {
   760                 status = U_MEMORY_ALLOCATION_ERROR;
   761                 return result;
   762             }
   764             int32_t pos = -1;
   765             const UHashElement* entry = NULL;
   766             while ((entry = m->nextElement(pos)) != NULL) {
   767                 const UnicodeString* id = (const UnicodeString*)entry->key.pointer;
   768                 ICUServiceFactory* f = (ICUServiceFactory*)entry->value.pointer;
   769                 UnicodeString dname;
   770                 f->getDisplayName(*id, locale, dname);
   771                 if (dname.isBogus()) {
   772                     status = U_MEMORY_ALLOCATION_ERROR;
   773                 } else {
   774                     dnCache->cache.put(dname, (void*)id, status); // share pointer with visibleIDMap
   775                     if (U_SUCCESS(status)) {
   776                         continue;
   777                     }
   778                 }
   779                 delete dnCache;
   780                 ncthis->dnCache = NULL;
   781                 return result;
   782             }
   783         }
   784     }
   786     ICUServiceKey* matchKey = createKey(matchID, status);
   787     /* To ensure that all elements in the hashtable are iterated, set pos to -1.
   788      * nextElement(pos) will skip the position at pos and begin the iteration
   789      * at the next position, which in this case will be 0.
   790      */
   791     int32_t pos = -1; 
   792     const UHashElement *entry = NULL;
   793     while ((entry = dnCache->cache.nextElement(pos)) != NULL) {
   794         const UnicodeString* id = (const UnicodeString*)entry->value.pointer;
   795         if (matchKey != NULL && !matchKey->isFallbackOf(*id)) {
   796             continue;
   797         }
   798         const UnicodeString* dn = (const UnicodeString*)entry->key.pointer;
   799         StringPair* sp = StringPair::create(*id, *dn, status);
   800         result.addElement(sp, status);
   801         if (U_FAILURE(status)) {
   802             result.removeAllElements();
   803             break;
   804         }
   805     }
   806     delete matchKey;
   808     return result;
   809 }
   811 URegistryKey
   812 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UErrorCode& status) 
   813 {
   814     return registerInstance(objToAdopt, id, TRUE, status);
   815 }
   817 URegistryKey
   818 ICUService::registerInstance(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status) 
   819 {
   820     ICUServiceKey* key = createKey(&id, status);
   821     if (key != NULL) {
   822         UnicodeString canonicalID;
   823         key->canonicalID(canonicalID);
   824         delete key;
   826         ICUServiceFactory* f = createSimpleFactory(objToAdopt, canonicalID, visible, status);
   827         if (f != NULL) {
   828             return registerFactory(f, status);
   829         }
   830     }
   831     delete objToAdopt;
   832     return NULL;
   833 }
   835 ICUServiceFactory* 
   836 ICUService::createSimpleFactory(UObject* objToAdopt, const UnicodeString& id, UBool visible, UErrorCode& status)
   837 {
   838     if (U_SUCCESS(status)) {
   839         if ((objToAdopt != NULL) && (!id.isBogus())) {
   840             return new SimpleFactory(objToAdopt, id, visible);
   841         }
   842         status = U_ILLEGAL_ARGUMENT_ERROR;
   843     }
   844     return NULL;
   845 }
   847 URegistryKey
   848 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) 
   849 {
   850     if (U_SUCCESS(status) && factoryToAdopt != NULL) {
   851         Mutex mutex(&lock);
   853         if (factories == NULL) {
   854             factories = new UVector(deleteUObject, NULL, status);
   855             if (U_FAILURE(status)) {
   856                 delete factories;
   857                 return NULL;
   858             }
   859         }
   860         factories->insertElementAt(factoryToAdopt, 0, status);
   861         if (U_SUCCESS(status)) {
   862             clearCaches();
   863         } else {
   864             delete factoryToAdopt;
   865             factoryToAdopt = NULL;
   866         }
   867     }
   869     if (factoryToAdopt != NULL) {
   870         notifyChanged();
   871     }
   873     return (URegistryKey)factoryToAdopt;
   874 }
   876 UBool 
   877 ICUService::unregister(URegistryKey rkey, UErrorCode& status) 
   878 {
   879     ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
   880     UBool result = FALSE;
   881     if (factory != NULL && factories != NULL) {
   882         Mutex mutex(&lock);
   884         if (factories->removeElement(factory)) {
   885             clearCaches();
   886             result = TRUE;
   887         } else {
   888             status = U_ILLEGAL_ARGUMENT_ERROR;
   889             delete factory;
   890         }
   891     }
   892     if (result) {
   893         notifyChanged();
   894     }
   895     return result;
   896 }
   898 void 
   899 ICUService::reset() 
   900 {
   901     {
   902         Mutex mutex(&lock);
   903         reInitializeFactories();
   904         clearCaches();
   905     }
   906     notifyChanged();
   907 }
   909 void 
   910 ICUService::reInitializeFactories() 
   911 {
   912     if (factories != NULL) {
   913         factories->removeAllElements();
   914     }
   915 }
   917 UBool 
   918 ICUService::isDefault() const 
   919 {
   920     return countFactories() == 0;
   921 }
   923 ICUServiceKey* 
   924 ICUService::createKey(const UnicodeString* id, UErrorCode& status) const 
   925 {
   926     return (U_FAILURE(status) || id == NULL) ? NULL : new ICUServiceKey(*id);
   927 }
   929 void 
   930 ICUService::clearCaches() 
   931 {
   932     // callers synchronize before use
   933     ++timestamp;
   934     delete dnCache;
   935     dnCache = NULL;
   936     delete idCache;
   937     idCache = NULL;
   938     delete serviceCache; serviceCache = NULL;
   939 }
   941 void 
   942 ICUService::clearServiceCache() 
   943 {
   944     // callers synchronize before use
   945     delete serviceCache; serviceCache = NULL;
   946 }
   948 UBool 
   949 ICUService::acceptsListener(const EventListener& l) const 
   950 {
   951     return dynamic_cast<const ServiceListener*>(&l) != NULL;
   952 }
   954 void 
   955 ICUService::notifyListener(EventListener& l) const 
   956 {
   957     ((ServiceListener&)l).serviceChanged(*this);
   958 }
   960 UnicodeString&
   961 ICUService::getName(UnicodeString& result) const 
   962 {
   963     return result.append(name);
   964 }
   966 int32_t 
   967 ICUService::countFactories() const 
   968 {
   969     return factories == NULL ? 0 : factories->size();
   970 }
   972 int32_t
   973 ICUService::getTimestamp() const
   974 {
   975     return timestamp;
   976 }
   978 U_NAMESPACE_END
   980 /* UCONFIG_NO_SERVICE */
   981 #endif

mercurial