Coverage Report

Created: 2024-04-24 06:23

/src/icu/source/common/locdispnames.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
*
6
*   Copyright (C) 1997-2016, International Business Machines
7
*   Corporation and others.  All Rights Reserved.
8
*
9
*******************************************************************************
10
*   file name:  locdispnames.cpp
11
*   encoding:   UTF-8
12
*   tab size:   8 (not used)
13
*   indentation:4
14
*
15
*   created on: 2010feb25
16
*   created by: Markus W. Scherer
17
*
18
*   Code for locale display names, separated out from other .cpp files
19
*   that then do not depend on resource bundle code and display name data.
20
*/
21
22
#include "unicode/utypes.h"
23
#include "unicode/brkiter.h"
24
#include "unicode/locid.h"
25
#include "unicode/uenum.h"
26
#include "unicode/uloc.h"
27
#include "unicode/ures.h"
28
#include "unicode/ustring.h"
29
#include "bytesinkutil.h"
30
#include "charstr.h"
31
#include "cmemory.h"
32
#include "cstring.h"
33
#include "putilimp.h"
34
#include "ulocimp.h"
35
#include "uresimp.h"
36
#include "ureslocs.h"
37
#include "ustr_imp.h"
38
39
// C++ API ----------------------------------------------------------------- ***
40
41
U_NAMESPACE_BEGIN
42
43
UnicodeString&
44
Locale::getDisplayLanguage(UnicodeString& dispLang) const
45
0
{
46
0
    return this->getDisplayLanguage(getDefault(), dispLang);
47
0
}
48
49
/*We cannot make any assumptions on the size of the output display strings
50
* Yet, since we are calling through to a C API, we need to set limits on
51
* buffer size. For all the following getDisplay functions we first attempt
52
* to fill up a stack allocated buffer. If it is to small we heap allocated
53
* the exact buffer we need copy it to the UnicodeString and delete it*/
54
55
UnicodeString&
56
Locale::getDisplayLanguage(const Locale &displayLocale,
57
0
                           UnicodeString &result) const {
58
0
    UChar *buffer;
59
0
    UErrorCode errorCode=U_ZERO_ERROR;
60
0
    int32_t length;
61
62
0
    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
63
0
    if(buffer==0) {
64
0
        result.truncate(0);
65
0
        return result;
66
0
    }
67
68
0
    length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
69
0
                                   buffer, result.getCapacity(),
70
0
                                   &errorCode);
71
0
    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
72
73
0
    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
74
0
        buffer=result.getBuffer(length);
75
0
        if(buffer==0) {
76
0
            result.truncate(0);
77
0
            return result;
78
0
        }
79
0
        errorCode=U_ZERO_ERROR;
80
0
        length=uloc_getDisplayLanguage(fullName, displayLocale.fullName,
81
0
                                       buffer, result.getCapacity(),
82
0
                                       &errorCode);
83
0
        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
84
0
    }
85
86
0
    return result;
87
0
}
88
89
UnicodeString&
90
Locale::getDisplayScript(UnicodeString& dispScript) const
91
0
{
92
0
    return this->getDisplayScript(getDefault(), dispScript);
93
0
}
94
95
UnicodeString&
96
Locale::getDisplayScript(const Locale &displayLocale,
97
0
                          UnicodeString &result) const {
98
0
    UChar *buffer;
99
0
    UErrorCode errorCode=U_ZERO_ERROR;
100
0
    int32_t length;
101
102
0
    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
103
0
    if(buffer==0) {
104
0
        result.truncate(0);
105
0
        return result;
106
0
    }
107
108
0
    length=uloc_getDisplayScript(fullName, displayLocale.fullName,
109
0
                                  buffer, result.getCapacity(),
110
0
                                  &errorCode);
111
0
    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
112
113
0
    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
114
0
        buffer=result.getBuffer(length);
115
0
        if(buffer==0) {
116
0
            result.truncate(0);
117
0
            return result;
118
0
        }
119
0
        errorCode=U_ZERO_ERROR;
120
0
        length=uloc_getDisplayScript(fullName, displayLocale.fullName,
121
0
                                      buffer, result.getCapacity(),
122
0
                                      &errorCode);
123
0
        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
124
0
    }
125
126
0
    return result;
