Coverage Report

Created: 2025-06-24 06:43

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