/* This file is part of Darling. Copyright (C) 2013 Lubos Dolezel Darling is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Darling is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Darling. If not, see . */ #include "UnicodeUtilities.h" #include #include #include #include #include "UniChar.h" #include "MacErrors.h" namespace Darling { int getLocaleUID(const std::string& str); const char* getLocaleString(int uid); } static UColAttributeValue optsToColAttr(uint32_t options) { UColAttributeValue strength = UCOL_DEFAULT_STRENGTH; if (options & kUCCollateComposeInsensitiveMask) strength = UCOL_QUATERNARY; //if (options & kUCCollateWidthInsensitiveMask) if (options & kUCCollateCaseInsensitiveMask) strength = UCOL_SECONDARY; if (options & kUCCollateDiacritInsensitiveMask) strength = UCOL_PRIMARY; return strength; } OSStatus UCCreateCollator(LocaleRef locale, LocaleOperationVariant opVariant, uint32_t options, CollatorRef* collator) { UErrorCode code = U_ZERO_ERROR; const char* localeStr = Darling::getLocaleString(locale); Collator* c = Collator::createInstance(localeStr, code); *collator = c; if (!c) return paramErr; code = U_ZERO_ERROR; c->setAttribute(UCOL_STRENGTH, optsToColAttr(options), code); return noErr; } OSStatus UCGetCollationKey(CollatorRef collator, const UniChar* text, unsigned long textlen, unsigned long maxKeySize, unsigned long* actualKeySize, uint32_t* collationKey) { if (!text || !actualKeySize || !collationKey || !collator) return paramErr; UnicodeString str1((const char*) text, textlen*2, UNICHAR_ENCODING); Collator* c = static_cast(collator); CollationKey key; UErrorCode code = U_ZERO_ERROR; int32_t count; const uint8_t* data; *actualKeySize = 0; c->getCollationKey(str1, key, code); if (code != U_ZERO_ERROR) return -1; data = key.getByteArray(count); if (count > sizeof(uint32_t)*maxKeySize) return kUCOutputBufferTooSmall; *actualKeySize = (count + sizeof(uint32_t) - 1) / sizeof(uint32_t); memset(collationKey, 0, *actualKeySize); memcpy(collationKey, data, count); return noErr; } OSStatus UCCompareCollationKeys(const uint32_t* key1, unsigned long key1len, const uint32_t* key2, unsigned long key2len, Boolean* equiv, int32_t* order) { if (!equiv && !order) return paramErr; CollationKey ckey1((const uint8_t*)key1, key1len); CollationKey ckey2((const uint8_t*)key2, key2len); UCollationResult result; UErrorCode code = U_ZERO_ERROR; result = ckey1.compareTo(ckey2, code); if (code != U_ZERO_ERROR) return -1; if (equiv != nullptr) *equiv = result == UCOL_EQUAL; if (order != nullptr) { if (result == UCOL_GREATER) *order = 1; else if (result == UCOL_LESS) *order = -1; else *order = 0; } return noErr; } OSStatus UCCompareText(CollatorRef collator, const UniChar* text1, unsigned long text1len, const UniChar* text2, unsigned long text2len, Boolean* equiv, int32_t* order) { if (!equiv && !order) return paramErr; if (!text1 || !text2 || !collator) return paramErr; UnicodeString str1((const char*) text1, text1len*2, UNICHAR_ENCODING); UnicodeString str2((const char*) text2, text2len*2, UNICHAR_ENCODING); Collator* c = static_cast(collator); UCollationResult result; UErrorCode code = U_ZERO_ERROR; result = c->compare(str1, str2, code); if (code != U_ZERO_ERROR) return -1; if (equiv != nullptr) *equiv = (result == UCOL_EQUAL); if (order != nullptr) { if (result == UCOL_GREATER) *order = 1; else if (result == UCOL_LESS) *order = -1; else *order = 0; } return noErr; } OSStatus UCDisposeCollator(CollatorRef* collator) { delete static_cast(*collator); *collator = nullptr; return noErr; } OSStatus UCCompareTextDefault(uint32_t options, const UniChar* text1, unsigned long text1len, const UniChar* text2, unsigned long text2len, Boolean* equiv, int32_t* order) { UErrorCode code = U_ZERO_ERROR; Collator* col = Collator::createInstance(code); OSStatus rv; code = U_ZERO_ERROR; col->setAttribute(UCOL_STRENGTH, optsToColAttr(options), code); rv = UCCompareText(col, text1, text1len, text2, text2len, equiv, order); delete col; return rv; } OSStatus UCCompareTextNoLocale(uint32_t options, const UniChar* text1, unsigned long text1len, const UniChar* text2, unsigned long text2len, Boolean* equiv, int32_t* order) { UErrorCode code = U_ZERO_ERROR; Collator* col = Collator::createInstance(Locale::getRoot(), code); // is getRoot correct? OSStatus rv; code = U_ZERO_ERROR; col->setAttribute(UCOL_STRENGTH, optsToColAttr(options), code); rv = UCCompareText(col, text1, text1len, text2, text2len, equiv, order); delete col; return rv; }