127
0
}
128
129
UnicodeString&
130
Locale::getDisplayCountry(UnicodeString& dispCntry) const
131
0
{
132
0
    return this->getDisplayCountry(getDefault(), dispCntry);
133
0
}
134
135
UnicodeString&
136
Locale::getDisplayCountry(const Locale &displayLocale,
137
0
                          UnicodeString &result) const {
138
0
    UChar *buffer;
139
0
    UErrorCode errorCode=U_ZERO_ERROR;
140
0
    int32_t length;
141
142
0
    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
143
0
    if(buffer==0) {
144
0
        result.truncate(0);
145
0
        return result;
146
0
    }
147
148
0
    length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
149
0
                                  buffer, result.getCapacity(),
150
0
                                  &errorCode);
151
0
    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
152
153
0
    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
154
0
        buffer=result.getBuffer(length);
155
0
        if(buffer==0) {
156
0
            result.truncate(0);
157
0
            return result;
158
0
        }
159
0
        errorCode=U_ZERO_ERROR;
160
0
        length=uloc_getDisplayCountry(fullName, displayLocale.fullName,
161
0
                                      buffer, result.getCapacity(),
162
0
                                      &errorCode);
163
0
        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
164
0
    }
165
166
0
    return result;
167
0
}
168
169
UnicodeString&
170
Locale::getDisplayVariant(UnicodeString& dispVar) const
171
0
{
172
0
    return this->getDisplayVariant(getDefault(), dispVar);
173
0
}
174
175
UnicodeString&
176
Locale::getDisplayVariant(const Locale &displayLocale,
177
0
                          UnicodeString &result) const {
178
0
    UChar *buffer;
179
0
    UErrorCode errorCode=U_ZERO_ERROR;
180
0
    int32_t length;
181
182
0
    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
183
0
    if(buffer==0) {
184
0
        result.truncate(0);
185
0
        return result;
186
0
    }
187
188
0
    length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
189
0
                                  buffer, result.getCapacity(),
190
0
                                  &errorCode);
191
0
    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
192
193
0
    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
194
0
        buffer=result.getBuffer(length);
195
0
        if(buffer==0) {
196
0
            result.truncate(0);
197
0
            return result;
198
0
        }
199
0
        errorCode=U_ZERO_ERROR;
200
0
        length=uloc_getDisplayVariant(fullName, displayLocale.fullName,
201
0
                                      buffer, result.getCapacity(),
202
0
                                      &errorCode);
203
0
        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
204
0
    }
205
206
0
    return result;
207
0
}
208
209
UnicodeString&
210
Locale::getDisplayName( UnicodeString& name ) const
211
0
{
212
0
    return this->getDisplayName(getDefault(), name);
213
0
}
214
215
UnicodeString&
216
Locale::getDisplayName(const Locale &displayLocale,
217
0
                       UnicodeString &result) const {
218
0
    UChar *buffer;
219
0
    UErrorCode errorCode=U_ZERO_ERROR;
220
0
    int32_t length;
221
222
0
    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
223
0
    if(buffer==0) {
224
0
        result.truncate(0);
225
0
        return result;
226
0
    }
227
228
0
    length=uloc_getDisplayName(fullName, displayLocale.fullName,
229
0
                               buffer, result.getCapacity(),
230
0
                               &errorCode);
231
0
    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
232
233
0
    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
234
0
        buffer=result.getBuffer(length);
235
0
        if(buffer==0) {
236
0
            result.truncate(0);
237
0
            return result;
238
0
        }
239
0
        errorCode=U_ZERO_ERROR;
240
0
        length=uloc_getDisplayName(fullName, displayLocale.fullName,
241
0
                                   buffer, result.getCapacity(),
242
0
                                   &errorCode);
243
0
        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
244
0
    }
245
246
0
    return result;
247
0
}
248
249
#if ! UCONFIG_NO_BREAK_ITERATION
250
251
// -------------------------------------
252
// Gets the objectLocale display name in the default locale language.
253
UnicodeString& U_EXPORT2
254
BreakIterator::getDisplayName(const Locale& objectLocale,
255
                             UnicodeString& name)
256
0
{
257
0
    return objectLocale.getDisplayName(name);
258
0
}
259
260
// -------------------------------------
261
// Gets the objectLocale display name in the displayLocale language.
262
UnicodeString& U_EXPORT2
263
BreakIterator::getDisplayName(const Locale& objectLocale,
264
                             const Locale& displayLocale,
265
                             UnicodeString& name)
