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 25 U_NAMESPACE_USE 26 27 28 class BNumberFormatImpl { 29 public: 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 43 private: 44 NumberFormat* fIntegerFormat; 45 NumberFormat* fFloatFormat; 46 NumberFormat* fCurrencyFormat; 47 NumberFormat* fPercentFormat; 48 }; 49 50 51 BNumberFormatImpl::BNumberFormatImpl() 52 { 53 // They are initialized lazily as needed 54 fIntegerFormat = NULL; 55 fFloatFormat = NULL; 56 fCurrencyFormat = NULL; 57 fPercentFormat = NULL; 58 } 59 60 61 BNumberFormatImpl::~BNumberFormatImpl() 62 { 63 delete fIntegerFormat; 64 delete fFloatFormat; 65 delete fCurrencyFormat; 66 delete fPercentFormat; 67 } 68 69 70 NumberFormat* 71 BNumberFormatImpl::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 92 NumberFormat* 93 BNumberFormatImpl::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 114 NumberFormat* 115 BNumberFormatImpl::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 136 NumberFormat* 137 BNumberFormatImpl::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 158 ssize_t 159 BNumberFormatImpl::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 171 status_t 172 BNumberFormatImpl::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 189 BNumberFormat::BNumberFormat() 190 : BFormat() 191 { 192 fPrivateData = new BNumberFormatImpl(); 193 } 194 195 196 BNumberFormat::BNumberFormat(const BLocale* locale) 197 : BFormat(locale) 198 { 199 fPrivateData = new BNumberFormatImpl(); 200 } 201 202 203 BNumberFormat::BNumberFormat(const BNumberFormat &other) 204 : BFormat(other) 205 { 206 fPrivateData = new BNumberFormatImpl(*other.fPrivateData); 207 } 208 209 210 BNumberFormat::~BNumberFormat() 211 { 212 delete fPrivateData; 213 } 214 215 216 // #pragma mark - Formatting 217 218 219 ssize_t 220 BNumberFormat::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 231 status_t 232 BNumberFormat::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 250 ssize_t 251 BNumberFormat::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 262 status_t 263 BNumberFormat::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 281 status_t 282 BNumberFormat::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 304 ssize_t 305 BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value) 306 { 307 return fPrivateData->ApplyFormatter( 308 fPrivateData->GetCurrency(&fConventions), string, maxSize, value); 309 } 310 311 312 status_t 313 BNumberFormat::FormatMonetary(BString& string, const double value) 314 { 315 return fPrivateData->ApplyFormatter( 316 fPrivateData->GetCurrency(&fConventions), string, value); 317 } 318 319 320 ssize_t 321 BNumberFormat::FormatPercent(char* string, size_t maxSize, const double value) 322 { 323 return fPrivateData->ApplyFormatter( 324 fPrivateData->GetPercent(&fConventions), string, maxSize, value); 325 } 326 327 328 status_t 329 BNumberFormat::FormatPercent(BString& string, const double value) 330 { 331 return fPrivateData->ApplyFormatter( 332 fPrivateData->GetPercent(&fConventions), string, value); 333 } 334 335 336 status_t 337 BNumberFormat::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 359 BString 360 BNumberFormat::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