#include "ICUCategoryData.h"
#include <string.h>
#include <unicode/uchar.h>
U_NAMESPACE_USE
namespace BPrivate {
namespace Libroot {
ICUCategoryData::ICUCategoryData(pthread_key_t tlsKey)
:
fThreadLocalStorageKey(tlsKey)
{
*fPosixLocaleName = '\0';
*fGivenCharset = '\0';
}
ICUCategoryData::~ICUCategoryData()
{
}
status_t
ICUCategoryData::SetTo(const Locale& locale, const char* posixLocaleName)
{
if (!posixLocaleName)
return B_BAD_VALUE;
fLocale = locale;
strlcpy(fPosixLocaleName, posixLocaleName, skMaxPosixLocaleNameLen);
*fGivenCharset = '\0';
const char* charsetStart = strchr(fPosixLocaleName, '.');
if (charsetStart) {
++charsetStart;
int l = 0;
while (charsetStart[l] != '\0' && charsetStart[l] != '@')
++l;
snprintf(fGivenCharset, UCNV_MAX_CONVERTER_NAME_LENGTH, "%.*s", l,
charsetStart);
}
if (!strlen(fGivenCharset))
strcpy(fGivenCharset, "utf-8");
return _SetupConverter();
}
status_t
ICUCategoryData::SetToPosix()
{
fLocale = Locale::createFromName("en_US_POSIX");
strcpy(fPosixLocaleName, "POSIX");
strcpy(fGivenCharset, "US-ASCII");
return _SetupConverter();
}
status_t
ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
const UnicodeString& string, char* destination, int destinationSize,
const char* defaultValue)
{
UConverter* converter;
status_t result = _GetConverter(converter);
if (result != B_OK)
return result;
UErrorCode icuStatus = U_ZERO_ERROR;
ucnv_fromUChars(converter, destination, destinationSize, string.getBuffer(),
string.length(), &icuStatus);
if (!U_SUCCESS(icuStatus)) {
switch (icuStatus) {
case U_BUFFER_OVERFLOW_ERROR:
result = B_NAME_TOO_LONG;
break;
case U_INVALID_CHAR_FOUND:
case U_TRUNCATED_CHAR_FOUND:
case U_ILLEGAL_CHAR_FOUND:
result = B_BAD_DATA;
break;
default:
result = B_ERROR;
break;
}
strlcpy(destination, defaultValue, destinationSize);
}
return result;
}
status_t
ICUCategoryData::_GetConverter(UConverter*& converterOut)
{
ICUThreadLocalStorageValue* tlsValue = NULL;
status_t result = ICUThreadLocalStorageValue::GetInstanceForKey(
fThreadLocalStorageKey, tlsValue);
if (result != B_OK)
return result;
if (tlsValue->converter != NULL) {
if (strcmp(tlsValue->charset, fGivenCharset) == 0) {
converterOut = tlsValue->converter;
return B_OK;
}
ucnv_close(tlsValue->converter);
tlsValue->converter = NULL;
}
UErrorCode icuStatus = U_ZERO_ERROR;
UConverter* icuConverter = ucnv_open(fGivenCharset, &icuStatus);
if (icuConverter == NULL)
return B_NAME_NOT_FOUND;
icuStatus = U_ZERO_ERROR;
ucnv_setToUCallBack(icuConverter, UCNV_TO_U_CALLBACK_STOP, NULL, NULL, NULL,
&icuStatus);
if (!U_SUCCESS(icuStatus)) {
ucnv_close(icuConverter);
return B_ERROR;
}
icuStatus = U_ZERO_ERROR;
ucnv_setFromUCallBack(icuConverter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL,
NULL, &icuStatus);
if (!U_SUCCESS(icuStatus)) {
ucnv_close(icuConverter);
return B_ERROR;
}
tlsValue->converter = icuConverter;
strlcpy(tlsValue->charset, fGivenCharset, sizeof(tlsValue->charset));
converterOut = icuConverter;
return B_OK;
}
status_t
ICUCategoryData::_SetupConverter()
{
UConverter* converter;
return _GetConverter(converter);
}
}
}