diff --git a/headers/private/libroot/locale/ICUCollateData.h b/headers/private/libroot/locale/ICUCollateData.h index 3b6707ec01..7d73267d29 100644 --- a/headers/private/libroot/locale/ICUCollateData.h +++ b/headers/private/libroot/locale/ICUCollateData.h @@ -29,6 +29,10 @@ public: status_t Strcoll(const char* a, const char* b, int& out); status_t Strxfrm(char* out, const char* in, size_t size, size_t& outSize); + status_t Wcscoll(const wchar_t* a, const wchar_t* b, + int& out); + status_t Wcsxfrm(wchar_t* out, const wchar_t* in, + size_t size, size_t& outSize); private: status_t _ToUnicodeString(const char* in, diff --git a/headers/private/libroot/locale/ICULocaleBackend.h b/headers/private/libroot/locale/ICULocaleBackend.h index 4d18db31b7..4b9f22dd41 100644 --- a/headers/private/libroot/locale/ICULocaleBackend.h +++ b/headers/private/libroot/locale/ICULocaleBackend.h @@ -61,6 +61,10 @@ public: virtual status_t Strcoll(const char* a, const char* b, int& out); virtual status_t Strxfrm(char* out, const char* in, size_t size, size_t& outSize); + virtual status_t Wcscoll(const wchar_t* a, const wchar_t* b, + int& out); + virtual status_t Wcsxfrm(wchar_t* out, const wchar_t* in, + size_t size, size_t& outSize); virtual status_t TZSet(const char* timeZoneID, const char* tz); virtual status_t Localtime(const time_t* inTime, diff --git a/headers/private/libroot/locale/LocaleBackend.h b/headers/private/libroot/locale/LocaleBackend.h index 8f5fdc80d1..670253c4b7 100644 --- a/headers/private/libroot/locale/LocaleBackend.h +++ b/headers/private/libroot/locale/LocaleBackend.h @@ -144,6 +144,10 @@ public: int& out) = 0; virtual status_t Strxfrm(char* out, const char* in, size_t size, size_t& outSize) = 0; + virtual status_t Wcscoll(const wchar_t* a, const wchar_t* b, + int& out) = 0; + virtual status_t Wcsxfrm(wchar_t* out, const wchar_t* in, + size_t size, size_t& outSize) = 0; virtual status_t TZSet(const char* timeZoneID, const char* tz) = 0; diff --git a/src/system/libroot/add-ons/icu/ICUCollateData.cpp b/src/system/libroot/add-ons/icu/ICUCollateData.cpp index 70e88e4026..d2ab5d55d0 100644 --- a/src/system/libroot/add-ons/icu/ICUCollateData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCollateData.cpp @@ -7,9 +7,12 @@ #include "ICUCollateData.h" #include +#include #include +#include + namespace BPrivate { namespace Libroot { @@ -63,7 +66,7 @@ ICUCollateData::SetToPosix() status_t ICUCollateData::Strcoll(const char* a, const char* b, int& result) { - if (strcmp(fPosixLocaleName, "POSIX") == 0) { + if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) { // handle POSIX here as the collator ICU uses for that (english) is // incompatible in too many ways result = strcmp(a, b); @@ -109,7 +112,7 @@ ICUCollateData::Strcoll(const char* a, const char* b, int& result) status_t ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize) { - if (strcmp(fPosixLocaleName, "POSIX") == 0) { + if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) { // handle POSIX here as the collator ICU uses for that (english) is // incompatible in too many ways outSize = strlcpy(out, in, size); @@ -125,13 +128,40 @@ ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize) return B_OK; } - UErrorCode icuStatus = U_ZERO_ERROR; - UnicodeString unicodeIn; if (_ToUnicodeString(in, unicodeIn) != B_OK) return B_BAD_VALUE; outSize = fCollator->getSortKey(unicodeIn, (uint8_t*)out, size); + + return B_OK; +} + + +status_t +ICUCollateData::Wcscoll(const wchar_t* a, const wchar_t* b, int& result) +{ + if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) { + // handle POSIX here as the collator ICU uses for that (english) is + // incompatible in too many ways + result = wcscmp(a, b); + for (const wchar_t* aIter = a; *aIter != 0; ++aIter) { + if (*aIter > 127) + return B_BAD_VALUE; + } + for (const wchar_t* bIter = b; *bIter != 0; ++bIter) { + if (*bIter > 127) + return B_BAD_VALUE; + } + return B_OK; + } + + UnicodeString unicodeA = UnicodeString::fromUTF32((UChar32*)a, -1); + UnicodeString unicodeB = UnicodeString::fromUTF32((UChar32*)b, -1); + + UErrorCode icuStatus = U_ZERO_ERROR; + result = fCollator->compare(unicodeA, unicodeB, icuStatus); + if (!U_SUCCESS(icuStatus)) return B_BAD_VALUE; @@ -139,6 +169,40 @@ ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize) } +status_t +ICUCollateData::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size, + size_t& outSize) +{ + if (in == NULL) { + outSize = 0; + return B_OK; + } + + if (fCollator == NULL || strcmp(fPosixLocaleName, "POSIX") == 0) { + // handle POSIX here as the collator ICU uses for that (english) is + // incompatible in too many ways + outSize = wcslcpy(out, in, size); + for (const wchar_t* inIter = in; *inIter != 0; ++inIter) { + if (*inIter > 127) + return B_BAD_VALUE; + } + return B_OK; + } + + UnicodeString unicodeIn = UnicodeString::fromUTF32((UChar32*)in, -1); + size_t requiredSize = fCollator->getSortKey(unicodeIn, NULL, 0); + + uint8_t* buffer = (uint8_t*)out; + outSize = fCollator->getSortKey(unicodeIn, buffer, requiredSize); + + // convert 1-byte characters to 4-byte wide characters: + for (size_t i = 0; i < outSize; ++i) + out[outSize - 1 - i] = buffer[outSize - 1 - i]; + + return B_OK; +} + + status_t ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) { diff --git a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp index 89d6f14f10..ca9078555d 100644 --- a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp +++ b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp @@ -294,6 +294,25 @@ ICULocaleBackend::Strxfrm(char* out, const char* in, size_t size, } +status_t +ICULocaleBackend::Wcscoll(const wchar_t* a, const wchar_t* b, int& result) +{ + ErrnoMaintainer errnoMaintainer; + + return fCollateData.Wcscoll(a, b, result); +} + + +status_t +ICULocaleBackend::Wcsxfrm(wchar_t* out, const wchar_t* in, size_t size, + size_t& outSize) +{ + ErrnoMaintainer errnoMaintainer; + + return fCollateData.Wcsxfrm(out, in, size, outSize); +} + + status_t ICULocaleBackend::TZSet(const char* timeZoneID, const char* tz) { diff --git a/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp b/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp index a6760339f9..64a3db86c9 100644 --- a/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp +++ b/src/system/libroot/add-ons/icu/ICUTimeConversion.cpp @@ -11,8 +11,6 @@ #include -#include - namespace BPrivate { namespace Libroot { diff --git a/src/system/libroot/posix/wchar/wcscoll.cpp b/src/system/libroot/posix/wchar/wcscoll.cpp new file mode 100644 index 0000000000..0623efea12 --- /dev/null +++ b/src/system/libroot/posix/wchar/wcscoll.cpp @@ -0,0 +1,32 @@ +/* +** Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. All rights reserved. +** Distributed under the terms of the Haiku License. +*/ + +#include +#include +#include + + +using BPrivate::Libroot::gLocaleBackend; + + +extern "C" int +__wcscoll(const wchar_t* wcs1, const wchar_t* wcs2) +{ + if (gLocaleBackend != NULL) { + int result = 0; + status_t status = gLocaleBackend->Wcscoll(wcs1, wcs2, result); + + if (status != B_OK) + __set_errno(EINVAL); + + return result; + } + + return wcscmp(wcs1, wcs2); +} + + +extern "C" +B_DEFINE_WEAK_ALIAS(__wcscoll, wcscoll); diff --git a/src/system/libroot/posix/wchar/wcsxfrm.cpp b/src/system/libroot/posix/wchar/wcsxfrm.cpp new file mode 100644 index 0000000000..5843349fe5 --- /dev/null +++ b/src/system/libroot/posix/wchar/wcsxfrm.cpp @@ -0,0 +1,34 @@ +/* + * Copyright 2011, Oliver Tappe, zooey@hirschkaefer.de. + * All rights reserved. Distributed under the terms of the MIT license. + */ + +#include + +#include +#include +#include + + +using BPrivate::Libroot::gLocaleBackend; + + +extern "C" size_t +__wcsxfrm(wchar_t* dest, const wchar_t* src, size_t destSize) +{ + if (gLocaleBackend != NULL) { + size_t outSize = 0; + status_t status = gLocaleBackend->Wcsxfrm(dest, src, destSize, outSize); + + if (status != B_OK) + __set_errno(EINVAL); + + return outSize; + } + + return wcslcpy(dest, src, destSize); +} + + +extern "C" +B_DEFINE_WEAK_ALIAS(__wcsxfrm, wcsxfrm);