1 /*
2 **********************************************************************
3 * Copyright (c) 2002-2012, 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 "utypeinfo.h" // 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(U_SUCCESS(status) && 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(U_SUCCESS(status) && s!=NULL) {
63 unistr=*s;
64 if(resultLength!=NULL) {
65 *resultLength=unistr.length();
66 }
67 return unistr.getTerminatedBuffer();
68 }
69
70 return NULL;
71 }
72
73 const UnicodeString *
snext(UErrorCode & status)74 StringEnumeration::snext(UErrorCode &status) {
75 int32_t length;
76 const char *s=next(&length, status);
77 return setChars(s, length, status);
78 }
79
80 void
ensureCharsCapacity(int32_t capacity,UErrorCode & status)81 StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) {
82 if(U_SUCCESS(status) && capacity>charsCapacity) {
83 if(capacity<(charsCapacity+charsCapacity/2)) {
84 // avoid allocation thrashing
85 capacity=charsCapacity+charsCapacity/2;
86 }
87 if(chars!=charsBuffer) {
88 uprv_free(chars);
89 }
90 chars=(char *)uprv_malloc(capacity);
91 if(chars==NULL) {
92 chars=charsBuffer;
93 charsCapacity=sizeof(charsBuffer);
94 status=U_MEMORY_ALLOCATION_ERROR;
95 } else {
96 charsCapacity=capacity;
97 }
98 }
99 }
100
101 UnicodeString *
setChars(const char * s,int32_t length,UErrorCode & status)102 StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) {
103 if(U_SUCCESS(status) && s!=NULL) {
104 if(length<0) {
105 length=(int32_t)uprv_strlen(s);
106 }
107
108 UChar *buffer=unistr.getBuffer(length+1);
109 if(buffer!=NULL) {
110 u_charsToUChars(s, buffer, length);
111 buffer[length]=0;
112 unistr.releaseBuffer(length);
113 return &unistr;
114 } else {
115 status=U_MEMORY_ALLOCATION_ERROR;
116 }
117 }
118
119 return NULL;
120 }
121 UBool
operator ==(const StringEnumeration & that) const122 StringEnumeration::operator==(const StringEnumeration& that)const {
123 return typeid(*this) == typeid(that);
124 }
125
126 UBool
operator !=(const StringEnumeration & that) const127 StringEnumeration::operator!=(const StringEnumeration& that)const {
128 return !operator==(that);
129 }
130
131 // UStringEnumeration implementation --------------------------------------- ***
132
UStringEnumeration(UEnumeration * _uenum)133 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
134 uenum(_uenum) {
135 U_ASSERT(_uenum != 0);
136 }
137
~UStringEnumeration()138 UStringEnumeration::~UStringEnumeration() {
139 uenum_close(uenum);
140 }
141
count(UErrorCode & status) const142 int32_t UStringEnumeration::count(UErrorCode& status) const {
143 return uenum_count(uenum, &status);
144 }
145
next(int32_t * resultLength,UErrorCode & status)146 const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
147 return uenum_next(uenum, resultLength, &status);
148 }
149
snext(UErrorCode & status)150 const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
151 int32_t length;
152 const UChar* str = uenum_unext(uenum, &length, &status);
153 if (str == 0 || U_FAILURE(status)) {
154 return 0;
155 }
156 return &unistr.setTo(str, length);
157 }
158
reset(UErrorCode & status)159 void UStringEnumeration::reset(UErrorCode& status) {
160 uenum_reset(uenum, &status);
161 }
162
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)163 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
164 U_NAMESPACE_END
165
166 // C wrapper --------------------------------------------------------------- ***
167
168 #define THIS(en) ((icu::StringEnumeration*)(en->context))
169
170 U_CDECL_BEGIN
171
172 /**
173 * Wrapper API to make StringEnumeration look like UEnumeration.
174 */
175 static void U_CALLCONV
176 ustrenum_close(UEnumeration* en) {
177 delete THIS(en);
178 uprv_free(en);
179 }
180
181 /**
182 * Wrapper API to make StringEnumeration look like UEnumeration.
183 */
184 static int32_t U_CALLCONV
ustrenum_count(UEnumeration * en,UErrorCode * ec)185 ustrenum_count(UEnumeration* en,
186 UErrorCode* ec)
187 {
188 return THIS(en)->count(*ec);
189 }
190
191 /**
192 * Wrapper API to make StringEnumeration look like UEnumeration.
193 */
194 static const UChar* U_CALLCONV
ustrenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)195 ustrenum_unext(UEnumeration* en,
196 int32_t* resultLength,
197 UErrorCode* ec)
198 {
199 return THIS(en)->unext(resultLength, *ec);
200 }
201
202 /**
203 * Wrapper API to make StringEnumeration look like UEnumeration.
204 */
205 static const char* U_CALLCONV
ustrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)206 ustrenum_next(UEnumeration* en,
207 int32_t* resultLength,
208 UErrorCode* ec)
209 {
210 return THIS(en)->next(resultLength, *ec);
211 }
212
213 /**
214 * Wrapper API to make StringEnumeration look like UEnumeration.
215 */
216 static void U_CALLCONV
ustrenum_reset(UEnumeration * en,UErrorCode * ec)217 ustrenum_reset(UEnumeration* en,
218 UErrorCode* ec)
219 {
220 THIS(en)->reset(*ec);
221 }
222
223 /**
224 * Pseudo-vtable for UEnumeration wrapper around StringEnumeration.
225 * The StringEnumeration pointer will be stored in 'context'.
226 */
227 static const UEnumeration USTRENUM_VT = {
228 NULL,
229 NULL, // store StringEnumeration pointer here
230 ustrenum_close,
231 ustrenum_count,
232 ustrenum_unext,
233 ustrenum_next,
234 ustrenum_reset
235 };
236
237 U_CDECL_END
238
239 /**
240 * Given a StringEnumeration, wrap it in a UEnumeration. The
241 * StringEnumeration is adopted; after this call, the caller must not
242 * delete it (regardless of error status).
243 */
244 U_CAPI UEnumeration* U_EXPORT2
uenum_openFromStringEnumeration(icu::StringEnumeration * adopted,UErrorCode * ec)245 uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) {
246 UEnumeration* result = NULL;
247 if (U_SUCCESS(*ec) && adopted != NULL) {
248 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
249 if (result == NULL) {
250 *ec = U_MEMORY_ALLOCATION_ERROR;
251 } else {
252 uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
253 result->context = adopted;
254 }
255 }
256 if (result == NULL) {
257 delete adopted;
258 }
259 return result;
260 }
261
262 // C wrapper --------------------------------------------------------------- ***
263
264 U_CDECL_BEGIN
265
266 typedef struct UCharStringEnumeration {
267 UEnumeration uenum;
268 int32_t index, count;
269 } UCharStringEnumeration;
270
271 static void U_CALLCONV
ucharstrenum_close(UEnumeration * en)272 ucharstrenum_close(UEnumeration* en) {
273 uprv_free(en);
274 }
275
276 static int32_t U_CALLCONV
ucharstrenum_count(UEnumeration * en,UErrorCode *)277 ucharstrenum_count(UEnumeration* en,
278 UErrorCode* /*ec*/) {
279 return ((UCharStringEnumeration*)en)->count;
280 }
281
282 static const UChar* U_CALLCONV
ucharstrenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode *)283 ucharstrenum_unext(UEnumeration* en,
284 int32_t* resultLength,
285 UErrorCode* /*ec*/) {
286 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
287 if (e->index >= e->count) {
288 return NULL;
289 }
290 const UChar* result = ((const UChar**)e->uenum.context)[e->index++];
291 if (resultLength) {
292 *resultLength = (int32_t)u_strlen(result);
293 }
294 return result;
295 }
296
297
298 static const char* U_CALLCONV
ucharstrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode *)299 ucharstrenum_next(UEnumeration* en,
300 int32_t* resultLength,
301 UErrorCode* /*ec*/) {
302 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
303 if (e->index >= e->count) {
304 return NULL;
305 }
306 const char* result = ((const char**)e->uenum.context)[e->index++];
307 if (resultLength) {
308 *resultLength = (int32_t)uprv_strlen(result);
309 }
310 return result;
311 }
312
313 static void U_CALLCONV
ucharstrenum_reset(UEnumeration * en,UErrorCode *)314 ucharstrenum_reset(UEnumeration* en,
315 UErrorCode* /*ec*/) {
316 ((UCharStringEnumeration*)en)->index = 0;
317 }
318
319 static const UEnumeration UCHARSTRENUM_VT = {
320 NULL,
321 NULL, // store StringEnumeration pointer here
322 ucharstrenum_close,
323 ucharstrenum_count,
324 uenum_unextDefault,
325 ucharstrenum_next,
326 ucharstrenum_reset
327 };
328
329 static const UEnumeration UCHARSTRENUM_U_VT = {
330 NULL,
331 NULL, // store StringEnumeration pointer here
332 ucharstrenum_close,
333 ucharstrenum_count,
334 ucharstrenum_unext,
335 uenum_nextDefault,
336 ucharstrenum_reset
337 };
338
339 U_CDECL_END
340
341 U_CAPI UEnumeration* U_EXPORT2
uenum_openCharStringsEnumeration(const char * const strings[],int32_t count,UErrorCode * ec)342 uenum_openCharStringsEnumeration(const char* const strings[], int32_t count,
343 UErrorCode* ec) {
344 UCharStringEnumeration* result = NULL;
345 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
346 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
347 if (result == NULL) {
348 *ec = U_MEMORY_ALLOCATION_ERROR;
349 } else {
350 U_ASSERT((char*)result==(char*)(&result->uenum));
351 uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
352 result->uenum.context = (void*)strings;
353 result->index = 0;
354 result->count = count;
355 }
356 }
357 return (UEnumeration*) result;
358 }
359
360 U_CAPI UEnumeration* U_EXPORT2
uenum_openUCharStringsEnumeration(const UChar * const strings[],int32_t count,UErrorCode * ec)361 uenum_openUCharStringsEnumeration(const UChar* const strings[], int32_t count,
362 UErrorCode* ec) {
363 UCharStringEnumeration* result = NULL;
364 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
365 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
366 if (result == NULL) {
367 *ec = U_MEMORY_ALLOCATION_ERROR;
368 } else {
369 U_ASSERT((char*)result==(char*)(&result->uenum));
370 uprv_memcpy(result, &UCHARSTRENUM_U_VT, sizeof(UCHARSTRENUM_U_VT));
371 result->uenum.context = (void*)strings;
372 result->index = 0;
373 result->count = count;
374 }
375 }
376 return (UEnumeration*) result;
377 }
378
379
380 // end C Wrapper
381