1 /* 2 ** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. 3 ** Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de. 4 ** All rights reserved. Distributed under the terms of the OpenBeOS License. 5 */ 6 7 8 #include <AutoDeleter.h> 9 #include <Autolock.h> 10 #include <CalendarView.h> 11 #include <Catalog.h> 12 #include <FormattingConventionsPrivate.h> 13 #include <LanguagePrivate.h> 14 #include <Locale.h> 15 #include <LocaleRoster.h> 16 #include <MutableLocaleRoster.h> 17 #include <TimeZone.h> 18 19 #include <unicode/datefmt.h> 20 #include <unicode/dcfmtsym.h> 21 #include <unicode/decimfmt.h> 22 #include <unicode/dtfmtsym.h> 23 #include <unicode/numfmt.h> 24 #include <unicode/smpdtfmt.h> 25 #include <unicode/ustring.h> 26 #include <ICUWrapper.h> 27 28 #include <vector> 29 30 31 #define ICU_VERSION icu_44 32 33 34 using BPrivate::ObjectDeleter; 35 using BPrivate::B_WEEK_START_MONDAY; 36 using BPrivate::B_WEEK_START_SUNDAY; 37 38 39 BLocale::BLocale(const BLanguage* language, 40 const BFormattingConventions* conventions) 41 { 42 if (conventions != NULL) 43 fConventions = *conventions; 44 else 45 BLocale::Default()->GetFormattingConventions(&fConventions); 46 47 if (language != NULL) 48 fLanguage = *language; 49 else 50 BLocale::Default()->GetLanguage(&fLanguage); 51 } 52 53 54 BLocale::BLocale(const BLocale& other) 55 : 56 fConventions(other.fConventions), 57 fLanguage(other.fLanguage) 58 { 59 } 60 61 62 /*static*/ const BLocale* 63 BLocale::Default() 64 { 65 return &BPrivate::RosterData::Default()->fDefaultLocale; 66 } 67 68 69 BLocale& 70 BLocale::operator=(const BLocale& other) 71 { 72 if (this == &other) 73 return *this; 74 75 BAutolock lock(fLock); 76 BAutolock otherLock(other.fLock); 77 if (!lock.IsLocked() || !otherLock.IsLocked()) 78 return *this; 79 80 fConventions = other.fConventions; 81 fLanguage = other.fLanguage; 82 83 return *this; 84 } 85 86 87 BLocale::~BLocale() 88 { 89 } 90 91 92 status_t 93 BLocale::GetCollator(BCollator* collator) const 94 { 95 if (!collator) 96 return B_BAD_VALUE; 97 98 BAutolock lock(fLock); 99 if (!lock.IsLocked()) 100 return B_ERROR; 101 102 *collator = fCollator; 103 104 return B_OK; 105 } 106 107 108 status_t 109 BLocale::GetLanguage(BLanguage* language) const 110 { 111 if (!language) 112 return B_BAD_VALUE; 113 114 BAutolock lock(fLock); 115 if (!lock.IsLocked()) 116 return B_ERROR; 117 118 *language = fLanguage; 119 120 return B_OK; 121 } 122 123 124 status_t 125 BLocale::GetFormattingConventions(BFormattingConventions* conventions) const 126 { 127 if (!conventions) 128 return B_BAD_VALUE; 129 130 BAutolock lock(fLock); 131 if (!lock.IsLocked()) 132 return B_ERROR; 133 134 *conventions = fConventions; 135 136 return B_OK; 137 } 138 139 140 const char * 141 BLocale::GetString(uint32 id) const 142 { 143 // Note: this code assumes a certain order of the string bases 144 145 BAutolock lock(fLock); 146 if (!lock.IsLocked()) 147 return ""; 148 149 if (id >= B_OTHER_STRINGS_BASE) { 150 if (id == B_CODESET) 151 return "UTF-8"; 152 153 return ""; 154 } 155 return fLanguage.GetString(id); 156 } 157 158 159 void 160 BLocale::SetFormattingConventions(const BFormattingConventions& conventions) 161 { 162 BAutolock lock(fLock); 163 if (!lock.IsLocked()) 164 return; 165 166 fConventions = conventions; 167 } 168 169 170 void 171 BLocale::SetCollator(const BCollator& newCollator) 172 { 173 BAutolock lock(fLock); 174 if (!lock.IsLocked()) 175 return; 176 177 fCollator = newCollator; 178 } 179 180 181 void 182 BLocale::SetLanguage(const BLanguage& newLanguage) 183 { 184 BAutolock lock(fLock); 185 if (!lock.IsLocked()) 186 return; 187 188 fLanguage = newLanguage; 189 } 190 191 192 // #pragma mark - Date 193 194 195 ssize_t 196 BLocale::FormatDate(char* string, size_t maxSize, time_t time, 197 BDateFormatStyle style) const 198 { 199 BAutolock lock(fLock); 200 if (!lock.IsLocked()) 201 return B_ERROR; 202 203 BString format; 204 fConventions.GetDateFormat(style, format); 205 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 206 if (dateFormatter.Get() == NULL) 207 return B_NO_MEMORY; 208 209 UnicodeString icuString; 210 dateFormatter->format((UDate)time * 1000, icuString); 211 212 CheckedArrayByteSink stringConverter(string, maxSize); 213 icuString.toUTF8(stringConverter); 214 215 if (stringConverter.Overflowed()) 216 return B_BAD_VALUE; 217 218 return stringConverter.NumberOfBytesWritten(); 219 } 220 221 222 status_t 223 BLocale::FormatDate(BString *string, time_t time, BDateFormatStyle style, 224 const BTimeZone* timeZone) const 225 { 226 BAutolock lock(fLock); 227 if (!lock.IsLocked()) 228 return B_ERROR; 229 230 BString format; 231 fConventions.GetDateFormat(style, format); 232 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 233 if (dateFormatter.Get() == NULL) 234 return B_NO_MEMORY; 235 236 if (timeZone != NULL) { 237 ObjectDeleter<TimeZone> icuTimeZone( 238 TimeZone::createTimeZone(timeZone->ID().String())); 239 if (icuTimeZone.Get() == NULL) 240 return B_NO_MEMORY; 241 dateFormatter->setTimeZone(*icuTimeZone.Get()); 242 } 243 244 UnicodeString icuString; 245 dateFormatter->format((UDate)time * 1000, icuString); 246 247 string->Truncate(0); 248 BStringByteSink stringConverter(string); 249 icuString.toUTF8(stringConverter); 250 251 return B_OK; 252 } 253 254 255 status_t 256 BLocale::FormatDate(BString* string, int*& fieldPositions, int& fieldCount, 257 time_t time, BDateFormatStyle style) const 258 { 259 BAutolock lock(fLock); 260 if (!lock.IsLocked()) 261 return B_ERROR; 262 263 BString format; 264 fConventions.GetDateFormat(style, format); 265 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 266 if (dateFormatter.Get() == NULL) 267 return B_NO_MEMORY; 268 269 fieldPositions = NULL; 270 UErrorCode error = U_ZERO_ERROR; 271 ICU_VERSION::FieldPositionIterator positionIterator; 272 UnicodeString icuString; 273 dateFormatter->format((UDate)time * 1000, icuString, &positionIterator, 274 error); 275 276 if (error != U_ZERO_ERROR) 277 return B_ERROR; 278 279 ICU_VERSION::FieldPosition field; 280 std::vector<int> fieldPosStorage; 281 fieldCount = 0; 282 while (positionIterator.next(field)) { 283 fieldPosStorage.push_back(field.getBeginIndex()); 284 fieldPosStorage.push_back(field.getEndIndex()); 285 fieldCount += 2; 286 } 287 288 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 289 290 for (int i = 0 ; i < fieldCount ; i++ ) 291 fieldPositions[i] = fieldPosStorage[i]; 292 293 string->Truncate(0); 294 BStringByteSink stringConverter(string); 295 296 icuString.toUTF8(stringConverter); 297 298 return B_OK; 299 } 300 301 302 status_t 303 BLocale::GetDateFields(BDateElement*& fields, int& fieldCount, 304 BDateFormatStyle style) const 305 { 306 BAutolock lock(fLock); 307 if (!lock.IsLocked()) 308 return B_ERROR; 309 310 BString format; 311 fConventions.GetDateFormat(style, format); 312 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 313 if (dateFormatter.Get() == NULL) 314 return B_NO_MEMORY; 315 316 fields = NULL; 317 UErrorCode error = U_ZERO_ERROR; 318 ICU_VERSION::FieldPositionIterator positionIterator; 319 UnicodeString icuString; 320 time_t now; 321 dateFormatter->format((UDate)time(&now) * 1000, icuString, 322 &positionIterator, error); 323 324 if (U_FAILURE(error)) 325 return B_ERROR; 326 327 ICU_VERSION::FieldPosition field; 328 std::vector<int> fieldPosStorage; 329 fieldCount = 0; 330 while (positionIterator.next(field)) { 331 fieldPosStorage.push_back(field.getField()); 332 fieldCount ++; 333 } 334 335 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 336 337 for (int i = 0 ; i < fieldCount ; i++ ) { 338 switch (fieldPosStorage[i]) { 339 case UDAT_YEAR_FIELD: 340 fields[i] = B_DATE_ELEMENT_YEAR; 341 break; 342 case UDAT_MONTH_FIELD: 343 fields[i] = B_DATE_ELEMENT_MONTH; 344 break; 345 case UDAT_DATE_FIELD: 346 fields[i] = B_DATE_ELEMENT_DAY; 347 break; 348 default: 349 fields[i] = B_DATE_ELEMENT_INVALID; 350 break; 351 } 352 } 353 354 return B_OK; 355 } 356 357 358 int 359 BLocale::StartOfWeek() const 360 { 361 BAutolock lock(fLock); 362 if (!lock.IsLocked()) 363 return B_ERROR; 364 365 UErrorCode err = U_ZERO_ERROR; 366 Calendar* c = Calendar::createInstance( 367 *BFormattingConventions::Private(&fConventions).ICULocale(), 368 err); 369 370 if (err == U_ZERO_ERROR && c->getFirstDayOfWeek(err) == UCAL_SUNDAY) { 371 delete c; 372 return B_WEEK_START_SUNDAY; 373 } else { 374 delete c; 375 // Might be another day, but BeAPI will not handle it 376 return B_WEEK_START_MONDAY; 377 } 378 } 379 380 381 ssize_t 382 BLocale::FormatDateTime(char* target, size_t maxSize, time_t time, 383 BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle) const 384 { 385 BAutolock lock(fLock); 386 if (!lock.IsLocked()) 387 return B_ERROR; 388 389 BString format; 390 fConventions.GetDateFormat(dateStyle, format); 391 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 392 if (dateFormatter.Get() == NULL) 393 return B_NO_MEMORY; 394 395 fConventions.GetTimeFormat(timeStyle, format); 396 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 397 if (timeFormatter.Get() == NULL) 398 return B_NO_MEMORY; 399 400 UnicodeString icuString; 401 dateFormatter->format((UDate)time * 1000, icuString); 402 403 icuString.append(UnicodeString::fromUTF8(", ")); 404 405 timeFormatter->format((UDate)time * 1000, icuString); 406 407 CheckedArrayByteSink stringConverter(target, maxSize); 408 icuString.toUTF8(stringConverter); 409 410 if (stringConverter.Overflowed()) 411 return B_BAD_VALUE; 412 413 return stringConverter.NumberOfBytesWritten(); 414 } 415 416 417 status_t 418 BLocale::FormatDateTime(BString* target, time_t time, 419 BDateFormatStyle dateStyle, BTimeFormatStyle timeStyle, 420 const BTimeZone* timeZone) const 421 { 422 BAutolock lock(fLock); 423 if (!lock.IsLocked()) 424 return B_ERROR; 425 426 BString format; 427 fConventions.GetDateFormat(dateStyle, format); 428 ObjectDeleter<DateFormat> dateFormatter(_CreateDateFormatter(format)); 429 if (dateFormatter.Get() == NULL) 430 return B_NO_MEMORY; 431 432 fConventions.GetTimeFormat(timeStyle, format); 433 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 434 if (timeFormatter.Get() == NULL) 435 return B_NO_MEMORY; 436 437 if (timeZone != NULL) { 438 ObjectDeleter<TimeZone> icuTimeZone( 439 TimeZone::createTimeZone(timeZone->ID().String())); 440 if (icuTimeZone.Get() == NULL) 441 return B_NO_MEMORY; 442 timeFormatter->setTimeZone(*icuTimeZone.Get()); 443 } 444 445 UnicodeString icuString; 446 dateFormatter->format((UDate)time * 1000, icuString); 447 icuString.append(UnicodeString::fromUTF8(", ")); 448 timeFormatter->format((UDate)time * 1000, icuString); 449 450 target->Truncate(0); 451 BStringByteSink stringConverter(target); 452 icuString.toUTF8(stringConverter); 453 454 return B_OK; 455 } 456 457 458 // #pragma mark - Time 459 460 461 ssize_t 462 BLocale::FormatTime(char* string, size_t maxSize, time_t time, 463 BTimeFormatStyle style) const 464 { 465 BAutolock lock(fLock); 466 if (!lock.IsLocked()) 467 return B_ERROR; 468 469 BString format; 470 fConventions.GetTimeFormat(style, format); 471 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 472 if (timeFormatter.Get() == NULL) 473 return B_NO_MEMORY; 474 475 UnicodeString icuString; 476 timeFormatter->format((UDate)time * 1000, icuString); 477 478 CheckedArrayByteSink stringConverter(string, maxSize); 479 icuString.toUTF8(stringConverter); 480 481 if (stringConverter.Overflowed()) 482 return B_BAD_VALUE; 483 484 return stringConverter.NumberOfBytesWritten(); 485 } 486 487 488 status_t 489 BLocale::FormatTime(BString* string, time_t time, BTimeFormatStyle style, 490 const BTimeZone* timeZone) const 491 { 492 BAutolock lock(fLock); 493 if (!lock.IsLocked()) 494 return B_ERROR; 495 496 BString format; 497 fConventions.GetTimeFormat(style, format); 498 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 499 if (timeFormatter.Get() == NULL) 500 return B_NO_MEMORY; 501 502 if (timeZone != NULL) { 503 ObjectDeleter<TimeZone> icuTimeZone( 504 TimeZone::createTimeZone(timeZone->ID().String())); 505 if (icuTimeZone.Get() == NULL) 506 return B_NO_MEMORY; 507 timeFormatter->setTimeZone(*icuTimeZone.Get()); 508 } 509 510 UnicodeString icuString; 511 timeFormatter->format((UDate)time * 1000, icuString); 512 513 string->Truncate(0); 514 BStringByteSink stringConverter(string); 515 icuString.toUTF8(stringConverter); 516 517 return B_OK; 518 } 519 520 521 status_t 522 BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount, 523 time_t time, BTimeFormatStyle style) const 524 { 525 BAutolock lock(fLock); 526 if (!lock.IsLocked()) 527 return B_ERROR; 528 529 BString format; 530 fConventions.GetTimeFormat(style, format); 531 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 532 if (timeFormatter.Get() == NULL) 533 return B_NO_MEMORY; 534 535 fieldPositions = NULL; 536 UErrorCode error = U_ZERO_ERROR; 537 ICU_VERSION::FieldPositionIterator positionIterator; 538 UnicodeString icuString; 539 timeFormatter->format((UDate)time * 1000, icuString, &positionIterator, 540 error); 541 542 if (error != U_ZERO_ERROR) 543 return B_ERROR; 544 545 ICU_VERSION::FieldPosition field; 546 std::vector<int> fieldPosStorage; 547 fieldCount = 0; 548 while (positionIterator.next(field)) { 549 fieldPosStorage.push_back(field.getBeginIndex()); 550 fieldPosStorage.push_back(field.getEndIndex()); 551 fieldCount += 2; 552 } 553 554 fieldPositions = (int*) malloc(fieldCount * sizeof(int)); 555 556 for (int i = 0 ; i < fieldCount ; i++ ) 557 fieldPositions[i] = fieldPosStorage[i]; 558 559 string->Truncate(0); 560 BStringByteSink stringConverter(string); 561 icuString.toUTF8(stringConverter); 562 563 return B_OK; 564 } 565 566 567 status_t 568 BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount, 569 BTimeFormatStyle style) const 570 { 571 BAutolock lock(fLock); 572 if (!lock.IsLocked()) 573 return B_ERROR; 574 575 BString format; 576 fConventions.GetTimeFormat(style, format); 577 ObjectDeleter<DateFormat> timeFormatter(_CreateTimeFormatter(format)); 578 if (timeFormatter.Get() == NULL) 579 return B_NO_MEMORY; 580 581 fields = NULL; 582 UErrorCode error = U_ZERO_ERROR; 583 ICU_VERSION::FieldPositionIterator positionIterator; 584 UnicodeString icuString; 585 time_t now; 586 timeFormatter->format((UDate)time(&now) * 1000, icuString, 587 &positionIterator, error); 588 589 if (error != U_ZERO_ERROR) 590 return B_ERROR; 591 592 ICU_VERSION::FieldPosition field; 593 std::vector<int> fieldPosStorage; 594 fieldCount = 0; 595 while (positionIterator.next(field)) { 596 fieldPosStorage.push_back(field.getField()); 597 fieldCount ++; 598 } 599 600 fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement)); 601 602 for (int i = 0 ; i < fieldCount ; i++ ) { 603 switch (fieldPosStorage[i]) { 604 case UDAT_HOUR_OF_DAY1_FIELD: 605 case UDAT_HOUR_OF_DAY0_FIELD: 606 case UDAT_HOUR1_FIELD: 607 case UDAT_HOUR0_FIELD: 608 fields[i] = B_DATE_ELEMENT_HOUR; 609 break; 610 case UDAT_MINUTE_FIELD: 611 fields[i] = B_DATE_ELEMENT_MINUTE; 612 break; 613 case UDAT_SECOND_FIELD: 614 fields[i] = B_DATE_ELEMENT_SECOND; 615 break; 616 case UDAT_AM_PM_FIELD: 617 fields[i] = B_DATE_ELEMENT_AM_PM; 618 break; 619 default: 620 fields[i] = B_DATE_ELEMENT_INVALID; 621 break; 622 } 623 } 624 625 return B_OK; 626 } 627 628 629 // #pragma mark - Numbers 630 631 632 ssize_t 633 BLocale::FormatNumber(char* string, size_t maxSize, double value) const 634 { 635 BString fullString; 636 status_t status = FormatNumber(&fullString, value); 637 if (status != B_OK) 638 return status; 639 640 return strlcpy(string, fullString.String(), maxSize); 641 } 642 643 644 status_t 645 BLocale::FormatNumber(BString* string, double value) const 646 { 647 BAutolock lock(fLock); 648 if (!lock.IsLocked()) 649 return B_ERROR; 650 651 UErrorCode err = U_ZERO_ERROR; 652 ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance( 653 *BFormattingConventions::Private(&fConventions).ICULocale(), 654 NumberFormat::kNumberStyle, err)); 655 656 if (numberFormatter.Get() == NULL) 657 return B_NO_MEMORY; 658 if (U_FAILURE(err)) 659 return B_ERROR; 660 661 UnicodeString icuString; 662 numberFormatter->format(value, icuString); 663 664 string->Truncate(0); 665 BStringByteSink stringConverter(string); 666 icuString.toUTF8(stringConverter); 667 668 return B_OK; 669 } 670 671 672 ssize_t 673 BLocale::FormatNumber(char* string, size_t maxSize, int32 value) const 674 { 675 BString fullString; 676 status_t status = FormatNumber(&fullString, value); 677 if (status != B_OK) 678 return status; 679 680 return strlcpy(string, fullString.String(), maxSize); 681 } 682 683 684 status_t 685 BLocale::FormatNumber(BString* string, int32 value) const 686 { 687 BAutolock lock(fLock); 688 if (!lock.IsLocked()) 689 return B_ERROR; 690 691 UErrorCode err = U_ZERO_ERROR; 692 ObjectDeleter<NumberFormat> numberFormatter(NumberFormat::createInstance( 693 *BFormattingConventions::Private(&fConventions).ICULocale(), 694 NumberFormat::kNumberStyle, err)); 695 696 if (numberFormatter.Get() == NULL) 697 return B_NO_MEMORY; 698 if (U_FAILURE(err)) 699 return B_ERROR; 700 701 UnicodeString icuString; 702 numberFormatter->format((int32_t)value, icuString); 703 704 string->Truncate(0); 705 BStringByteSink stringConverter(string); 706 icuString.toUTF8(stringConverter); 707 708 return B_OK; 709 } 710 711 712 ssize_t 713 BLocale::FormatMonetary(char* string, size_t maxSize, double value) const 714 { 715 BString fullString; 716 status_t status = FormatMonetary(&fullString, value); 717 if (status != B_OK) 718 return status; 719 720 return strlcpy(string, fullString.String(), maxSize); 721 } 722 723 724 status_t 725 BLocale::FormatMonetary(BString* string, double value) const 726 { 727 if (string == NULL) 728 return B_BAD_VALUE; 729 730 BAutolock lock(fLock); 731 if (!lock.IsLocked()) 732 return B_ERROR; 733 734 UErrorCode err = U_ZERO_ERROR; 735 ObjectDeleter<NumberFormat> numberFormatter( 736 NumberFormat::createCurrencyInstance( 737 *BFormattingConventions::Private(&fConventions).ICULocale(), 738 err)); 739 740 if (numberFormatter.Get() == NULL) 741 return B_NO_MEMORY; 742 if (U_FAILURE(err)) 743 return B_ERROR; 744 745 UnicodeString icuString; 746 numberFormatter->format(value, icuString); 747 748 string->Truncate(0); 749 BStringByteSink stringConverter(string); 750 icuString.toUTF8(stringConverter); 751 752 return B_OK; 753 } 754 755 756 DateFormat* 757 BLocale::_CreateDateFormatter(const BString& format) const 758 { 759 Locale* icuLocale 760 = fConventions.UseStringsFromPreferredLanguage() 761 ? BLanguage::Private(&fLanguage).ICULocale() 762 : BFormattingConventions::Private(&fConventions).ICULocale(); 763 764 DateFormat* dateFormatter 765 = DateFormat::createDateInstance(DateFormat::kShort, *icuLocale); 766 if (dateFormatter == NULL) 767 return NULL; 768 769 SimpleDateFormat* dateFormatterImpl 770 = static_cast<SimpleDateFormat*>(dateFormatter); 771 772 UnicodeString pattern(format.String()); 773 dateFormatterImpl->applyPattern(pattern); 774 775 return dateFormatter; 776 } 777 778 779 DateFormat* 780 BLocale::_CreateTimeFormatter(const BString& format) const 781 { 782 Locale* icuLocale 783 = fConventions.UseStringsFromPreferredLanguage() 784 ? BLanguage::Private(&fLanguage).ICULocale() 785 : BFormattingConventions::Private(&fConventions).ICULocale(); 786 787 DateFormat* timeFormatter 788 = DateFormat::createTimeInstance(DateFormat::kShort, *icuLocale); 789 if (timeFormatter == NULL) 790 return NULL; 791 792 SimpleDateFormat* timeFormatterImpl 793 = static_cast<SimpleDateFormat*>(timeFormatter); 794 795 UnicodeString pattern(format.String()); 796 timeFormatterImpl->applyPattern(pattern); 797 798 return timeFormatter; 799 } 800