]>
git.saurik.com Git - apple/icu.git/blob - icuSources/common/unistr_case.cpp
2 *******************************************************************************
4 * Copyright (C) 1999-2010, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: unistr_case.cpp
10 * tab size: 8 (not used)
13 * created on: 2004aug19
14 * created by: Markus W. Scherer
16 * Case-mapping functions moved here from unistr.cpp
19 #include "unicode/utypes.h"
20 #include "unicode/putil.h"
21 #include "unicode/locid.h"
24 #include "unicode/ustring.h"
25 #include "unicode/unistr.h"
26 #include "unicode/uchar.h"
27 #include "unicode/ubrk.h"
33 //========================================
34 // Read-only implementation
35 //========================================
38 UnicodeString::doCaseCompare(int32_t start
,
40 const UChar
*srcChars
,
43 uint32_t options
) const
45 // compare illegal string values
46 // treat const UChar *srcChars==NULL as an empty string
51 // pin indices to legal values
52 pinIndices(start
, length
);
54 if(srcChars
== NULL
) {
55 srcStart
= srcLength
= 0;
58 // get the correct pointer
59 const UChar
*chars
= getArrayStart();
64 if(chars
!= srcChars
) {
65 UErrorCode errorCode
=U_ZERO_ERROR
;
66 int32_t result
=u_strcmpFold(chars
, length
, srcChars
, srcLength
,
67 options
|U_COMPARE_IGNORE_CASE
, &errorCode
);
69 return (int8_t)(result
>> 24 | 1);
72 // get the srcLength if necessary
74 srcLength
= u_strlen(srcChars
+ srcStart
);
76 if(length
!= srcLength
) {
77 return (int8_t)((length
- srcLength
) >> 24 | 1);
83 //========================================
84 // Write implementation
85 //========================================
88 * Implement argument checking and buffer handling
89 * for string case mapping as a common function.
93 UnicodeString::caseMap(BreakIterator
*titleIter
,
96 int32_t toWhichCase
) {
97 if(isEmpty() || !isWritable()) {
102 const UCaseProps
*csp
=ucase_getSingleton();
104 // We need to allocate a new buffer for the internal string case mapping function.
105 // This is very similar to how doReplace() keeps the old array pointer
106 // and deletes the old array itself after it is done.
107 // In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array.
108 UChar oldStackBuffer
[US_STACKBUF_SIZE
];
112 if(fFlags
&kUsingStackBuffer
) {
113 // copy the stack buffer contents because it will be overwritten
114 u_memcpy(oldStackBuffer
, fUnion
.fStackBuffer
, fShortLength
);
115 oldArray
= oldStackBuffer
;
116 oldLength
= fShortLength
;
118 oldArray
= getArrayStart();
119 oldLength
= length();
123 if(oldLength
<= US_STACKBUF_SIZE
) {
124 capacity
= US_STACKBUF_SIZE
;
126 capacity
= oldLength
+ 20;
128 int32_t *bufferToDelete
= 0;
129 if(!cloneArrayIfNeeded(capacity
, capacity
, FALSE
, &bufferToDelete
, TRUE
)) {
133 // Case-map, and if the result is too long, then reallocate and repeat.
134 UErrorCode errorCode
;
137 errorCode
= U_ZERO_ERROR
;
138 if(toWhichCase
==TO_LOWER
) {
139 newLength
= ustr_toLower(csp
, getArrayStart(), getCapacity(),
142 } else if(toWhichCase
==TO_UPPER
) {
143 newLength
= ustr_toUpper(csp
, getArrayStart(), getCapacity(),
146 } else if(toWhichCase
==TO_TITLE
) {
147 #if UCONFIG_NO_BREAK_ITERATION
148 errorCode
=U_UNSUPPORTED_ERROR
;
150 newLength
= ustr_toTitle(csp
, getArrayStart(), getCapacity(),
152 (UBreakIterator
*)titleIter
, locale
, options
, &errorCode
);
155 newLength
= ustr_foldCase(csp
, getArrayStart(), getCapacity(),
160 setLength(newLength
);
161 } while(errorCode
==U_BUFFER_OVERFLOW_ERROR
&& cloneArrayIfNeeded(newLength
, newLength
, FALSE
));
163 if (bufferToDelete
) {
164 uprv_free(bufferToDelete
);
166 if(U_FAILURE(errorCode
)) {
173 UnicodeString::toLower() {
174 return caseMap(0, Locale::getDefault().getName(), 0, TO_LOWER
);
178 UnicodeString::toLower(const Locale
&locale
) {
179 return caseMap(0, locale
.getName(), 0, TO_LOWER
);
183 UnicodeString::toUpper() {
184 return caseMap(0, Locale::getDefault().getName(), 0, TO_UPPER
);
188 UnicodeString::toUpper(const Locale
&locale
) {
189 return caseMap(0, locale
.getName(), 0, TO_UPPER
);
192 #if !UCONFIG_NO_BREAK_ITERATION
195 UnicodeString::toTitle(BreakIterator
*titleIter
) {
196 return caseMap(titleIter
, Locale::getDefault().getName(), 0, TO_TITLE
);
200 UnicodeString::toTitle(BreakIterator
*titleIter
, const Locale
&locale
) {
201 return caseMap(titleIter
, locale
.getName(), 0, TO_TITLE
);
205 UnicodeString::toTitle(BreakIterator
*titleIter
, const Locale
&locale
, uint32_t options
) {
206 return caseMap(titleIter
, locale
.getName(), options
, TO_TITLE
);
212 UnicodeString::foldCase(uint32_t options
) {
213 /* The Locale parameter isn't used. Use "" instead. */
214 return caseMap(0, "", options
, FOLD_CASE
);
219 // Defined here to reduce dependencies on break iterator
220 U_CAPI
int32_t U_EXPORT2
221 uhash_hashCaselessUnicodeString(const UHashTok key
) {
223 const UnicodeString
*str
= (const UnicodeString
*) key
.pointer
;
227 // Inefficient; a better way would be to have a hash function in
228 // UnicodeString that does case folding on the fly.
229 UnicodeString
copy(*str
);
230 return copy
.foldCase().hashCode();
233 // Defined here to reduce dependencies on break iterator
234 U_CAPI UBool U_EXPORT2
235 uhash_compareCaselessUnicodeString(const UHashTok key1
, const UHashTok key2
) {
237 const UnicodeString
*str1
= (const UnicodeString
*) key1
.pointer
;
238 const UnicodeString
*str2
= (const UnicodeString
*) key2
.pointer
;
242 if (str1
== NULL
|| str2
== NULL
) {
245 return str1
->caseCompare(*str2
, U_FOLD_CASE_DEFAULT
) == 0;