xref: /haiku/src/kits/locale/Locale.cpp (revision 56187df6ebd9d1fb16bf954fce8df0999e9e3048)
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 <CountryPrivate.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 static DateFormat* CreateDateFormat(bool longFormat, const Locale& locale,
40 						const BString& format);
41 static DateFormat* CreateTimeFormat(bool longFormat, const Locale& locale,
42 						const BString& format);
43 static void FetchDateFormat(bool longFormat, const Locale& locale,
44 				BString& format);
45 static void FetchTimeFormat(bool longFormat, const Locale& locale,
46 				BString& format);
47 
48 
49 BLocale::BLocale(const BLanguage* language, const BCountry* country)
50 {
51 	if (country != NULL)
52 		fCountry = *country;
53 	else
54 		be_locale->GetCountry(&fCountry);
55 
56 	if (language != NULL)
57 		fLanguage = *language;
58 	else
59 		be_locale->GetLanguage(&fLanguage);
60 
61 	_UpdateFormats();
62 }
63 
64 
65 BLocale::BLocale(const BLocale& other)
66 	:
67 	fCountry(other.fCountry),
68 	fLanguage(other.fLanguage),
69 	fLongDateFormat(other.fLongDateFormat),
70 	fShortDateFormat(other.fShortDateFormat),
71 	fLongTimeFormat(other.fLongTimeFormat),
72 	fShortTimeFormat(other.fShortTimeFormat)
73 {
74 }
75 
76 
77 BLocale&
78 BLocale::operator=(const BLocale& other)
79 {
80 	if (this == &other)
81 		return *this;
82 
83 	fLongDateFormat = other.fLongDateFormat;
84 	fShortDateFormat = other.fShortDateFormat;
85 	fLongTimeFormat = other.fLongTimeFormat;
86 	fShortTimeFormat = other.fShortTimeFormat;
87 
88 	fCountry = other.fCountry;
89 	fLanguage = other.fLanguage;
90 
91 	return *this;
92 }
93 
94 
95 BLocale::~BLocale()
96 {
97 }
98 
99 
100 status_t
101 BLocale::GetCollator(BCollator* collator) const
102 {
103 	if (!collator)
104 		return B_BAD_VALUE;
105 
106 	BAutolock lock(fLock);
107 	if (!lock.IsLocked())
108 		return B_ERROR;
109 
110 	*collator = fCollator;
111 
112 	return B_OK;
113 }
114 
115 
116 status_t
117 BLocale::GetLanguage(BLanguage* language) const
118 {
119 	if (!language)
120 		return B_BAD_VALUE;
121 
122 	BAutolock lock(fLock);
123 	if (!lock.IsLocked())
124 		return B_ERROR;
125 
126 	*language = fLanguage;
127 
128 	return B_OK;
129 }
130 
131 
132 status_t
133 BLocale::GetCountry(BCountry* country) const
134 {
135 	if (!country)
136 		return B_BAD_VALUE;
137 
138 	BAutolock lock(fLock);
139 	if (!lock.IsLocked())
140 		return B_ERROR;
141 
142 	*country = fCountry;
143 
144 	return B_OK;
145 }
146 
147 
148 const char *
149 BLocale::GetString(uint32 id) const
150 {
151 	// Note: this code assumes a certain order of the string bases
152 
153 	BAutolock lock(fLock);
154 	if (!lock.IsLocked())
155 		return "";
156 
157 	if (id >= B_OTHER_STRINGS_BASE) {
158 		if (id == B_CODESET)
159 			return "UTF-8";
160 
161 		return "";
162 	}
163 	return fLanguage.GetString(id);
164 }
165 
166 
167 void
168 BLocale::SetCountry(const BCountry& newCountry)
169 {
170 	BAutolock lock(fLock);
171 	if (!lock.IsLocked())
172 		return;
173 
174 	fCountry = newCountry;
175 
176 	_UpdateFormats();
177 }
178 
179 
180 void
181 BLocale::SetCollator(const BCollator& newCollator)
182 {
183 	BAutolock lock(fLock);
184 	if (!lock.IsLocked())
185 		return;
186 
187 	fCollator = newCollator;
188 }
189 
190 
191 void
192 BLocale::SetLanguage(const BLanguage& newLanguage)
193 {
194 	BAutolock lock(fLock);
195 	if (!lock.IsLocked())
196 		return;
197 
198 	fLanguage = newLanguage;
199 }
200 
201 
202 bool
203 BLocale::GetName(BString& name) const
204 {
205 	Locale icuLocale = Locale::createCanonical(fCountry.Code());
206 	if (icuLocale.isBogus())
207 		return false;
208 
209 	UnicodeString uString;
210 	const Locale* countryLocale = BCountry::Private(&fCountry).ICULocale();
211 	countryLocale->getDisplayName(icuLocale, uString);
212 	BStringByteSink stringConverter(&name);
213 	uString.toUTF8(stringConverter);
214 	return true;
215 }
216 
217 
218 // #pragma mark - Date
219 
220 
221 status_t
222 BLocale::FormatDate(char* string, size_t maxSize, time_t time,
223 	bool longFormat) const
224 {
225 	BAutolock lock(fLock);
226 	if (!lock.IsLocked())
227 		return B_ERROR;
228 
229 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
230 		*BLanguage::Private(&fLanguage).ICULocale(),
231 		longFormat ? fLongDateFormat : fShortDateFormat);
232 	if (dateFormatter.Get() == NULL)
233 		return B_NO_MEMORY;
234 
235 	UnicodeString ICUString;
236 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
237 
238 	CheckedArrayByteSink stringConverter(string, maxSize);
239 	ICUString.toUTF8(stringConverter);
240 
241 	if (stringConverter.Overflowed())
242 		return B_BAD_VALUE;
243 
244 	return B_OK;
245 }
246 
247 
248 status_t
249 BLocale::FormatDate(BString *string, time_t time, bool longFormat,
250 	const BTimeZone* timeZone) const
251 {
252 	BAutolock lock(fLock);
253 	if (!lock.IsLocked())
254 		return B_ERROR;
255 
256 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
257 		*BLanguage::Private(&fLanguage).ICULocale(),
258 		longFormat ? fLongDateFormat : fShortDateFormat);
259 	if (dateFormatter.Get() == NULL)
260 		return B_NO_MEMORY;
261 
262 	if (timeZone != NULL) {
263 		ObjectDeleter<TimeZone> icuTimeZone
264 			= TimeZone::createTimeZone(timeZone->ID().String());
265 		if (icuTimeZone.Get() == NULL)
266 			return B_NO_MEMORY;
267 		dateFormatter->setTimeZone(*icuTimeZone.Get());
268 	}
269 
270 	UnicodeString ICUString;
271 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
272 
273 	string->Truncate(0);
274 	BStringByteSink stringConverter(string);
275 	ICUString.toUTF8(stringConverter);
276 
277 	return B_OK;
278 }
279 
280 
281 status_t
282 BLocale::FormatDate(BString* string, int*& fieldPositions, int& fieldCount,
283 	time_t time, bool longFormat) const
284 {
285 	BAutolock lock(fLock);
286 	if (!lock.IsLocked())
287 		return B_ERROR;
288 
289 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
290 		*BLanguage::Private(&fLanguage).ICULocale(),
291 		longFormat ? fLongDateFormat : fShortDateFormat);
292 	if (dateFormatter.Get() == NULL)
293 		return B_NO_MEMORY;
294 
295 	fieldPositions = NULL;
296 	UErrorCode error = U_ZERO_ERROR;
297 	ICU_VERSION::FieldPositionIterator positionIterator;
298 	UnicodeString ICUString;
299 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString,
300 		&positionIterator, error);
301 
302 	if (error != U_ZERO_ERROR)
303 		return B_ERROR;
304 
305 	ICU_VERSION::FieldPosition field;
306 	std::vector<int> fieldPosStorage;
307 	fieldCount  = 0;
308 	while (positionIterator.next(field)) {
309 		fieldPosStorage.push_back(field.getBeginIndex());
310 		fieldPosStorage.push_back(field.getEndIndex());
311 		fieldCount += 2;
312 	}
313 
314 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
315 
316 	for (int i = 0 ; i < fieldCount ; i++ )
317 		fieldPositions[i] = fieldPosStorage[i];
318 
319 	string->Truncate(0);
320 	BStringByteSink stringConverter(string);
321 
322 	ICUString.toUTF8(stringConverter);
323 
324 	return B_OK;
325 }
326 
327 
328 status_t
329 BLocale::GetDateFormat(BString& format, bool longFormat) const
330 {
331 	BAutolock lock(fLock);
332 	if (!lock.IsLocked())
333 		return B_ERROR;
334 
335 	if (longFormat && fLongDateFormat.Length() > 0)
336 		format = fLongDateFormat;
337 	else if (!longFormat && fShortDateFormat.Length() > 0)
338 		format = fShortDateFormat;
339 	else {
340 		format.Truncate(0);
341 
342 		ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
343 			*BCountry::Private(&fCountry).ICULocale(), format);
344 		if (dateFormatter.Get() == NULL)
345 			return B_NO_MEMORY;
346 
347 		SimpleDateFormat* dateFormatterImpl
348 			= static_cast<SimpleDateFormat*>(dateFormatter.Get());
349 
350 		UnicodeString ICUString;
351 		ICUString = dateFormatterImpl->toPattern(ICUString);
352 
353 		BStringByteSink stringConverter(&format);
354 
355 		ICUString.toUTF8(stringConverter);
356 	}
357 
358 	return B_OK;
359 }
360 
361 
362 status_t
363 BLocale::SetDateFormat(const char* formatString, bool longFormat)
364 {
365 	BAutolock lock(fLock);
366 	if (!lock.IsLocked())
367 		return B_ERROR;
368 
369 	if (longFormat)
370 		fLongDateFormat = formatString;
371 	else
372 		fShortDateFormat = formatString;
373 
374 	return B_OK;
375 }
376 
377 
378 status_t
379 BLocale::GetDateFields(BDateElement*& fields, int& fieldCount,
380 	bool longFormat) const
381 {
382 	BAutolock lock(fLock);
383 	if (!lock.IsLocked())
384 		return B_ERROR;
385 
386 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
387 		*BCountry::Private(&fCountry).ICULocale(),
388 		longFormat ? fLongDateFormat : fShortDateFormat);
389 	if (dateFormatter.Get() == NULL)
390 		return B_NO_MEMORY;
391 
392 	fields = NULL;
393 	UErrorCode error = U_ZERO_ERROR;
394 	ICU_VERSION::FieldPositionIterator positionIterator;
395 	UnicodeString ICUString;
396 	time_t now;
397 	ICUString = dateFormatter->format((UDate)time(&now) * 1000, ICUString,
398 		&positionIterator, error);
399 
400 	if (U_FAILURE(error))
401 		return B_ERROR;
402 
403 	ICU_VERSION::FieldPosition field;
404 	std::vector<int> fieldPosStorage;
405 	fieldCount  = 0;
406 	while (positionIterator.next(field)) {
407 		fieldPosStorage.push_back(field.getField());
408 		fieldCount ++;
409 	}
410 
411 	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
412 
413 	for (int i = 0 ; i < fieldCount ; i++ ) {
414 		switch (fieldPosStorage[i]) {
415 			case UDAT_YEAR_FIELD:
416 				fields[i] = B_DATE_ELEMENT_YEAR;
417 				break;
418 			case UDAT_MONTH_FIELD:
419 				fields[i] = B_DATE_ELEMENT_MONTH;
420 				break;
421 			case UDAT_DATE_FIELD:
422 				fields[i] = B_DATE_ELEMENT_DAY;
423 				break;
424 			default:
425 				fields[i] = B_DATE_ELEMENT_INVALID;
426 				break;
427 		}
428 	}
429 
430 	return B_OK;
431 }
432 
433 
434 int
435 BLocale::StartOfWeek() const
436 {
437 	BAutolock lock(fLock);
438 	if (!lock.IsLocked())
439 		return B_ERROR;
440 
441 	UErrorCode err = U_ZERO_ERROR;
442 	Calendar* c
443 		= Calendar::createInstance(*BCountry::Private(&fCountry).ICULocale(),
444 			err);
445 
446 	if (err == U_ZERO_ERROR && c->getFirstDayOfWeek(err) == UCAL_SUNDAY) {
447 		delete c;
448 		return B_WEEK_START_SUNDAY;
449 	} else {
450 		delete c;
451 		// Might be another day, but BeAPI will not handle it
452 		return B_WEEK_START_MONDAY;
453 	}
454 }
455 
456 
457 status_t
458 BLocale::FormatDateTime(char* target, size_t maxSize, time_t time,
459 	bool longFormat) const
460 {
461 	BAutolock lock(fLock);
462 	if (!lock.IsLocked())
463 		return B_ERROR;
464 
465 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
466 		*BLanguage::Private(&fLanguage).ICULocale(),
467 		longFormat ? fLongDateFormat : fShortDateFormat);
468 	if (dateFormatter.Get() == NULL)
469 		return B_NO_MEMORY;
470 
471 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
472 		*BLanguage::Private(&fLanguage).ICULocale(),
473 		longFormat ? fLongTimeFormat : fShortTimeFormat);
474 	if (timeFormatter.Get() == NULL)
475 		return B_NO_MEMORY;
476 
477 	UnicodeString ICUString;
478 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
479 
480 	ICUString.append(UnicodeString::fromUTF8(", "));
481 
482 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
483 
484 	CheckedArrayByteSink stringConverter(target, maxSize);
485 	ICUString.toUTF8(stringConverter);
486 
487 	if (stringConverter.Overflowed())
488 		return B_BAD_VALUE;
489 
490 	return B_OK;
491 }
492 
493 
494 status_t
495 BLocale::FormatDateTime(BString* target, time_t time, bool longFormat,
496 	const BTimeZone* timeZone) const
497 {
498 	BAutolock lock(fLock);
499 	if (!lock.IsLocked())
500 		return B_ERROR;
501 
502 	ObjectDeleter<DateFormat> dateFormatter = CreateDateFormat(longFormat,
503 		*BLanguage::Private(&fLanguage).ICULocale(),
504 		longFormat ? fLongDateFormat : fShortDateFormat);
505 	if (dateFormatter.Get() == NULL)
506 		return B_NO_MEMORY;
507 
508 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
509 		*BLanguage::Private(&fLanguage).ICULocale(),
510 		longFormat ? fLongTimeFormat : fShortTimeFormat);
511 	if (timeFormatter.Get() == NULL)
512 		return B_NO_MEMORY;
513 
514 	if (timeZone != NULL) {
515 		ObjectDeleter<TimeZone> icuTimeZone
516 			= TimeZone::createTimeZone(timeZone->ID().String());
517 		if (icuTimeZone.Get() == NULL)
518 			return B_NO_MEMORY;
519 		timeFormatter->setTimeZone(*icuTimeZone.Get());
520 	}
521 
522 	UnicodeString ICUString;
523 	ICUString = dateFormatter->format((UDate)time * 1000, ICUString);
524 
525 	ICUString.append(UnicodeString::fromUTF8(", "));
526 
527 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
528 
529 	target->Truncate(0);
530 	BStringByteSink stringConverter(target);
531 	ICUString.toUTF8(stringConverter);
532 
533 	return B_OK;
534 }
535 
536 
537 // #pragma mark - Time
538 
539 
540 status_t
541 BLocale::FormatTime(char* string, size_t maxSize, time_t time,
542 	bool longFormat) const
543 {
544 	BAutolock lock(fLock);
545 	if (!lock.IsLocked())
546 		return B_ERROR;
547 
548 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
549 		*BLanguage::Private(&fLanguage).ICULocale(),
550 		longFormat ? fLongTimeFormat : fShortTimeFormat);
551 	if (timeFormatter.Get() == NULL)
552 		return B_NO_MEMORY;
553 
554 	UnicodeString ICUString;
555 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
556 
557 	CheckedArrayByteSink stringConverter(string, maxSize);
558 
559 	ICUString.toUTF8(stringConverter);
560 
561 	if (stringConverter.Overflowed())
562 		return B_BAD_VALUE;
563 
564 	return B_OK;
565 }
566 
567 
568 status_t
569 BLocale::FormatTime(BString* string, time_t time, bool longFormat,
570 	const BTimeZone* timeZone) const
571 {
572 	BAutolock lock(fLock);
573 	if (!lock.IsLocked())
574 		return B_ERROR;
575 
576 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
577 		*BLanguage::Private(&fLanguage).ICULocale(),
578 		longFormat ? fLongTimeFormat : fShortTimeFormat);
579 	if (timeFormatter.Get() == NULL)
580 		return B_NO_MEMORY;
581 
582 	if (timeZone != NULL) {
583 		ObjectDeleter<TimeZone> icuTimeZone
584 			= TimeZone::createTimeZone(timeZone->ID().String());
585 		if (icuTimeZone.Get() == NULL)
586 			return B_NO_MEMORY;
587 		timeFormatter->setTimeZone(*icuTimeZone.Get());
588 	}
589 
590 	UnicodeString ICUString;
591 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString);
592 
593 	string->Truncate(0);
594 	BStringByteSink stringConverter(string);
595 
596 	ICUString.toUTF8(stringConverter);
597 
598 	return B_OK;
599 }
600 
601 
602 status_t
603 BLocale::FormatTime(BString* string, int*& fieldPositions, int& fieldCount,
604 	time_t time, bool longFormat) const
605 {
606 	BAutolock lock(fLock);
607 	if (!lock.IsLocked())
608 		return B_ERROR;
609 
610 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
611 		*BLanguage::Private(&fLanguage).ICULocale(),
612 		longFormat ? fLongTimeFormat : fShortTimeFormat);
613 	if (timeFormatter.Get() == NULL)
614 		return B_NO_MEMORY;
615 
616 	fieldPositions = NULL;
617 	UErrorCode error = U_ZERO_ERROR;
618 	ICU_VERSION::FieldPositionIterator positionIterator;
619 	UnicodeString ICUString;
620 	ICUString = timeFormatter->format((UDate)time * 1000, ICUString,
621 		&positionIterator, error);
622 
623 	if (error != U_ZERO_ERROR)
624 		return B_ERROR;
625 
626 	ICU_VERSION::FieldPosition field;
627 	std::vector<int> fieldPosStorage;
628 	fieldCount  = 0;
629 	while (positionIterator.next(field)) {
630 		fieldPosStorage.push_back(field.getBeginIndex());
631 		fieldPosStorage.push_back(field.getEndIndex());
632 		fieldCount += 2;
633 	}
634 
635 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
636 
637 	for (int i = 0 ; i < fieldCount ; i++ )
638 		fieldPositions[i] = fieldPosStorage[i];
639 
640 	string->Truncate(0);
641 	BStringByteSink stringConverter(string);
642 
643 	ICUString.toUTF8(stringConverter);
644 
645 	return B_OK;
646 }
647 
648 
649 status_t
650 BLocale::GetTimeFields(BDateElement*& fields, int& fieldCount,
651 	bool longFormat) const
652 {
653 	BAutolock lock(fLock);
654 	if (!lock.IsLocked())
655 		return B_ERROR;
656 
657 	ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
658 		*BCountry::Private(&fCountry).ICULocale(),
659 		longFormat ? fLongTimeFormat : fShortTimeFormat);
660 	if (timeFormatter.Get() == NULL)
661 		return B_NO_MEMORY;
662 
663 	fields = NULL;
664 	UErrorCode error = U_ZERO_ERROR;
665 	ICU_VERSION::FieldPositionIterator positionIterator;
666 	UnicodeString ICUString;
667 	time_t now;
668 	ICUString = timeFormatter->format((UDate)time(&now) * 1000,	ICUString,
669 		&positionIterator, error);
670 
671 	if (error != U_ZERO_ERROR)
672 		return B_ERROR;
673 
674 	ICU_VERSION::FieldPosition field;
675 	std::vector<int> fieldPosStorage;
676 	fieldCount  = 0;
677 	while (positionIterator.next(field)) {
678 		fieldPosStorage.push_back(field.getField());
679 		fieldCount ++;
680 	}
681 
682 	fields = (BDateElement*) malloc(fieldCount * sizeof(BDateElement));
683 
684 	for (int i = 0 ; i < fieldCount ; i++ ) {
685 		switch (fieldPosStorage[i]) {
686 			case UDAT_HOUR_OF_DAY1_FIELD:
687 			case UDAT_HOUR_OF_DAY0_FIELD:
688 			case UDAT_HOUR1_FIELD:
689 			case UDAT_HOUR0_FIELD:
690 				fields[i] = B_DATE_ELEMENT_HOUR;
691 				break;
692 			case UDAT_MINUTE_FIELD:
693 				fields[i] = B_DATE_ELEMENT_MINUTE;
694 				break;
695 			case UDAT_SECOND_FIELD:
696 				fields[i] = B_DATE_ELEMENT_SECOND;
697 				break;
698 			case UDAT_AM_PM_FIELD:
699 				fields[i] = B_DATE_ELEMENT_AM_PM;
700 				break;
701 			default:
702 				fields[i] = B_DATE_ELEMENT_INVALID;
703 				break;
704 		}
705 	}
706 
707 	return B_OK;
708 }
709 
710 
711 status_t
712 BLocale::SetTimeFormat(const char* formatString, bool longFormat)
713 {
714 	BAutolock lock(fLock);
715 	if (!lock.IsLocked())
716 		return B_ERROR;
717 
718 	if (longFormat)
719 		fLongTimeFormat = formatString;
720 	else
721 		fShortTimeFormat = formatString;
722 
723 	return B_OK;
724 }
725 
726 
727 status_t
728 BLocale::GetTimeFormat(BString& format, bool longFormat) const
729 {
730 	BAutolock lock(fLock);
731 	if (!lock.IsLocked())
732 		return B_ERROR;
733 
734 	if (longFormat && fLongTimeFormat.Length() > 0)
735 		format = fLongTimeFormat;
736 	else if (!longFormat && fShortTimeFormat.Length() > 0)
737 		format = fShortTimeFormat;
738 	else {
739 		format.Truncate(0);
740 
741 		ObjectDeleter<DateFormat> timeFormatter = CreateTimeFormat(longFormat,
742 			*BCountry::Private(&fCountry).ICULocale(),
743 			longFormat ? fLongTimeFormat : fShortTimeFormat);
744 		if (timeFormatter.Get() == NULL)
745 			return B_NO_MEMORY;
746 
747 		SimpleDateFormat* timeFormatterImpl
748 			= static_cast<SimpleDateFormat*>(timeFormatter.Get());
749 
750 		UnicodeString ICUString;
751 		ICUString = timeFormatterImpl->toPattern(ICUString);
752 
753 		BStringByteSink stringConverter(&format);
754 		ICUString.toUTF8(stringConverter);
755 	}
756 
757 	return B_OK;
758 }
759 
760 
761 void
762 BLocale::_UpdateFormats()
763 {
764 	FetchDateFormat(true, *BCountry::Private(&fCountry).ICULocale(),
765 		this->fLongDateFormat);
766 	FetchDateFormat(false, *BCountry::Private(&fCountry).ICULocale(),
767 		this->fShortDateFormat);
768 	FetchTimeFormat(true, *BCountry::Private(&fCountry).ICULocale(),
769 		this->fLongTimeFormat);
770 	FetchTimeFormat(false, *BCountry::Private(&fCountry).ICULocale(),
771 		this->fShortTimeFormat);
772 }
773 
774 
775 // #pragma mark - Numbers
776 
777 
778 status_t
779 BLocale::FormatNumber(char* string, size_t maxSize, double value) const
780 {
781 	BString fullString;
782 	status_t status = FormatNumber(&fullString, value);
783 	if (status == B_OK)
784 		strlcpy(string, fullString.String(), maxSize);
785 
786 	return status;
787 }
788 
789 
790 status_t
791 BLocale::FormatNumber(BString* string, double value) const
792 {
793 	BAutolock lock(fLock);
794 	if (!lock.IsLocked())
795 		return B_ERROR;
796 
797 	UErrorCode err = U_ZERO_ERROR;
798 	ObjectDeleter<NumberFormat> numberFormatter	= NumberFormat::createInstance(
799 		*BCountry::Private(&fCountry).ICULocale(), NumberFormat::kNumberStyle,
800 		err);
801 
802 	if (numberFormatter.Get() == NULL)
803 		return B_NO_MEMORY;
804 	if (U_FAILURE(err))
805 		return B_ERROR;
806 
807 	UnicodeString ICUString;
808 	ICUString = numberFormatter->format(value, ICUString);
809 
810 	string->Truncate(0);
811 	BStringByteSink stringConverter(string);
812 	ICUString.toUTF8(stringConverter);
813 
814 	return B_OK;
815 }
816 
817 
818 status_t
819 BLocale::FormatNumber(char* string, size_t maxSize, int32 value) const
820 {
821 	BString fullString;
822 	status_t status = FormatNumber(&fullString, value);
823 	if (status == B_OK)
824 		strlcpy(string, fullString.String(), maxSize);
825 
826 	return status;
827 }
828 
829 
830 status_t
831 BLocale::FormatNumber(BString* string, int32 value) const
832 {
833 	BAutolock lock(fLock);
834 	if (!lock.IsLocked())
835 		return B_ERROR;
836 
837 	UErrorCode err = U_ZERO_ERROR;
838 	ObjectDeleter<NumberFormat> numberFormatter	= NumberFormat::createInstance(
839 		*BCountry::Private(&fCountry).ICULocale(), NumberFormat::kNumberStyle,
840 		err);
841 
842 	if (numberFormatter.Get() == NULL)
843 		return B_NO_MEMORY;
844 	if (U_FAILURE(err))
845 		return B_ERROR;
846 
847 	UnicodeString ICUString;
848 	ICUString = numberFormatter->format((int32_t)value, ICUString);
849 
850 	string->Truncate(0);
851 	BStringByteSink stringConverter(string);
852 	ICUString.toUTF8(stringConverter);
853 
854 	return B_OK;
855 }
856 
857 
858 ssize_t
859 BLocale::FormatMonetary(char* string, size_t maxSize, double value) const
860 {
861 	BString fullString;
862 	ssize_t written = FormatMonetary(&fullString, value);
863 	if (written < 0)
864 		return written;
865 
866 	return strlcpy(string, fullString.String(), maxSize);
867 }
868 
869 
870 ssize_t
871 BLocale::FormatMonetary(BString* string, double value) const
872 {
873 	if (string == NULL)
874 		return B_BAD_VALUE;
875 
876 	BAutolock lock(fLock);
877 	if (!lock.IsLocked())
878 		return B_ERROR;
879 
880 	UErrorCode err;
881 	ObjectDeleter<NumberFormat> numberFormatter
882 		= NumberFormat::createCurrencyInstance(
883 			*BCountry::Private(&fCountry).ICULocale(), err);
884 
885 	if (numberFormatter.Get() == NULL)
886 		return B_NO_MEMORY;
887 	if (U_FAILURE(err))
888 		return B_ERROR;
889 
890 	UnicodeString ICUString;
891 	ICUString = numberFormatter->format(value, ICUString);
892 
893 	string->Truncate(0);
894 	BStringByteSink stringConverter(string);
895 	ICUString.toUTF8(stringConverter);
896 
897 	return string->Length();
898 }
899 
900 
901 status_t
902 BLocale::FormatMonetary(BString* string, int*& fieldPositions,
903 	BNumberElement*& fieldTypes, int& fieldCount, double value) const
904 {
905 	BAutolock lock(fLock);
906 	if (!lock.IsLocked())
907 		return B_ERROR;
908 
909 	UErrorCode err = U_ZERO_ERROR;
910 	ObjectDeleter<NumberFormat> numberFormatter
911 		= NumberFormat::createCurrencyInstance(
912 			*BCountry::Private(&fCountry).ICULocale(), err);
913 	if (U_FAILURE(err))
914 		return B_NO_MEMORY;
915 
916 	fieldPositions = NULL;
917 	fieldTypes = NULL;
918 	ICU_VERSION::FieldPositionIterator positionIterator;
919 	UnicodeString ICUString;
920 	ICUString = numberFormatter->format(value, ICUString, &positionIterator,
921 		err);
922 
923 	if (err != U_ZERO_ERROR)
924 		return B_ERROR;
925 
926 	ICU_VERSION::FieldPosition field;
927 	std::vector<int> fieldPosStorage;
928 	std::vector<int> fieldTypeStorage;
929 	fieldCount  = 0;
930 	while (positionIterator.next(field)) {
931 		fieldTypeStorage.push_back(field.getField());
932 		fieldPosStorage.push_back(field.getBeginIndex() | (field.getEndIndex() << 16));
933 		fieldCount ++;
934 
935 	}
936 
937 	fieldPositions = (int*) malloc(fieldCount * sizeof(int));
938 	fieldTypes = (BNumberElement*) malloc(fieldCount * sizeof(BNumberElement));
939 
940 	for (int i = 0 ; i < fieldCount ; i++ ) {
941 		fieldPositions[i] = fieldPosStorage[i];
942 		switch (fieldTypeStorage[i]) {
943 			case NumberFormat::kCurrencyField:
944 				fieldTypes[i] = B_NUMBER_ELEMENT_CURRENCY;
945 				break;
946 			case NumberFormat::kIntegerField:
947 				fieldTypes[i] = B_NUMBER_ELEMENT_INTEGER;
948 				break;
949 			case NumberFormat::kFractionField:
950 				fieldTypes[i] = B_NUMBER_ELEMENT_FRACTIONAL;
951 				break;
952 			default:
953 				fieldTypes[i] = B_NUMBER_ELEMENT_INVALID;
954 				break;
955 		}
956 	}
957 
958 	string->Truncate(0);
959 	BStringByteSink stringConverter(string);
960 
961 	ICUString.toUTF8(stringConverter);
962 
963 	return B_OK;
964 }
965 
966 
967 status_t
968 BLocale::GetCurrencySymbol(BString& result) const
969 {
970 	BAutolock lock(fLock);
971 	if (!lock.IsLocked())
972 		return B_ERROR;
973 
974 	UErrorCode error = U_ZERO_ERROR;
975 	NumberFormat* format = NumberFormat::createCurrencyInstance(
976 		*BCountry::Private(&fCountry).ICULocale(), error);
977 
978 	if (U_FAILURE(error))
979 		return B_ERROR;
980 
981 	char* symbol = (char*)malloc(20);
982 	u_strToUTF8(symbol, 20, NULL, format->getCurrency(), -1, &error);
983 	if (U_FAILURE(error))
984 		return B_BAD_DATA;
985 	result.Append(symbol);
986 	delete format;
987 	delete symbol;
988 	return B_OK;
989 }
990 
991 
992 // #pragma mark - Helpers
993 
994 
995 static DateFormat*
996 CreateDateFormat(bool longFormat, const Locale& locale,	const BString& format)
997 {
998 	DateFormat* dateFormatter = DateFormat::createDateInstance(
999 		longFormat ? DateFormat::kFull : DateFormat::kShort, locale);
1000 
1001 	if (format.Length() > 0) {
1002 		SimpleDateFormat* dateFormatterImpl
1003 			= static_cast<SimpleDateFormat*>(dateFormatter);
1004 
1005 		UnicodeString pattern(format.String());
1006 		dateFormatterImpl->applyPattern(pattern);
1007 	}
1008 
1009 	return dateFormatter;
1010 }
1011 
1012 
1013 static DateFormat*
1014 CreateTimeFormat(bool longFormat, const Locale& locale, const BString& format)
1015 {
1016 	DateFormat* timeFormatter = DateFormat::createTimeInstance(
1017 		longFormat ? DateFormat::kMedium: DateFormat::kShort, locale);
1018 
1019 	if (format.Length() > 0) {
1020 		SimpleDateFormat* timeFormatterImpl
1021 			= static_cast<SimpleDateFormat*>(timeFormatter);
1022 
1023 		UnicodeString pattern(format.String());
1024 		timeFormatterImpl->applyPattern(pattern);
1025 	}
1026 
1027 	return timeFormatter;
1028 }
1029 
1030 
1031 static void
1032 FetchDateFormat(bool longFormat, const Locale& locale, BString& format)
1033 {
1034 	DateFormat* dateFormatter = DateFormat::createDateInstance(
1035 		longFormat ? DateFormat::kFull : DateFormat::kShort, locale);
1036 
1037 	SimpleDateFormat* dateFormatterImpl
1038 		= static_cast<SimpleDateFormat*>(dateFormatter);
1039 
1040 	UnicodeString pattern;
1041 	dateFormatterImpl->toPattern(pattern);
1042 	format.Truncate(0);
1043 	BStringByteSink stringConverter(&format);
1044 	pattern.toUTF8(stringConverter);
1045 }
1046 
1047 
1048 static void
1049 FetchTimeFormat(bool longFormat, const Locale& locale, BString& format)
1050 {
1051 	DateFormat* timeFormatter = DateFormat::createTimeInstance(
1052 		longFormat ? DateFormat::kMedium : DateFormat::kShort, locale);
1053 
1054 	SimpleDateFormat* timeFormatterImpl
1055 		= static_cast<SimpleDateFormat*>(timeFormatter);
1056 
1057 	UnicodeString pattern;
1058 	timeFormatterImpl->toPattern(pattern);
1059 	format.Truncate(0);
1060 	BStringByteSink stringConverter(&format);
1061 	pattern.toUTF8(stringConverter);
1062 }
1063