michael@0: /* michael@0: ******************************************************************************* michael@0: * michael@0: * Copyright (C) 1999-2011, International Business Machines michael@0: * Corporation and others. All Rights Reserved. michael@0: * michael@0: ******************************************************************************* michael@0: * file name: unistr_case.cpp michael@0: * encoding: US-ASCII michael@0: * tab size: 8 (not used) michael@0: * indentation:2 michael@0: * michael@0: * created on: 2004aug19 michael@0: * created by: Markus W. Scherer michael@0: * michael@0: * Case-mapping functions moved here from unistr.cpp michael@0: */ michael@0: michael@0: #include "unicode/utypes.h" michael@0: #include "unicode/putil.h" michael@0: #include "cstring.h" michael@0: #include "cmemory.h" michael@0: #include "unicode/ustring.h" michael@0: #include "unicode/unistr.h" michael@0: #include "unicode/uchar.h" michael@0: #include "uelement.h" michael@0: #include "ustr_imp.h" michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: //======================================== michael@0: // Read-only implementation michael@0: //======================================== michael@0: michael@0: int8_t michael@0: UnicodeString::doCaseCompare(int32_t start, michael@0: int32_t length, michael@0: const UChar *srcChars, michael@0: int32_t srcStart, michael@0: int32_t srcLength, michael@0: uint32_t options) const michael@0: { michael@0: // compare illegal string values michael@0: // treat const UChar *srcChars==NULL as an empty string michael@0: if(isBogus()) { michael@0: return -1; michael@0: } michael@0: michael@0: // pin indices to legal values michael@0: pinIndices(start, length); michael@0: michael@0: if(srcChars == NULL) { michael@0: srcStart = srcLength = 0; michael@0: } michael@0: michael@0: // get the correct pointer michael@0: const UChar *chars = getArrayStart(); michael@0: michael@0: chars += start; michael@0: if(srcStart!=0) { michael@0: srcChars += srcStart; michael@0: } michael@0: michael@0: if(chars != srcChars) { michael@0: UErrorCode errorCode=U_ZERO_ERROR; michael@0: int32_t result=u_strcmpFold(chars, length, srcChars, srcLength, michael@0: options|U_COMPARE_IGNORE_CASE, &errorCode); michael@0: if(result!=0) { michael@0: return (int8_t)(result >> 24 | 1); michael@0: } michael@0: } else { michael@0: // get the srcLength if necessary michael@0: if(srcLength < 0) { michael@0: srcLength = u_strlen(srcChars + srcStart); michael@0: } michael@0: if(length != srcLength) { michael@0: return (int8_t)((length - srcLength) >> 24 | 1); michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: //======================================== michael@0: // Write implementation michael@0: //======================================== michael@0: michael@0: UnicodeString & michael@0: UnicodeString::caseMap(const UCaseMap *csm, michael@0: UStringCaseMapper *stringCaseMapper) { michael@0: if(isEmpty() || !isWritable()) { michael@0: // nothing to do michael@0: return *this; michael@0: } michael@0: michael@0: // We need to allocate a new buffer for the internal string case mapping function. michael@0: // This is very similar to how doReplace() keeps the old array pointer michael@0: // and deletes the old array itself after it is done. michael@0: // In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array. michael@0: UChar oldStackBuffer[US_STACKBUF_SIZE]; michael@0: UChar *oldArray; michael@0: int32_t oldLength; michael@0: michael@0: if(fFlags&kUsingStackBuffer) { michael@0: // copy the stack buffer contents because it will be overwritten michael@0: u_memcpy(oldStackBuffer, fUnion.fStackBuffer, fShortLength); michael@0: oldArray = oldStackBuffer; michael@0: oldLength = fShortLength; michael@0: } else { michael@0: oldArray = getArrayStart(); michael@0: oldLength = length(); michael@0: } michael@0: michael@0: int32_t capacity; michael@0: if(oldLength <= US_STACKBUF_SIZE) { michael@0: capacity = US_STACKBUF_SIZE; michael@0: } else { michael@0: capacity = oldLength + 20; michael@0: } michael@0: int32_t *bufferToDelete = 0; michael@0: if(!cloneArrayIfNeeded(capacity, capacity, FALSE, &bufferToDelete, TRUE)) { michael@0: return *this; michael@0: } michael@0: michael@0: // Case-map, and if the result is too long, then reallocate and repeat. michael@0: UErrorCode errorCode; michael@0: int32_t newLength; michael@0: do { michael@0: errorCode = U_ZERO_ERROR; michael@0: newLength = stringCaseMapper(csm, getArrayStart(), getCapacity(), michael@0: oldArray, oldLength, &errorCode); michael@0: setLength(newLength); michael@0: } while(errorCode==U_BUFFER_OVERFLOW_ERROR && cloneArrayIfNeeded(newLength, newLength, FALSE)); michael@0: michael@0: if (bufferToDelete) { michael@0: uprv_free(bufferToDelete); michael@0: } michael@0: if(U_FAILURE(errorCode)) { michael@0: setToBogus(); michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: UnicodeString & michael@0: UnicodeString::foldCase(uint32_t options) { michael@0: UCaseMap csm=UCASEMAP_INITIALIZER; michael@0: csm.csp=ucase_getSingleton(); michael@0: csm.options=options; michael@0: return caseMap(&csm, ustrcase_internalFold); michael@0: } michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: // Defined here to reduce dependencies on break iterator michael@0: U_CAPI int32_t U_EXPORT2 michael@0: uhash_hashCaselessUnicodeString(const UElement key) { michael@0: U_NAMESPACE_USE michael@0: const UnicodeString *str = (const UnicodeString*) key.pointer; michael@0: if (str == NULL) { michael@0: return 0; michael@0: } michael@0: // Inefficient; a better way would be to have a hash function in michael@0: // UnicodeString that does case folding on the fly. michael@0: UnicodeString copy(*str); michael@0: return copy.foldCase().hashCode(); michael@0: } michael@0: michael@0: // Defined here to reduce dependencies on break iterator michael@0: U_CAPI UBool U_EXPORT2 michael@0: uhash_compareCaselessUnicodeString(const UElement key1, const UElement key2) { michael@0: U_NAMESPACE_USE michael@0: const UnicodeString *str1 = (const UnicodeString*) key1.pointer; michael@0: const UnicodeString *str2 = (const UnicodeString*) key2.pointer; michael@0: if (str1 == str2) { michael@0: return TRUE; michael@0: } michael@0: if (str1 == NULL || str2 == NULL) { michael@0: return FALSE; michael@0: } michael@0: return str1->caseCompare(*str2, U_FOLD_CASE_DEFAULT) == 0; michael@0: }