266
0
{
267
0
    return objectLocale.getDisplayName(displayLocale, name);
268
0
}
269
270
#endif
271
272
273
U_NAMESPACE_END
274
275
// C API ------------------------------------------------------------------- ***
276
277
U_NAMESPACE_USE
278
279
/* ### Constants **************************************************/
280
281
/* These strings describe the resources we attempt to load from
282
 the locale ResourceBundle data file.*/
283
static const char _kLanguages[]       = "Languages";
284
static const char _kScripts[]         = "Scripts";
285
static const char _kScriptsStandAlone[] = "Scripts%stand-alone";
286
static const char _kCountries[]       = "Countries";
287
static const char _kVariants[]        = "Variants";
288
static const char _kKeys[]            = "Keys";
289
static const char _kTypes[]           = "Types";
290
//static const char _kRootName[]        = "root";
291
static const char _kCurrency[]        = "currency";
292
static const char _kCurrencies[]      = "Currencies";
293
static const char _kLocaleDisplayPattern[] = "localeDisplayPattern";
294
static const char _kPattern[]         = "pattern";
295
static const char _kSeparator[]       = "separator";
296
297
/* ### Display name **************************************************/
298
299
static int32_t
300
_getStringOrCopyKey(const char *path, const char *locale,
301
                    const char *tableKey, 
302
                    const char* subTableKey,
303
                    const char *itemKey,
304
                    const char *substitute,
305
                    UChar *dest, int32_t destCapacity,
306
0
                    UErrorCode *pErrorCode) {
307
0
    const UChar *s = NULL;
308
0
    int32_t length = 0;
309
310
0
    if(itemKey==NULL) {
311
        /* top-level item: normal resource bundle access */
312
0
        icu::LocalUResourceBundlePointer rb(ures_open(path, locale, pErrorCode));
313
314
0
        if(U_SUCCESS(*pErrorCode)) {
315
0
            s=ures_getStringByKey(rb.getAlias(), tableKey, &length, pErrorCode);
316
            /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
317
0
        }
318
0
    } else {
319
0
        bool isLanguageCode = (uprv_strncmp(tableKey, _kLanguages, 9) == 0);
320
        /* Language code should not be a number. If it is, set the error code. */
321
0
        if (isLanguageCode && uprv_strtol(itemKey, NULL, 10)) {
322
0
            *pErrorCode = U_MISSING_RESOURCE_ERROR;
323
0
        } else {
324
            /* second-level item, use special fallback */
325
0
            s=uloc_getTableStringWithFallback(path, locale,
326
0
                                               tableKey,
327
0
                                               subTableKey,
328
0
                                               itemKey,
329
0
                                               &length,
330
0
                                               pErrorCode);
331
0
            if (U_FAILURE(*pErrorCode) && isLanguageCode && itemKey != nullptr) {
332
                // convert itemKey locale code to canonical form and try again, ICU-20870
333
0
                *pErrorCode = U_ZERO_ERROR;
334
0
                Locale canonKey = Locale::createCanonical(itemKey);
335
0
                s=uloc_getTableStringWithFallback(path, locale,
336
0
                                                    tableKey,
337
0
                                                    subTableKey,
338
0
                                                    canonKey.getName(),
339
0
                                                    &length,
340
0
                                                    pErrorCode);
341
0
            }
342
0
        }
343
0
    }
344
345
0
    if(U_SUCCESS(*pErrorCode)) {
346
0
        int32_t copyLength=uprv_min(length, destCapacity);
347
0
        if(copyLength>0 && s != NULL) {
348
0
            u_memcpy(dest, s, copyLength);
349
0
        }
350
0
    } else {
351
        /* no string from a resource bundle: convert the substitute */
352
0
        length=(int32_t)uprv_strlen(substitute);
353
0
        u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
354
0
        *pErrorCode=U_USING_DEFAULT_WARNING;
355
0
    }
356
357
0
    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
358
0
}
359
360
typedef  int32_t U_CALLCONV UDisplayNameGetter(const char *, char *, int32_t, UErrorCode *);
361
362
static int32_t
363
_getDisplayNameForComponent(const char *locale,
364
                            const char *displayLocale,
365
                            UChar *dest, int32_t destCapacity,
366
                            UDisplayNameGetter *getter,
367
                            const char *tag,
368
0
                            UErrorCode *pErrorCode) {
369
0
    char localeBuffer[ULOC_FULLNAME_CAPACITY*4];
370
0
    int32_t length;
371
0
    UErrorCode localStatus;
372
0
    const char* root = NULL;
373
374
    /* argument checking */
375
0
    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
376
0
        return 0;
377
0
    }
