xref: /aosp_15_r20/external/icu/icu4c/source/common/locdspnm.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 * Copyright (C) 2010-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
8 */
9 
10 #include "unicode/utypes.h"
11 
12 #if !UCONFIG_NO_FORMATTING
13 
14 #include "unicode/locdspnm.h"
15 #include "unicode/simpleformatter.h"
16 #include "unicode/ucasemap.h"
17 #include "unicode/ures.h"
18 #include "unicode/udisplaycontext.h"
19 #include "unicode/brkiter.h"
20 #include "unicode/ucurr.h"
21 #include "bytesinkutil.h"
22 #include "charstr.h"
23 #include "cmemory.h"
24 #include "cstring.h"
25 #include "mutex.h"
26 #include "uassert.h"
27 #include "ulocimp.h"
28 #include "umutex.h"
29 #include "ureslocs.h"
30 #include "uresimp.h"
31 
32 U_NAMESPACE_BEGIN
33 
34 ////////////////////////////////////////////////////////////////////////////////////////////////////
35 
36 // Access resource data for locale components.
37 // Wrap code in uloc.c for now.
38 class ICUDataTable {
39     const char* const path;
40     Locale locale;
41 
42 public:
43     // Note: path should be a pointer to a statically allocated string.
44     ICUDataTable(const char* path, const Locale& locale);
45     ~ICUDataTable() = default;
46 
47     const Locale& getLocale();
48 
49     UnicodeString& get(const char* tableKey, const char* itemKey,
50                         UnicodeString& result) const;
51     UnicodeString& get(const char* tableKey, const char* subTableKey, const char* itemKey,
52                         UnicodeString& result) const;
53 
54     UnicodeString& getNoFallback(const char* tableKey, const char* itemKey,
55                                 UnicodeString &result) const;
56     UnicodeString& getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey,
57                                 UnicodeString &result) const;
58 };
59 
60 inline UnicodeString &
get(const char * tableKey,const char * itemKey,UnicodeString & result) const61 ICUDataTable::get(const char* tableKey, const char* itemKey, UnicodeString& result) const {
62     return get(tableKey, nullptr, itemKey, result);
63 }
64 
65 inline UnicodeString &
getNoFallback(const char * tableKey,const char * itemKey,UnicodeString & result) const66 ICUDataTable::getNoFallback(const char* tableKey, const char* itemKey, UnicodeString& result) const {
67     return getNoFallback(tableKey, nullptr, itemKey, result);
68 }
69 
ICUDataTable(const char * path,const Locale & locale)70 ICUDataTable::ICUDataTable(const char* path, const Locale& locale)
71     : path(path), locale(locale)
72 {
73     U_ASSERT(path != nullptr);
74 }
75 
76 const Locale&
getLocale()77 ICUDataTable::getLocale() {
78   return locale;
79 }
80 
81 UnicodeString &
get(const char * tableKey,const char * subTableKey,const char * itemKey,UnicodeString & result) const82 ICUDataTable::get(const char* tableKey, const char* subTableKey, const char* itemKey,
83                   UnicodeString &result) const {
84   UErrorCode status = U_ZERO_ERROR;
85   int32_t len = 0;
86 
87   const char16_t *s = uloc_getTableStringWithFallback(path, locale.getName(),
88                                                    tableKey, subTableKey, itemKey,
89                                                    &len, &status);
90   if (U_SUCCESS(status) && len > 0) {
91     return result.setTo(s, len);
92   }
93   return result.setTo(UnicodeString(itemKey, -1, US_INV));
94 }
95 
96 UnicodeString &
getNoFallback(const char * tableKey,const char * subTableKey,const char * itemKey,UnicodeString & result) const97 ICUDataTable::getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey,
98                             UnicodeString& result) const {
99   UErrorCode status = U_ZERO_ERROR;
100   int32_t len = 0;
101 
102   const char16_t *s = uloc_getTableStringWithFallback(path, locale.getName(),
103                                                    tableKey, subTableKey, itemKey,
104                                                    &len, &status);
105   if (U_SUCCESS(status)) {
106     return result.setTo(s, len);
107   }
108 
109   result.setToBogus();
110   return result;
111 }
112 
113 ////////////////////////////////////////////////////////////////////////////////////////////////////
114 
~LocaleDisplayNames()115 LocaleDisplayNames::~LocaleDisplayNames() {}
116 
117 ////////////////////////////////////////////////////////////////////////////////////////////////////
118 
119 #if 0  // currently unused
120 
121 class DefaultLocaleDisplayNames : public LocaleDisplayNames {
122   UDialectHandling dialectHandling;
123 
124 public:
125   // constructor
126   DefaultLocaleDisplayNames(UDialectHandling dialectHandling);
127 
128   virtual ~DefaultLocaleDisplayNames();
129 
130   virtual const Locale& getLocale() const;
131   virtual UDialectHandling getDialectHandling() const;
132 
133   virtual UnicodeString& localeDisplayName(const Locale& locale,
134                                            UnicodeString& result) const;
135   virtual UnicodeString& localeDisplayName(const char* localeId,
136                                            UnicodeString& result) const;
137   virtual UnicodeString& languageDisplayName(const char* lang,
138                                              UnicodeString& result) const;
139   virtual UnicodeString& scriptDisplayName(const char* script,
140                                            UnicodeString& result) const;
141   virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
142                                            UnicodeString& result) const;
143   virtual UnicodeString& regionDisplayName(const char* region,
144                                            UnicodeString& result) const;
145   virtual UnicodeString& variantDisplayName(const char* variant,
146                                             UnicodeString& result) const;
147   virtual UnicodeString& keyDisplayName(const char* key,
148                                         UnicodeString& result) const;
149   virtual UnicodeString& keyValueDisplayName(const char* key,
150                                              const char* value,
151                                              UnicodeString& result) const;
152 };
153 
154 DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling)
155     : dialectHandling(dialectHandling) {
156 }
157 
158 DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() {
159 }
160 
161 const Locale&
162 DefaultLocaleDisplayNames::getLocale() const {
163   return Locale::getRoot();
164 }
165 
166 UDialectHandling
167 DefaultLocaleDisplayNames::getDialectHandling() const {
168   return dialectHandling;
169 }
170 
171 UnicodeString&
172 DefaultLocaleDisplayNames::localeDisplayName(const Locale& locale,
173                                              UnicodeString& result) const {
174   return result = UnicodeString(locale.getName(), -1, US_INV);
175 }
176 
177 UnicodeString&
178 DefaultLocaleDisplayNames::localeDisplayName(const char* localeId,
179                                              UnicodeString& result) const {
180   return result = UnicodeString(localeId, -1, US_INV);
181 }
182 
183 UnicodeString&
184 DefaultLocaleDisplayNames::languageDisplayName(const char* lang,
185                                                UnicodeString& result) const {
186   return result = UnicodeString(lang, -1, US_INV);
187 }
188 
189 UnicodeString&
190 DefaultLocaleDisplayNames::scriptDisplayName(const char* script,
191                                              UnicodeString& result) const {
192   return result = UnicodeString(script, -1, US_INV);
193 }
194 
195 UnicodeString&
196 DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode,
197                                              UnicodeString& result) const {
198   const char* name = uscript_getName(scriptCode);
199   if (name) {
200     return result = UnicodeString(name, -1, US_INV);
201   }
202   return result.remove();
203 }
204 
205 UnicodeString&
206 DefaultLocaleDisplayNames::regionDisplayName(const char* region,
207                                              UnicodeString& result) const {
208   return result = UnicodeString(region, -1, US_INV);
209 }
210 
211 UnicodeString&
212 DefaultLocaleDisplayNames::variantDisplayName(const char* variant,
213                                               UnicodeString& result) const {
214   return result = UnicodeString(variant, -1, US_INV);
215 }
216 
217 UnicodeString&
218 DefaultLocaleDisplayNames::keyDisplayName(const char* key,
219                                           UnicodeString& result) const {
220   return result = UnicodeString(key, -1, US_INV);
221 }
222 
223 UnicodeString&
224 DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */,
225                                                const char* value,
226                                                UnicodeString& result) const {
227   return result = UnicodeString(value, -1, US_INV);
228 }
229 
230 #endif  // currently unused class DefaultLocaleDisplayNames
231 
232 ////////////////////////////////////////////////////////////////////////////////////////////////////
233 
234 class LocaleDisplayNamesImpl : public LocaleDisplayNames {
235     Locale locale;
236     UDialectHandling dialectHandling;
237     ICUDataTable langData;
238     ICUDataTable regionData;
239     SimpleFormatter separatorFormat;
240     SimpleFormatter format;
241     SimpleFormatter keyTypeFormat;
242     UDisplayContext capitalizationContext;
243 #if !UCONFIG_NO_BREAK_ITERATION
244     BreakIterator* capitalizationBrkIter;
245 #else
246     UObject* capitalizationBrkIter;
247 #endif
248     UnicodeString formatOpenParen;
249     UnicodeString formatReplaceOpenParen;
250     UnicodeString formatCloseParen;
251     UnicodeString formatReplaceCloseParen;
252     UDisplayContext nameLength;
253     UDisplayContext substitute;
254 
255     // Constants for capitalization context usage types.
256     enum CapContextUsage {
257         kCapContextUsageLanguage,
258         kCapContextUsageScript,
259         kCapContextUsageTerritory,
260         kCapContextUsageVariant,
261         kCapContextUsageKey,
262         kCapContextUsageKeyValue,
263         kCapContextUsageCount
264     };
265     // Capitalization transforms. For each usage type, indicates whether to titlecase for
266     // the context specified in capitalizationContext (which we know at construction time)
267      bool fCapitalization[kCapContextUsageCount];
268 
269 public:
270     // constructor
271     LocaleDisplayNamesImpl(const Locale& locale, UDialectHandling dialectHandling);
272     LocaleDisplayNamesImpl(const Locale& locale, UDisplayContext *contexts, int32_t length);
273     virtual ~LocaleDisplayNamesImpl();
274 
275     virtual const Locale& getLocale() const override;
276     virtual UDialectHandling getDialectHandling() const override;
277     virtual UDisplayContext getContext(UDisplayContextType type) const override;
278 
279     virtual UnicodeString& localeDisplayName(const Locale& locale,
280                                                 UnicodeString& result) const override;
281     virtual UnicodeString& localeDisplayName(const char* localeId,
282                                                 UnicodeString& result) const override;
283     virtual UnicodeString& languageDisplayName(const char* lang,
284                                                UnicodeString& result) const override;
285     virtual UnicodeString& scriptDisplayName(const char* script,
286                                                 UnicodeString& result) const override;
287     virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
288                                                 UnicodeString& result) const override;
289     virtual UnicodeString& regionDisplayName(const char* region,
290                                                 UnicodeString& result) const override;
291     virtual UnicodeString& variantDisplayName(const char* variant,
292                                                 UnicodeString& result) const override;
293     virtual UnicodeString& keyDisplayName(const char* key,
294                                                 UnicodeString& result) const override;
295     virtual UnicodeString& keyValueDisplayName(const char* key,
296                                                 const char* value,
297                                                 UnicodeString& result) const override;
298 private:
299     UnicodeString& localeIdName(const char* localeId,
300                                 UnicodeString& result, bool substitute) const;
301     UnicodeString& appendWithSep(UnicodeString& buffer, const UnicodeString& src) const;
302     UnicodeString& adjustForUsageAndContext(CapContextUsage usage, UnicodeString& result) const;
303     UnicodeString& scriptDisplayName(const char* script, UnicodeString& result, bool skipAdjust) const;
304     UnicodeString& regionDisplayName(const char* region, UnicodeString& result, bool skipAdjust) const;
305     UnicodeString& variantDisplayName(const char* variant, UnicodeString& result, bool skipAdjust) const;
306     UnicodeString& keyDisplayName(const char* key, UnicodeString& result, bool skipAdjust) const;
307     UnicodeString& keyValueDisplayName(const char* key, const char* value,
308                                         UnicodeString& result, bool skipAdjust) const;
309     void initialize();
310 
311     struct CapitalizationContextSink;
312 };
313 
LocaleDisplayNamesImpl(const Locale & locale,UDialectHandling dialectHandling)314 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
315                                                UDialectHandling dialectHandling)
316     : dialectHandling(dialectHandling)
317     , langData(U_ICUDATA_LANG, locale)
318     , regionData(U_ICUDATA_REGION, locale)
319     , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
320     , capitalizationBrkIter(nullptr)
321     , nameLength(UDISPCTX_LENGTH_FULL)
322     , substitute(UDISPCTX_SUBSTITUTE)
323 {
324     initialize();
325 }
326 
LocaleDisplayNamesImpl(const Locale & locale,UDisplayContext * contexts,int32_t length)327 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
328                                                UDisplayContext *contexts, int32_t length)
329     : dialectHandling(ULDN_STANDARD_NAMES)
330     , langData(U_ICUDATA_LANG, locale)
331     , regionData(U_ICUDATA_REGION, locale)
332     , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
333     , capitalizationBrkIter(nullptr)
334     , nameLength(UDISPCTX_LENGTH_FULL)
335     , substitute(UDISPCTX_SUBSTITUTE)
336 {
337     while (length-- > 0) {
338         UDisplayContext value = *contexts++;
339         UDisplayContextType selector = (UDisplayContextType)((uint32_t)value >> 8);
340         switch (selector) {
341             case UDISPCTX_TYPE_DIALECT_HANDLING:
342                 dialectHandling = (UDialectHandling)value;
343                 break;
344             case UDISPCTX_TYPE_CAPITALIZATION:
345                 capitalizationContext = value;
346                 break;
347             case UDISPCTX_TYPE_DISPLAY_LENGTH:
348                 nameLength = value;
349                 break;
350             case UDISPCTX_TYPE_SUBSTITUTE_HANDLING:
351                 substitute = value;
352                 break;
353             default:
354                 break;
355         }
356     }
357     initialize();
358 }
359 
360 struct LocaleDisplayNamesImpl::CapitalizationContextSink : public ResourceSink {
361     bool hasCapitalizationUsage;
362     LocaleDisplayNamesImpl& parent;
363 
CapitalizationContextSinkLocaleDisplayNamesImpl::CapitalizationContextSink364     CapitalizationContextSink(LocaleDisplayNamesImpl& _parent)
365       : hasCapitalizationUsage(false), parent(_parent) {}
366     virtual ~CapitalizationContextSink();
367 
putLocaleDisplayNamesImpl::CapitalizationContextSink368     virtual void put(const char *key, ResourceValue &value, UBool /*noFallback*/,
369             UErrorCode &errorCode) override {
370         ResourceTable contexts = value.getTable(errorCode);
371         if (U_FAILURE(errorCode)) { return; }
372         for (int i = 0; contexts.getKeyAndValue(i, key, value); ++i) {
373 
374             CapContextUsage usageEnum;
375             if (uprv_strcmp(key, "key") == 0) {
376                 usageEnum = kCapContextUsageKey;
377             } else if (uprv_strcmp(key, "keyValue") == 0) {
378                 usageEnum = kCapContextUsageKeyValue;
379             } else if (uprv_strcmp(key, "languages") == 0) {
380                 usageEnum = kCapContextUsageLanguage;
381             } else if (uprv_strcmp(key, "script") == 0) {
382                 usageEnum = kCapContextUsageScript;
383             } else if (uprv_strcmp(key, "territory") == 0) {
384                 usageEnum = kCapContextUsageTerritory;
385             } else if (uprv_strcmp(key, "variant") == 0) {
386                 usageEnum = kCapContextUsageVariant;
387             } else {
388                 continue;
389             }
390 
391             int32_t len = 0;
392             const int32_t* intVector = value.getIntVector(len, errorCode);
393             if (U_FAILURE(errorCode)) { return; }
394             if (len < 2) { continue; }
395 
396             int32_t titlecaseInt = (parent.capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU) ? intVector[0] : intVector[1];
397             if (titlecaseInt == 0) { continue; }
398 
399             parent.fCapitalization[usageEnum] = true;
400             hasCapitalizationUsage = true;
401         }
402     }
403 };
404 
405 // Virtual destructors must be defined out of line.
~CapitalizationContextSink()406 LocaleDisplayNamesImpl::CapitalizationContextSink::~CapitalizationContextSink() {}
407 
408 void
initialize()409 LocaleDisplayNamesImpl::initialize() {
410     LocaleDisplayNamesImpl *nonConstThis = (LocaleDisplayNamesImpl *)this;
411     nonConstThis->locale = langData.getLocale() == Locale::getRoot()
412         ? regionData.getLocale()
413         : langData.getLocale();
414 
415     UnicodeString sep;
416     langData.getNoFallback("localeDisplayPattern", "separator", sep);
417     if (sep.isBogus()) {
418         sep = UnicodeString("{0}, {1}", -1, US_INV);
419     }
420     UErrorCode status = U_ZERO_ERROR;
421     separatorFormat.applyPatternMinMaxArguments(sep, 2, 2, status);
422 
423     UnicodeString pattern;
424     langData.getNoFallback("localeDisplayPattern", "pattern", pattern);
425     if (pattern.isBogus()) {
426         pattern = UnicodeString("{0} ({1})", -1, US_INV);
427     }
428     format.applyPatternMinMaxArguments(pattern, 2, 2, status);
429     if (pattern.indexOf((char16_t)0xFF08) >= 0) {
430         formatOpenParen.setTo((char16_t)0xFF08);         // fullwidth (
431         formatReplaceOpenParen.setTo((char16_t)0xFF3B);  // fullwidth [
432         formatCloseParen.setTo((char16_t)0xFF09);        // fullwidth )
433         formatReplaceCloseParen.setTo((char16_t)0xFF3D); // fullwidth ]
434     } else {
435         formatOpenParen.setTo((char16_t)0x0028);         // (
436         formatReplaceOpenParen.setTo((char16_t)0x005B);  // [
437         formatCloseParen.setTo((char16_t)0x0029);        // )
438         formatReplaceCloseParen.setTo((char16_t)0x005D); // ]
439     }
440 
441     UnicodeString ktPattern;
442     langData.get("localeDisplayPattern", "keyTypePattern", ktPattern);
443     if (ktPattern.isBogus()) {
444         ktPattern = UnicodeString("{0}={1}", -1, US_INV);
445     }
446     keyTypeFormat.applyPatternMinMaxArguments(ktPattern, 2, 2, status);
447 
448     uprv_memset(fCapitalization, 0, sizeof(fCapitalization));
449 #if !UCONFIG_NO_BREAK_ITERATION
450     // Only get the context data if we need it! This is a const object so we know now...
451     // Also check whether we will need a break iterator (depends on the data)
452     bool needBrkIter = false;
453     if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
454         LocalUResourceBundlePointer resource(ures_open(nullptr, locale.getName(), &status));
455         if (U_FAILURE(status)) { return; }
456         CapitalizationContextSink sink(*this);
457         ures_getAllItemsWithFallback(resource.getAlias(), "contextTransforms", sink, status);
458         if (status == U_MISSING_RESOURCE_ERROR) {
459             // Silently ignore.  Not every locale has contextTransforms.
460             status = U_ZERO_ERROR;
461         } else if (U_FAILURE(status)) {
462             return;
463         }
464         needBrkIter = sink.hasCapitalizationUsage;
465     }
466     // Get a sentence break iterator if we will need it
467     if (needBrkIter || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
468         status = U_ZERO_ERROR;
469         capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
470         if (U_FAILURE(status)) {
471             delete capitalizationBrkIter;
472             capitalizationBrkIter = nullptr;
473         }
474     }
475 #endif
476 }
477 
~LocaleDisplayNamesImpl()478 LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
479 #if !UCONFIG_NO_BREAK_ITERATION
480     delete capitalizationBrkIter;
481 #endif
482 }
483 
484 const Locale&
getLocale() const485 LocaleDisplayNamesImpl::getLocale() const {
486     return locale;
487 }
488 
489 UDialectHandling
getDialectHandling() const490 LocaleDisplayNamesImpl::getDialectHandling() const {
491     return dialectHandling;
492 }
493 
494 UDisplayContext
getContext(UDisplayContextType type) const495 LocaleDisplayNamesImpl::getContext(UDisplayContextType type) const {
496     switch (type) {
497         case UDISPCTX_TYPE_DIALECT_HANDLING:
498             return (UDisplayContext)dialectHandling;
499         case UDISPCTX_TYPE_CAPITALIZATION:
500             return capitalizationContext;
501         case UDISPCTX_TYPE_DISPLAY_LENGTH:
502             return nameLength;
503         case UDISPCTX_TYPE_SUBSTITUTE_HANDLING:
504             return substitute;
505         default:
506             break;
507     }
508     return (UDisplayContext)0;
509 }
510 
511 UnicodeString&
adjustForUsageAndContext(CapContextUsage usage,UnicodeString & result) const512 LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage,
513                                                 UnicodeString& result) const {
514 #if !UCONFIG_NO_BREAK_ITERATION
515     // check to see whether we need to titlecase result
516     if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= nullptr &&
517           ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
518         // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
519         static UMutex capitalizationBrkIterLock;
520         Mutex lock(&capitalizationBrkIterLock);
521         result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
522     }
523 #endif
524     return result;
525 }
526 
527 UnicodeString&
localeDisplayName(const Locale & loc,UnicodeString & result) const528 LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
529                                           UnicodeString& result) const {
530   if (loc.isBogus()) {
531     result.setToBogus();
532     return result;
533   }
534   UnicodeString resultName;
535 
536   const char* lang = loc.getLanguage();
537   if (uprv_strlen(lang) == 0) {
538     lang = "root";
539   }
540   const char* script = loc.getScript();
541   const char* country = loc.getCountry();
542   const char* variant = loc.getVariant();
543 
544   bool hasScript = uprv_strlen(script) > 0;
545   bool hasCountry = uprv_strlen(country) > 0;
546   bool hasVariant = uprv_strlen(variant) > 0;
547 
548   if (dialectHandling == ULDN_DIALECT_NAMES) {
549     UErrorCode status = U_ZERO_ERROR;
550     CharString buffer;
551     do { // loop construct is so we can break early out of search
552       if (hasScript && hasCountry) {
553         buffer.append(lang, status)
554               .append('_', status)
555               .append(script, status)
556               .append('_', status)
557               .append(country, status);
558         if (U_SUCCESS(status)) {
559           localeIdName(buffer.data(), resultName, false);
560           if (!resultName.isBogus()) {
561             hasScript = false;
562             hasCountry = false;
563             break;
564           }
565         }
566       }
567       if (hasScript) {
568         buffer.append(lang, status)
569               .append('_', status)
570               .append(script, status);
571         if (U_SUCCESS(status)) {
572           localeIdName(buffer.data(), resultName, false);
573           if (!resultName.isBogus()) {
574             hasScript = false;
575             break;
576           }
577         }
578       }
579       if (hasCountry) {
580         buffer.append(lang, status)
581               .append('_', status)
582               .append(country, status);
583         if (U_SUCCESS(status)) {
584           localeIdName(buffer.data(), resultName, false);
585           if (!resultName.isBogus()) {
586             hasCountry = false;
587             break;
588           }
589         }
590       }
591     } while (false);
592   }
593   if (resultName.isBogus() || resultName.isEmpty()) {
594     localeIdName(lang, resultName, substitute == UDISPCTX_SUBSTITUTE);
595     if (resultName.isBogus()) {
596       result.setToBogus();
597       return result;
598     }
599   }
600 
601   UnicodeString resultRemainder;
602   UnicodeString temp;
603   UErrorCode status = U_ZERO_ERROR;
604 
605   if (hasScript) {
606     UnicodeString script_str = scriptDisplayName(script, temp, true);
607     if (script_str.isBogus()) {
608       result.setToBogus();
609       return result;
610     }
611     resultRemainder.append(script_str);
612   }
613   if (hasCountry) {
614     UnicodeString region_str = regionDisplayName(country, temp, true);
615     if (region_str.isBogus()) {
616       result.setToBogus();
617       return result;
618     }
619     appendWithSep(resultRemainder, region_str);
620   }
621   if (hasVariant) {
622     UnicodeString variant_str = variantDisplayName(variant, temp, true);
623     if (variant_str.isBogus()) {
624       result.setToBogus();
625       return result;
626     }
627     appendWithSep(resultRemainder, variant_str);
628   }
629   resultRemainder.findAndReplace(formatOpenParen, formatReplaceOpenParen);
630   resultRemainder.findAndReplace(formatCloseParen, formatReplaceCloseParen);
631 
632   LocalPointer<StringEnumeration> e(loc.createKeywords(status));
633   if (e.isValid() && U_SUCCESS(status)) {
634     UnicodeString temp2;
635     const char* key;
636     while ((key = e->next((int32_t*)nullptr, status)) != nullptr) {
637         auto value = loc.getKeywordValue<CharString>(key, status);
638         if (U_FAILURE(status)) {
639             return result;
640       }
641       keyDisplayName(key, temp, true);
642       temp.findAndReplace(formatOpenParen, formatReplaceOpenParen);
643       temp.findAndReplace(formatCloseParen, formatReplaceCloseParen);
644       keyValueDisplayName(key, value.data(), temp2, true);
645       temp2.findAndReplace(formatOpenParen, formatReplaceOpenParen);
646       temp2.findAndReplace(formatCloseParen, formatReplaceCloseParen);
647       if (temp2 != UnicodeString(value.data(), -1, US_INV)) {
648         appendWithSep(resultRemainder, temp2);
649       } else if (temp != UnicodeString(key, -1, US_INV)) {
650         UnicodeString temp3;
651         keyTypeFormat.format(temp, temp2, temp3, status);
652         appendWithSep(resultRemainder, temp3);
653       } else {
654         appendWithSep(resultRemainder, temp)
655           .append((char16_t)0x3d /* = */)
656           .append(temp2);
657       }
658     }
659   }
660 
661   if (!resultRemainder.isEmpty()) {
662     format.format(resultName, resultRemainder, result.remove(), status);
663     return adjustForUsageAndContext(kCapContextUsageLanguage, result);
664   }
665 
666   result = resultName;
667   return adjustForUsageAndContext(kCapContextUsageLanguage, result);
668 }
669 
670 UnicodeString&
appendWithSep(UnicodeString & buffer,const UnicodeString & src) const671 LocaleDisplayNamesImpl::appendWithSep(UnicodeString& buffer, const UnicodeString& src) const {
672     if (buffer.isEmpty()) {
673         buffer.setTo(src);
674     } else {
675         const UnicodeString *values[2] = { &buffer, &src };
676         UErrorCode status = U_ZERO_ERROR;
677         separatorFormat.formatAndReplace(values, 2, buffer, nullptr, 0, status);
678     }
679     return buffer;
680 }
681 
682 UnicodeString&
localeDisplayName(const char * localeId,UnicodeString & result) const683 LocaleDisplayNamesImpl::localeDisplayName(const char* localeId,
684                                           UnicodeString& result) const {
685     return localeDisplayName(Locale(localeId), result);
686 }
687 
688 // private
689 UnicodeString&
localeIdName(const char * localeId,UnicodeString & result,bool substitute) const690 LocaleDisplayNamesImpl::localeIdName(const char* localeId,
691                                      UnicodeString& result, bool substitute) const {
692     if (nameLength == UDISPCTX_LENGTH_SHORT) {
693         langData.getNoFallback("Languages%short", localeId, result);
694         if (!result.isBogus()) {
695             return result;
696         }
697     }
698     langData.getNoFallback("Languages", localeId, result);
699     if (result.isBogus() && uprv_strchr(localeId, '_') == nullptr) {
700         // Canonicalize lang and try again, ICU-20870
701         // (only for language codes without script or region)
702         Locale canonLocale = Locale::createCanonical(localeId);
703         const char* canonLocId = canonLocale.getName();
704         if (nameLength == UDISPCTX_LENGTH_SHORT) {
705             langData.getNoFallback("Languages%short", canonLocId, result);
706             if (!result.isBogus()) {
707                 return result;
708             }
709         }
710         langData.getNoFallback("Languages", canonLocId, result);
711     }
712     if (result.isBogus() && substitute) {
713         // use key, this is what langData.get (with fallback) falls back to.
714         result.setTo(UnicodeString(localeId, -1, US_INV)); // use key (
715     }
716     return result;
717 }
718 
719 UnicodeString&
languageDisplayName(const char * lang,UnicodeString & result) const720 LocaleDisplayNamesImpl::languageDisplayName(const char* lang,
721                                             UnicodeString& result) const {
722     if (uprv_strcmp("root", lang) == 0 || uprv_strchr(lang, '_') != nullptr) {
723         return result = UnicodeString(lang, -1, US_INV);
724     }
725     if (nameLength == UDISPCTX_LENGTH_SHORT) {
726         langData.getNoFallback("Languages%short", lang, result);
727         if (!result.isBogus()) {
728             return adjustForUsageAndContext(kCapContextUsageLanguage, result);
729         }
730     }
731     langData.getNoFallback("Languages", lang, result);
732     if (result.isBogus()) {
733         // Canonicalize lang and try again, ICU-20870
734         Locale canonLocale = Locale::createCanonical(lang);
735         const char* canonLocId = canonLocale.getName();
736         if (nameLength == UDISPCTX_LENGTH_SHORT) {
737             langData.getNoFallback("Languages%short", canonLocId, result);
738             if (!result.isBogus()) {
739                 return adjustForUsageAndContext(kCapContextUsageLanguage, result);
740             }
741         }
742         langData.getNoFallback("Languages", canonLocId, result);
743     }
744     if (result.isBogus() && substitute == UDISPCTX_SUBSTITUTE) {
745         // use key, this is what langData.get (with fallback) falls back to.
746         result.setTo(UnicodeString(lang, -1, US_INV)); // use key (
747     }
748     return adjustForUsageAndContext(kCapContextUsageLanguage, result);
749 }
750 
751 UnicodeString&
scriptDisplayName(const char * script,UnicodeString & result,bool skipAdjust) const752 LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
753                                           UnicodeString& result,
754                                           bool skipAdjust) const {
755     if (nameLength == UDISPCTX_LENGTH_SHORT) {
756         langData.getNoFallback("Scripts%short", script, result);
757         if (!result.isBogus()) {
758             return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageScript, result);
759         }
760     }
761     if (substitute == UDISPCTX_SUBSTITUTE) {
762         langData.get("Scripts", script, result);
763     } else {
764         langData.getNoFallback("Scripts", script, result);
765     }
766     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageScript, result);
767 }
768 
769 UnicodeString&
scriptDisplayName(const char * script,UnicodeString & result) const770 LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
771                                           UnicodeString& result) const {
772     return scriptDisplayName(script, result, false);
773 }
774 
775 UnicodeString&
scriptDisplayName(UScriptCode scriptCode,UnicodeString & result) const776 LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode,
777                                           UnicodeString& result) const {
778     return scriptDisplayName(uscript_getName(scriptCode), result, false);
779 }
780 
781 UnicodeString&
regionDisplayName(const char * region,UnicodeString & result,bool skipAdjust) const782 LocaleDisplayNamesImpl::regionDisplayName(const char* region,
783                                           UnicodeString& result,
784                                           bool skipAdjust) const {
785     if (nameLength == UDISPCTX_LENGTH_SHORT) {
786          regionData.getNoFallback("Countries%short", region, result);
787         if (!result.isBogus()) {
788             return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageTerritory, result);
789         }
790     }
791     if (substitute == UDISPCTX_SUBSTITUTE) {
792         regionData.get("Countries", region, result);
793     } else {
794         regionData.getNoFallback("Countries", region, result);
795     }
796     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageTerritory, result);
797 }
798 
799 UnicodeString&
regionDisplayName(const char * region,UnicodeString & result) const800 LocaleDisplayNamesImpl::regionDisplayName(const char* region,
801                                           UnicodeString& result) const {
802     return regionDisplayName(region, result, false);
803 }
804 
805 
806 UnicodeString&
variantDisplayName(const char * variant,UnicodeString & result,bool skipAdjust) const807 LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
808                                            UnicodeString& result,
809                                            bool skipAdjust) const {
810     // don't have a resource for short variant names
811     if (substitute == UDISPCTX_SUBSTITUTE) {
812         langData.get("Variants", variant, result);
813     } else {
814         langData.getNoFallback("Variants", variant, result);
815     }
816     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageVariant, result);
817 }
818 
819 UnicodeString&
variantDisplayName(const char * variant,UnicodeString & result) const820 LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
821                                            UnicodeString& result) const {
822     return variantDisplayName(variant, result, false);
823 }
824 
825 UnicodeString&
keyDisplayName(const char * key,UnicodeString & result,bool skipAdjust) const826 LocaleDisplayNamesImpl::keyDisplayName(const char* key,
827                                        UnicodeString& result,
828                                        bool skipAdjust) const {
829     // don't have a resource for short key names
830     if (substitute == UDISPCTX_SUBSTITUTE) {
831         langData.get("Keys", key, result);
832     } else {
833         langData.getNoFallback("Keys", key, result);
834     }
835     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKey, result);
836 }
837 
838 UnicodeString&
keyDisplayName(const char * key,UnicodeString & result) const839 LocaleDisplayNamesImpl::keyDisplayName(const char* key,
840                                        UnicodeString& result) const {
841     return keyDisplayName(key, result, false);
842 }
843 
844 UnicodeString&
keyValueDisplayName(const char * key,const char * value,UnicodeString & result,bool skipAdjust) const845 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
846                                             const char* value,
847                                             UnicodeString& result,
848                                             bool skipAdjust) const {
849     if (uprv_strcmp(key, "currency") == 0) {
850         // ICU4C does not have ICU4J CurrencyDisplayInfo equivalent for now.
851         UErrorCode sts = U_ZERO_ERROR;
852         UnicodeString ustrValue(value, -1, US_INV);
853         int32_t len;
854         const char16_t *currencyName = ucurr_getName(ustrValue.getTerminatedBuffer(),
855             locale.getBaseName(), UCURR_LONG_NAME, nullptr /* isChoiceFormat */, &len, &sts);
856         if (U_FAILURE(sts)) {
857             // Return the value as is on failure
858             result = ustrValue;
859             return result;
860         }
861         result.setTo(currencyName, len);
862         return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKeyValue, result);
863     }
864 
865     if (nameLength == UDISPCTX_LENGTH_SHORT) {
866         langData.getNoFallback("Types%short", key, value, result);
867         if (!result.isBogus()) {
868             return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKeyValue, result);
869         }
870     }
871     if (substitute == UDISPCTX_SUBSTITUTE) {
872         langData.get("Types", key, value, result);
873     } else {
874         langData.getNoFallback("Types", key, value, result);
875     }
876     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKeyValue, result);
877 }
878 
879 UnicodeString&
keyValueDisplayName(const char * key,const char * value,UnicodeString & result) const880 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
881                                             const char* value,
882                                             UnicodeString& result) const {
883     return keyValueDisplayName(key, value, result, false);
884 }
885 
886 ////////////////////////////////////////////////////////////////////////////////////////////////////
887 
888 LocaleDisplayNames*
createInstance(const Locale & locale,UDialectHandling dialectHandling)889 LocaleDisplayNames::createInstance(const Locale& locale,
890                                    UDialectHandling dialectHandling) {
891     return new LocaleDisplayNamesImpl(locale, dialectHandling);
892 }
893 
894 LocaleDisplayNames*
createInstance(const Locale & locale,UDisplayContext * contexts,int32_t length)895 LocaleDisplayNames::createInstance(const Locale& locale,
896                                    UDisplayContext *contexts, int32_t length) {
897     if (contexts == nullptr) {
898         length = 0;
899     }
900     return new LocaleDisplayNamesImpl(locale, contexts, length);
901 }
902 
903 U_NAMESPACE_END
904 
905 ////////////////////////////////////////////////////////////////////////////////////////////////////
906 
907 U_NAMESPACE_USE
908 
909 U_CAPI ULocaleDisplayNames * U_EXPORT2
uldn_open(const char * locale,UDialectHandling dialectHandling,UErrorCode * pErrorCode)910 uldn_open(const char * locale,
911           UDialectHandling dialectHandling,
912           UErrorCode *pErrorCode) {
913   if (U_FAILURE(*pErrorCode)) {
914     return nullptr;
915   }
916   if (locale == nullptr) {
917     locale = uloc_getDefault();
918   }
919   return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), dialectHandling);
920 }
921 
922 U_CAPI ULocaleDisplayNames * U_EXPORT2
uldn_openForContext(const char * locale,UDisplayContext * contexts,int32_t length,UErrorCode * pErrorCode)923 uldn_openForContext(const char * locale,
924                     UDisplayContext *contexts, int32_t length,
925                     UErrorCode *pErrorCode) {
926   if (U_FAILURE(*pErrorCode)) {
927     return nullptr;
928   }
929   if (locale == nullptr) {
930     locale = uloc_getDefault();
931   }
932   return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), contexts, length);
933 }
934 
935 
936 U_CAPI void U_EXPORT2
uldn_close(ULocaleDisplayNames * ldn)937 uldn_close(ULocaleDisplayNames *ldn) {
938   delete (LocaleDisplayNames *)ldn;
939 }
940 
941 U_CAPI const char * U_EXPORT2
uldn_getLocale(const ULocaleDisplayNames * ldn)942 uldn_getLocale(const ULocaleDisplayNames *ldn) {
943   if (ldn) {
944     return ((const LocaleDisplayNames *)ldn)->getLocale().getName();
945   }
946   return nullptr;
947 }
948 
949 U_CAPI UDialectHandling U_EXPORT2
uldn_getDialectHandling(const ULocaleDisplayNames * ldn)950 uldn_getDialectHandling(const ULocaleDisplayNames *ldn) {
951   if (ldn) {
952     return ((const LocaleDisplayNames *)ldn)->getDialectHandling();
953   }
954   return ULDN_STANDARD_NAMES;
955 }
956 
957 U_CAPI UDisplayContext U_EXPORT2
uldn_getContext(const ULocaleDisplayNames * ldn,UDisplayContextType type,UErrorCode * pErrorCode)958 uldn_getContext(const ULocaleDisplayNames *ldn,
959               UDisplayContextType type,
960               UErrorCode *pErrorCode) {
961   if (U_FAILURE(*pErrorCode)) {
962     return (UDisplayContext)0;
963   }
964   return ((const LocaleDisplayNames *)ldn)->getContext(type);
965 }
966 
967 U_CAPI int32_t U_EXPORT2
uldn_localeDisplayName(const ULocaleDisplayNames * ldn,const char * locale,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)968 uldn_localeDisplayName(const ULocaleDisplayNames *ldn,
969                        const char *locale,
970                        char16_t *result,
971                        int32_t maxResultSize,
972                        UErrorCode *pErrorCode) {
973   if (U_FAILURE(*pErrorCode)) {
974     return 0;
975   }
976   if (ldn == nullptr || locale == nullptr || (result == nullptr && maxResultSize > 0) || maxResultSize < 0) {
977     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
978     return 0;
979   }
980   UnicodeString temp(result, 0, maxResultSize);
981   ((const LocaleDisplayNames *)ldn)->localeDisplayName(locale, temp);
982   if (temp.isBogus()) {
983     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
984     return 0;
985   }
986   return temp.extract(result, maxResultSize, *pErrorCode);
987 }
988 
989 U_CAPI int32_t U_EXPORT2
uldn_languageDisplayName(const ULocaleDisplayNames * ldn,const char * lang,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)990 uldn_languageDisplayName(const ULocaleDisplayNames *ldn,
991                          const char *lang,
992                          char16_t *result,
993                          int32_t maxResultSize,
994                          UErrorCode *pErrorCode) {
995   if (U_FAILURE(*pErrorCode)) {
996     return 0;
997   }
998   if (ldn == nullptr || lang == nullptr || (result == nullptr && maxResultSize > 0) || maxResultSize < 0) {
999     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
1000     return 0;
1001   }
1002   UnicodeString temp(result, 0, maxResultSize);
1003   ((const LocaleDisplayNames *)ldn)->languageDisplayName(lang, temp);
1004   return temp.extract(result, maxResultSize, *pErrorCode);
1005 }
1006 
1007 U_CAPI int32_t U_EXPORT2
uldn_scriptDisplayName(const ULocaleDisplayNames * ldn,const char * script,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)1008 uldn_scriptDisplayName(const ULocaleDisplayNames *ldn,
1009                        const char *script,
1010                        char16_t *result,
1011                        int32_t maxResultSize,
1012                        UErrorCode *pErrorCode) {
1013   if (U_FAILURE(*pErrorCode)) {
1014     return 0;
1015   }
1016   if (ldn == nullptr || script == nullptr || (result == nullptr && maxResultSize > 0) || maxResultSize < 0) {
1017     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
1018     return 0;
1019   }
1020   UnicodeString temp(result, 0, maxResultSize);
1021   ((const LocaleDisplayNames *)ldn)->scriptDisplayName(script, temp);
1022   return temp.extract(result, maxResultSize, *pErrorCode);
1023 }
1024 
1025 U_CAPI int32_t U_EXPORT2
uldn_scriptCodeDisplayName(const ULocaleDisplayNames * ldn,UScriptCode scriptCode,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)1026 uldn_scriptCodeDisplayName(const ULocaleDisplayNames *ldn,
1027                            UScriptCode scriptCode,
1028                            char16_t *result,
1029                            int32_t maxResultSize,
1030                            UErrorCode *pErrorCode) {
1031   return uldn_scriptDisplayName(ldn, uscript_getName(scriptCode), result, maxResultSize, pErrorCode);
1032 }
1033 
1034 U_CAPI int32_t U_EXPORT2
uldn_regionDisplayName(const ULocaleDisplayNames * ldn,const char * region,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)1035 uldn_regionDisplayName(const ULocaleDisplayNames *ldn,
1036                        const char *region,
1037                        char16_t *result,
1038                        int32_t maxResultSize,
1039                        UErrorCode *pErrorCode) {
1040   if (U_FAILURE(*pErrorCode)) {
1041     return 0;
1042   }
1043   if (ldn == nullptr || region == nullptr || (result == nullptr && maxResultSize > 0) || maxResultSize < 0) {
1044     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
1045     return 0;
1046   }
1047   UnicodeString temp(result, 0, maxResultSize);
1048   ((const LocaleDisplayNames *)ldn)->regionDisplayName(region, temp);
1049   return temp.extract(result, maxResultSize, *pErrorCode);
1050 }
1051 
1052 U_CAPI int32_t U_EXPORT2
uldn_variantDisplayName(const ULocaleDisplayNames * ldn,const char * variant,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)1053 uldn_variantDisplayName(const ULocaleDisplayNames *ldn,
1054                         const char *variant,
1055                         char16_t *result,
1056                         int32_t maxResultSize,
1057                         UErrorCode *pErrorCode) {
1058   if (U_FAILURE(*pErrorCode)) {
1059     return 0;
1060   }
1061   if (ldn == nullptr || variant == nullptr || (result == nullptr && maxResultSize > 0) || maxResultSize < 0) {
1062     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
1063     return 0;
1064   }
1065   UnicodeString temp(result, 0, maxResultSize);
1066   ((const LocaleDisplayNames *)ldn)->variantDisplayName(variant, temp);
1067   return temp.extract(result, maxResultSize, *pErrorCode);
1068 }
1069 
1070 U_CAPI int32_t U_EXPORT2
uldn_keyDisplayName(const ULocaleDisplayNames * ldn,const char * key,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)1071 uldn_keyDisplayName(const ULocaleDisplayNames *ldn,
1072                     const char *key,
1073                     char16_t *result,
1074                     int32_t maxResultSize,
1075                     UErrorCode *pErrorCode) {
1076   if (U_FAILURE(*pErrorCode)) {
1077     return 0;
1078   }
1079   if (ldn == nullptr || key == nullptr || (result == nullptr && maxResultSize > 0) || maxResultSize < 0) {
1080     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
1081     return 0;
1082   }
1083   UnicodeString temp(result, 0, maxResultSize);
1084   ((const LocaleDisplayNames *)ldn)->keyDisplayName(key, temp);
1085   return temp.extract(result, maxResultSize, *pErrorCode);
1086 }
1087 
1088 U_CAPI int32_t U_EXPORT2
uldn_keyValueDisplayName(const ULocaleDisplayNames * ldn,const char * key,const char * value,char16_t * result,int32_t maxResultSize,UErrorCode * pErrorCode)1089 uldn_keyValueDisplayName(const ULocaleDisplayNames *ldn,
1090                          const char *key,
1091                          const char *value,
1092                          char16_t *result,
1093                          int32_t maxResultSize,
1094                          UErrorCode *pErrorCode) {
1095   if (U_FAILURE(*pErrorCode)) {
1096     return 0;
1097   }
1098   if (ldn == nullptr || key == nullptr || value == nullptr || (result == nullptr && maxResultSize > 0)
1099       || maxResultSize < 0) {
1100     *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
1101     return 0;
1102   }
1103   UnicodeString temp(result, 0, maxResultSize);
1104   ((const LocaleDisplayNames *)ldn)->keyValueDisplayName(key, value, temp);
1105   return temp.extract(result, maxResultSize, *pErrorCode);
1106 }
1107 
1108 #endif
1109