1 /*
2 **********************************************************************
3 * Copyright (c) 2002-2010, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 * Author: Alan Liu
7 * Created: November 11 2002
8 * Since: ICU 2.4
9 **********************************************************************
10 */
11 #include <typeinfo> // for 'typeid' to work
12
13 #include "unicode/ustring.h"
14 #include "unicode/strenum.h"
15 #include "unicode/putil.h"
16 #include "uenumimp.h"
17 #include "ustrenum.h"
18 #include "cstring.h"
19 #include "cmemory.h"
20 #include "uassert.h"
21
22 U_NAMESPACE_BEGIN
23 // StringEnumeration implementation ---------------------------------------- ***
24
StringEnumeration()25 StringEnumeration::StringEnumeration()
26 : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) {
27 }
28
~StringEnumeration()29 StringEnumeration::~StringEnumeration() {
30 if (chars != NULL && chars != charsBuffer) {
31 uprv_free(chars);
32 }
33 }
34
35 // StringEnumeration base class clone() default implementation, does not clone
36 StringEnumeration *
clone() const37 StringEnumeration::clone() const {
38 return NULL;
39 }
40
41 const char *
next(int32_t * resultLength,UErrorCode & status)42 StringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
43 const UnicodeString *s=snext(status);
44 if(s!=NULL) {
45 unistr=*s;
46 ensureCharsCapacity(unistr.length()+1, status);
47 if(U_SUCCESS(status)) {
48 if(resultLength!=NULL) {
49 *resultLength=unistr.length();
50 }
51 unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV);
52 return chars;
53 }
54 }
55
56 return NULL;
57 }
58
59 const UChar *
unext(int32_t * resultLength,UErrorCode & status)60 StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) {
61 const UnicodeString *s=snext(status);
62 if(s!=NULL) {
63 unistr=*s;
64 if(U_SUCCESS(status)) {
65 if(resultLength!=NULL) {
66 *resultLength=unistr.length();
67 }
68 return unistr.getTerminatedBuffer();
69 }
70 }
71
72 return NULL;
73 }
74
75 void
ensureCharsCapacity(int32_t capacity,UErrorCode & status)76 StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) {
77 if(U_SUCCESS(status) && capacity>charsCapacity) {
78 if(capacity<(charsCapacity+charsCapacity/2)) {
79 // avoid allocation thrashing
80 capacity=charsCapacity+charsCapacity/2;
81 }
82 if(chars!=charsBuffer) {
83 uprv_free(chars);
84 }
85 chars=(char *)uprv_malloc(capacity);
86 if(chars==NULL) {
87 chars=charsBuffer;
88 charsCapacity=sizeof(charsBuffer);
89 status=U_MEMORY_ALLOCATION_ERROR;
90 } else {
91 charsCapacity=capacity;
92 }
93 }
94 }
95
96 UnicodeString *
setChars(const char * s,int32_t length,UErrorCode & status)97 StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) {
98 if(U_SUCCESS(status) && s!=NULL) {
99 if(length<0) {
100 length=(int32_t)uprv_strlen(s);
101 }
102
103 UChar *buffer=unistr.getBuffer(length+1);
104 if(buffer!=NULL) {
105 u_charsToUChars(s, buffer, length);
106 buffer[length]=0;
107 unistr.releaseBuffer(length);
108 return &unistr;
109 } else {
110 status=U_MEMORY_ALLOCATION_ERROR;
111 }
112 }
113
114 return NULL;
115 }
116 UBool
operator ==(const StringEnumeration & that) const117 StringEnumeration::operator==(const StringEnumeration& that)const {
118 return typeid(*this) == typeid(that);
119 }
120
121 UBool
operator !=(const StringEnumeration & that) const122 StringEnumeration::operator!=(const StringEnumeration& that)const {
123 return !operator==(that);
124 }
125
126 // UStringEnumeration implementation --------------------------------------- ***
127
UStringEnumeration(UEnumeration * _uenum)128 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
129 uenum(_uenum) {
130 U_ASSERT(_uenum != 0);
131 }
132
~UStringEnumeration()133 UStringEnumeration::~UStringEnumeration() {
134 uenum_close(uenum);
135 }
136
count(UErrorCode & status) const137 int32_t UStringEnumeration::count(UErrorCode& status) const {
138 return uenum_count(uenum, &status);
139 }
140
snext(UErrorCode & status)141 const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
142 int32_t length;
143 const UChar* str = uenum_unext(uenum, &length, &status);
144 if (str == 0 || U_FAILURE(status)) {
145 return 0;
146 }
147 return &unistr.setTo(str, length);
148 }
149
reset(UErrorCode & status)150 void UStringEnumeration::reset(UErrorCode& status) {
151 uenum_reset(uenum, &status);
152 }
153
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)154 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
155 U_NAMESPACE_END
156
157 // C wrapper --------------------------------------------------------------- ***
158
159 #define THIS(en) ((U_NAMESPACE_QUALIFIER StringEnumeration*)(en->context))
160
161 U_CDECL_BEGIN
162
163 /**
164 * Wrapper API to make StringEnumeration look like UEnumeration.
165 */
166 static void U_CALLCONV
167 ustrenum_close(UEnumeration* en) {
168 delete THIS(en);
169 uprv_free(en);
170 }
171
172 /**
173 * Wrapper API to make StringEnumeration look like UEnumeration.
174 */
175 static int32_t U_CALLCONV
ustrenum_count(UEnumeration * en,UErrorCode * ec)176 ustrenum_count(UEnumeration* en,
177 UErrorCode* ec)
178 {
179 return THIS(en)->count(*ec);
180 }
181
182 /**
183 * Wrapper API to make StringEnumeration look like UEnumeration.
184 */
185 static const UChar* U_CALLCONV
ustrenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)186 ustrenum_unext(UEnumeration* en,
187 int32_t* resultLength,
188 UErrorCode* ec)
189 {
190 return THIS(en)->unext(resultLength, *ec);
191 }
192
193 /**
194 * Wrapper API to make StringEnumeration look like UEnumeration.
195 */
196 static const char* U_CALLCONV
ustrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)197 ustrenum_next(UEnumeration* en,
198 int32_t* resultLength,
199 UErrorCode* ec)
200 {
201 return THIS(en)->next(resultLength, *ec);
202 }
203
204 /**
205 * Wrapper API to make StringEnumeration look like UEnumeration.
206 */
207 static void U_CALLCONV
ustrenum_reset(UEnumeration * en,UErrorCode * ec)208 ustrenum_reset(UEnumeration* en,
209 UErrorCode* ec)
210 {
211 THIS(en)->reset(*ec);
212 }
213
214 /**
215 * Pseudo-vtable for UEnumeration wrapper around StringEnumeration.
216 * The StringEnumeration pointer will be stored in 'context'.
217 */
218 static const UEnumeration USTRENUM_VT = {
219 NULL,
220 NULL, // store StringEnumeration pointer here
221 ustrenum_close,
222 ustrenum_count,
223 ustrenum_unext,
224 ustrenum_next,
225 ustrenum_reset
226 };
227
228 U_CDECL_END
229
230 /**
231 * Given a StringEnumeration, wrap it in a UEnumeration. The
232 * StringEnumeration is adopted; after this call, the caller must not
233 * delete it (regardless of error status).
234 */
235 U_CAPI UEnumeration* U_EXPORT2
uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration * adopted,UErrorCode * ec)236 uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration* adopted, UErrorCode* ec) {
237 UEnumeration* result = NULL;
238 if (U_SUCCESS(*ec) && adopted != NULL) {
239 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
240 if (result == NULL) {
241 *ec = U_MEMORY_ALLOCATION_ERROR;
242 } else {
243 uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
244 result->context = adopted;
245 }
246 }
247 if (result == NULL) {
248 delete adopted;
249 }
250 return result;
251 }
252
253 // C wrapper --------------------------------------------------------------- ***
254
255 U_CDECL_BEGIN
256
257 typedef struct UCharStringEnumeration {
258 UEnumeration uenum;
259 int32_t index, count;
260 } UCharStringEnumeration;
261
262 static void U_CALLCONV
ucharstrenum_close(UEnumeration * en)263 ucharstrenum_close(UEnumeration* en) {
264 uprv_free(en);
265 }
266
267 static int32_t U_CALLCONV
ucharstrenum_count(UEnumeration * en,UErrorCode *)268 ucharstrenum_count(UEnumeration* en,
269 UErrorCode* /*ec*/) {
270 return ((UCharStringEnumeration*)en)->count;
271 }
272
273 static const char* U_CALLCONV
ucharstrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode *)274 ucharstrenum_next(UEnumeration* en,
275 int32_t* resultLength,
276 UErrorCode* /*ec*/) {
277 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
278 if (e->index >= e->count) {
279 return NULL;
280 }
281 const char* result = ((const char**)e->uenum.context)[e->index++];
282 if (resultLength) {
283 *resultLength = (int32_t)uprv_strlen(result);
284 }
285 return result;
286 }
287
288 static void U_CALLCONV
ucharstrenum_reset(UEnumeration * en,UErrorCode *)289 ucharstrenum_reset(UEnumeration* en,
290 UErrorCode* /*ec*/) {
291 ((UCharStringEnumeration*)en)->index = 0;
292 }
293
294 static const UEnumeration UCHARSTRENUM_VT = {
295 NULL,
296 NULL, // store StringEnumeration pointer here
297 ucharstrenum_close,
298 ucharstrenum_count,
299 uenum_unextDefault,
300 ucharstrenum_next,
301 ucharstrenum_reset
302 };
303
304 U_CDECL_END
305
306 U_CAPI UEnumeration* U_EXPORT2
uenum_openCharStringsEnumeration(const char * const * strings,int32_t count,UErrorCode * ec)307 uenum_openCharStringsEnumeration(const char* const* strings, int32_t count,
308 UErrorCode* ec) {
309 UCharStringEnumeration* result = NULL;
310 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
311 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
312 if (result == NULL) {
313 *ec = U_MEMORY_ALLOCATION_ERROR;
314 } else {
315 U_ASSERT((char*)result==(char*)(&result->uenum));
316 uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
317 result->uenum.context = (void*)strings;
318 result->index = 0;
319 result->count = count;
320 }
321 }
322 return (UEnumeration*) result;
323 }
324
325
326