378
379
0
    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
380
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
381
0
        return 0;
382
0
    }
383
384
0
    localStatus = U_ZERO_ERROR;
385
0
    length=(*getter)(locale, localeBuffer, sizeof(localeBuffer), &localStatus);
386
0
    if(U_FAILURE(localStatus) || localStatus==U_STRING_NOT_TERMINATED_WARNING) {
387
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
388
0
        return 0;
389
0
    }
390
0
    if(length==0) {
391
        // For the display name, we treat this as unknown language (ICU-20273).
392
0
        if (getter == uloc_getLanguage) {
393
0
            uprv_strcpy(localeBuffer, "und");
394
0
        } else {
395
0
            return u_terminateUChars(dest, destCapacity, 0, pErrorCode);
396
0
        }
397
0
    }
398
399
0
    root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
400
401
0
    return _getStringOrCopyKey(root, displayLocale,
402
0
                               tag, NULL, localeBuffer,
403
0
                               localeBuffer,
404
0
                               dest, destCapacity,
405
0
                               pErrorCode);
406
0
}
407
408
U_CAPI int32_t U_EXPORT2
409
uloc_getDisplayLanguage(const char *locale,
410
                        const char *displayLocale,
411
                        UChar *dest, int32_t destCapacity,
412
0
                        UErrorCode *pErrorCode) {
413
0
    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
414
0
                uloc_getLanguage, _kLanguages, pErrorCode);
415
0
}
416
417
U_CAPI int32_t U_EXPORT2
418
uloc_getDisplayScript(const char* locale,
419
                      const char* displayLocale,
420
                      UChar *dest, int32_t destCapacity,
421
                      UErrorCode *pErrorCode)
422
0
{
423
0
    UErrorCode err = U_ZERO_ERROR;
424
0
    int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
425
0
                uloc_getScript, _kScriptsStandAlone, &err);
426
427
0
    if (destCapacity == 0 && err == U_BUFFER_OVERFLOW_ERROR) {
428
        // For preflight, return the max of the value and the fallback.
429
0
        int32_t fallback_res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
430
0
                                                           uloc_getScript, _kScripts, pErrorCode);
431
0
        return (fallback_res > res) ? fallback_res : res;
432
0
    }
433
0
    if ( err == U_USING_DEFAULT_WARNING ) {
434
0
        return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
435
0
                                           uloc_getScript, _kScripts, pErrorCode);
436
0
    } else {
437
0
        *pErrorCode = err;
438
0
        return res;
439
0
    }
440
0
}
441
442
static int32_t
443
uloc_getDisplayScriptInContext(const char* locale,
444
                      const char* displayLocale,
445
                      UChar *dest, int32_t destCapacity,
446
                      UErrorCode *pErrorCode)
447
0
{
448
0
    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
449
0
                    uloc_getScript, _kScripts, pErrorCode);
450
0
}
451
452
U_CAPI int32_t U_EXPORT2
453
uloc_getDisplayCountry(const char *locale,
454
                       const char *displayLocale,
455
                       UChar *dest, int32_t destCapacity,
456
0
                       UErrorCode *pErrorCode) {
457
0
    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
458
0
                uloc_getCountry, _kCountries, pErrorCode);
459
0
}
460
461
/*
462
 * TODO separate variant1_variant2_variant3...
463
 * by getting each tag's display string and concatenating them with ", "
464
 * in between - similar to uloc_getDisplayName()
465
 */
466
U_CAPI int32_t U_EXPORT2
467
uloc_getDisplayVariant(const char *locale,
468
                       const char *displayLocale,
469
                       UChar *dest, int32_t destCapacity,
470
0
                       UErrorCode *pErrorCode) {
471
0
    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
472
0
                uloc_getVariant, _kVariants, pErrorCode);
