]>
git.saurik.com Git - apple/icu.git/blob - icuSources/common/unistr_case.cpp
2 *******************************************************************************
4 * Copyright (C) 1999-2005, 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"
34 //========================================
35 // Read-only implementation
36 //========================================
39 UnicodeString::doCaseCompare(int32_t start
,
41 const UChar
*srcChars
,
44 uint32_t options
) const
46 // compare illegal string values
47 // treat const UChar *srcChars==NULL as an empty string
52 // pin indices to legal values
53 pinIndices(start
, length
);
55 if(srcChars
== NULL
) {
56 srcStart
= srcLength
= 0;
59 // get the correct pointer
60 const UChar
*chars
= getArrayStart();
65 if(chars
!= srcChars
) {
66 UErrorCode errorCode
=U_ZERO_ERROR
;
67 int32_t result
=u_strcmpFold(chars
, length
, srcChars
, srcLength
,
68 options
|U_COMPARE_IGNORE_CASE
, &errorCode
);
70 return (int8_t)(result
>> 24 | 1);
73 // get the srcLength if necessary
75 srcLength
= u_strlen(srcChars
+ srcStart
);
77 if(length
!= srcLength
) {
78 return (int8_t)((length
- srcLength
) >> 24 | 1);
84 //========================================
85 // Write implementation
86 //========================================
89 * Implement argument checking and buffer handling
90 * for string case mapping as a common function.
100 UnicodeString::caseMap(BreakIterator
*titleIter
,
103 int32_t toWhichCase
) {
109 UErrorCode errorCode
;
111 errorCode
= U_ZERO_ERROR
;
112 const UCaseProps
*csp
=ucase_getSingleton(&errorCode
);
113 if(U_FAILURE(errorCode
)) {
118 // We need to allocate a new buffer for the internal string case mapping function.
119 // This is very similar to how doReplace() below keeps the old array pointer
120 // and deletes the old array itself after it is done.
121 // In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array.
122 UChar
*oldArray
= fArray
;
123 int32_t oldLength
= fLength
;
124 int32_t *bufferToDelete
= 0;
126 // Make sure that if the string is in fStackBuffer we do not overwrite it!
128 if(fLength
<= US_STACKBUF_SIZE
) {
129 if(fArray
== fStackBuffer
) {
130 capacity
= 2 * US_STACKBUF_SIZE
; // make sure that cloneArrayIfNeeded() allocates a new buffer
132 capacity
= US_STACKBUF_SIZE
;
135 capacity
= fLength
+ 20;
137 if(!cloneArrayIfNeeded(capacity
, capacity
, FALSE
, &bufferToDelete
, TRUE
)) {
141 #if !UCONFIG_NO_BREAK_ITERATION
142 // set up the titlecasing break iterator
143 UBreakIterator
*cTitleIter
= 0;
145 if(toWhichCase
== TO_TITLE
) {
146 errorCode
= U_ZERO_ERROR
;
148 cTitleIter
= (UBreakIterator
*)titleIter
;
149 ubrk_setText(cTitleIter
, oldArray
, oldLength
, &errorCode
);
151 cTitleIter
= ubrk_open(UBRK_WORD
, locale
,
155 if(U_FAILURE(errorCode
)) {
156 uprv_free(bufferToDelete
);
163 // Case-map, and if the result is too long, then reallocate and repeat.
165 errorCode
= U_ZERO_ERROR
;
166 if(toWhichCase
==TO_LOWER
) {
167 fLength
= ustr_toLower(csp
, fArray
, fCapacity
,
170 } else if(toWhichCase
==TO_UPPER
) {
171 fLength
= ustr_toUpper(csp
, fArray
, fCapacity
,
174 } else if(toWhichCase
==TO_TITLE
) {
175 #if UCONFIG_NO_BREAK_ITERATION
176 errorCode
=U_UNSUPPORTED_ERROR
;
178 fLength
= ustr_toTitle(csp
, fArray
, fCapacity
,
180 cTitleIter
, locale
, &errorCode
);
183 fLength
= ustr_foldCase(csp
, fArray
, fCapacity
,
188 } while(errorCode
==U_BUFFER_OVERFLOW_ERROR
&& cloneArrayIfNeeded(fLength
, fLength
, FALSE
));
190 #if !UCONFIG_NO_BREAK_ITERATION
191 if(cTitleIter
!= 0 && titleIter
== 0) {
192 ubrk_close(cTitleIter
);
196 if (bufferToDelete
) {
197 uprv_free(bufferToDelete
);
199 if(U_FAILURE(errorCode
)) {
206 UnicodeString::toLower() {
207 return caseMap(0, Locale::getDefault().getName(), 0, TO_LOWER
);
211 UnicodeString::toLower(const Locale
&locale
) {
212 return caseMap(0, locale
.getName(), 0, TO_LOWER
);
216 UnicodeString::toUpper() {
217 return caseMap(0, Locale::getDefault().getName(), 0, TO_UPPER
);
221 UnicodeString::toUpper(const Locale
&locale
) {
222 return caseMap(0, locale
.getName(), 0, TO_UPPER
);
225 #if !UCONFIG_NO_BREAK_ITERATION
228 UnicodeString::toTitle(BreakIterator
*titleIter
) {
229 return caseMap(titleIter
, Locale::getDefault().getName(), 0, TO_TITLE
);
233 UnicodeString::toTitle(BreakIterator
*titleIter
, const Locale
&locale
) {
234 return caseMap(titleIter
, locale
.getName(), 0, TO_TITLE
);
240 UnicodeString::foldCase(uint32_t options
) {
241 /* The Locale parameter isn't used. Use "" instead. */
242 return caseMap(0, "", options
, FOLD_CASE
);
247 // Defined here to reduce dependencies on break iterator
248 U_CAPI
int32_t U_EXPORT2
249 uhash_hashCaselessUnicodeString(const UHashTok key
) {
251 const UnicodeString
*str
= (const UnicodeString
*) key
.pointer
;
255 // Inefficient; a better way would be to have a hash function in
256 // UnicodeString that does case folding on the fly.
257 UnicodeString
copy(*str
);
258 return copy
.foldCase().hashCode();
261 // Defined here to reduce dependencies on break iterator
262 U_CAPI UBool U_EXPORT2
263 uhash_compareCaselessUnicodeString(const UHashTok key1
, const UHashTok key2
) {
265 const UnicodeString
*str1
= (const UnicodeString
*) key1
.pointer
;
266 const UnicodeString
*str2
= (const UnicodeString
*) key2
.pointer
;
270 if (str1
== NULL
|| str2
== NULL
) {
273 return str1
->caseCompare(*str2
, U_FOLD_CASE_DEFAULT
) == 0;