Bug Summary

File:root/firefox-clang/intl/icu/source/common/locdispnames.cpp
Warning:line 356, column 39
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

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