473
0
}
474
475
/* Instead of having a separate pass for 'special' patterns, reintegrate the two
476
 * so we don't get bitten by preflight bugs again.  We can be reasonably efficient
477
 * without two separate code paths, this code isn't that performance-critical.
478
 *
479
 * This code is general enough to deal with patterns that have a prefix or swap the
480
 * language and remainder components, since we gave developers enough rope to do such
481
 * things if they futz with the pattern data.  But since we don't give them a way to
482
 * specify a pattern for arbitrary combinations of components, there's not much use in
483
 * that.  I don't think our data includes such patterns, the only variable I know if is
484
 * whether there is a space before the open paren, or not.  Oh, and zh uses different
485
 * chars than the standard open/close paren (which ja and ko use, btw).
486
 */
487
U_CAPI int32_t U_EXPORT2
488
uloc_getDisplayName(const char *locale,
489
                    const char *displayLocale,
490
                    UChar *dest, int32_t destCapacity,
491
                    UErrorCode *pErrorCode)
492
0
{
493
0
    static const UChar defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
494
0
    static const UChar sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
495
0
    static const UChar sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
496
0
    static const int32_t subLen = 3;
497
0
    static const UChar defaultPattern[10] = {
498
0
        0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
499
0
    }; /* {0} ({1}) */
500
0
    static const int32_t defaultPatLen = 9;
501
0
    static const int32_t defaultSub0Pos = 0;
502
0
    static const int32_t defaultSub1Pos = 5;
503
504
0
    int32_t length; /* of formatted result */
505
506
0
    const UChar *separator;
507
0
    int32_t sepLen = 0;
508
0
    const UChar *pattern;
509
0
    int32_t patLen = 0;
510
0
    int32_t sub0Pos, sub1Pos;
511
    
512
0
    UChar formatOpenParen         = 0x0028; // (
513
0
    UChar formatReplaceOpenParen  = 0x005B; // [
514
0
    UChar formatCloseParen        = 0x0029; // )
515
0
    UChar formatReplaceCloseParen = 0x005D; // ]
516
517
0
    UBool haveLang = TRUE; /* assume true, set false if we find we don't have
518
                              a lang component in the locale */
519
0
    UBool haveRest = TRUE; /* assume true, set false if we find we don't have
520
                              any other component in the locale */
521
0
    UBool retry = FALSE; /* set true if we need to retry, see below */
522
523
0
    int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
524
525
0
    if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
526
0
        return 0;
527
0
    }
528
529
0
    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
530
0
        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
531
0
        return 0;
532
0
    }
533
534
0
    {
535
0
        UErrorCode status = U_ZERO_ERROR;
536
537
0
        icu::LocalUResourceBundlePointer locbundle(
538
0
                ures_open(U_ICUDATA_LANG, displayLocale, &status));
539
0
        icu::LocalUResourceBundlePointer dspbundle(
540
0
                ures_getByKeyWithFallback(locbundle.getAlias(), _kLocaleDisplayPattern, NULL, &status));
541
542
0
        separator=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kSeparator, &sepLen, &status);
543
0
        pattern=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kPattern, &patLen, &status);
544
0
    }
545
546
    /* If we couldn't find any data, then use the defaults */
547
0
    if(sepLen == 0) {
548
0
       separator = defaultSeparator;
549
0
    }
550
    /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
551
     * here since we are trying to build the display string in place in the dest buffer,
552
     * and to handle it as a pattern would entail having separate storage for the
553
     * substrings that need to be combined (the first of which may be the result of
554
     * previous such combinations). So for now we continue to treat the portion between
555
     * {0} and {1} as a string to be appended when joining substrings, ignoring anything
556
     * that is before {0} or after {1} (no existing separator pattern has any such thing).
557
     * This is similar to how pattern is handled below.
558
     */
559
0
    {
560
0
        UChar *p0=u_strstr(separator, sub0);
561
0
        UChar *p1=u_strstr(separator, sub1);
562
0
        if (p0==NULL || p1==NULL || p1<p0) {
563
0
            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
564
0
            return 0;
565
0
        }
566
0
        separator = (const UChar *)p0 + subLen;
567
0
        sepLen = static_cast<int32_t>(p1 - separator);
568
0
    }
569
570
0
    if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
571
0
        pattern=defaultPattern;
572
0
        patLen=defaultPatLen;
