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:
@@ -30,9 +30,20 @@ public:
|
|||||||
status_t ToWCTrans(wint_t wc, wctrans_t transition,
|
status_t ToWCTrans(wint_t wc, wctrans_t transition,
|
||||||
wint_t& result);
|
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);
|
const char* GetLanginfo(int index);
|
||||||
|
|
||||||
private:
|
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
|
* The following arrays have 384 elements where the elements at
|
||||||
* index -128..-2 mirror the elements at index 128..255 (to protect
|
* 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,
|
virtual status_t ToWCTrans(wint_t wc, wctrans_t transition,
|
||||||
wint_t& result);
|
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 const char* GetLanginfo(int index);
|
||||||
|
|
||||||
virtual status_t Strcoll(const char* a, const char* b, int& out);
|
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,
|
virtual status_t ToWCTrans(wint_t wc, wctrans_t transition,
|
||||||
wint_t& result) = 0;
|
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 const char* GetLanginfo(int index) = 0;
|
||||||
|
|
||||||
virtual status_t Strcoll(const char* a, const char* b,
|
virtual status_t Strcoll(const char* a, const char* b,
|
||||||
|
|||||||
@@ -54,8 +54,10 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
UConverter* converter = converterRef->Converter();
|
UConverter* converter = converterRef->Converter();
|
||||||
|
|
||||||
ucnv_reset(converter);
|
ucnv_reset(converter);
|
||||||
|
|
||||||
|
fDataBridge->setMbCurMax(ucnv_getMaxCharSize(converter));
|
||||||
|
|
||||||
char buffer[] = { 0, 0 };
|
char buffer[] = { 0, 0 };
|
||||||
for (int i = 0; i < 256; ++i) {
|
for (int i = 0; i < 256; ++i) {
|
||||||
const char* source = buffer;
|
const char* source = buffer;
|
||||||
@@ -130,6 +132,8 @@ ICUCtypeData::SetToPosix()
|
|||||||
memcpy(fClassInfo, fDataBridge->posixClassInfo, sizeof(fClassInfo));
|
memcpy(fClassInfo, fDataBridge->posixClassInfo, sizeof(fClassInfo));
|
||||||
memcpy(fToLowerMap, fDataBridge->posixToLowerMap, sizeof(fToLowerMap));
|
memcpy(fToLowerMap, fDataBridge->posixToLowerMap, sizeof(fToLowerMap));
|
||||||
memcpy(fToUpperMap, fDataBridge->posixToUpperMap, sizeof(fToUpperMap));
|
memcpy(fToUpperMap, fDataBridge->posixToUpperMap, sizeof(fToUpperMap));
|
||||||
|
|
||||||
|
fDataBridge->setMbCurMax(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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*
|
const char*
|
||||||
ICUCtypeData::GetLanginfo(int index)
|
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 Libroot
|
||||||
} // namespace BPrivate
|
} // 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*
|
const char*
|
||||||
ICULocaleBackend::GetLanginfo(int index)
|
ICULocaleBackend::GetLanginfo(int index)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user