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