hrev43507 adds 3 changesets to branch 'master' old head: ed77847ca4be5b60fd1420d5bd204593aaf1c1e5 new head: ec99f3b2a665ab678c6c8ae3c7bd1c6a0d34fb68 ---------------------------------------------------------------------------- 05260c2: Fix build warnings with gcc4. 8726c67: Add test for use case found in readline (used by bash). * making a backup copy of an mbstate_t and then later restoring the original should allow to re-use the internal converter state ec99f3b: Adjust mbstate_t to embed the state of the ICU converter. * make room in mbstate_t for containing an ICU-converter's state (well, in fact the whole converter object) * adjust libroot's locale add-on to clone converters into a given mbstate_t directly * adjust ICUThreadLocalStorageValue to contain the converter pointer instead of a converter-ID (if the converter is related to an mbstate_t, it points into the mbstate_t). * adjust users of converters to directly use converter pointers instead of ICUConverterRef * drop now unused ICUConverterManager and ICUConverterRef * update gcc4 optional package This brings our multibyte implementation into a fully working state, both non-ascii and non-8-bit characters can now be handled normally in the Terminal, i.e. this finally fixes #6276. N.B.: Since the size of mbstate_t has changed, everything (including the compiler!) needs to be rebuilt. [ Oliver Tappe <zooey@xxxxxxxxxxxxxxx> ] ---------------------------------------------------------------------------- 13 files changed, 161 insertions(+), 227 deletions(-) build/jam/OptionalPackages | 6 +- headers/posix/wchar.h | 4 +- headers/private/libroot/locale/ICUCategoryData.h | 5 +- .../private/libroot/locale/ICUConverterManager.h | 106 --------------- headers/private/libroot/locale/ICUCtypeData.h | 2 +- .../libroot/locale/ICUThreadLocalStorageValue.h | 8 +- src/system/libroot/add-ons/icu/ICUCategoryData.cpp | 102 ++++++++------- src/system/libroot/add-ons/icu/ICUCollateData.cpp | 13 +- src/system/libroot/add-ons/icu/ICUCtypeData.cpp | 108 +++++++++------- .../add-ons/icu/ICUThreadLocalStorageValue.cpp | 9 +- src/system/libroot/add-ons/icu/Jamfile | 1 - .../system/libroot/posix/gnulib-test-mbrtowc.c | 16 +++ .../system/libroot/posix/gnulib-test-mbsrtowcs.c | 8 +- ############################################################################ Commit: 05260c25c237dfb4ee7693fd1fa571dca519aee4 URL: http://cgit.haiku-os.org/haiku/commit/?id=05260c2 Author: Oliver Tappe <zooey@xxxxxxxxxxxxxxx> Date: Thu Dec 15 10:45:45 2011 UTC Fix build warnings with gcc4. ---------------------------------------------------------------------------- diff --git a/src/tests/system/libroot/posix/gnulib-test-mbsrtowcs.c b/src/tests/system/libroot/posix/gnulib-test-mbsrtowcs.c index ab7e000..4412114 100644 --- a/src/tests/system/libroot/posix/gnulib-test-mbsrtowcs.c +++ b/src/tests/system/libroot/posix/gnulib-test-mbsrtowcs.c @@ -174,7 +174,7 @@ int main(int argc, char *argv[]) src = input + 2; ret = mbsrtowcs(buf, &src, unlimited ? BUFSIZE : 1, &state); - assert(ret == (unlimited ? 3 : 1)); + assert(ret == (unlimited ? 3u : 1u)); assert(src == (unlimited ? NULL : input + 3)); assert(wctob (buf[0]) == (unsigned char) '\337'); if (unlimited) { @@ -230,7 +230,7 @@ int main(int argc, char *argv[]) src = input + 2; ret = mbsrtowcs(buf, &src, unlimited ? BUFSIZE : 2, &state); - assert(ret == (unlimited ? 4 : 2)); + assert(ret == (unlimited ? 4u : 2u)); assert(src == (unlimited ? NULL : input + 5)); assert(wctob (buf[0]) == EOF); assert(wctob (buf[1]) == EOF); @@ -299,7 +299,7 @@ int main(int argc, char *argv[]) src = input + 4; ret = mbsrtowcs(buf, &src, unlimited ? BUFSIZE : 2, &state); - assert(ret == (unlimited ? 3 : 2)); + assert(ret == (unlimited ? 3u : 2u)); assert(src == (unlimited ? NULL : input + 7)); assert(wctob (buf[0]) == EOF); assert(wctob (buf[1]) == EOF); @@ -354,7 +354,7 @@ int main(int argc, char *argv[]) src = input + 2; ret = mbsrtowcs(buf, &src, unlimited ? BUFSIZE : 2, &state); - assert(ret == (unlimited ? 4 : 2)); + assert(ret == (unlimited ? 4u : 2u)); assert(src == (unlimited ? NULL : input + 7)); assert(wctob (buf[0]) == EOF); assert(wctob (buf[1]) == EOF); ############################################################################ Commit: 8726c67f5e70d20d3584164caf3ed93c780557f2 URL: http://cgit.haiku-os.org/haiku/commit/?id=8726c67 Author: Oliver Tappe <zooey@xxxxxxxxxxxxxxx> Date: Thu Dec 15 10:47:32 2011 UTC Add test for use case found in readline (used by bash). * making a backup copy of an mbstate_t and then later restoring the original should allow to re-use the internal converter state ---------------------------------------------------------------------------- diff --git a/src/tests/system/libroot/posix/gnulib-test-mbrtowc.c b/src/tests/system/libroot/posix/gnulib-test-mbrtowc.c index 35322e0..240d769 100644 --- a/src/tests/system/libroot/posix/gnulib-test-mbrtowc.c +++ b/src/tests/system/libroot/posix/gnulib-test-mbrtowc.c @@ -236,6 +236,22 @@ main (int argc, char *argv[]) assert (ret == 1); assert (wc == 'r'); assert (mbsinit (&state)); + + /* reproduce a valid use case from readline (as used in our bash): */ + { + char tooShort[] = "\303"; + char ok[] = "\303\274"; + /* make a backup of the state */ + mbstate_t stateBackup = state; + /* try with a source that's too short */ + ret = mbrtowc (&wc, tooShort, 1, &state); + assert (ret == (size_t)-2); + /* restore the state from the backup */ + state = stateBackup; + /* retry with enough source */ + ret = mbrtowc (&wc, ok, 2, &state); + assert (ret == 2); + } } break; ############################################################################ Revision: hrev43507 Commit: ec99f3b2a665ab678c6c8ae3c7bd1c6a0d34fb68 URL: http://cgit.haiku-os.org/haiku/commit/?id=ec99f3b Author: Oliver Tappe <zooey@xxxxxxxxxxxxxxx> Date: Thu Dec 15 12:10:26 2011 UTC Ticket: https://dev.haiku-os.org/ticket/6276 Adjust mbstate_t to embed the state of the ICU converter. * make room in mbstate_t for containing an ICU-converter's state (well, in fact the whole converter object) * adjust libroot's locale add-on to clone converters into a given mbstate_t directly * adjust ICUThreadLocalStorageValue to contain the converter pointer instead of a converter-ID (if the converter is related to an mbstate_t, it points into the mbstate_t). * adjust users of converters to directly use converter pointers instead of ICUConverterRef * drop now unused ICUConverterManager and ICUConverterRef * update gcc4 optional package This brings our multibyte implementation into a fully working state, both non-ascii and non-8-bit characters can now be handled normally in the Terminal, i.e. this finally fixes #6276. N.B.: Since the size of mbstate_t has changed, everything (including the compiler!) needs to be rebuilt. ---------------------------------------------------------------------------- diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 98dced5..f120cfb 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -536,8 +536,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] if $(HAIKU_GCC_VERSION[1]) = 4 || $(isHybridBuild) { InstallOptionalHaikuImagePackage - gcc-4.5.3-x86-gcc4-2011-11-22.zip - : $(baseURL)/gcc-4.5.3-x86-gcc4-2011-11-22.zip ; + gcc-4.5.3-x86-gcc4-2011-12-14.zip + : $(baseURL)/gcc-4.5.3-x86-gcc4-2011-12-14.zip ; } if $(HAIKU_GCC_VERSION[1]) = 4 { @@ -549,7 +549,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] local libs = libstdc++.so libsupc++.so ; for lib in $(libs) { AddSymlinkToHaikuHybridImage - develop abi x86 gcc4 tools gcc-4.5.3-haiku-111122 lib + develop abi x86 gcc4 tools gcc-4.5.3-haiku-111214 lib : /system/lib $(lib) : : true ; } } diff --git a/headers/posix/wchar.h b/headers/posix/wchar.h index d7c604b..16bf7b8 100644 --- a/headers/posix/wchar.h +++ b/headers/posix/wchar.h @@ -27,8 +27,10 @@ typedef __WINT_TYPE__ wint_t; typedef int wctype_t; typedef struct { + void* converter; + char charset[64]; unsigned int count; - unsigned int converterID; + char data[1024 + 8]; // 1024 bytes for data, 8 for alignment space } mbstate_t; diff --git a/headers/private/libroot/locale/ICUCategoryData.h b/headers/private/libroot/locale/ICUCategoryData.h index ad8088b..dd25d57 100644 --- a/headers/private/libroot/locale/ICUCategoryData.h +++ b/headers/private/libroot/locale/ICUCategoryData.h @@ -8,12 +8,11 @@ #include <pthread.h> #include <unicode/locid.h> -#include <unicode/ucnv.h> #include <unicode/unistr.h> #include <SupportDefs.h> -#include "ICUConverterManager.h" +#include "ICUThreadLocalStorageValue.h" namespace BPrivate { @@ -38,7 +37,7 @@ protected: char* destination, int destinationSize, const char* defaultValue = ""); - status_t _GetConverter(ICUConverterRef& converterRefOut); + status_t _GetConverter(UConverter*& converterOut); static const uint16 skMaxPosixLocaleNameLen = 128; static const size_t skLCBufSize = 16; diff --git a/headers/private/libroot/locale/ICUConverterManager.h b/headers/private/libroot/locale/ICUConverterManager.h deleted file mode 100644 index 68d0d5a..0000000 --- a/headers/private/libroot/locale/ICUConverterManager.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2011, Oliver Tappe, zooey@xxxxxxxxxxxxxxxx - * Distributed under the terms of the MIT License. - */ -#ifndef _ICU_CONVERTER_MANAGER_H -#define _ICU_CONVERTER_MANAGER_H - - -#include <pthread.h> - -#include <map> - -#include <unicode/ucnv.h> - -#include <SupportDefs.h> - -#include <locks.h> -#include <Referenceable.h> -#include <util/DoublyLinkedList.h> -//#include <util/OpenHashTable.h> - -#include "ICUThreadLocalStorageValue.h" - - -namespace BPrivate { -namespace Libroot { - - -class ICUConverterInfo : public BReferenceable { -public: - ICUConverterInfo(UConverter* converter, - const char* charset, ICUConverterID id); - virtual ~ICUConverterInfo(); - - UConverter* Converter() const - { return fConverter; } - - const char* Charset() const - { return fCharset; } - - ICUConverterID ID() const - { return fID; } - -private: - UConverter* fConverter; - char fCharset[UCNV_MAX_CONVERTER_NAME_LENGTH]; - ICUConverterID fID; -}; - - -typedef BReference<ICUConverterInfo> ICUConverterRef; - - -class ICUConverterManager { -public: - ICUConverterManager(); - ~ICUConverterManager(); - - status_t CreateConverter(const char* charset, - ICUConverterRef& converterRefOut, - ICUConverterID& idOut); - - status_t GetConverter(ICUConverterID id, - ICUConverterRef& converterRefOut); - - status_t DropConverter(ICUConverterID id); - - static ICUConverterManager* Instance(); - -private: - static void _CreateInstance(); - - static ICUConverterManager* sInstance; - - static const size_t skMaxConvertersPerProcess = 1024; - -private: - class LinkedConverterInfo - : - public ICUConverterInfo, - public DoublyLinkedListLinkImpl<LinkedConverterInfo> - { - public: - LinkedConverterInfo(UConverter* converter, const char* charset, - ICUConverterID id) - : - ICUConverterInfo(converter, charset, id) - { - } - }; - typedef std::map<ICUConverterID, LinkedConverterInfo*> ConverterMap; - typedef DoublyLinkedList<LinkedConverterInfo> ConverterList; - -private: - ConverterMap fConverterMap; - ConverterList fLRUConverters; - mutex fMutex; - ICUConverterID fNextConverterID; -}; - - -} // namespace Libroot -} // namespace BPrivate - - -#endif // _ICU_CONVERTER_MANAGER_H diff --git a/headers/private/libroot/locale/ICUCtypeData.h b/headers/private/libroot/locale/ICUCtypeData.h index ebf6016..72b335e 100644 --- a/headers/private/libroot/locale/ICUCtypeData.h +++ b/headers/private/libroot/locale/ICUCtypeData.h @@ -49,7 +49,7 @@ public: private: status_t _GetConverterForMbState(mbstate_t* mbState, - ICUConverterRef& converterRefOut); + UConverter*& converterOut); status_t _DropConverterFromMbState(mbstate_t* mbState); diff --git a/headers/private/libroot/locale/ICUThreadLocalStorageValue.h b/headers/private/libroot/locale/ICUThreadLocalStorageValue.h index 5ea3c26..3006a45 100644 --- a/headers/private/libroot/locale/ICUThreadLocalStorageValue.h +++ b/headers/private/libroot/locale/ICUThreadLocalStorageValue.h @@ -8,6 +8,8 @@ #include <pthread.h> +#include <unicode/ucnv.h> + #include <SupportDefs.h> @@ -15,11 +17,9 @@ namespace BPrivate { namespace Libroot { -typedef unsigned int ICUConverterID; - - struct ICUThreadLocalStorageValue { - ICUConverterID converterID; + UConverter* converter; + char charset[64]; ICUThreadLocalStorageValue(); ~ICUThreadLocalStorageValue(); diff --git a/src/system/libroot/add-ons/icu/ICUCategoryData.cpp b/src/system/libroot/add-ons/icu/ICUCategoryData.cpp index 88e3dd1..1a7af42 100644 --- a/src/system/libroot/add-ons/icu/ICUCategoryData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCategoryData.cpp @@ -30,44 +30,6 @@ ICUCategoryData::~ICUCategoryData() status_t -ICUCategoryData::_GetConverter(ICUConverterRef& converterRefOut) -{ - // we use different converter-IDs per thread in order to avoid converters - // being used by more than one thread - ICUThreadLocalStorageValue* tlsValue = NULL; - status_t result = ICUThreadLocalStorageValue::GetInstanceForKey( - fThreadLocalStorageKey, tlsValue); - if (result != B_OK) - return result; - - ICUConverterRef converterRef; - result = ICUConverterManager::Instance()->GetConverter( - tlsValue->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 - ICUConverterManager::Instance()->DropConverter(tlsValue->converterID); - tlsValue->converterID = 0; - } - - // create a new converter for the current charset - result = ICUConverterManager::Instance()->CreateConverter(fGivenCharset, - converterRef, tlsValue->converterID); - if (result != B_OK) - return result; - - converterRefOut = converterRef; - - return B_OK; -} - - -status_t ICUCategoryData::SetTo(const Locale& locale, const char* posixLocaleName) { if (!posixLocaleName) @@ -115,14 +77,14 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry( const UnicodeString& string, char* destination, int destinationSize, const char* defaultValue) { - ICUConverterRef converterRef; - status_t result = _GetConverter(converterRef); + UConverter* converter; + status_t result = _GetConverter(converter); if (result != B_OK) return result; UErrorCode icuStatus = U_ZERO_ERROR; - ucnv_fromUChars(converterRef->Converter(), destination, destinationSize, - string.getBuffer(), string.length(), &icuStatus); + ucnv_fromUChars(converter, destination, destinationSize, string.getBuffer(), + string.length(), &icuStatus); if (!U_SUCCESS(icuStatus)) { switch (icuStatus) { case U_BUFFER_OVERFLOW_ERROR: @@ -145,10 +107,62 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry( status_t +ICUCategoryData::_GetConverter(UConverter*& converterOut) +{ + // we use different converters per thread to avoid concurrent accesses + 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; + } + + // charset no longer matches the converter, we need to dump it and + // create a new one + ucnv_close(tlsValue->converter); + } + + // create a new converter for the current charset + UErrorCode icuStatus = U_ZERO_ERROR; + UConverter* icuConverter = ucnv_open(fGivenCharset, &icuStatus); + if (icuConverter == NULL) + return B_NAME_NOT_FOUND; + + // setup the new converter to stop upon any errors + 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() { - ICUConverterRef converterRef; - return _GetConverter(converterRef); + UConverter* converter; + return _GetConverter(converter); } diff --git a/src/system/libroot/add-ons/icu/ICUCollateData.cpp b/src/system/libroot/add-ons/icu/ICUCollateData.cpp index a9d9264..70e88e4 100644 --- a/src/system/libroot/add-ons/icu/ICUCollateData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCollateData.cpp @@ -10,8 +10,6 @@ #include <unicode/unistr.h> -#include "ICUConverterManager.h" - namespace BPrivate { namespace Libroot { @@ -153,14 +151,13 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) if (inLen == 0) return B_OK; - ICUConverterRef converterRef; - status_t result = _GetConverter(converterRef); + UConverter* converter; + status_t result = _GetConverter(converter); if (result != B_OK) return result; UErrorCode icuStatus = U_ZERO_ERROR; - int32_t outLen = ucnv_toUChars(converterRef->Converter(), NULL, 0, in, - inLen, &icuStatus); + int32_t outLen = ucnv_toUChars(converter, NULL, 0, in, inLen, &icuStatus); if (icuStatus != U_BUFFER_OVERFLOW_ERROR) return B_BAD_VALUE; if (outLen < 0) @@ -170,8 +167,8 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) UChar* outBuf = out.getBuffer(outLen + 1); icuStatus = U_ZERO_ERROR; - outLen = ucnv_toUChars(converterRef->Converter(), outBuf, outLen + 1, in, - inLen, &icuStatus); + outLen + = ucnv_toUChars(converter, outBuf, outLen + 1, in, inLen, &icuStatus); if (!U_SUCCESS(icuStatus)) { out.releaseBuffer(0); return B_BAD_VALUE; diff --git a/src/system/libroot/add-ons/icu/ICUCtypeData.cpp b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp index b47fd0f..9fd3ff2 100644 --- a/src/system/libroot/add-ons/icu/ICUCtypeData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp @@ -10,10 +10,15 @@ #include <stdlib.h> #include <string.h> +#include <algorithm> + #include <unicode/uchar.h> +#include <Debug.h> + //#define TRACE_CTYPE +#undef TRACE #ifdef TRACE_CTYPE # include <OS.h> # define TRACE(x) debug_printf x @@ -58,12 +63,11 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName) UErrorCode icuStatus = U_ZERO_ERROR; - ICUConverterRef converterRef; - result = _GetConverter(converterRef); + UConverter* converter; + result = _GetConverter(converter); if (result != B_OK) return result; - UConverter* converter = converterRef->Converter(); ucnv_reset(converter); fDataBridge->setMbCurMax(ucnv_getMaxCharSize(converter)); @@ -207,16 +211,14 @@ 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); + UConverter* converter = NULL; + status_t result = _GetConverterForMbState(mbState, converter); if (result != B_OK) { - TRACE(("MultibyteToWchar(): couldn't get converter for ID %d - %lx\n", - mbState->converterID, result)); + TRACE(("MultibyteToWchar(): couldn't get converter for mbstate %p - " + "%lx\n", mbState, result)); return result; } - UConverter* converter = converterRef->Converter(); - // do the conversion UErrorCode icuStatus = U_ZERO_ERROR; @@ -233,8 +235,6 @@ ICUCtypeData::MultibyteToWchar(wchar_t* wcOut, const char* mb, size_t mbLen, icuStatus = U_ZERO_ERROR; } - UChar32 unicodeChar = 0xBADBEEF; - if (!U_SUCCESS(icuStatus)) { // conversion failed because of illegal character sequence TRACE(("MultibyteToWchar(): illegal character sequence\n")); @@ -247,6 +247,7 @@ ICUCtypeData::MultibyteToWchar(wchar_t* wcOut, const char* mb, size_t mbLen, mbState->count = sourceLengthUsed; result = B_BAD_INDEX; } else { + UChar32 unicodeChar = 0xBADBEEF; U16_GET(targetBuffer, 0, 0, 2, unicodeChar); if (unicodeChar == 0) { @@ -274,16 +275,14 @@ ICUCtypeData::MultibyteStringToWchar(wchar_t* wcDest, size_t wcDestLength, const char** mbSource, size_t mbSourceLength, mbstate_t* mbState, size_t& lengthOut) { - ICUConverterRef converterRef; - status_t result = _GetConverterForMbState(mbState, converterRef); + UConverter* converter = NULL; + status_t result = _GetConverterForMbState(mbState, converter); if (result != B_OK) { - TRACE(("MultibyteStringToWchar(): couldn't get converter for ID %d -" - " %lx\n", mbState->converterID, result)); + TRACE(("MultibyteStringToWchar(): couldn't get converter for mbstate %p" + " - %lx\n", mbState, result)); return result; } - UConverter* converter = converterRef->Converter(); - bool wcsIsTerminated = false; const char* source = *mbSource; const char* sourceEnd = source + mbSourceLength; @@ -346,16 +345,14 @@ status_t ICUCtypeData::WcharToMultibyte(char* mbOut, wchar_t wc, mbstate_t* mbState, size_t& lengthOut) { - ICUConverterRef converterRef; - status_t result = _GetConverterForMbState(mbState, converterRef); + UConverter* converter = NULL; + status_t result = _GetConverterForMbState(mbState, converter); if (result != B_OK) { - TRACE(("WcharToMultibyte(): couldn't get converter for ID %d - %lx\n", - mbState->converterID, result)); + TRACE(("WcharToMultibyte(): couldn't get converter for mbstate %p - " + "%lx\n", mbState, result)); return result; } - UConverter* converter = converterRef->Converter(); - // convert input from UTF-32 to UTF-16 UChar ucharBuffer[2]; size_t ucharLength; @@ -409,16 +406,14 @@ ICUCtypeData::WcharStringToMultibyte(char* mbDest, size_t mbDestLength, const wchar_t** wcSource, size_t wcSourceLength, mbstate_t* mbState, size_t& lengthOut) { - ICUConverterRef converterRef; - status_t result = _GetConverterForMbState(mbState, converterRef); + UConverter* converter = NULL; + status_t result = _GetConverterForMbState(mbState, converter); if (result != B_OK) { - TRACE(("WcharStringToMultibyte(): couldn't get converter for ID %d " - "- %lx\n", mbState->converterID, result)); + TRACE(("WcharStringToMultibyte(): couldn't get converter for mbstate %p" + " - %lx\n", mbState, result)); return result; } - UConverter* converter = converterRef->Converter(); - bool mbsIsTerminated = false; const UChar32* source = (UChar32*)*wcSource; @@ -509,29 +504,45 @@ ICUCtypeData::GetLanginfo(int index) status_t ICUCtypeData::_GetConverterForMbState(mbstate_t* mbState, - ICUConverterRef& converterRefOut) + UConverter*& converterOut) { - 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); + if (strcmp(mbState->charset, fGivenCharset) == 0 + && (char*)mbState->converter >= mbState->data + && (char*)mbState->converter < mbState->data + 8) { + // charset matches and converter actually lives in *this* mbState, + // so we can use it (if the converter points to the outside, it means + // that the mbstate_t has been copied) + converterOut = (UConverter*)mbState->converter; + return B_OK; } - // create a new converter for the current charset - result = ICUConverterManager::Instance()->CreateConverter(fGivenCharset, - converterRef, mbState->converterID); + // 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 ... + UConverter* icuConverter; + status_t result = _GetConverter(icuConverter); if (result != B_OK) return result; - converterRefOut = converterRef; + // ... and clone it into the mbstate + UErrorCode icuStatus = U_ZERO_ERROR; + int32_t bufferSize = sizeof(mbState->data); + UConverter* clone + = ucnv_safeClone(icuConverter, mbState->data, &bufferSize, &icuStatus); + if (clone == NULL || !U_SUCCESS(icuStatus)) + return B_ERROR; + + if ((char*)clone < mbState->data || (char*)clone >= mbState->data + 8) { + // buffer is too small (shouldn't happen according to ICU docs) + return B_NO_MEMORY; + } + + strlcpy(mbState->charset, fGivenCharset, sizeof(mbState->charset)); + mbState->converter = clone; + + converterOut = clone; return B_OK; } @@ -540,8 +551,9 @@ ICUCtypeData::_GetConverterForMbState(mbstate_t* mbState, status_t ICUCtypeData::_DropConverterFromMbState(mbstate_t* mbState) { - ICUConverterManager::Instance()->DropConverter(mbState->converterID); - mbState->converterID = 0; + if (mbState->converter != NULL) + ucnv_close((UConverter*)mbState->converter); + memset(mbState, 0, sizeof(mbstate_t)); return B_OK; } diff --git a/src/system/libroot/add-ons/icu/ICUThreadLocalStorageValue.cpp b/src/system/libroot/add-ons/icu/ICUThreadLocalStorageValue.cpp index d88410b..e671f29 100644 --- a/src/system/libroot/add-ons/icu/ICUThreadLocalStorageValue.cpp +++ b/src/system/libroot/add-ons/icu/ICUThreadLocalStorageValue.cpp @@ -8,7 +8,7 @@ #include <new> -#include "ICUConverterManager.h" +#include <unicode/ucnv.h> namespace BPrivate { @@ -16,15 +16,16 @@ namespace Libroot { ICUThreadLocalStorageValue::ICUThreadLocalStorageValue() - : converterID(0) + : converter(NULL) { + charset[0] = '\0'; } ICUThreadLocalStorageValue::~ICUThreadLocalStorageValue() { - if (converterID != 0) - ICUConverterManager::Instance()->DropConverter(converterID); + if (converter != NULL) + ucnv_close(converter); } diff --git a/src/system/libroot/add-ons/icu/Jamfile b/src/system/libroot/add-ons/icu/Jamfile index 5640a26..7627236 100644 --- a/src/system/libroot/add-ons/icu/Jamfile +++ b/src/system/libroot/add-ons/icu/Jamfile @@ -11,7 +11,6 @@ UsePrivateHeaders local sources = ICUCategoryData.cpp ICUCollateData.cpp - ICUConverterManager.cpp ICUCtypeData.cpp ICULocaleBackend.cpp ICULocaleconvData.cpp