2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
7 #include "ICUCategoryData.h"
11 #include <unicode/uchar.h>
18 ICUCategoryData::ICUCategoryData(pthread_key_t tlsKey
)
20 fThreadLocalStorageKey(tlsKey
)
22 *fPosixLocaleName
= '\0';
23 *fGivenCharset
= '\0';
27 ICUCategoryData::~ICUCategoryData()
33 ICUCategoryData::SetTo(const Locale
& locale
, const char* posixLocaleName
)
39 strlcpy(fPosixLocaleName
, posixLocaleName
, skMaxPosixLocaleNameLen
);
40 *fGivenCharset
= '\0';
42 // POSIX locales often contain an embedded charset, but ICU does not
43 // handle these within locales (that part of the name is simply
45 // We need to fetch the charset specification and lookup an appropriate
46 // ICU charset converter. This converter will later be used to get info
47 // about ctype properties.
48 const char* charsetStart
= strchr(fPosixLocaleName
, '.');
52 while (charsetStart
[l
] != '\0' && charsetStart
[l
] != '@')
54 snprintf(fGivenCharset
, UCNV_MAX_CONVERTER_NAME_LENGTH
, "%.*s", l
,
57 if (!strlen(fGivenCharset
))
58 strcpy(fGivenCharset
, "utf-8");
60 return _SetupConverter();
65 ICUCategoryData::SetToPosix()
67 fLocale
= Locale::createFromName("en_US_POSIX");
68 strcpy(fPosixLocaleName
, "POSIX");
69 strcpy(fGivenCharset
, "US-ASCII");
71 return _SetupConverter();
76 ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
77 const UnicodeString
& string
, char* destination
, int destinationSize
,
78 const char* defaultValue
)
80 UConverter
* converter
;
81 status_t result
= _GetConverter(converter
);
85 UErrorCode icuStatus
= U_ZERO_ERROR
;
86 ucnv_fromUChars(converter
, destination
, destinationSize
, string
.getBuffer(),
87 string
.length(), &icuStatus
);
88 if (!U_SUCCESS(icuStatus
)) {
90 case U_BUFFER_OVERFLOW_ERROR
:
91 result
= B_NAME_TOO_LONG
;
93 case U_INVALID_CHAR_FOUND
:
94 case U_TRUNCATED_CHAR_FOUND
:
95 case U_ILLEGAL_CHAR_FOUND
:
102 strlcpy(destination
, defaultValue
, destinationSize
);
110 ICUCategoryData::_GetConverter(UConverter
*& converterOut
)
112 // we use different converters per thread to avoid concurrent accesses
113 ICUThreadLocalStorageValue
* tlsValue
= NULL
;
114 status_t result
= ICUThreadLocalStorageValue::GetInstanceForKey(
115 fThreadLocalStorageKey
, tlsValue
);
119 if (tlsValue
->converter
!= NULL
) {
120 if (strcmp(tlsValue
->charset
, fGivenCharset
) == 0) {
121 converterOut
= tlsValue
->converter
;
125 // charset no longer matches the converter, we need to dump it and
127 ucnv_close(tlsValue
->converter
);
128 tlsValue
->converter
= NULL
;
131 // create a new converter for the current charset
132 UErrorCode icuStatus
= U_ZERO_ERROR
;
133 UConverter
* icuConverter
= ucnv_open(fGivenCharset
, &icuStatus
);
134 if (icuConverter
== NULL
)
135 return B_NAME_NOT_FOUND
;
137 // setup the new converter to stop upon any errors
138 icuStatus
= U_ZERO_ERROR
;
139 ucnv_setToUCallBack(icuConverter
, UCNV_TO_U_CALLBACK_STOP
, NULL
, NULL
, NULL
,
141 if (!U_SUCCESS(icuStatus
)) {
142 ucnv_close(icuConverter
);
145 icuStatus
= U_ZERO_ERROR
;
146 ucnv_setFromUCallBack(icuConverter
, UCNV_FROM_U_CALLBACK_STOP
, NULL
, NULL
,
148 if (!U_SUCCESS(icuStatus
)) {
149 ucnv_close(icuConverter
);
153 tlsValue
->converter
= icuConverter
;
154 strlcpy(tlsValue
->charset
, fGivenCharset
, sizeof(tlsValue
->charset
));
156 converterOut
= icuConverter
;
163 ICUCategoryData::_SetupConverter()
165 UConverter
* converter
;
166 return _GetConverter(converter
);
170 } // namespace Libroot
171 } // namespace BPrivate