1 /* 2 * Copyright 2010-2011, Oliver Tappe, zooey@hirschkaefer.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ICUCollateData.h" 8 9 #include <string.h> 10 11 #include <unicode/unistr.h> 12 13 #include "ICUConverterManager.h" 14 15 16 namespace BPrivate { 17 namespace Libroot { 18 19 20 ICUCollateData::ICUCollateData(pthread_key_t tlsKey) 21 : 22 inherited(tlsKey), 23 fCollator(NULL) 24 { 25 } 26 27 28 ICUCollateData::~ICUCollateData() 29 { 30 delete fCollator; 31 } 32 33 34 status_t 35 ICUCollateData::SetTo(const Locale& locale, const char* posixLocaleName) 36 { 37 status_t result = inherited::SetTo(locale, posixLocaleName); 38 39 if (result == B_OK) { 40 UErrorCode icuStatus = U_ZERO_ERROR; 41 delete fCollator; 42 fCollator = Collator::createInstance(fLocale, icuStatus); 43 if (!U_SUCCESS(icuStatus)) 44 return B_NO_MEMORY; 45 } 46 47 return result; 48 } 49 50 51 status_t 52 ICUCollateData::SetToPosix() 53 { 54 status_t result = inherited::SetToPosix(); 55 56 if (result == B_OK) { 57 delete fCollator; 58 fCollator = NULL; 59 } 60 61 return result; 62 } 63 64 65 status_t 66 ICUCollateData::Strcoll(const char* a, const char* b, int& result) 67 { 68 if (strcmp(fPosixLocaleName, "POSIX") == 0) { 69 // handle POSIX here as the collator ICU uses for that (english) is 70 // incompatible in too many ways 71 result = strcmp(a, b); 72 for (const char* aIter = a; *aIter != 0; ++aIter) { 73 if (*aIter < 0) 74 return B_BAD_VALUE; 75 } 76 for (const char* bIter = b; *bIter != 0; ++bIter) { 77 if (*bIter < 0) 78 return B_BAD_VALUE; 79 } 80 return B_OK; 81 } 82 83 status_t status = B_OK; 84 UErrorCode icuStatus = U_ZERO_ERROR; 85 86 if (strcasecmp(fGivenCharset, "utf-8") == 0) { 87 UCharIterator aIter, bIter; 88 uiter_setUTF8(&aIter, a, -1); 89 uiter_setUTF8(&bIter, b, -1); 90 91 result = fCollator->compare(aIter, bIter, icuStatus); 92 } else { 93 UnicodeString unicodeA; 94 UnicodeString unicodeB; 95 96 if (_ToUnicodeString(a, unicodeA) != B_OK 97 || _ToUnicodeString(b, unicodeB) != B_OK) { 98 status = B_BAD_VALUE; 99 } 100 101 result = fCollator->compare(unicodeA, unicodeB, icuStatus); 102 } 103 104 if (!U_SUCCESS(icuStatus)) 105 status = B_BAD_VALUE; 106 107 return status; 108 } 109 110 111 status_t 112 ICUCollateData::Strxfrm(char* out, const char* in, size_t size, size_t& outSize) 113 { 114 if (strcmp(fPosixLocaleName, "POSIX") == 0) { 115 // handle POSIX here as the collator ICU uses for that (english) is 116 // incompatible in too many ways 117 outSize = strlcpy(out, in, size); 118 for (const char* inIter = in; *inIter != 0; ++inIter) { 119 if (*inIter < 0) 120 return B_BAD_VALUE; 121 } 122 return B_OK; 123 } 124 125 if (in == NULL) { 126 outSize = 0; 127 return B_OK; 128 } 129 130 UErrorCode icuStatus = U_ZERO_ERROR; 131 132 UnicodeString unicodeIn; 133 if (_ToUnicodeString(in, unicodeIn) != B_OK) 134 return B_BAD_VALUE; 135 136 outSize = fCollator->getSortKey(unicodeIn, (uint8_t*)out, size); 137 if (!U_SUCCESS(icuStatus)) 138 return B_BAD_VALUE; 139 140 return B_OK; 141 } 142 143 144 status_t 145 ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) 146 { 147 out.remove(); 148 149 if (in == NULL) 150 return B_OK; 151 152 size_t inLen = strlen(in); 153 if (inLen == 0) 154 return B_OK; 155 156 ICUConverterRef converterRef; 157 status_t result = _GetConverter(converterRef); 158 if (result != B_OK) 159 return result; 160 161 UErrorCode icuStatus = U_ZERO_ERROR; 162 int32_t outLen = ucnv_toUChars(converterRef->Converter(), NULL, 0, in, 163 inLen, &icuStatus); 164 if (icuStatus != U_BUFFER_OVERFLOW_ERROR) 165 return B_BAD_VALUE; 166 if (outLen < 0) 167 return B_ERROR; 168 if (outLen == 0) 169 return B_OK; 170 171 UChar* outBuf = out.getBuffer(outLen + 1); 172 icuStatus = U_ZERO_ERROR; 173 outLen = ucnv_toUChars(converterRef->Converter(), outBuf, outLen + 1, in, 174 inLen, &icuStatus); 175 if (!U_SUCCESS(icuStatus)) { 176 out.releaseBuffer(0); 177 return B_BAD_VALUE; 178 } 179 180 out.releaseBuffer(outLen); 181 182 return B_OK; 183 } 184 185 186 } // namespace Libroot 187 } // namespace BPrivate 188