Coverage Report

Created: 2018-09-25 14:53

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