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 * All rights reserved. Distributed under the terms of the MIT License. 7 */ 8 9 10 #include <unicode/uversion.h> 11 #include <NumberFormat.h> 12 13 #include <AutoDeleter.h> 14 #include <Autolock.h> 15 #include <FormattingConventionsPrivate.h> 16 17 #include <ICUWrapper.h> 18 19 #include <unicode/dcfmtsym.h> 20 #include <unicode/decimfmt.h> 21 #include <unicode/numfmt.h> 22 23 24 class BNumberFormatImpl { 25 public: 26 BNumberFormatImpl(); 27 ~BNumberFormatImpl(); 28 29 NumberFormat* GetInteger(BFormattingConventions* convention); 30 NumberFormat* GetFloat(BFormattingConventions* convention); 31 NumberFormat* GetCurrency(BFormattingConventions* convention); 32 33 private: 34 NumberFormat* fIntegerFormat; 35 NumberFormat* fFloatFormat; 36 NumberFormat* fCurrencyFormat; 37 }; 38 39 40 BNumberFormatImpl::BNumberFormatImpl() 41 { 42 // They are initialized lazily as needed 43 fIntegerFormat = NULL; 44 fFloatFormat = NULL; 45 fCurrencyFormat = NULL; 46 } 47 48 49 BNumberFormatImpl::~BNumberFormatImpl() 50 { 51 delete fIntegerFormat; 52 delete fFloatFormat; 53 delete fCurrencyFormat; 54 } 55 56 57 NumberFormat* 58 BNumberFormatImpl::GetInteger(BFormattingConventions* convention) 59 { 60 if (fIntegerFormat == NULL) { 61 UErrorCode err = U_ZERO_ERROR; 62 fIntegerFormat = NumberFormat::createInstance( 63 *BFormattingConventions::Private(convention).ICULocale(), 64 UNUM_DECIMAL, err); 65 66 if (fIntegerFormat == NULL) 67 return NULL; 68 if (U_FAILURE(err)) { 69 delete fIntegerFormat; 70 fIntegerFormat = NULL; 71 return NULL; 72 } 73 } 74 75 return fIntegerFormat; 76 } 77 78 79 NumberFormat* 80 BNumberFormatImpl::GetFloat(BFormattingConventions* convention) 81 { 82 if (fFloatFormat == NULL) { 83 UErrorCode err = U_ZERO_ERROR; 84 fFloatFormat = NumberFormat::createInstance( 85 *BFormattingConventions::Private(convention).ICULocale(), 86 UNUM_DECIMAL, err); 87 88 if (fFloatFormat == NULL) 89 return NULL; 90 if (U_FAILURE(err)) { 91 delete fFloatFormat; 92 fFloatFormat = NULL; 93 return NULL; 94 } 95 } 96 97 return fFloatFormat; 98 } 99 100 101 NumberFormat* 102 BNumberFormatImpl::GetCurrency(BFormattingConventions* convention) 103 { 104 if (fCurrencyFormat == NULL) { 105 UErrorCode err = U_ZERO_ERROR; 106 fCurrencyFormat = NumberFormat::createCurrencyInstance( 107 *BFormattingConventions::Private(convention).ICULocale(), 108 err); 109 110 if (fCurrencyFormat == NULL) 111 return NULL; 112 if (U_FAILURE(err)) { 113 delete fCurrencyFormat; 114 fCurrencyFormat = NULL; 115 return NULL; 116 } 117 } 118 119 return fCurrencyFormat; 120 } 121 122 123 BNumberFormat::BNumberFormat() 124 : BFormat() 125 { 126 fPrivateData = new BNumberFormatImpl(); 127 } 128 129 130 BNumberFormat::BNumberFormat(const BNumberFormat &other) 131 : BFormat(other) 132 { 133 fPrivateData = new BNumberFormatImpl(*other.fPrivateData); 134 } 135 136 137 BNumberFormat::~BNumberFormat() 138 { 139 delete fPrivateData; 140 } 141 142 143 // #pragma mark - Formatting 144 145 146 ssize_t 147 BNumberFormat::Format(char* string, size_t maxSize, const double value) 148 { 149 BString fullString; 150 status_t status = Format(fullString, value); 151 if (status != B_OK) 152 return status; 153 154 return strlcpy(string, fullString.String(), maxSize); 155 } 156 157 158 status_t 159 BNumberFormat::Format(BString& string, const double value) 160 { 161 NumberFormat* formatter = fPrivateData->GetFloat(&fConventions); 162 163 if (formatter == NULL) 164 return B_NO_MEMORY; 165 166 UnicodeString icuString; 167 formatter->format(value, icuString); 168 169 string.Truncate(0); 170 BStringByteSink stringConverter(&string); 171 icuString.toUTF8(stringConverter); 172 173 return B_OK; 174 } 175 176 177 ssize_t 178 BNumberFormat::Format(char* string, size_t maxSize, const int32 value) 179 { 180 BString fullString; 181 status_t status = Format(fullString, value); 182 if (status != B_OK) 183 return status; 184 185 return strlcpy(string, fullString.String(), maxSize); 186 } 187 188 189 status_t 190 BNumberFormat::Format(BString& string, const int32 value) 191 { 192 NumberFormat* formatter = fPrivateData->GetInteger(&fConventions); 193 194 if (formatter == NULL) 195 return B_NO_MEMORY; 196 197 UnicodeString icuString; 198 formatter->format((int32_t)value, icuString); 199 200 string.Truncate(0); 201 BStringByteSink stringConverter(&string); 202 icuString.toUTF8(stringConverter); 203 204 return B_OK; 205 } 206 207 208 ssize_t 209 BNumberFormat::FormatMonetary(char* string, size_t maxSize, const double value) 210 { 211 BString fullString; 212 status_t status = FormatMonetary(fullString, value); 213 if (status != B_OK) 214 return status; 215 216 return strlcpy(string, fullString.String(), maxSize); 217 } 218 219 220 status_t 221 BNumberFormat::FormatMonetary(BString& string, const double value) 222 { 223 NumberFormat* formatter = fPrivateData->GetCurrency(&fConventions); 224 225 if (formatter == NULL) 226 return B_NO_MEMORY; 227 228 UnicodeString icuString; 229 formatter->format(value, icuString); 230 231 string.Truncate(0); 232 BStringByteSink stringConverter(&string); 233 icuString.toUTF8(stringConverter); 234 235 return B_OK; 236 } 237 238 239 status_t 240 BNumberFormat::Parse(const BString& string, double& value) 241 { 242 NumberFormat* parser = fPrivateData->GetFloat(&fConventions); 243 244 if (parser == NULL) 245 return B_NO_MEMORY; 246 247 UnicodeString unicode(string.String()); 248 Formattable result(0); 249 UErrorCode err = U_ZERO_ERROR; 250 251 parser->parse(unicode, result, err); 252 253 if (err != U_ZERO_ERROR) 254 return B_BAD_DATA; 255 256 value = result.getDouble(); 257 258 return B_OK; 259 } 260 261 262 BString 263 BNumberFormat::GetSeparator(BNumberElement element) 264 { 265 DecimalFormatSymbols::ENumberFormatSymbol symbol; 266 BString result; 267 268 switch(element) { 269 case B_DECIMAL_SEPARATOR: 270 symbol = DecimalFormatSymbols::kDecimalSeparatorSymbol; 271 break; 272 case B_GROUPING_SEPARATOR: 273 symbol = DecimalFormatSymbols::kGroupingSeparatorSymbol; 274 break; 275 276 default: 277 return result; 278 } 279 280 NumberFormat* format = fPrivateData->GetFloat(&fConventions); 281 DecimalFormat* decimal = dynamic_cast<DecimalFormat*>(format); 282 283 if (decimal == NULL) 284 return result; 285 286 const DecimalFormatSymbols* symbols = decimal->getDecimalFormatSymbols(); 287 UnicodeString string = symbols->getSymbol(symbol); 288 289 BStringByteSink stringConverter(&result); 290 string.toUTF8(stringConverter); 291 292 return result; 293 } 294