1 /*
2 **********************************************************************
3 * Copyright (c) 2002-2014, 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 
133 UStringEnumeration * U_EXPORT2
fromUEnumeration(UEnumeration * uenumToAdopt,UErrorCode & status)134 UStringEnumeration::fromUEnumeration(
135         UEnumeration *uenumToAdopt, UErrorCode &status) {
136     if (U_FAILURE(status)) {
137         uenum_close(uenumToAdopt);
138         return NULL;
139     }
140     UStringEnumeration *result = new UStringEnumeration(uenumToAdopt);
141     if (result == NULL) {
142         status = U_MEMORY_ALLOCATION_ERROR;
143         uenum_close(uenumToAdopt);
144         return NULL;
145     }
146     return result;
147 }
148 
UStringEnumeration(UEnumeration * _uenum)149 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
150     uenum(_uenum) {
151     U_ASSERT(_uenum != 0);
152 }
153 
~UStringEnumeration()154 UStringEnumeration::~UStringEnumeration() {
155     uenum_close(uenum);
156 }
157 
count(UErrorCode & status) const158 int32_t UStringEnumeration::count(UErrorCode& status) const {
159     return uenum_count(uenum, &status);
160 }
161 
next(int32_t * resultLength,UErrorCode & status)162 const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
163     return uenum_next(uenum, resultLength, &status);
164 }
165 
snext(UErrorCode & status)166 const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
167     int32_t length;
168     const UChar* str = uenum_unext(uenum, &length, &status);
169     if (str == 0 || U_FAILURE(status)) {
170         return 0;
171     }
172     return &unistr.setTo(str, length);
173 }
174 
reset(UErrorCode & status)175 void UStringEnumeration::reset(UErrorCode& status) {
176     uenum_reset(uenum, &status);
177 }
178 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)179 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
180 U_NAMESPACE_END
181 
182 // C wrapper --------------------------------------------------------------- ***
183 
184 #define THIS(en) ((icu::StringEnumeration*)(en->context))
185 
186 U_CDECL_BEGIN
187 
188 /**
189  * Wrapper API to make StringEnumeration look like UEnumeration.
190  */
191 static void U_CALLCONV
192 ustrenum_close(UEnumeration* en) {
193     delete THIS(en);
194     uprv_free(en);
195 }
196 
197 /**
198  * Wrapper API to make StringEnumeration look like UEnumeration.
199  */
200 static int32_t U_CALLCONV
ustrenum_count(UEnumeration * en,UErrorCode * ec)201 ustrenum_count(UEnumeration* en,
202                UErrorCode* ec)
203 {
204     return THIS(en)->count(*ec);
205 }
206 
207 /**
208  * Wrapper API to make StringEnumeration look like UEnumeration.
209  */
210 static const UChar* U_CALLCONV
ustrenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)211 ustrenum_unext(UEnumeration* en,
212                int32_t* resultLength,
213                UErrorCode* ec)
214 {
215     return THIS(en)->unext(resultLength, *ec);
216 }
217 
218 /**
219  * Wrapper API to make StringEnumeration look like UEnumeration.
220  */
221 static const char* U_CALLCONV
ustrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)222 ustrenum_next(UEnumeration* en,
223               int32_t* resultLength,
224               UErrorCode* ec)
225 {
226     return THIS(en)->next(resultLength, *ec);
227 }
228 
229 /**
230  * Wrapper API to make StringEnumeration look like UEnumeration.
231  */
232 static void U_CALLCONV
ustrenum_reset(UEnumeration * en,UErrorCode * ec)233 ustrenum_reset(UEnumeration* en,
234                UErrorCode* ec)
235 {
236     THIS(en)->reset(*ec);
237 }
238 
239 /**
240  * Pseudo-vtable for UEnumeration wrapper around StringEnumeration.
241  * The StringEnumeration pointer will be stored in 'context'.
242  */
243 static const UEnumeration USTRENUM_VT = {
244     NULL,
245     NULL, // store StringEnumeration pointer here
246     ustrenum_close,
247     ustrenum_count,
248     ustrenum_unext,
249     ustrenum_next,
250     ustrenum_reset
251 };
252 
253 U_CDECL_END
254 
255 /**
256  * Given a StringEnumeration, wrap it in a UEnumeration.  The
257  * StringEnumeration is adopted; after this call, the caller must not
258  * delete it (regardless of error status).
259  */
260 U_CAPI UEnumeration* U_EXPORT2
uenum_openFromStringEnumeration(icu::StringEnumeration * adopted,UErrorCode * ec)261 uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) {
262     UEnumeration* result = NULL;
263     if (U_SUCCESS(*ec) && adopted != NULL) {
264         result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
265         if (result == NULL) {
266             *ec = U_MEMORY_ALLOCATION_ERROR;
267         } else {
268             uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
269             result->context = adopted;
270         }
271     }
272     if (result == NULL) {
273         delete adopted;
274     }
275     return result;
276 }
277 
278 // C wrapper --------------------------------------------------------------- ***
279 
280 U_CDECL_BEGIN
281 
282 typedef struct UCharStringEnumeration {
283     UEnumeration uenum;
284     int32_t index, count;
285 } UCharStringEnumeration;
286 
287 static void U_CALLCONV
ucharstrenum_close(UEnumeration * en)288 ucharstrenum_close(UEnumeration* en) {
289     uprv_free(en);
290 }
291 
292 static int32_t U_CALLCONV
ucharstrenum_count(UEnumeration * en,UErrorCode *)293 ucharstrenum_count(UEnumeration* en,
294                    UErrorCode* /*ec*/) {
295     return ((UCharStringEnumeration*)en)->count;
296 }
297 
298 static const UChar* U_CALLCONV
ucharstrenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode *)299 ucharstrenum_unext(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 UChar* result = ((const UChar**)e->uenum.context)[e->index++];
307     if (resultLength) {
308         *resultLength = (int32_t)u_strlen(result);
309     }
310     return result;
311 }
312 
313 
314 static const char* U_CALLCONV
ucharstrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode *)315 ucharstrenum_next(UEnumeration* en,
316                   int32_t* resultLength,
317                   UErrorCode* /*ec*/) {
318     UCharStringEnumeration *e = (UCharStringEnumeration*) en;
319     if (e->index >= e->count) {
320         return NULL;
321     }
322     const char* result = ((const char**)e->uenum.context)[e->index++];
323     if (resultLength) {
324         *resultLength = (int32_t)uprv_strlen(result);
325     }
326     return result;
327 }
328 
329 static void U_CALLCONV
ucharstrenum_reset(UEnumeration * en,UErrorCode *)330 ucharstrenum_reset(UEnumeration* en,
331                    UErrorCode* /*ec*/) {
332     ((UCharStringEnumeration*)en)->index = 0;
333 }
334 
335 static const UEnumeration UCHARSTRENUM_VT = {
336     NULL,
337     NULL, // store StringEnumeration pointer here
338     ucharstrenum_close,
339     ucharstrenum_count,
340     uenum_unextDefault,
341     ucharstrenum_next,
342     ucharstrenum_reset
343 };
344 
345 static const UEnumeration UCHARSTRENUM_U_VT = {
346     NULL,
347     NULL, // store StringEnumeration pointer here
348     ucharstrenum_close,
349     ucharstrenum_count,
350     ucharstrenum_unext,
351     uenum_nextDefault,
352     ucharstrenum_reset
353 };
354 
355 U_CDECL_END
356 
357 U_CAPI UEnumeration* U_EXPORT2
uenum_openCharStringsEnumeration(const char * const strings[],int32_t count,UErrorCode * ec)358 uenum_openCharStringsEnumeration(const char* const strings[], int32_t count,
359                                  UErrorCode* ec) {
360     UCharStringEnumeration* result = NULL;
361     if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
362         result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
363         if (result == NULL) {
364             *ec = U_MEMORY_ALLOCATION_ERROR;
365         } else {
366             U_ASSERT((char*)result==(char*)(&result->uenum));
367             uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
368             result->uenum.context = (void*)strings;
369             result->index = 0;
370             result->count = count;
371         }
372     }
373     return (UEnumeration*) result;
374 }
375 
376 U_CAPI UEnumeration* U_EXPORT2
uenum_openUCharStringsEnumeration(const UChar * const strings[],int32_t count,UErrorCode * ec)377 uenum_openUCharStringsEnumeration(const UChar* const strings[], int32_t count,
378                                  UErrorCode* ec) {
379     UCharStringEnumeration* result = NULL;
380     if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
381         result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
382         if (result == NULL) {
383             *ec = U_MEMORY_ALLOCATION_ERROR;
384         } else {
385             U_ASSERT((char*)result==(char*)(&result->uenum));
386             uprv_memcpy(result, &UCHARSTRENUM_U_VT, sizeof(UCHARSTRENUM_U_VT));
387             result->uenum.context = (void*)strings;
388             result->index = 0;
389             result->count = count;
390         }
391     }
392     return (UEnumeration*) result;
393 }
394 
395 
396 // end C Wrapper
397