Add multibyte-support to ctype-locale backend.

* add actual converter methods MultibyteToWchar() and WcharToMultibyte()
  to locale backend and implement them in the ctype subpart
* add management code for maintaining converters referenced by mbstate_t
This commit is contained in:
Oliver Tappe
2011-11-22 18:17:58 +01:00
parent 0f21cf0ca0
commit 28ae43d033
5 changed files with 176 additions and 1 deletions
@@ -30,9 +30,20 @@ public:
status_t ToWCTrans(wint_t wc, wctrans_t transition,
wint_t& result);
status_t MultibyteToWchar(wchar_t* wcOut, const char* mb,
size_t mbLength, mbstate_t* mbState,
size_t& lengthOut);
status_t WcharToMultibyte(char* mbOut, wchar_t wc,
mbstate_t* mbState, size_t& lengthOut);
const char* GetLanginfo(int index);
private:
status_t _GetConverterForMbState(mbstate_t* mbState,
ICUConverterRef& converterRefOut);
status_t _DropConverterFromMbState(mbstate_t* mbState);
/*
* The following arrays have 384 elements where the elements at
* index -128..-2 mirror the elements at index 128..255 (to protect
@@ -41,6 +41,12 @@ public:
virtual status_t ToWCTrans(wint_t wc, wctrans_t transition,
wint_t& result);
virtual status_t MultibyteToWchar(wchar_t* wcOut, const char* mb,
size_t mbLength, mbstate_t* mbState,
size_t& lengthOut);
virtual status_t WcharToMultibyte(char* mbOut, wchar_t wc,
mbstate_t* mbState, size_t& lengthOut);
virtual const char* GetLanginfo(int index);
virtual status_t Strcoll(const char* a, const char* b, int& out);
@@ -123,6 +123,12 @@ public:
virtual status_t ToWCTrans(wint_t wc, wctrans_t transition,
wint_t& result) = 0;
virtual status_t MultibyteToWchar(wchar_t* wcOut, const char* mb,
size_t mbLength, mbstate_t* mbState,
size_t& lengthOut) = 0;
virtual status_t WcharToMultibyte(char* mbOut, wchar_t wc,
mbstate_t* mbState, size_t& lengthOut) = 0;
virtual const char* GetLanginfo(int index) = 0;
virtual status_t Strcoll(const char* a, const char* b,
+133 -1
View File
@@ -54,8 +54,10 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
return result;
UConverter* converter = converterRef->Converter();
ucnv_reset(converter);
fDataBridge->setMbCurMax(ucnv_getMaxCharSize(converter));
char buffer[] = { 0, 0 };
for (int i = 0; i < 256; ++i) {
const char* source = buffer;
@@ -130,6 +132,8 @@ ICUCtypeData::SetToPosix()
memcpy(fClassInfo, fDataBridge->posixClassInfo, sizeof(fClassInfo));
memcpy(fToLowerMap, fDataBridge->posixToLowerMap, sizeof(fToLowerMap));
memcpy(fToUpperMap, fDataBridge->posixToUpperMap, sizeof(fToUpperMap));
fDataBridge->setMbCurMax(1);
}
return result;
@@ -189,6 +193,94 @@ ICUCtypeData::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result)
}
status_t
ICUCtypeData::MultibyteToWchar(wchar_t* wcOut, const char* mb, size_t mbLen,
mbstate_t* mbState, size_t& lengthOut)
{
ICUConverterRef converterRef;
status_t result = _GetConverterForMbState(mbState, converterRef);
if (result != B_OK)
return result;
UConverter* converter = converterRef->Converter();
// do the conversion
UErrorCode icuStatus = U_ZERO_ERROR;
const char* buffer = mb;
UChar targetBuffer[2];
UChar* target = targetBuffer;
ucnv_toUnicode(converter, &target, target + 1, &buffer, buffer + mbLen,
NULL, FALSE, &icuStatus);
size_t sourceLengthUsed = buffer - mb;
size_t targetLengthUsed = (size_t)(target - targetBuffer);
if (icuStatus == U_BUFFER_OVERFLOW_ERROR && targetLengthUsed > 0) {
// we've got one character, which is all that we wanted
icuStatus = U_ZERO_ERROR;
}
UChar32 unicodeChar = 0xBADBEEF;
if (!U_SUCCESS(icuStatus)) {
// conversion failed because of illegal character sequence
result = B_BAD_DATA;
} else if (targetLengthUsed == 0) {
mbState->count = sourceLengthUsed;
result = B_BAD_INDEX;
} else {
U16_GET(targetBuffer, 0, 0, 2, unicodeChar);
if (unicodeChar == 0) {
// reset to initial state
_DropConverterFromMbState(mbState);
memset(mbState, 0, sizeof(mbstate_t));
lengthOut = 0;
} else {
mbState->count = 0;
lengthOut = sourceLengthUsed;
}
if (wcOut != NULL)
*wcOut = unicodeChar;
result = B_OK;
}
return result;
}
status_t
ICUCtypeData::WcharToMultibyte(char* mbOut, wchar_t wc, mbstate_t* mbState,
size_t& lengthOut)
{
ICUConverterRef converterRef;
status_t result = _GetConverterForMbState(mbState, converterRef);
if (result != B_OK)
return result;
UConverter* converter = converterRef->Converter();
// do the conversion
UErrorCode icuStatus = U_ZERO_ERROR;
lengthOut = ucnv_fromUChars(converter, mbOut, MB_LEN_MAX, (UChar*)&wc,
1, &icuStatus);
if (!U_SUCCESS(icuStatus)) {
if (icuStatus == U_ILLEGAL_ARGUMENT_ERROR) {
// bad converter (shouldn't really happen)
return B_BAD_VALUE;
}
// conversion failed because of illegal/unmappable character
return B_BAD_DATA;
}
return B_OK;
}
const char*
ICUCtypeData::GetLanginfo(int index)
{
@@ -201,5 +293,45 @@ ICUCtypeData::GetLanginfo(int index)
}
status_t
ICUCtypeData::_GetConverterForMbState(mbstate_t* mbState,
ICUConverterRef& converterRefOut)
{
ICUConverterRef converterRef;
status_t result = ICUConverterManager::Instance()->GetConverter(
mbState->converterID, converterRef);
if (result == B_OK) {
if (strcmp(converterRef->Charset(), fGivenCharset) == 0) {
converterRefOut = converterRef;
return B_OK;
}
// charset no longer matches the converter, we need to dump it and
// create a new one
_DropConverterFromMbState(mbState);
}
// create a new converter for the current charset
result = ICUConverterManager::Instance()->CreateConverter(fGivenCharset,
converterRef, mbState->converterID);
if (result != B_OK)
return result;
converterRefOut = converterRef;
return B_OK;
}
status_t
ICUCtypeData::_DropConverterFromMbState(mbstate_t* mbState)
{
ICUConverterManager::Instance()->DropConverter(mbState->converterID);
mbState->converterID = 0;
return B_OK;
}
} // namespace Libroot
} // namespace BPrivate
@@ -152,6 +152,26 @@ ICULocaleBackend::ToWCTrans(wint_t wc, wctrans_t transition, wint_t& result)
}
status_t
ICULocaleBackend::MultibyteToWchar(wchar_t* wcOut, const char* mb,
size_t mbLength, mbstate_t* mbState, size_t& lengthOut)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.MultibyteToWchar(wcOut, mb, mbLength, mbState, lengthOut);
}
status_t
ICULocaleBackend::WcharToMultibyte(char* mbOut, wchar_t wc, mbstate_t* mbState,
size_t& lengthOut)
{
ErrnoMaintainer errnoMaintainer;
return fCtypeData.WcharToMultibyte(mbOut, wc, mbState, lengthOut);
}
const char*
ICULocaleBackend::GetLanginfo(int index)
{