573
0
        sub0Pos=defaultSub0Pos;
574
0
        sub1Pos=defaultSub1Pos;
575
        // use default formatOpenParen etc. set above
576
0
    } else { /* non-default pattern */
577
0
        UChar *p0=u_strstr(pattern, sub0);
578
0
        UChar *p1=u_strstr(pattern, sub1);
579
0
        if (p0==NULL || p1==NULL) {
580
0
            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
581
0
            return 0;
582
0
        }
583
0
        sub0Pos = static_cast<int32_t>(p0-pattern);
584
0
        sub1Pos = static_cast<int32_t>(p1-pattern);
585
0
        if (sub1Pos < sub0Pos) { /* a very odd pattern */
586
0
            int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
587
0
            langi=1;
588
0
        }
589
0
        if (u_strchr(pattern, 0xFF08) != NULL) {
590
0
            formatOpenParen         = 0xFF08; // fullwidth (
591
0
            formatReplaceOpenParen  = 0xFF3B; // fullwidth [
592
0
            formatCloseParen        = 0xFF09; // fullwidth )
593
0
            formatReplaceCloseParen = 0xFF3D; // fullwidth ]
594
0
        }
595
0
    }
596
597
    /* We loop here because there is one case in which after the first pass we could need to
598
     * reextract the data.  If there's initial padding before the first element, we put in
599
     * the padding and then write that element.  If it turns out there's no second element,
600
     * we didn't need the padding.  If we do need the data (no preflight), and the first element
601
     * would have fit but for the padding, we need to reextract.  In this case (only) we
602
     * adjust the parameters so padding is not added, and repeat.
603
     */
604
0
    do {
605
0
        UChar* p=dest;
606
0
        int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
607
0
        int32_t langLen=0; /* length of language substitution */
608
0
        int32_t langPos=0; /* position in output of language substitution */
609
0
        int32_t restLen=0; /* length of 'everything else' substitution */
610
0
        int32_t restPos=0; /* position in output of 'everything else' substitution */
611
0
        icu::LocalUEnumerationPointer kenum; /* keyword enumeration */
612
613
        /* prefix of pattern, extremely likely to be empty */
614
0
        if(sub0Pos) {
615
0
            if(destCapacity >= sub0Pos) {
616
0
                while (patPos < sub0Pos) {
617
0
                    *p++ = pattern[patPos++];
618
0
                }
619
0
            } else {
620
0
                patPos=sub0Pos;
621
0
            }
622
0
            length=sub0Pos;
623
0
        } else {
624
0
            length=0;
625
0
        }
626
627
0
        for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
628
0
            UBool subdone = FALSE; /* set true when ready to move to next substitution */
629
630
            /* prep p and cap for calls to get display components, pin cap to 0 since
631
               they complain if cap is negative */
632
0
            int32_t cap=destCapacity-length;
633
0
            if (cap <= 0) {
634
0
                cap=0;
635
0
            } else {
636
0
                p=dest+length;
637
0
            }
638
639
0
            if (subi == langi) { /* {0}*/
640
0
                if(haveLang) {
641
0
                    langPos=length;
642
0
                    langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
643
0
                    length+=langLen;
644
0
                    haveLang=langLen>0;
645
0
                }
646
0
                subdone=TRUE;
647
0
            } else { /* {1} */
648
0
                if(!haveRest) {
649
0
                    subdone=TRUE;
650
0
                } else {
651
0
                    int32_t len; /* length of component (plus other stuff) we just fetched */
652
0
                    switch(resti++) {
653
0
                        case 0:
654
0
                            restPos=length;
655
0
                            len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
656
0
                            break;
657
0
                        case 1:
658
0
                            len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
659
0
                            break;
660
0
                        case 2:
661
0
                            len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
662
0
                            break;
663
0
                        case 3:
664
0
                            kenum.adoptInstead(uloc_openKeywords(locale, pErrorCode));
665
0
                            U_FALLTHROUGH;
666
0
                        default: {
667
0
                            const char* kw=uenum_next(kenum.getAlias(), &len, pErrorCode);
668
0
                            if (kw == NULL) {
669
0
                                len=0; /* mark that we didn't add a component */
670
0
                                subdone=TRUE;
671
0
                            } else {
672
                                /* incorporating this behavior into the loop made it even more complex,
673
                                   so just special case it here */
674
0
                                len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
675
0
                                if(len) {
676
0
                                    if(len < cap) {
677
0
                                        p[len]=0x3d; /* '=', assume we'll need it */
678
0
                                    }
679
0
                                    len+=1;
680
681
                                    /* adjust for call to get keyword */
682
0
                                    cap-=len;
683
0
                                    if(cap <= 0) {
684
0
                                        cap=0;
685
0
                                    } else {
686
0
                                        p+=len;
687
0
                                    }
688
0
                                }
689
                                /* reset for call below */
690
0
                                if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
691
0
                                    *pErrorCode=U_ZERO_ERROR;
692
0
                                }
693
0
                                int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
694
0
                                                                           p, cap, pErrorCode);
695
0
                                if(len) {
696
0
                                    if(vlen==0) {
697
0
                                        --len; /* remove unneeded '=' */
698
0
                                    }
699
                                    /* restore cap and p to what they were at start */
700
0
                                    cap=destCapacity-length;
701
0
                                    if(cap <= 0) {
702
0
                                        cap=0;
703
0
                                    } else {
704
0
                                        p=dest+length;
705
0
                                    }
706
0
                                }
707
0
                                len+=vlen; /* total we added for key + '=' + value */
708
0
                            }
709
0
                        } break;
710
0
                    } /* end switch */
711
712
0
                    if (len>0) {
713
                        /* we added a component, so add separator and write it if there's room. */
714
0
                        if(len+sepLen<=cap) {
715
0
                            const UChar * plimit = p + len;
716
0
                            for (; p < plimit; p++) {
717
0
                                if (*p == formatOpenParen) {
718
0
                                    *p = formatReplaceOpenParen;
719
0
                                } else if (*p == formatCloseParen) {
720
0
                                    *p = formatReplaceCloseParen;
721
0
                                }
722
0
                            }
723
0
                            for(int32_t i=0;i<sepLen;++i) {
724
0
                                *p++=separator[i];
725
0
                            }
726
0
                        }
727
0
                        length+=len+sepLen;
728
0
                    } else if(subdone) {
729
                        /* remove separator if we added it */
730
0
                        if (length!=restPos) {
731
0
                            length-=sepLen;
732
0
                        }
733
0
                        restLen=length-restPos;
734
0
                        haveRest=restLen>0;
735
0
                    }
736
0
                }
