]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/unistr_case.cpp
ICU-57163.0.1.tar.gz
[apple/icu.git] / icuSources / common / unistr_case.cpp
CommitLineData
374ca955
A
1/*
2*******************************************************************************
3*
b331163b 4* Copyright (C) 1999-2014, International Business Machines
374ca955
A
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"
374ca955
A
21#include "cstring.h"
22#include "cmemory.h"
23#include "unicode/ustring.h"
24#include "unicode/unistr.h"
25#include "unicode/uchar.h"
4388f060 26#include "uelement.h"
374ca955 27#include "ustr_imp.h"
374ca955
A
28
29U_NAMESPACE_BEGIN
30
31//========================================
32// Read-only implementation
33//========================================
34
35int8_t
36UnicodeString::doCaseCompare(int32_t start,
37 int32_t length,
38 const UChar *srcChars,
39 int32_t srcStart,
40 int32_t srcLength,
41 uint32_t options) const
42{
43 // compare illegal string values
44 // treat const UChar *srcChars==NULL as an empty string
45 if(isBogus()) {
46 return -1;
47 }
48
49 // pin indices to legal values
50 pinIndices(start, length);
51
52 if(srcChars == NULL) {
53 srcStart = srcLength = 0;
54 }
55
56 // get the correct pointer
57 const UChar *chars = getArrayStart();
58
59 chars += start;
4388f060
A
60 if(srcStart!=0) {
61 srcChars += srcStart;
62 }
374ca955
A
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
374ca955 87UnicodeString &
4388f060
A
88UnicodeString::caseMap(const UCaseMap *csm,
89 UStringCaseMapper *stringCaseMapper) {
46f4442e 90 if(isEmpty() || !isWritable()) {
374ca955
A
91 // nothing to do
92 return *this;
93 }
94
374ca955 95 // We need to allocate a new buffer for the internal string case mapping function.
46f4442e 96 // This is very similar to how doReplace() keeps the old array pointer
374ca955
A
97 // and deletes the old array itself after it is done.
98 // In addition, we are forcing cloneArrayIfNeeded() to always allocate a new array.
46f4442e
A
99 UChar oldStackBuffer[US_STACKBUF_SIZE];
100 UChar *oldArray;
101 int32_t oldLength;
102
b331163b 103 if(fUnion.fFields.fLengthAndFlags&kUsingStackBuffer) {
46f4442e 104 // copy the stack buffer contents because it will be overwritten
46f4442e 105 oldArray = oldStackBuffer;
b331163b
A
106 oldLength = getShortLength();
107 u_memcpy(oldStackBuffer, fUnion.fStackFields.fBuffer, oldLength);
46f4442e
A
108 } else {
109 oldArray = getArrayStart();
110 oldLength = length();
111 }
374ca955 112
374ca955 113 int32_t capacity;
46f4442e
A
114 if(oldLength <= US_STACKBUF_SIZE) {
115 capacity = US_STACKBUF_SIZE;
374ca955 116 } else {
46f4442e 117 capacity = oldLength + 20;
374ca955 118 }
46f4442e 119 int32_t *bufferToDelete = 0;
374ca955
A
120 if(!cloneArrayIfNeeded(capacity, capacity, FALSE, &bufferToDelete, TRUE)) {
121 return *this;
122 }
123
374ca955 124 // Case-map, and if the result is too long, then reallocate and repeat.
729e4ab9 125 UErrorCode errorCode;
46f4442e 126 int32_t newLength;
374ca955
A
127 do {
128 errorCode = U_ZERO_ERROR;
4388f060
A
129 newLength = stringCaseMapper(csm, getArrayStart(), getCapacity(),
130 oldArray, oldLength, &errorCode);
46f4442e
A
131 setLength(newLength);
132 } while(errorCode==U_BUFFER_OVERFLOW_ERROR && cloneArrayIfNeeded(newLength, newLength, FALSE));
374ca955
A
133
134 if (bufferToDelete) {
135 uprv_free(bufferToDelete);
136 }
137 if(U_FAILURE(errorCode)) {
138 setToBogus();
139 }
140 return *this;
141}
142
374ca955
A
143UnicodeString &
144UnicodeString::foldCase(uint32_t options) {
4388f060
A
145 UCaseMap csm=UCASEMAP_INITIALIZER;
146 csm.csp=ucase_getSingleton();
147 csm.options=options;
148 return caseMap(&csm, ustrcase_internalFold);
374ca955
A
149}
150
151U_NAMESPACE_END
73c04bcf
A
152
153// Defined here to reduce dependencies on break iterator
154U_CAPI int32_t U_EXPORT2
4388f060 155uhash_hashCaselessUnicodeString(const UElement key) {
73c04bcf
A
156 U_NAMESPACE_USE
157 const UnicodeString *str = (const UnicodeString*) key.pointer;
158 if (str == NULL) {
159 return 0;
160 }
161 // Inefficient; a better way would be to have a hash function in
162 // UnicodeString that does case folding on the fly.
163 UnicodeString copy(*str);
164 return copy.foldCase().hashCode();
165}
166
167// Defined here to reduce dependencies on break iterator
168U_CAPI UBool U_EXPORT2
4388f060 169uhash_compareCaselessUnicodeString(const UElement key1, const UElement key2) {
73c04bcf
A
170 U_NAMESPACE_USE
171 const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
172 const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
173 if (str1 == str2) {
174 return TRUE;
175 }
176 if (str1 == NULL || str2 == NULL) {
177 return FALSE;
178 }
179 return str1->caseCompare(*str2, U_FOLD_CASE_DEFAULT) == 0;
180}