Bug Summary

File:root/firefox-clang/intl/icu/source/i18n/unum.cpp
Warning:line 467, column 9
Null pointer passed as 1st argument to string copy function

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 unum.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/i18n -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -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_I18N_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/i18n -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -I /root/firefox-clang/intl/icu/source/common -I /root/firefox-clang/mfbt/double-conversion -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/i18n/unum.cpp
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4*******************************************************************************
5* Copyright (C) 1996-2015, International Business Machines
6* Corporation and others. All Rights Reserved.
7*******************************************************************************
8* Modification History:
9*
10* Date Name Description
11* 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
12*******************************************************************************
13*/
14
15#include "unicode/utypes.h"
16
17#if !UCONFIG_NO_FORMATTING0
18
19#include "unicode/unum.h"
20
21#include "unicode/uloc.h"
22#include "unicode/numfmt.h"
23#include "unicode/decimfmt.h"
24#include "unicode/rbnf.h"
25#include "unicode/compactdecimalformat.h"
26#include "unicode/ustring.h"
27#include "unicode/fmtable.h"
28#include "unicode/dcfmtsym.h"
29#include "unicode/curramt.h"
30#include "unicode/localpointer.h"
31#include "unicode/measfmt.h"
32#include "unicode/udisplaycontext.h"
33#include "uassert.h"
34#include "cpputils.h"
35#include "cstring.h"
36#include "putilimp.h"
37
38
39U_NAMESPACE_USEusing namespace icu_77;
40
41
42U_CAPIextern "C" UNumberFormat* U_EXPORT2
43unum_openunum_open_77( UNumberFormatStyle style,
44 const char16_t* pattern,
45 int32_t patternLength,
46 const char* locale,
47 UParseError* parseErr,
48 UErrorCode* status) {
49 if(U_FAILURE(*status)) {
50 return nullptr;
51 }
52
53 NumberFormat *retVal = nullptr;
54
55 switch(style) {
56 case UNUM_DECIMAL:
57 case UNUM_CURRENCY:
58 case UNUM_PERCENT:
59 case UNUM_SCIENTIFIC:
60 case UNUM_CURRENCY_ISO:
61 case UNUM_CURRENCY_PLURAL:
62 case UNUM_CURRENCY_ACCOUNTING:
63 case UNUM_CASH_CURRENCY:
64 case UNUM_CURRENCY_STANDARD:
65 retVal = NumberFormat::createInstance(Locale(locale), style, *status);
66 break;
67
68 case UNUM_PATTERN_DECIMAL: {
69 UParseError tErr;
70 /* UnicodeString can handle the case when patternLength = -1. */
71 const UnicodeString pat(pattern, patternLength);
72
73 if(parseErr==nullptr){
74 parseErr = &tErr;
75 }
76
77 DecimalFormatSymbols *syms = new DecimalFormatSymbols(Locale(locale), *status);
78 if(syms == nullptr) {
79 *status = U_MEMORY_ALLOCATION_ERROR;
80 return nullptr;
81 }
82 if (U_FAILURE(*status)) {
83 delete syms;
84 return nullptr;
85 }
86
87 retVal = new DecimalFormat(pat, syms, *parseErr, *status);
88 if(retVal == nullptr) {
89 delete syms;
90 }
91 } break;
92
93#if U_HAVE_RBNF1
94 case UNUM_PATTERN_RULEBASED: {
95 UParseError tErr;
96 /* UnicodeString can handle the case when patternLength = -1. */
97 const UnicodeString pat(pattern, patternLength);
98
99 if(parseErr==nullptr){
100 parseErr = &tErr;
101 }
102
103 retVal = new RuleBasedNumberFormat(pat, Locale(locale), *parseErr, *status);
104 } break;
105
106 case UNUM_SPELLOUT:
107 retVal = new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
108 break;
109
110 case UNUM_ORDINAL:
111 retVal = new RuleBasedNumberFormat(URBNF_ORDINAL, Locale(locale), *status);
112 break;
113
114 case UNUM_DURATION:
115 retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
116 break;
117
118 case UNUM_NUMBERING_SYSTEM: {
119 // if the locale ID specifies a numbering system, go through NumberFormat::createInstance()
120 // to handle it properly (we have to specify UNUM_DEFAULT to get it to handle the numbering
121 // system, but we'll always get a RuleBasedNumberFormat back); otherwise, just go ahead and
122 // create a RuleBasedNumberFormat ourselves
123 UErrorCode localErr = U_ZERO_ERROR;
124 Locale localeObj(locale);
125 int32_t keywordLength = localeObj.getKeywordValue("numbers", nullptr, 0, localErr);
126 if (keywordLength > 0) {
127 retVal = NumberFormat::createInstance(localeObj, UNUM_DEFAULT, *status);
128 } else {
129 retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, localeObj, *status);
130 }
131 } break;
132#endif
133
134 case UNUM_DECIMAL_COMPACT_SHORT:
135 retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_SHORT, *status);
136 break;
137
138 case UNUM_DECIMAL_COMPACT_LONG:
139 retVal = CompactDecimalFormat::createInstance(Locale(locale), UNUM_LONG, *status);
140 break;
141
142 default:
143 *status = U_UNSUPPORTED_ERROR;
144 return nullptr;
145 }
146
147 if(retVal == nullptr && U_SUCCESS(*status)) {
148 *status = U_MEMORY_ALLOCATION_ERROR;
149 }
150
151 if (U_FAILURE(*status) && retVal != nullptr) {
152 delete retVal;
153 retVal = nullptr;
154 }
155
156 return reinterpret_cast<UNumberFormat *>(retVal);
157}
158
159U_CAPIextern "C" void U_EXPORT2
160unum_closeunum_close_77(UNumberFormat* fmt)
161{
162 delete (NumberFormat*) fmt;
163}
164
165U_CAPIextern "C" UNumberFormat* U_EXPORT2
166unum_cloneunum_clone_77(const UNumberFormat *fmt,
167 UErrorCode *status)
168{
169 if(U_FAILURE(*status))
170 return nullptr;
171
172 Format* res = nullptr;
173 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
174 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
175 if (df != nullptr) {
176 res = df->clone();
177 } else {
178 const RuleBasedNumberFormat* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf);
179 U_ASSERT(rbnf != nullptr)(static_cast <bool> (rbnf != nullptr) ? void (0) : __assert_fail
("rbnf != nullptr", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
180 res = rbnf->clone();
181 }
182
183 if (res == nullptr) {
184 *status = U_MEMORY_ALLOCATION_ERROR;
185 return nullptr;
186 }
187
188 return (UNumberFormat*) res;
189}
190
191U_CAPIextern "C" int32_t U_EXPORT2
192unum_formatunum_format_77( const UNumberFormat* fmt,
193 int32_t number,
194 char16_t* result,
195 int32_t resultLength,
196 UFieldPosition *pos,
197 UErrorCode* status)
198{
199 return unum_formatInt64unum_formatInt64_77(fmt, number, result, resultLength, pos, status);
200}
201
202U_CAPIextern "C" int32_t U_EXPORT2
203unum_formatInt64unum_formatInt64_77(const UNumberFormat* fmt,
204 int64_t number,
205 char16_t* result,
206 int32_t resultLength,
207 UFieldPosition *pos,
208 UErrorCode* status)
209{
210 if(U_FAILURE(*status))
211 return -1;
212
213 UnicodeString res;
214 if(!(result==nullptr && resultLength==0)) {
215 // nullptr destination for pure preflighting: empty dummy string
216 // otherwise, alias the destination buffer
217 res.setTo(result, 0, resultLength);
218 }
219
220 FieldPosition fp;
221
222 if (pos != nullptr)
223 fp.setField(pos->field);
224
225 ((const NumberFormat*)fmt)->format(number, res, fp, *status);
226
227 if (pos != nullptr) {
228 pos->beginIndex = fp.getBeginIndex();
229 pos->endIndex = fp.getEndIndex();
230 }
231
232 return res.extract(result, resultLength, *status);
233}
234
235U_CAPIextern "C" int32_t U_EXPORT2
236unum_formatDoubleunum_formatDouble_77( const UNumberFormat* fmt,
237 double number,
238 char16_t* result,
239 int32_t resultLength,
240 UFieldPosition *pos, /* 0 if ignore */
241 UErrorCode* status)
242{
243
244 if(U_FAILURE(*status)) return -1;
245
246 UnicodeString res;
247 if(!(result==nullptr && resultLength==0)) {
248 // nullptr destination for pure preflighting: empty dummy string
249 // otherwise, alias the destination buffer
250 res.setTo(result, 0, resultLength);
251 }
252
253 FieldPosition fp;
254
255 if (pos != nullptr)
256 fp.setField(pos->field);
257
258 ((const NumberFormat*)fmt)->format(number, res, fp, *status);
259
260 if (pos != nullptr) {
261 pos->beginIndex = fp.getBeginIndex();
262 pos->endIndex = fp.getEndIndex();
263 }
264
265 return res.extract(result, resultLength, *status);
266}
267
268U_CAPIextern "C" int32_t U_EXPORT2
269unum_formatDoubleForFieldsunum_formatDoubleForFields_77(const UNumberFormat* format,
270 double number,
271 char16_t* result,
272 int32_t resultLength,
273 UFieldPositionIterator* fpositer,
274 UErrorCode* status)
275{
276 if (U_FAILURE(*status))
277 return -1;
278
279 if (result == nullptr ? resultLength != 0 : resultLength < 0) {
280 *status = U_ILLEGAL_ARGUMENT_ERROR;
281 return -1;
282 }
283
284 UnicodeString res;
285 if (result != nullptr) {
286 // nullptr destination for pure preflighting: empty dummy string
287 // otherwise, alias the destination buffer
288 res.setTo(result, 0, resultLength);
289 }
290
291 ((const NumberFormat*)format)->format(number, res, (FieldPositionIterator*)fpositer, *status);
292
293 return res.extract(result, resultLength, *status);
294}
295
296U_CAPIextern "C" int32_t U_EXPORT2
297unum_formatDecimalunum_formatDecimal_77(const UNumberFormat* fmt,
298 const char * number,
299 int32_t length,
300 char16_t* result,
301 int32_t resultLength,
302 UFieldPosition *pos, /* 0 if ignore */
303 UErrorCode* status) {
304
305 if(U_FAILURE(*status)) {
306 return -1;
307 }
308 if ((result == nullptr && resultLength != 0) || resultLength < 0) {
309 *status = U_ILLEGAL_ARGUMENT_ERROR;
310 return -1;
311 }
312
313 FieldPosition fp;
314 if (pos != nullptr) {
315 fp.setField(pos->field);
316 }
317
318 if (length < 0) {
319 length = static_cast<int32_t>(uprv_strlen(number):: strlen(number));
320 }
321 StringPiece numSP(number, length);
322 Formattable numFmtbl(numSP, *status);
323
324 UnicodeString resultStr;
325 if (resultLength > 0) {
326 // Alias the destination buffer.
327 resultStr.setTo(result, 0, resultLength);
328 }
329 ((const NumberFormat*)fmt)->format(numFmtbl, resultStr, fp, *status);
330 if (pos != nullptr) {
331 pos->beginIndex = fp.getBeginIndex();
332 pos->endIndex = fp.getEndIndex();
333 }
334 return resultStr.extract(result, resultLength, *status);
335}
336
337
338
339
340U_CAPIextern "C" int32_t U_EXPORT2
341unum_formatDoubleCurrencyunum_formatDoubleCurrency_77(const UNumberFormat* fmt,
342 double number,
343 char16_t* currency,
344 char16_t* result,
345 int32_t resultLength,
346 UFieldPosition* pos, /* ignored if 0 */
347 UErrorCode* status) {
348 if (U_FAILURE(*status)) return -1;
349
350 UnicodeString res;
351 if (!(result==nullptr && resultLength==0)) {
352 // nullptr destination for pure preflighting: empty dummy string
353 // otherwise, alias the destination buffer
354 res.setTo(result, 0, resultLength);
355 }
356
357 FieldPosition fp;
358 if (pos != nullptr) {
359 fp.setField(pos->field);
360 }
361 CurrencyAmount *tempCurrAmnt = new CurrencyAmount(number, currency, *status);
362 // Check for null pointer.
363 if (tempCurrAmnt == nullptr) {
364 *status = U_MEMORY_ALLOCATION_ERROR;
365 return -1;
366 }
367 Formattable n(tempCurrAmnt);
368 ((const NumberFormat*)fmt)->format(n, res, fp, *status);
369
370 if (pos != nullptr) {
371 pos->beginIndex = fp.getBeginIndex();
372 pos->endIndex = fp.getEndIndex();
373 }
374
375 return res.extract(result, resultLength, *status);
376}
377
378static void
379parseRes(Formattable& res,
380 const UNumberFormat* fmt,
381 const char16_t* text,
382 int32_t textLength,
383 int32_t *parsePos /* 0 = start */,
384 UErrorCode *status)
385{
386 if(U_FAILURE(*status))
387 return;
388
389 const UnicodeString src(static_cast<UBool>(textLength == -1), text, textLength);
390 ParsePosition pp;
391
392 if (parsePos != nullptr)
393 pp.setIndex(*parsePos);
394
395 reinterpret_cast<const NumberFormat*>(fmt)->parse(src, res, pp);
396
397 if(pp.getErrorIndex() != -1) {
398 *status = U_PARSE_ERROR;
399 if (parsePos != nullptr) {
400 *parsePos = pp.getErrorIndex();
401 }
402 } else if (parsePos != nullptr) {
403 *parsePos = pp.getIndex();
404 }
405}
406
407U_CAPIextern "C" int32_t U_EXPORT2
408unum_parseunum_parse_77( const UNumberFormat* fmt,
409 const char16_t* text,
410 int32_t textLength,
411 int32_t *parsePos /* 0 = start */,
412 UErrorCode *status)
413{
414 Formattable res;
415 parseRes(res, fmt, text, textLength, parsePos, status);
416 return res.getLong(*status);
417}
418
419U_CAPIextern "C" int64_t U_EXPORT2
420unum_parseInt64unum_parseInt64_77( const UNumberFormat* fmt,
421 const char16_t* text,
422 int32_t textLength,
423 int32_t *parsePos /* 0 = start */,
424 UErrorCode *status)
425{
426 Formattable res;
427 parseRes(res, fmt, text, textLength, parsePos, status);
428 return res.getInt64(*status);
429}
430
431U_CAPIextern "C" double U_EXPORT2
432unum_parseDoubleunum_parseDouble_77( const UNumberFormat* fmt,
433 const char16_t* text,
434 int32_t textLength,
435 int32_t *parsePos /* 0 = start */,
436 UErrorCode *status)
437{
438 Formattable res;
439 parseRes(res, fmt, text, textLength, parsePos, status);
440 return res.getDouble(*status);
441}
442
443U_CAPIextern "C" int32_t U_EXPORT2
444unum_parseDecimalunum_parseDecimal_77(const UNumberFormat* fmt,
445 const char16_t* text,
446 int32_t textLength,
447 int32_t *parsePos /* 0 = start */,
448 char *outBuf,
449 int32_t outBufLength,
450 UErrorCode *status)
451{
452 if (U_FAILURE(*status)) {
453 return -1;
454 }
455 if ((outBuf == nullptr && outBufLength != 0) || outBufLength
2.1
'outBufLength' is >= 0
< 0) {
1
Assuming pointer value is null
2
Assuming 'outBufLength' is equal to 0
3
Taking false branch
456 *status = U_ILLEGAL_ARGUMENT_ERROR;
457 return -1;
458 }
459 Formattable res;
460 parseRes(res, fmt, text, textLength, parsePos, status);
461 StringPiece sp = res.getDecimalNumber(*status);
462 if (U_FAILURE(*status)) {
4
Taking false branch
463 return -1;
464 } else if (sp.size() > outBufLength) {
5
Assuming the condition is false
6
Taking false branch
465 *status = U_BUFFER_OVERFLOW_ERROR;
466 } else if (sp.size() == outBufLength) {
7
Assuming the condition is true
8
Taking true branch
467 uprv_strncpy(outBuf, sp.data(), sp.size()):: strncpy(outBuf, sp.data(), sp.size());
9
Null pointer passed as 1st argument to string copy function
468 *status = U_STRING_NOT_TERMINATED_WARNING;
469 } else {
470 U_ASSERT(outBufLength > 0)(static_cast <bool> (outBufLength > 0) ? void (0) : __assert_fail
("outBufLength > 0", __builtin_FILE (), __builtin_LINE ()
, __extension__ __PRETTY_FUNCTION__))
;
471 uprv_strcpy(outBuf, sp.data()):: strcpy(outBuf, sp.data());
472 }
473 return sp.size();
474}
475
476U_CAPIextern "C" double U_EXPORT2
477unum_parseDoubleCurrencyunum_parseDoubleCurrency_77(const UNumberFormat* fmt,
478 const char16_t* text,
479 int32_t textLength,
480 int32_t* parsePos, /* 0 = start */
481 char16_t* currency,
482 UErrorCode* status) {
483 double doubleVal = 0.0;
484 currency[0] = 0;
485 if (U_FAILURE(*status)) {
486 return doubleVal;
487 }
488 const UnicodeString src(textLength == -1, text, textLength);
489 ParsePosition pp;
490 if (parsePos != nullptr) {
491 pp.setIndex(*parsePos);
492 }
493 *status = U_PARSE_ERROR; // assume failure, reset if succeed
494 LocalPointer<CurrencyAmount> currAmt(((const NumberFormat*)fmt)->parseCurrency(src, pp));
495 if (pp.getErrorIndex() != -1) {
496 if (parsePos != nullptr) {
497 *parsePos = pp.getErrorIndex();
498 }
499 } else {
500 if (parsePos != nullptr) {
501 *parsePos = pp.getIndex();
502 }
503 if (pp.getIndex() > 0) {
504 *status = U_ZERO_ERROR;
505 u_strcpyu_strcpy_77(currency, currAmt->getISOCurrency());
506 doubleVal = currAmt->getNumber().getDouble(*status);
507 }
508 }
509 return doubleVal;
510}
511
512U_CAPIextern "C" const char* U_EXPORT2
513unum_getAvailableunum_getAvailable_77(int32_t index)
514{
515 return uloc_getAvailableuloc_getAvailable_77(index);
516}
517
518U_CAPIextern "C" int32_t U_EXPORT2
519unum_countAvailableunum_countAvailable_77()
520{
521 return uloc_countAvailableuloc_countAvailable_77();
522}
523
524U_CAPIextern "C" bool U_EXPORT2
525unum_hasAttributeunum_hasAttribute_77(const UNumberFormat* fmt,
526 UNumberFormatAttribute attr)
527{
528 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
529 bool isDecimalFormat = dynamic_cast<const DecimalFormat*>(nf) != nullptr;
530
531 switch (attr) {
532 case UNUM_LENIENT_PARSE:
533 case UNUM_MAX_INTEGER_DIGITS:
534 case UNUM_MIN_INTEGER_DIGITS:
535 case UNUM_INTEGER_DIGITS:
536 case UNUM_MAX_FRACTION_DIGITS:
537 case UNUM_MIN_FRACTION_DIGITS:
538 case UNUM_FRACTION_DIGITS:
539 case UNUM_ROUNDING_MODE:
540 return true;
541 default:
542 return isDecimalFormat;
543 }
544}
545
546U_CAPIextern "C" int32_t U_EXPORT2
547unum_getAttributeunum_getAttribute_77(const UNumberFormat* fmt,
548 UNumberFormatAttribute attr)
549{
550 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
551 if (attr == UNUM_LENIENT_PARSE) {
552 // Supported for all subclasses
553 return nf->isLenient();
554 }
555 else if (attr == UNUM_MAX_INTEGER_DIGITS) {
556 return nf->getMaximumIntegerDigits();
557 }
558 else if (attr == UNUM_MIN_INTEGER_DIGITS) {
559 return nf->getMinimumIntegerDigits();
560 }
561 else if (attr == UNUM_INTEGER_DIGITS) {
562 // TODO: what should this return?
563 return nf->getMinimumIntegerDigits();
564 }
565 else if (attr == UNUM_MAX_FRACTION_DIGITS) {
566 return nf->getMaximumFractionDigits();
567 }
568 else if (attr == UNUM_MIN_FRACTION_DIGITS) {
569 return nf->getMinimumFractionDigits();
570 }
571 else if (attr == UNUM_FRACTION_DIGITS) {
572 // TODO: what should this return?
573 return nf->getMinimumFractionDigits();
574 }
575 else if (attr == UNUM_ROUNDING_MODE) {
576 return nf->getRoundingMode();
577 }
578
579 // The remaining attributes are only supported for DecimalFormat
580 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
581 if (df != nullptr) {
582 UErrorCode ignoredStatus = U_ZERO_ERROR;
583 return df->getAttribute(attr, ignoredStatus);
584 }
585
586 return -1;
587}
588
589U_CAPIextern "C" void U_EXPORT2
590unum_setAttributeunum_setAttribute_77( UNumberFormat* fmt,
591 UNumberFormatAttribute attr,
592 int32_t newValue)
593{
594 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
595 if (attr == UNUM_LENIENT_PARSE) {
596 // Supported for all subclasses
597 // keep this here as the class may not be a DecimalFormat
598 return nf->setLenient(newValue != 0);
599 }
600 else if (attr == UNUM_MAX_INTEGER_DIGITS) {
601 return nf->setMaximumIntegerDigits(newValue);
602 }
603 else if (attr == UNUM_MIN_INTEGER_DIGITS) {
604 return nf->setMinimumIntegerDigits(newValue);
605 }
606 else if (attr == UNUM_INTEGER_DIGITS) {
607 nf->setMinimumIntegerDigits(newValue);
608 return nf->setMaximumIntegerDigits(newValue);
609 }
610 else if (attr == UNUM_MAX_FRACTION_DIGITS) {
611 return nf->setMaximumFractionDigits(newValue);
612 }
613 else if (attr == UNUM_MIN_FRACTION_DIGITS) {
614 return nf->setMinimumFractionDigits(newValue);
615 }
616 else if (attr == UNUM_FRACTION_DIGITS) {
617 nf->setMinimumFractionDigits(newValue);
618 return nf->setMaximumFractionDigits(newValue);
619 }
620 else if (attr == UNUM_ROUNDING_MODE) {
621 return nf->setRoundingMode((NumberFormat::ERoundingMode)newValue);
622 }
623
624 // The remaining attributes are only supported for DecimalFormat
625 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
626 if (df != nullptr) {
627 UErrorCode ignoredStatus = U_ZERO_ERROR;
628 df->setAttribute(attr, newValue, ignoredStatus);
629 }
630}
631
632U_CAPIextern "C" double U_EXPORT2
633unum_getDoubleAttributeunum_getDoubleAttribute_77(const UNumberFormat* fmt,
634 UNumberFormatAttribute attr)
635{
636 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
637 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
638 if (df != nullptr && attr == UNUM_ROUNDING_INCREMENT) {
639 return df->getRoundingIncrement();
640 } else {
641 return -1.0;
642 }
643}
644
645U_CAPIextern "C" void U_EXPORT2
646unum_setDoubleAttributeunum_setDoubleAttribute_77( UNumberFormat* fmt,
647 UNumberFormatAttribute attr,
648 double newValue)
649{
650 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
651 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
652 if (df != nullptr && attr == UNUM_ROUNDING_INCREMENT) {
653 df->setRoundingIncrement(newValue);
654 }
655}
656
657U_CAPIextern "C" int32_t U_EXPORT2
658unum_getTextAttributeunum_getTextAttribute_77(const UNumberFormat* fmt,
659 UNumberFormatTextAttribute tag,
660 char16_t* result,
661 int32_t resultLength,
662 UErrorCode* status)
663{
664 if(U_FAILURE(*status))
665 return -1;
666
667 UnicodeString res;
668 if(!(result==nullptr && resultLength==0)) {
669 // nullptr destination for pure preflighting: empty dummy string
670 // otherwise, alias the destination buffer
671 res.setTo(result, 0, resultLength);
672 }
673
674 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
675 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
676 const RuleBasedNumberFormat* rbnf = nullptr; // cast is below for performance
677 if (df != nullptr) {
678 switch(tag) {
679 case UNUM_POSITIVE_PREFIX:
680 df->getPositivePrefix(res);
681 break;
682
683 case UNUM_POSITIVE_SUFFIX:
684 df->getPositiveSuffix(res);
685 break;
686
687 case UNUM_NEGATIVE_PREFIX:
688 df->getNegativePrefix(res);
689 break;
690
691 case UNUM_NEGATIVE_SUFFIX:
692 df->getNegativeSuffix(res);
693 break;
694
695 case UNUM_PADDING_CHARACTER:
696 res = df->getPadCharacterString();
697 break;
698
699 case UNUM_CURRENCY_CODE:
700 res = UnicodeString(df->getCurrency());
701 break;
702
703 default:
704 *status = U_UNSUPPORTED_ERROR;
705 return -1;
706 }
707 } else if ((rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf)) != nullptr) {
708 U_ASSERT(rbnf != nullptr)(static_cast <bool> (rbnf != nullptr) ? void (0) : __assert_fail
("rbnf != nullptr", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
709 if (tag == UNUM_DEFAULT_RULESET) {
710 res = rbnf->getDefaultRuleSetName();
711 } else if (tag == UNUM_PUBLIC_RULESETS) {
712 int32_t count = rbnf->getNumberOfRuleSetNames();
713 for (int i = 0; i < count; ++i) {
714 res += rbnf->getRuleSetName(i);
715 res += (char16_t)0x003b; // semicolon
716 }
717 } else {
718 *status = U_UNSUPPORTED_ERROR;
719 return -1;
720 }
721 } else {
722 *status = U_UNSUPPORTED_ERROR;
723 return -1;
724 }
725
726 return res.extract(result, resultLength, *status);
727}
728
729U_CAPIextern "C" void U_EXPORT2
730unum_setTextAttributeunum_setTextAttribute_77( UNumberFormat* fmt,
731 UNumberFormatTextAttribute tag,
732 const char16_t* newValue,
733 int32_t newValueLength,
734 UErrorCode *status)
735{
736 if(U_FAILURE(*status))
737 return;
738
739 UnicodeString val(newValue, newValueLength);
740 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
741 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
742 if (df != nullptr) {
743 switch(tag) {
744 case UNUM_POSITIVE_PREFIX:
745 df->setPositivePrefix(val);
746 break;
747
748 case UNUM_POSITIVE_SUFFIX:
749 df->setPositiveSuffix(val);
750 break;
751
752 case UNUM_NEGATIVE_PREFIX:
753 df->setNegativePrefix(val);
754 break;
755
756 case UNUM_NEGATIVE_SUFFIX:
757 df->setNegativeSuffix(val);
758 break;
759
760 case UNUM_PADDING_CHARACTER:
761 df->setPadCharacter(val);
762 break;
763
764 case UNUM_CURRENCY_CODE:
765 df->setCurrency(val.getTerminatedBuffer(), *status);
766 break;
767
768 default:
769 *status = U_UNSUPPORTED_ERROR;
770 break;
771 }
772 } else {
773 RuleBasedNumberFormat* rbnf = dynamic_cast<RuleBasedNumberFormat*>(nf);
774 U_ASSERT(rbnf != nullptr)(static_cast <bool> (rbnf != nullptr) ? void (0) : __assert_fail
("rbnf != nullptr", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
775 if (tag == UNUM_DEFAULT_RULESET) {
776 rbnf->setDefaultRuleSet(val, *status);
777 } else {
778 *status = U_UNSUPPORTED_ERROR;
779 }
780 }
781}
782
783U_CAPIextern "C" int32_t U_EXPORT2
784unum_toPatternunum_toPattern_77( const UNumberFormat* fmt,
785 UBool isPatternLocalized,
786 char16_t* result,
787 int32_t resultLength,
788 UErrorCode* status)
789{
790 if(U_FAILURE(*status))
791 return -1;
792
793 UnicodeString pat;
794 if(!(result==nullptr && resultLength==0)) {
795 // nullptr destination for pure preflighting: empty dummy string
796 // otherwise, alias the destination buffer
797 pat.setTo(result, 0, resultLength);
798 }
799
800 const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
801 const DecimalFormat* df = dynamic_cast<const DecimalFormat*>(nf);
802 const RuleBasedNumberFormat* rbnf = nullptr; // cast is below for performance
803 if (df != nullptr) {
804 if(isPatternLocalized)
805 df->toLocalizedPattern(pat);
806 else
807 df->toPattern(pat);
808 } else if ((rbnf = dynamic_cast<const RuleBasedNumberFormat*>(nf)) != nullptr) {
809 pat = rbnf->getRules();
810 } else {
811 // leave `pat` empty
812 }
813 return pat.extract(result, resultLength, *status);
814}
815
816U_CAPIextern "C" int32_t U_EXPORT2
817unum_getSymbolunum_getSymbol_77(const UNumberFormat *fmt,
818 UNumberFormatSymbol symbol,
819 char16_t *buffer,
820 int32_t size,
821 UErrorCode *status) UPRV_NO_SANITIZE_UNDEFINED__attribute__((no_sanitize("undefined"))) {
822 if(status==nullptr || U_FAILURE(*status)) {
823 return 0;
824 }
825 if(fmt==nullptr || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT) {
826 *status=U_ILLEGAL_ARGUMENT_ERROR;
827 return 0;
828 }
829 const NumberFormat *nf = reinterpret_cast<const NumberFormat *>(fmt);
830 const DecimalFormat *dcf = dynamic_cast<const DecimalFormat *>(nf);
831 if (dcf == nullptr) {
832 *status = U_UNSUPPORTED_ERROR;
833 return 0;
834 }
835
836 return dcf->
837 getDecimalFormatSymbols()->
838 getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol).
839 extract(buffer, size, *status);
840}
841
842U_CAPIextern "C" void U_EXPORT2
843unum_setSymbolunum_setSymbol_77(UNumberFormat *fmt,
844 UNumberFormatSymbol symbol,
845 const char16_t *value,
846 int32_t length,
847 UErrorCode *status) UPRV_NO_SANITIZE_UNDEFINED__attribute__((no_sanitize("undefined"))) {
848 if(status==nullptr || U_FAILURE(*status)) {
849 return;
850 }
851 if(fmt==nullptr || symbol< 0 || symbol>=UNUM_FORMAT_SYMBOL_COUNT || value==nullptr || length<-1) {
852 *status=U_ILLEGAL_ARGUMENT_ERROR;
853 return;
854 }
855 NumberFormat *nf = reinterpret_cast<NumberFormat *>(fmt);
856 DecimalFormat *dcf = dynamic_cast<DecimalFormat *>(nf);
857 if (dcf == nullptr) {
858 *status = U_UNSUPPORTED_ERROR;
859 return;
860 }
861
862 DecimalFormatSymbols symbols(*dcf->getDecimalFormatSymbols());
863 symbols.setSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbol,
864 UnicodeString(value, length)); /* UnicodeString can handle the case when length = -1. */
865 dcf->setDecimalFormatSymbols(symbols);
866}
867
868U_CAPIextern "C" void U_EXPORT2
869unum_applyPatternunum_applyPattern_77( UNumberFormat *fmt,
870 UBool localized,
871 const char16_t *pattern,
872 int32_t patternLength,
873 UParseError *parseError,
874 UErrorCode* status)
875{
876 UErrorCode tStatus = U_ZERO_ERROR;
877 UParseError tParseError;
878
879 if(parseError == nullptr){
880 parseError = &tParseError;
881 }
882
883 if(status==nullptr){
884 status = &tStatus;
885 }
886
887 int32_t len = (patternLength == -1 ? u_strlenu_strlen_77(pattern) : patternLength);
888 const UnicodeString pat((char16_t*)pattern, len, len);
889
890 // Verify if the object passed is a DecimalFormat object
891 NumberFormat* nf = reinterpret_cast<NumberFormat*>(fmt);
892 DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
893 if (df != nullptr) {
894 if(localized) {
895 df->applyLocalizedPattern(pat,*parseError, *status);
896 } else {
897 df->applyPattern(pat,*parseError, *status);
898 }
899 } else {
900 *status = U_UNSUPPORTED_ERROR;
901 return;
902 }
903}
904
905U_CAPIextern "C" const char* U_EXPORT2
906unum_getLocaleByTypeunum_getLocaleByType_77(const UNumberFormat *fmt,
907 ULocDataLocaleType type,
908 UErrorCode* status)
909{
910 if (fmt == nullptr) {
911 if (U_SUCCESS(*status)) {
912 *status = U_ILLEGAL_ARGUMENT_ERROR;
913 }
914 return nullptr;
915 }
916 return ((const Format*)fmt)->getLocaleID(type, *status);
917}
918
919U_CAPIextern "C" void U_EXPORT2
920unum_setContextunum_setContext_77(UNumberFormat* fmt, UDisplayContext value, UErrorCode* status)
921{
922 if (U_FAILURE(*status)) {
923 return;
924 }
925 ((NumberFormat*)fmt)->setContext(value, *status);
926}
927
928U_CAPIextern "C" UDisplayContext U_EXPORT2
929unum_getContextunum_getContext_77(const UNumberFormat *fmt, UDisplayContextType type, UErrorCode* status)
930{
931 if (U_FAILURE(*status)) {
932 return (UDisplayContext)0;
933 }
934 return ((const NumberFormat*)fmt)->getContext(type, *status);
935}
936
937U_CAPIextern "C" UFormattable * U_EXPORT2
938unum_parseToUFormattableunum_parseToUFormattable_77(const UNumberFormat* fmt,
939 UFormattable *result,
940 const char16_t* text,
941 int32_t textLength,
942 int32_t* parsePos, /* 0 = start */
943 UErrorCode* status) {
944 UFormattable *newFormattable = nullptr;
945 if (U_FAILURE(*status)) return result;
946 if (fmt == nullptr || (text==nullptr && textLength!=0)) {
947 *status = U_ILLEGAL_ARGUMENT_ERROR;
948 return result;
949 }
950 if (result == nullptr) { // allocate if not allocated.
951 newFormattable = result = ufmt_openufmt_open_77(status);
952 }
953 parseRes(*(Formattable::fromUFormattable(result)), fmt, text, textLength, parsePos, status);
954 if (U_FAILURE(*status) && newFormattable != nullptr) {
955 ufmt_closeufmt_close_77(newFormattable);
956 result = nullptr; // deallocate if there was a parse error
957 }
958 return result;
959}
960
961U_CAPIextern "C" int32_t U_EXPORT2
962unum_formatUFormattableunum_formatUFormattable_77(const UNumberFormat* fmt,
963 const UFormattable *number,
964 char16_t *result,
965 int32_t resultLength,
966 UFieldPosition *pos, /* ignored if 0 */
967 UErrorCode *status) {
968 if (U_FAILURE(*status)) {
969 return 0;
970 }
971 if (fmt == nullptr || number==nullptr ||
972 (result==nullptr ? resultLength!=0 : resultLength<0)) {
973 *status = U_ILLEGAL_ARGUMENT_ERROR;
974 return 0;
975 }
976 UnicodeString res(result, 0, resultLength);
977
978 FieldPosition fp;
979
980 if (pos != nullptr)
981 fp.setField(pos->field);
982
983 ((const NumberFormat*)fmt)->format(*(Formattable::fromUFormattable(number)), res, fp, *status);
984
985 if (pos != nullptr) {
986 pos->beginIndex = fp.getBeginIndex();
987 pos->endIndex = fp.getEndIndex();
988 }
989
990 return res.extract(result, resultLength, *status);
991}
992
993#endif /* #if !UCONFIG_NO_FORMATTING */