737
0
            }
738
739
0
            if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
740
0
                *pErrorCode=U_ZERO_ERROR;
741
0
            }
742
743
0
            if(subdone) {
744
0
                if(haveLang && haveRest) {
745
                    /* append internal portion of pattern, the first time,
746
                       or last portion of pattern the second time */
747
0
                    int32_t padLen;
748
0
                    patPos+=subLen;
749
0
                    padLen=(subi==0 ? sub1Pos : patLen)-patPos;
750
0
                    if(length+padLen <= destCapacity) {
751
0
                        p=dest+length;
752
0
                        for(int32_t i=0;i<padLen;++i) {
753
0
                            *p++=pattern[patPos++];
754
0
                        }
755
0
                    } else {
756
0
                        patPos+=padLen;
757
0
                    }
758
0
                    length+=padLen;
759
0
                } else if(subi==0) {
760
                    /* don't have first component, reset for second component */
761
0
                    sub0Pos=0;
762
0
                    length=0;
763
0
                } else if(length>0) {
764
                    /* true length is the length of just the component we got. */
765
0
                    length=haveLang?langLen:restLen;
766
0
                    if(dest && sub0Pos!=0) {
767
0
                        if (sub0Pos+length<=destCapacity) {
768
                            /* first component not at start of result,
769
                               but we have full component in buffer. */
770
0
                            u_memmove(dest, dest+(haveLang?langPos:restPos), length);
771
0
                        } else {
772
                            /* would have fit, but didn't because of pattern prefix. */
773
0
                            sub0Pos=0; /* stops initial padding (and a second retry,
774
                                          so we won't end up here again) */
775
0
                            retry=TRUE;
776
0
                        }
777
0
                    }
778
0
                }
779
780
0
                ++subi; /* move on to next substitution */
781
0
            }
782
0
        }
783
0
    } while(retry);
784
785
0
    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
