headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / add-ons / icu / ICUCategoryData.cpp
bloba2ca4c13f1112c460ba577ab92c6e14ce5fc2bc8
1 /*
2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ICUCategoryData.h"
9 #include <string.h>
11 #include <unicode/uchar.h>
14 namespace BPrivate {
15 namespace Libroot {
18 ICUCategoryData::ICUCategoryData(pthread_key_t tlsKey)
20 fThreadLocalStorageKey(tlsKey)
22 *fPosixLocaleName = '\0';
23 *fGivenCharset = '\0';
27 ICUCategoryData::~ICUCategoryData()
32 status_t
33 ICUCategoryData::SetTo(const Locale& locale, const char* posixLocaleName)
35 if (!posixLocaleName)
36 return B_BAD_VALUE;
38 fLocale = locale;
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
44 // ignored).
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, '.');
49 if (charsetStart) {
50 ++charsetStart;
51 int l = 0;
52 while (charsetStart[l] != '\0' && charsetStart[l] != '@')
53 ++l;
54 snprintf(fGivenCharset, UCNV_MAX_CONVERTER_NAME_LENGTH, "%.*s", l,
55 charsetStart);
57 if (!strlen(fGivenCharset))
58 strcpy(fGivenCharset, "utf-8");
60 return _SetupConverter();
64 status_t
65 ICUCategoryData::SetToPosix()
67 fLocale = Locale::createFromName("en_US_POSIX");
68 strcpy(fPosixLocaleName, "POSIX");
69 strcpy(fGivenCharset, "US-ASCII");
71 return _SetupConverter();
75 status_t
76 ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
77 const UnicodeString& string, char* destination, int destinationSize,
78 const char* defaultValue)
80 UConverter* converter;
81 status_t result = _GetConverter(converter);
82 if (result != B_OK)
83 return result;
85 UErrorCode icuStatus = U_ZERO_ERROR;
86 ucnv_fromUChars(converter, destination, destinationSize, string.getBuffer(),
87 string.length(), &icuStatus);
88 if (!U_SUCCESS(icuStatus)) {
89 switch (icuStatus) {
90 case U_BUFFER_OVERFLOW_ERROR:
91 result = B_NAME_TOO_LONG;
92 break;
93 case U_INVALID_CHAR_FOUND:
94 case U_TRUNCATED_CHAR_FOUND:
95 case U_ILLEGAL_CHAR_FOUND:
96 result = B_BAD_DATA;
97 break;
98 default:
99 result = B_ERROR;
100 break;
102 strlcpy(destination, defaultValue, destinationSize);
105 return result;
109 status_t
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);
116 if (result != B_OK)
117 return result;
119 if (tlsValue->converter != NULL) {
120 if (strcmp(tlsValue->charset, fGivenCharset) == 0) {
121 converterOut = tlsValue->converter;
122 return B_OK;
125 // charset no longer matches the converter, we need to dump it and
126 // create a new one
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,
140 &icuStatus);
141 if (!U_SUCCESS(icuStatus)) {
142 ucnv_close(icuConverter);
143 return B_ERROR;
145 icuStatus = U_ZERO_ERROR;
146 ucnv_setFromUCallBack(icuConverter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL,
147 NULL, &icuStatus);
148 if (!U_SUCCESS(icuStatus)) {
149 ucnv_close(icuConverter);
150 return B_ERROR;
153 tlsValue->converter = icuConverter;
154 strlcpy(tlsValue->charset, fGivenCharset, sizeof(tlsValue->charset));
156 converterOut = icuConverter;
158 return B_OK;
162 status_t
163 ICUCategoryData::_SetupConverter()
165 UConverter* converter;
166 return _GetConverter(converter);
170 } // namespace Libroot
171 } // namespace BPrivate