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