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