]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/unistr_case.cpp
ICU-6.2.22.tar.gz
[apple/icu.git] / icuSources / common / unistr_case.cpp
CommitLineData
374ca955
A
1/*
2*******************************************************************************
3*
4* Copyright (C) 1999-2004, International Business Machines
5* Corporation and others. All Rights Reserved.
6*
7*******************************************************************************
8* file name: unistr_case.cpp
9* encoding: US-ASCII
10* tab size: 8 (not used)
11* indentation:2
12*
13* created on: 2004aug19
14* created by: Markus W. Scherer
15*
16* Case-mapping functions moved here from unistr.cpp
17*/
18
19#include "unicode/utypes.h"
20#include "unicode/putil.h"
21#include "unicode/locid.h"
22#include "cstring.h"
23#include "cmemory.h"
24#include "unicode/ustring.h"
25#include "unicode/unistr.h"
26#include "unicode/uchar.h"
27#include "unicode/ubrk.h"
28#include "ustr_imp.h"
29#include "unormimp.h"
30
31U_NAMESPACE_BEGIN
32
33//========================================
34// Read-only implementation
35//========================================
36
37int8_t
38UnicodeString::doCaseCompare(int32_t start,
39 int32_t length,
40 const UChar *srcChars,
41 int32_t srcStart,
42 int32_t srcLength,
43 uint32_t options) const
44{
45 // compare illegal string values
46 // treat const UChar *srcChars==NULL as an empty string
47 if(isBogus()) {
48 return -1;
49 }
50
51 // pin indices to legal values
52 pinIndices(start, length);
53
54 if(srcChars == NULL) {
55 srcStart = srcLength = 0;
56 }
57
58 // get the correct pointer
59 const UChar *chars = getArrayStart();
60
61 chars += start;
62 srcChars += srcStart;
63
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);
68 if(result!=0) {
69 return (int8_t)(result >> 24 | 1);
70 }
71 } else {
72 // get the srcLength if necessary
73 if(srcLength < 0) {
74 srcLength = u_strlen(srcChars + srcStart);
75 }
76 if(length != srcLength) {
77 return (int8_t)((length - srcLength) >> 24 | 1);
78 }
79 }
80 return 0;
81}
82
83//========================================
84// Write implementation
85//========================================
86
87/*
88 * Implement argument checking and buffer handling
89 * for string case mapping as a common function.
90 */
91enum {
92 TO_LOWER,
93 TO_UPPER,
94 TO_TITLE,
95 FOLD_CASE
96};
97
98UnicodeString &
99UnicodeString::caseMap(BreakIterator *titleIter,
100 const char *locale,
101 uint32_t options,
102 int32_t toWhichCase) {
103 if(fLength <= 0) {
104 // nothing to do
105 return *this;
106 }
107
108 UErrorCode errorCode;
109
110 errorCode = U_ZERO_ERROR;
111 UCaseProps *csp=ucase_getSingleton(&errorCode);
112 if(U_FAILURE(errorCode)) {
113 setToBogus();
114 return *this;
115 }
116
117 // We need to allocate a new buffer for the internal string case mapping function.
118 // This is very similar to how doReplace() below keeps the old array pointer
119 // and deletes the old array itself after it is done.
120 // In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array.
121 UChar *oldArray = fArray;
122 int32_t oldLength = fLength;
123 int32_t *bufferToDelete = 0;
124
125 // Make sure that if the string is in fStackBuffer we do not overwrite it!
126 int32_t capacity;
127 if(fLength <= US_STACKBUF_SIZE) {
128 if(fArray == fStackBuffer) {
129 capacity = 2 * US_STACKBUF_SIZE; // make sure that cloneArrayIfNeeded() allocates a new buffer
130 } else {
131 capacity = US_STACKBUF_SIZE;
132 }
133 } else {
134 capacity = fLength + 20;
135 }
136 if(!cloneArrayIfNeeded(capacity, capacity, FALSE, &bufferToDelete, TRUE)) {
137 return *this;
138 }
139
140#if !UCONFIG_NO_BREAK_ITERATION
141 // set up the titlecasing break iterator
142 UBreakIterator *cTitleIter = 0;
143
144 if(toWhichCase == TO_TITLE) {
145 errorCode = U_ZERO_ERROR;
146 if(titleIter != 0) {
147 cTitleIter = (UBreakIterator *)titleIter;
148 ubrk_setText(cTitleIter, oldArray, oldLength, &errorCode);
149 } else {
150 cTitleIter = ubrk_open(UBRK_WORD, locale,
151 oldArray, oldLength,
152 &errorCode);
153 }
154 if(U_FAILURE(errorCode)) {
155 uprv_free(bufferToDelete);
156 setToBogus();
157 return *this;
158 }
159 }
160#endif
161
162 // Case-map, and if the result is too long, then reallocate and repeat.
163 do {
164 errorCode = U_ZERO_ERROR;
165 if(toWhichCase==TO_LOWER) {
166 fLength = ustr_toLower(csp, fArray, fCapacity,
167 oldArray, oldLength,
168 locale, &errorCode);
169 } else if(toWhichCase==TO_UPPER) {
170 fLength = ustr_toUpper(csp, fArray, fCapacity,
171 oldArray, oldLength,
172 locale, &errorCode);
173 } else if(toWhichCase==TO_TITLE) {
174#if UCONFIG_NO_BREAK_ITERATION
175 errorCode=U_UNSUPPORTED_ERROR;
176#else
177 fLength = ustr_toTitle(csp, fArray, fCapacity,
178 oldArray, oldLength,
179 cTitleIter, locale, &errorCode);
180#endif
181 } else {
182 fLength = ustr_foldCase(csp, fArray, fCapacity,
183 oldArray, oldLength,
184 options,
185 &errorCode);
186 }
187 } while(errorCode==U_BUFFER_OVERFLOW_ERROR && cloneArrayIfNeeded(fLength, fLength, FALSE));
188
189#if !UCONFIG_NO_BREAK_ITERATION
190 if(cTitleIter != 0 && titleIter == 0) {
191 ubrk_close(cTitleIter);
192 }
193#endif
194
195 if (bufferToDelete) {
196 uprv_free(bufferToDelete);
197 }
198 if(U_FAILURE(errorCode)) {
199 setToBogus();
200 }
201 return *this;
202}
203
204UnicodeString &
205UnicodeString::toLower() {
206 return caseMap(0, Locale::getDefault().getName(), 0, TO_LOWER);
207}
208
209UnicodeString &
210UnicodeString::toLower(const Locale &locale) {
211 return caseMap(0, locale.getName(), 0, TO_LOWER);
212}
213
214UnicodeString &
215UnicodeString::toUpper() {
216 return caseMap(0, Locale::getDefault().getName(), 0, TO_UPPER);
217}
218
219UnicodeString &
220UnicodeString::toUpper(const Locale &locale) {
221 return caseMap(0, locale.getName(), 0, TO_UPPER);
222}
223
224#if !UCONFIG_NO_BREAK_ITERATION
225
226UnicodeString &
227UnicodeString::toTitle(BreakIterator *titleIter) {
228 return caseMap(titleIter, Locale::getDefault().getName(), 0, TO_TITLE);
229}
230
231UnicodeString &
232UnicodeString::toTitle(BreakIterator *titleIter, const Locale &locale) {
233 return caseMap(titleIter, locale.getName(), 0, TO_TITLE);
234}
235
236#endif
237
238UnicodeString &
239UnicodeString::foldCase(uint32_t options) {
240 /* The Locale parameter isn't used. Use "" instead. */
241 return caseMap(0, "", options, FOLD_CASE);
242}
243
244U_NAMESPACE_END