1 /* 2 * Copyright 2003-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2009, Destugues, pulkomandy@gmail.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <Country.h> 9 10 #include <assert.h> 11 12 #include <IconUtils.h> 13 #include <Resources.h> 14 #include <String.h> 15 16 #include <unicode/datefmt.h> 17 #include <unicode/dcfmtsym.h> 18 #include <unicode/decimfmt.h> 19 #include <unicode/dtfmtsym.h> 20 #include <unicode/smpdtfmt.h> 21 #include <ICUWrapper.h> 22 23 #include <monetary.h> 24 #include <stdarg.h> 25 26 27 const char* gStrings[] = { 28 // date/time format 29 "", 30 "", 31 // short date/time format 32 "", 33 "", 34 // am/pm string 35 "AM", 36 "PM", 37 // separators 38 ".", 39 ":", 40 41 // currency/monetary 42 "." 43 "," 44 }; 45 46 47 BCountry::BCountry(const char* languageCode, const char* countryCode) 48 : 49 fStrings(gStrings) 50 { 51 fICULocale = new icu_4_2::Locale(languageCode, countryCode); 52 } 53 54 55 BCountry::BCountry(const char* languageAndCountryCode) 56 : 57 fStrings(gStrings) 58 { 59 fICULocale = new icu_4_2::Locale(languageAndCountryCode); 60 fICULongDateFormatter = DateFormat::createDateInstance( 61 DateFormat::FULL, *fICULocale); 62 fICUShortDateFormatter = DateFormat::createDateInstance( 63 DateFormat::SHORT, *fICULocale); 64 } 65 66 67 BCountry::~BCountry() 68 { 69 delete fICULocale; 70 } 71 72 73 bool 74 BCountry::Name(BString& name) const 75 { 76 UnicodeString uString; 77 fICULocale->getDisplayName(uString); 78 BStringByteSink stringConverter(&name); 79 uString.toUTF8(stringConverter); 80 return true; 81 } 82 83 84 const char* 85 BCountry::Code() const 86 { 87 return fICULocale->getName(); 88 } 89 90 91 status_t 92 BCountry::GetIcon(BBitmap* result) 93 { 94 if (result == NULL) 95 return B_BAD_DATA; 96 // TODO: a proper way to locate the library being used ? 97 BResources storage("/boot/system/lib/liblocale.so"); 98 if (storage.InitCheck() != B_OK) 99 return B_ERROR; 100 size_t size; 101 const char* code = fICULocale->getCountry(); 102 if (code != NULL) { 103 printf("this is %s drawing\n",code); 104 const void* buffer = storage.LoadResource(B_VECTOR_ICON_TYPE, code, 105 &size); 106 if (buffer != NULL && size != 0) { 107 puts(" icon found!"); 108 return BIconUtils::GetVectorIcon(static_cast<const uint8*>(buffer), 109 size, result); 110 } 111 } 112 return B_BAD_DATA; 113 } 114 115 116 // TODO use ICU backend keywords instead 117 const char* 118 BCountry::GetString(uint32 id) const 119 { 120 if (id < B_COUNTRY_STRINGS_BASE || id >= B_NUM_COUNTRY_STRINGS) 121 return NULL; 122 123 return gStrings[id - B_COUNTRY_STRINGS_BASE]; 124 } 125 126 127 void 128 BCountry::FormatDate(char* string, size_t maxSize, time_t time, bool longFormat) 129 { 130 BString fullString; 131 FormatDate(&fullString, time, longFormat); 132 strncpy(string, fullString.String(), maxSize); 133 } 134 135 136 void 137 BCountry::FormatDate(BString *string, time_t time, bool longFormat) 138 { 139 // TODO: ICU allows for 4 different levels of expansion : 140 // short, medium, long, and full. Our bool parameter is not enough... 141 icu_4_2::DateFormat* dateFormatter 142 = longFormat ? fICULongDateFormatter : fICUShortDateFormatter; 143 UnicodeString ICUString; 144 ICUString = dateFormatter->format((UDate)time * 1000, ICUString); 145 146 string->Truncate(0); 147 BStringByteSink stringConverter(string); 148 149 ICUString.toUTF8(stringConverter); 150 } 151 152 153 void 154 BCountry::FormatTime(char* string, size_t maxSize, time_t time, bool longFormat) 155 { 156 BString fullString; 157 FormatTime(&fullString, time, longFormat); 158 strncpy(string, fullString.String(), maxSize); 159 } 160 161 162 void 163 BCountry::FormatTime(BString* string, time_t time, bool longFormat) 164 { 165 // TODO: ICU allows for 4 different levels of expansion : 166 // short, medium, long, and full. Our bool parameter is not enough... 167 icu_4_2::DateFormat* timeFormatter; 168 timeFormatter = DateFormat::createTimeInstance( 169 longFormat ? DateFormat::FULL : DateFormat::SHORT, 170 *fICULocale); 171 UnicodeString ICUString; 172 ICUString = timeFormatter->format((UDate)time * 1000, ICUString); 173 174 string->Truncate(0); 175 BStringByteSink stringConverter(string); 176 177 ICUString.toUTF8(stringConverter); 178 } 179 180 181 bool 182 BCountry::DateFormat(BString& format, bool longFormat) const 183 { 184 icu_4_2::DateFormat* dateFormatter 185 = longFormat ? fICULongDateFormatter : fICUShortDateFormatter; 186 SimpleDateFormat* dateFormatterImpl 187 = static_cast<SimpleDateFormat*>(dateFormatter); 188 189 UnicodeString ICUString; 190 ICUString = dateFormatterImpl->toPattern(ICUString); 191 192 BStringByteSink stringConverter(&format); 193 194 ICUString.toUTF8(stringConverter); 195 196 return true; 197 } 198 199 200 void 201 BCountry::SetDateFormat(const char* formatString, bool longFormat) 202 { 203 icu_4_2::DateFormat* dateFormatter 204 = longFormat ? fICULongDateFormatter : fICUShortDateFormatter; 205 SimpleDateFormat* dateFormatterImpl 206 = static_cast<SimpleDateFormat*>(dateFormatter); 207 208 UnicodeString pattern(formatString); 209 dateFormatterImpl->applyPattern(pattern); 210 } 211 212 213 bool 214 BCountry::TimeFormat(BString& format, bool longFormat) const 215 { 216 icu_4_2::DateFormat* dateFormatter; 217 dateFormatter = DateFormat::createTimeInstance( 218 longFormat ? DateFormat::FULL : DateFormat::SHORT, 219 *fICULocale); 220 SimpleDateFormat* dateFormatterImpl 221 = static_cast<SimpleDateFormat*>(dateFormatter); 222 223 UnicodeString ICUString; 224 ICUString = dateFormatterImpl->toPattern(ICUString); 225 226 BStringByteSink stringConverter(&format); 227 228 ICUString.toUTF8(stringConverter); 229 230 return true; 231 } 232 233 234 // TODO find how to get it from ICU (setting it is ok, we use the pattern-string 235 // for that) 236 // Or remove this function ? 237 const char* 238 BCountry::DateSeparator() const 239 { 240 return fStrings[B_DATE_SEPARATOR]; 241 } 242 243 244 const char* 245 BCountry::TimeSeparator() const 246 { 247 return fStrings[B_TIME_SEPARATOR]; 248 } 249 250 251 void 252 BCountry::FormatNumber(char* string, size_t maxSize, double value) 253 { 254 BString fullString; 255 FormatNumber(&fullString, value); 256 strncpy(string, fullString.String(), maxSize); 257 } 258 259 260 status_t 261 BCountry::FormatNumber(BString* string, double value) 262 { 263 UErrorCode err = U_ZERO_ERROR; 264 NumberFormat* numberFormatter 265 = NumberFormat::createInstance(*fICULocale, NumberFormat::kNumberStyle, 266 err); 267 268 // Warning: we're returning an ICU error here but the type is status_t. 269 if (U_FAILURE(err)) return err; 270 271 UnicodeString ICUString; 272 ICUString = numberFormatter->format(value, ICUString); 273 274 string->Truncate(0); 275 BStringByteSink stringConverter(string); 276 277 ICUString.toUTF8(stringConverter); 278 279 return U_ZERO_ERROR; 280 } 281 282 283 void 284 BCountry::FormatNumber(char* string, size_t maxSize, int32 value) 285 { 286 BString fullString; 287 FormatNumber(&fullString, value); 288 strncpy(string, fullString.String(), maxSize); 289 } 290 291 292 void 293 BCountry::FormatNumber(BString* string, int32 value) 294 { 295 UErrorCode err; 296 NumberFormat* numberFormatter 297 = NumberFormat::createInstance(*fICULocale, err); 298 299 assert(err == U_ZERO_ERROR); 300 301 UnicodeString ICUString; 302 ICUString = numberFormatter->format((int32_t)value, ICUString); 303 304 string->Truncate(0); 305 BStringByteSink stringConverter(string); 306 307 ICUString.toUTF8(stringConverter); 308 } 309 310 311 // This will only work for locales using the decimal system... 312 bool 313 BCountry::DecimalPoint(BString& format) const 314 { 315 UErrorCode err; 316 NumberFormat* numberFormatter 317 = NumberFormat::createInstance(*fICULocale, err); 318 319 assert(err == U_ZERO_ERROR); 320 321 DecimalFormat* decimalFormatter 322 = dynamic_cast<DecimalFormat*>(numberFormatter); 323 324 assert(decimalFormatter != NULL); 325 326 const DecimalFormatSymbols* syms 327 = decimalFormatter->getDecimalFormatSymbols(); 328 329 UnicodeString ICUString; 330 ICUString = syms->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol); 331 332 BStringByteSink stringConverter(&format); 333 334 ICUString.toUTF8(stringConverter); 335 336 return true; 337 } 338 339 340 bool 341 BCountry::ThousandsSeparator(BString& separator) const 342 { 343 UErrorCode err; 344 NumberFormat* numberFormatter 345 = NumberFormat::createInstance(*fICULocale, err); 346 assert(err == U_ZERO_ERROR); 347 DecimalFormat* decimalFormatter 348 = dynamic_cast<DecimalFormat*>(numberFormatter); 349 350 assert(decimalFormatter != NULL); 351 352 const DecimalFormatSymbols* syms 353 = decimalFormatter->getDecimalFormatSymbols(); 354 355 UnicodeString ICUString; 356 ICUString = syms->getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); 357 358 BStringByteSink stringConverter(&separator); 359 360 ICUString.toUTF8(stringConverter); 361 362 return true; 363 } 364 365 366 bool 367 BCountry::Grouping(BString& grouping) const 368 { 369 UErrorCode err; 370 NumberFormat* numberFormatter 371 = NumberFormat::createInstance(*fICULocale, err); 372 assert(err == U_ZERO_ERROR); 373 DecimalFormat* decimalFormatter 374 = dynamic_cast<DecimalFormat*>(numberFormatter); 375 376 assert(decimalFormatter != NULL); 377 378 const DecimalFormatSymbols* syms 379 = decimalFormatter->getDecimalFormatSymbols(); 380 381 UnicodeString ICUString; 382 ICUString = syms->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); 383 384 BStringByteSink stringConverter(&grouping); 385 386 ICUString.toUTF8(stringConverter); 387 388 return true; 389 } 390 391 392 bool 393 BCountry::PositiveSign(BString& sign) const 394 { 395 UErrorCode err; 396 NumberFormat* numberFormatter 397 = NumberFormat::createInstance(*fICULocale, err); 398 assert(err == U_ZERO_ERROR); 399 DecimalFormat* decimalFormatter 400 = dynamic_cast<DecimalFormat*>(numberFormatter); 401 402 assert(decimalFormatter != NULL); 403 404 const DecimalFormatSymbols* syms 405 = decimalFormatter->getDecimalFormatSymbols(); 406 407 UnicodeString ICUString; 408 ICUString = syms->getSymbol(DecimalFormatSymbols::kPlusSignSymbol); 409 410 BStringByteSink stringConverter(&sign); 411 412 ICUString.toUTF8(stringConverter); 413 414 return true; 415 } 416 417 418 bool 419 BCountry::NegativeSign(BString& sign) const 420 { 421 UErrorCode err; 422 NumberFormat* numberFormatter 423 = NumberFormat::createInstance(*fICULocale, err); 424 assert(err == U_ZERO_ERROR); 425 DecimalFormat* decimalFormatter 426 = dynamic_cast<DecimalFormat*>(numberFormatter); 427 428 assert(decimalFormatter != NULL); 429 430 const DecimalFormatSymbols* syms 431 = decimalFormatter->getDecimalFormatSymbols(); 432 433 UnicodeString ICUString; 434 ICUString = syms->getSymbol(DecimalFormatSymbols::kMinusSignSymbol); 435 436 BStringByteSink stringConverter(&sign); 437 438 ICUString.toUTF8(stringConverter); 439 440 return true; 441 } 442 443 444 // TODO does ICU even support this ? Is it in the keywords ? 445 int8 446 BCountry::Measurement() const 447 { 448 return B_US; 449 } 450 451 452 ssize_t 453 BCountry::FormatMonetary(char* string, size_t maxSize, double value) 454 { 455 BString fullString; 456 ssize_t written = FormatMonetary(&fullString, value); 457 if (written < 0) 458 return written; 459 460 return strlcpy(string, fullString.String(), maxSize); 461 } 462 463 464 ssize_t 465 BCountry::FormatMonetary(BString* string, double value) 466 { 467 if (string == NULL) 468 return B_BAD_VALUE; 469 470 UErrorCode err; 471 NumberFormat* numberFormatter 472 = NumberFormat::createCurrencyInstance(*fICULocale, err); 473 474 assert(err == U_ZERO_ERROR); 475 476 UnicodeString ICUString; 477 ICUString = numberFormatter->format(value, ICUString); 478 479 string->Truncate(0); 480 BStringByteSink stringConverter(string); 481 482 ICUString.toUTF8(stringConverter); 483 484 return string->Length(); 485 } 486 487 488 bool 489 BCountry::CurrencySymbol(BString& symbol) const 490 { 491 UErrorCode err; 492 NumberFormat* numberFormatter 493 = NumberFormat::createCurrencyInstance(*fICULocale, err); 494 assert(err == U_ZERO_ERROR); 495 DecimalFormat* decimalFormatter 496 = dynamic_cast<DecimalFormat*>(numberFormatter); 497 498 assert(decimalFormatter != NULL); 499 500 const DecimalFormatSymbols* syms 501 = decimalFormatter->getDecimalFormatSymbols(); 502 503 UnicodeString ICUString; 504 ICUString = syms->getSymbol(DecimalFormatSymbols::kCurrencySymbol); 505 506 BStringByteSink stringConverter(&symbol); 507 508 ICUString.toUTF8(stringConverter); 509 510 return true; 511 } 512 513 514 bool 515 BCountry::InternationalCurrencySymbol(BString& symbol) const 516 { 517 UErrorCode err; 518 NumberFormat* numberFormatter 519 = NumberFormat::createCurrencyInstance(*fICULocale, err); 520 assert(err == U_ZERO_ERROR); 521 DecimalFormat* decimalFormatter 522 = dynamic_cast<DecimalFormat*>(numberFormatter); 523 524 assert(decimalFormatter != NULL); 525 526 const DecimalFormatSymbols* syms 527 = decimalFormatter->getDecimalFormatSymbols(); 528 529 UnicodeString ICUString; 530 ICUString = syms->getSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); 531 532 BStringByteSink stringConverter(&symbol); 533 534 ICUString.toUTF8(stringConverter); 535 536 return true; 537 } 538 539 540 bool 541 BCountry::MonDecimalPoint(BString& decimal) const 542 { 543 UErrorCode err; 544 NumberFormat* numberFormatter 545 = NumberFormat::createCurrencyInstance(*fICULocale, err); 546 assert(err == U_ZERO_ERROR); 547 DecimalFormat* decimalFormatter 548 = dynamic_cast<DecimalFormat*>(numberFormatter); 549 550 assert(decimalFormatter != NULL); 551 552 const DecimalFormatSymbols* syms 553 = decimalFormatter->getDecimalFormatSymbols(); 554 555 UnicodeString ICUString; 556 ICUString = syms->getSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol); 557 558 BStringByteSink stringConverter(&decimal); 559 560 ICUString.toUTF8(stringConverter); 561 562 return true; 563 } 564 565 566 bool 567 BCountry::MonThousandsSeparator(BString& separator) const 568 { 569 UErrorCode err; 570 NumberFormat* numberFormatter 571 = NumberFormat::createCurrencyInstance(*fICULocale, err); 572 assert(err == U_ZERO_ERROR); 573 DecimalFormat* decimalFormatter 574 = dynamic_cast<DecimalFormat*>(numberFormatter); 575 576 assert(decimalFormatter != NULL); 577 578 const DecimalFormatSymbols* syms 579 = decimalFormatter->getDecimalFormatSymbols(); 580 581 UnicodeString ICUString; 582 ICUString = syms->getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol); 583 584 BStringByteSink stringConverter(&separator); 585 586 ICUString.toUTF8(stringConverter); 587 588 return true; 589 } 590 591 592 bool 593 BCountry::MonGrouping(BString& grouping) const 594 { 595 UErrorCode err; 596 NumberFormat* numberFormatter 597 = NumberFormat::createCurrencyInstance(*fICULocale, err); 598 assert(err == U_ZERO_ERROR); 599 DecimalFormat* decimalFormatter 600 = dynamic_cast<DecimalFormat*>(numberFormatter); 601 602 assert(decimalFormatter != NULL); 603 604 const DecimalFormatSymbols* syms 605 = decimalFormatter->getDecimalFormatSymbols(); 606 607 UnicodeString ICUString; 608 ICUString = syms->getSymbol( 609 DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol); 610 611 BStringByteSink stringConverter(&grouping); 612 613 ICUString.toUTF8(stringConverter); 614 615 return true; 616 } 617 618 619 // TODO: is this possible to get from ICU ? 620 int32 621 BCountry::MonFracDigits() const 622 { 623 return 2; 624 } 625 626