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 ssize_t 282 BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value) 283 { 284 return fPrivateData->ApplyFormatter( 285 fPrivateData->GetCurrency(&fConventions), string, maxSize, value); 286 } 287 288 289 status_t 290 BNumberFormat::FormatMonetary(BString& string, const double value) 291 { 292 return fPrivateData->ApplyFormatter( 293 fPrivateData->GetCurrency(&fConventions), string, value); 294 } 295 296 297 ssize_t 298 BNumberFormat::FormatPercent(char* string, size_t maxSize, const double value) 299 { 300 return fPrivateData->ApplyFormatter( 301 fPrivateData->GetPercent(&fConventions), string, maxSize, value); 302 } 303 304 305 status_t 306 BNumberFormat::FormatPercent(BString& string, const double value) 307 { 308 return fPrivateData->ApplyFormatter( 309 fPrivateData->GetPercent(&fConventions), string, value); 310 } 311 312 313 status_t 314 BNumberFormat::Parse(const BString& string, double& value) 315 { 316 NumberFormat* parser = fPrivateData->GetFloat(&fConventions); 317 318 if (parser == NULL) 319 return B_NO_MEMORY; 320 321 UnicodeString unicode(string.String()); 322 Formattable result(0); 323 UErrorCode err = U_ZERO_ERROR; 324 325 parser->parse(unicode, result, err); 326 327 if (err != U_ZERO_ERROR) 328 return B_BAD_DATA; 329 330 value = result.getDouble(); 331 332 return B_OK; 333 } 334 335 336 BString 337 BNumberFormat::GetSeparator(BNumberElement element) 338 { 339 DecimalFormatSymbols::ENumberFormatSymbol symbol; 340 BString result; 341 342 switch(element) { 343 case B_DECIMAL_SEPARATOR: 344 symbol = DecimalFormatSymbols::kDecimalSeparatorSymbol; 345 break; 346 case B_GROUPING_SEPARATOR: 347 symbol = DecimalFormatSymbols::kGroupingSeparatorSymbol; 348 break; 349 350 default: 351 return result; 352 } 353 354 NumberFormat* format = fPrivateData->GetFloat(&fConventions); 355 DecimalFormat* decimal = dynamic_cast<DecimalFormat*>(format); 356 357 if (decimal == NULL) 358 return result; 359 360 const DecimalFormatSymbols* symbols = decimal->getDecimalFormatSymbols(); 361 UnicodeString string = symbols->getSymbol(symbol); 362 363 BStringByteSink stringConverter(&result); 364 string.toUTF8(stringConverter); 365 366 return result; 367 } 368