1/* 2 * Copyright 2003, Axel D��rfler, axeld@pinc-software.de. 3 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de. 4 * Copyright 2012, John Scipione, jscipione@gmail.com 5 * Copyright 2017, Adrien Destugues, pulkomandy@pulkomandy.tk 6 * Copyright 2021, Andrew Lindesay, apl@lindesay.co.nz 7 * All rights reserved. Distributed under the terms of the MIT License. 8 */ 9 10 11#include <unicode/uversion.h> 12#include <NumberFormat.h> 13 14#include <AutoDeleter.h> 15#include <Autolock.h> 16#include <FormattingConventionsPrivate.h> 17 18#include <ICUWrapper.h> 19 20#include <unicode/dcfmtsym.h> 21#include <unicode/decimfmt.h> 22#include <unicode/numfmt.h> 23 24 25U_NAMESPACE_USE 26 27 28class BNumberFormatImpl { 29public: 30 BNumberFormatImpl(); 31 ~BNumberFormatImpl(); 32 33 NumberFormat* GetInteger(BFormattingConventions* convention); 34 NumberFormat* GetFloat(BFormattingConventions* convention); 35 NumberFormat* GetCurrency(BFormattingConventions* convention); 36 NumberFormat* GetPercent(BFormattingConventions* convention); 37 38 ssize_t ApplyFormatter(NumberFormat* formatter, char* string, 39 size_t maxSize, const double value); 40 status_t ApplyFormatter(NumberFormat* formatter, BString& string, 41 const double value); 42 43private: 44 NumberFormat* fIntegerFormat; 45 NumberFormat* fFloatFormat; 46 NumberFormat* fCurrencyFormat; 47 NumberFormat* fPercentFormat; 48}; 49 50 51BNumberFormatImpl::BNumberFormatImpl() 52{ 53 // They are initialized lazily as needed 54 fIntegerFormat = NULL; 55 fFloatFormat = NULL; 56 fCurrencyFormat = NULL; 57 fPercentFormat = NULL; 58} 59 60 61BNumberFormatImpl::~BNumberFormatImpl() 62{ 63 delete fIntegerFormat; 64 delete fFloatFormat; 65 delete fCurrencyFormat; 66 delete fPercentFormat; 67} 68 69 70NumberFormat* 71BNumberFormatImpl::GetInteger(BFormattingConventions* convention) 72{ 73 if (fIntegerFormat == NULL) { 74 UErrorCode err = U_ZERO_ERROR; 75 fIntegerFormat = NumberFormat::createInstance( 76 *BFormattingConventions::Private(convention).ICULocale(), 77 UNUM_DECIMAL, err); 78 79 if (fIntegerFormat == NULL) 80 return NULL; 81 if (U_FAILURE(err)) { 82 delete fIntegerFormat; 83 fIntegerFormat = NULL; 84 return NULL; 85 } 86 } 87 88 return fIntegerFormat; 89} 90 91 92NumberFormat* 93BNumberFormatImpl::GetFloat(BFormattingConventions* convention) 94{ 95 if (fFloatFormat == NULL) { 96 UErrorCode err = U_ZERO_ERROR; 97 fFloatFormat = NumberFormat::createInstance( 98 *BFormattingConventions::Private(convention).ICULocale(), 99 UNUM_DECIMAL, err); 100 101 if (fFloatFormat == NULL) 102 return NULL; 103 if (U_FAILURE(err)) { 104 delete fFloatFormat; 105 fFloatFormat = NULL; 106 return NULL; 107 } 108 } 109 110 return fFloatFormat; 111} 112 113 114NumberFormat* 115BNumberFormatImpl::GetCurrency(BFormattingConventions* convention) 116{ 117 if (fCurrencyFormat == NULL) { 118 UErrorCode err = U_ZERO_ERROR; 119 fCurrencyFormat = NumberFormat::createCurrencyInstance( 120 *BFormattingConventions::Private(convention).ICULocale(), 121 err); 122 123 if (fCurrencyFormat == NULL) 124 return NULL; 125 if (U_FAILURE(err)) { 126 delete fCurrencyFormat; 127 fCurrencyFormat = NULL; 128 return NULL; 129 } 130 } 131 132 return fCurrencyFormat; 133} 134 135 136NumberFormat* 137BNumberFormatImpl::GetPercent(BFormattingConventions* convention) 138{ 139 if (fPercentFormat == NULL) { 140 UErrorCode err = U_ZERO_ERROR; 141 fPercentFormat = NumberFormat::createInstance( 142 *BFormattingConventions::Private(convention).ICULocale(), 143 UNUM_PERCENT, err); 144 145 if (fPercentFormat == NULL) 146 return NULL; 147 if (U_FAILURE(err)) { 148 delete fPercentFormat; 149 fPercentFormat = NULL; 150 return NULL; 151 } 152 } 153 154 return fPercentFormat; 155} 156 157 158ssize_t 159BNumberFormatImpl::ApplyFormatter(NumberFormat* formatter, char* string, 160 size_t maxSize, const double value) 161{ 162 BString fullString; 163 status_t status = ApplyFormatter(formatter, fullString, value); 164 if (status != B_OK) 165 return status; 166 167 return strlcpy(string, fullString.String(), maxSize); 168} 169 170 171status_t 172BNumberFormatImpl::ApplyFormatter(NumberFormat* formatter, BString& string, 173 const double value) 174{ 175 if (formatter == NULL) 176 return B_NO_MEMORY; 177 178 UnicodeString icuString; 179 formatter->format(value, icuString); 180 181 string.Truncate(0); 182 BStringByteSink stringConverter(&string); 183 icuString.toUTF8(stringConverter); 184 185 return B_OK; 186} 187 188 189BNumberFormat::BNumberFormat() 190 : BFormat() 191{ 192 fPrivateData = new BNumberFormatImpl(); 193} 194 195 196BNumberFormat::BNumberFormat(const BLocale* locale) 197 : BFormat(locale) 198{ 199 fPrivateData = new BNumberFormatImpl(); 200} 201 202 203BNumberFormat::BNumberFormat(const BNumberFormat &other) 204 : BFormat(other) 205{ 206 fPrivateData = new BNumberFormatImpl(*other.fPrivateData); 207} 208 209 210BNumberFormat::~BNumberFormat() 211{ 212 delete fPrivateData; 213} 214 215 216// #pragma mark - Formatting 217 218 219ssize_t 220BNumberFormat::Format(char* string, size_t maxSize, const double value) 221{ 222 BString fullString; 223 status_t status = Format(fullString, value); 224 if (status != B_OK) 225 return status; 226 227 return strlcpy(string, fullString.String(), maxSize); 228} 229 230 231status_t 232BNumberFormat::Format(BString& string, const double value) 233{ 234 NumberFormat* formatter = fPrivateData->GetFloat(&fConventions); 235 236 if (formatter == NULL) 237 return B_NO_MEMORY; 238 239 UnicodeString icuString; 240 formatter->format(value, icuString); 241 242 string.Truncate(0); 243 BStringByteSink stringConverter(&string); 244 icuString.toUTF8(stringConverter); 245 246 return B_OK; 247} 248 249 250ssize_t 251BNumberFormat::Format(char* string, size_t maxSize, const int32 value) 252{ 253 BString fullString; 254 status_t status = Format(fullString, value); 255 if (status != B_OK) 256 return status; 257 258 return strlcpy(string, fullString.String(), maxSize); 259} 260 261 262status_t 263BNumberFormat::Format(BString& string, const int32 value) 264{ 265 NumberFormat* formatter = fPrivateData->GetInteger(&fConventions); 266 267 if (formatter == NULL) 268 return B_NO_MEMORY; 269 270 UnicodeString icuString; 271 formatter->format((int32_t)value, icuString); 272 273 string.Truncate(0); 274 BStringByteSink stringConverter(&string); 275 icuString.toUTF8(stringConverter); 276 277 return B_OK; 278} 279 280 281status_t 282BNumberFormat::SetPrecision(int precision) 283{ 284 NumberFormat* decimalFormatter = fPrivateData->GetFloat(&fConventions); 285 NumberFormat* currencyFormatter = fPrivateData->GetCurrency(&fConventions); 286 NumberFormat* percentFormatter = fPrivateData->GetPercent(&fConventions); 287 288 if ((decimalFormatter == NULL) || (currencyFormatter == NULL) || (percentFormatter == NULL)) 289 return B_ERROR; 290 291 decimalFormatter->setMinimumFractionDigits(precision); 292 decimalFormatter->setMaximumFractionDigits(precision); 293 294 currencyFormatter->setMinimumFractionDigits(precision); 295 currencyFormatter->setMaximumFractionDigits(precision); 296 297 percentFormatter->setMinimumFractionDigits(precision); 298 percentFormatter->setMaximumFractionDigits(precision); 299 300 return B_OK; 301} 302 303 304ssize_t 305BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value) 306{ 307 return fPrivateData->ApplyFormatter( 308 fPrivateData->GetCurrency(&fConventions), string, maxSize, value); 309} 310 311 312status_t 313BNumberFormat::FormatMonetary(BString& string, const double value) 314{ 315 return fPrivateData->ApplyFormatter( 316 fPrivateData->GetCurrency(&fConventions), string, value); 317} 318 319 320ssize_t 321BNumberFormat::FormatPercent(char* string, size_t maxSize, const double value) 322{ 323 return fPrivateData->ApplyFormatter( 324 fPrivateData->GetPercent(&fConventions), string, maxSize, value); 325} 326 327 328status_t 329BNumberFormat::FormatPercent(BString& string, const double value) 330{ 331 return fPrivateData->ApplyFormatter( 332 fPrivateData->GetPercent(&fConventions), string, value); 333} 334 335 336status_t 337BNumberFormat::Parse(const BString& string, double& value) 338{ 339 NumberFormat* parser = fPrivateData->GetFloat(&fConventions); 340 341 if (parser == NULL) 342 return B_NO_MEMORY; 343 344 UnicodeString unicode(string.String()); 345 Formattable result(0); 346 UErrorCode err = U_ZERO_ERROR; 347 348 parser->parse(unicode, result, err); 349 350 if (err != U_ZERO_ERROR) 351 return B_BAD_DATA; 352 353 value = result.getDouble(); 354 355 return B_OK; 356} 357 358 359BString 360BNumberFormat::GetSeparator(BNumberElement element) 361{ 362 DecimalFormatSymbols::ENumberFormatSymbol symbol; 363 BString result; 364 365 switch(element) { 366 case B_DECIMAL_SEPARATOR: 367 symbol = DecimalFormatSymbols::kDecimalSeparatorSymbol; 368 break; 369 case B_GROUPING_SEPARATOR: 370 symbol = DecimalFormatSymbols::kGroupingSeparatorSymbol; 371 break; 372 373 default: 374 return result; 375 } 376 377 NumberFormat* format = fPrivateData->GetFloat(&fConventions); 378 DecimalFormat* decimal = dynamic_cast<DecimalFormat*>(format); 379 380 if (decimal == NULL) 381 return result; 382 383 const DecimalFormatSymbols* symbols = decimal->getDecimalFormatSymbols(); 384 UnicodeString string = symbols->getSymbol(symbol); 385 386 BStringByteSink stringConverter(&result); 387 string.toUTF8(stringConverter); 388 389 return result; 390} 391