786
0
}
787
788
U_CAPI int32_t U_EXPORT2
789
uloc_getDisplayKeyword(const char* keyword,
790
                       const char* displayLocale,
791
                       UChar* dest,
792
                       int32_t destCapacity,
793
0
                       UErrorCode* status){
794
795
    /* argument checking */
796
0
    if(status==NULL || U_FAILURE(*status)) {
797
0
        return 0;
798
0
    }
799
800
0
    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
801
0
        *status=U_ILLEGAL_ARGUMENT_ERROR;
802
0
        return 0;
803
0
    }
804
805
806
    /* pass itemKey=NULL to look for a top-level item */
807
0
    return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
808
0
                               _kKeys, NULL, 
809
0
                               keyword, 
810
0
                               keyword,      
811
0
                               dest, destCapacity,
812
0
                               status);
813
814
0
}
815
816
817
0
#define UCURRENCY_DISPLAY_NAME_INDEX 1
818
819
U_CAPI int32_t U_EXPORT2
820
uloc_getDisplayKeywordValue(   const char* locale,
821
                               const char* keyword,
822
                               const char* displayLocale,
823
                               UChar* dest,
824
                               int32_t destCapacity,
825
0
                               UErrorCode* status){
826
827
828
    /* argument checking */
829
0
    if(status==NULL || U_FAILURE(*status)) {
830
0
        return 0;
831
0
    }
832
833
0
    if(destCapacity<0 || (destCapacity>0 && dest==NULL)) {
834
0
        *status=U_ILLEGAL_ARGUMENT_ERROR;
835
0
        return 0;
836
0
    }
837
838
    /* get the keyword value */
839
0
    CharString keywordValue;
840
0
    {
841
0
        CharStringByteSink sink(&keywordValue);
842
0
        ulocimp_getKeywordValue(locale, keyword, sink, status);
843
0
    }
844
845
    /* 
846
     * if the keyword is equal to currency .. then to get the display name 
847
     * we need to do the fallback ourselves
848
     */
849
0
    if(uprv_stricmp(keyword, _kCurrency)==0){
850
851
0
        int32_t dispNameLen = 0;
852
0
        const UChar *dispName = NULL;
853
854
0
        icu::LocalUResourceBundlePointer bundle(
855
0
                ures_open(U_ICUDATA_CURR, displayLocale, status));
856
0
        icu::LocalUResourceBundlePointer currencies(
857
0
                ures_getByKey(bundle.getAlias(), _kCurrencies, NULL, status));
858
0
        icu::LocalUResourceBundlePointer currency(
859
0
                ures_getByKeyWithFallback(currencies.getAlias(), keywordValue.data(), NULL, status));
860
861
0
        dispName = ures_getStringByIndex(currency.getAlias(), UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
862
863
0
        if(U_FAILURE(*status)){
864
0
            if(*status == U_MISSING_RESOURCE_ERROR){
865
                /* we just want to write the value over if nothing is available */
866
0
                *status = U_USING_DEFAULT_WARNING;
867
0
            }else{
868
0
                return 0;
869
0
            }
870
0
        }
871
872
        /* now copy the dispName over if not NULL */
873
0
        if(dispName != NULL){
874
0
            if(dispNameLen <= destCapacity){
875
0
                u_memcpy(dest, dispName, dispNameLen);
876
0
                return u_terminateUChars(dest, destCapacity, dispNameLen, status);
877
0
            }else{
878
0
                *status = U_BUFFER_OVERFLOW_ERROR;
879
0
                return dispNameLen;
880
0
            }
881
0
        }else{
882
            /* we have not found the display name for the value .. just copy over */
883
0
            if(keywordValue.length() <= destCapacity){
884
0
                u_charsToUChars(keywordValue.data(), dest, keywordValue.length());
885
0
                return u_terminateUChars(dest, destCapacity, keywordValue.length(), status);
886
0
            }else{
887
0
                 *status = U_BUFFER_OVERFLOW_ERROR;
888
0
                return keywordValue.length();
889
0
            }
890
0
        }
891
892
        
893
0
    }else{
894
895
0
        return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
896
0
                                   _kTypes, keyword, 
897
0
                                   keywordValue.data(),
898
0
                                   keywordValue.data(),
899
0
                                   dest, destCapacity,
900
0
                                   status);
901
0
    }
902
0
}