• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
122 UBool
operator !=(const StringEnumeration & that) const123 StringEnumeration::operator!=(const StringEnumeration& that)const {
124     return !operator==(that);
125 }
126 
127 // UStringEnumeration implementation --------------------------------------- ***
128 
UStringEnumeration(UEnumeration * _uenum)129 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
130     uenum(_uenum) {
131     U_ASSERT(_uenum != 0);
132 }
133 
~UStringEnumeration()134 UStringEnumeration::~UStringEnumeration() {
135     uenum_close(uenum);
136 }
137 
count(UErrorCode & status) const138 int32_t UStringEnumeration::count(UErrorCode& status) const {
139     return uenum_count(uenum, &status);
140 }
141 
snext(UErrorCode & status)142 const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
143     int32_t length;
144     const UChar* str = uenum_unext(uenum, &length, &status);
145     if (str == 0 || U_FAILURE(status)) {
146         return 0;
147     }
148     return &unistr.setTo(str, length);
149 }
150 
reset(UErrorCode & status)151 void UStringEnumeration::reset(UErrorCode& status) {
152     uenum_reset(uenum, &status);
153 }
154 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)155 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
156 U_NAMESPACE_END
157 
158 // C wrapper --------------------------------------------------------------- ***
159 
160 #define THIS(en) ((U_NAMESPACE_QUALIFIER StringEnumeration*)(en->context))
161 
162 U_CDECL_BEGIN
163 
164 /**
165  * Wrapper API to make StringEnumeration look like UEnumeration.
166  */
167 static void U_CALLCONV
168 ustrenum_close(UEnumeration* en) {
169     delete THIS(en);
170     uprv_free(en);
171 }
172 
173 /**
174  * Wrapper API to make StringEnumeration look like UEnumeration.
175  */
176 static int32_t U_CALLCONV
ustrenum_count(UEnumeration * en,UErrorCode * ec)177 ustrenum_count(UEnumeration* en,
178                UErrorCode* ec)
179 {
180     return THIS(en)->count(*ec);
181 }
182 
183 /**
184  * Wrapper API to make StringEnumeration look like UEnumeration.
185  */
186 static const UChar* U_CALLCONV
ustrenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)187 ustrenum_unext(UEnumeration* en,
188                int32_t* resultLength,
189                UErrorCode* ec)
190 {
191     return THIS(en)->unext(resultLength, *ec);
192 }
193 
194 /**
195  * Wrapper API to make StringEnumeration look like UEnumeration.
196  */
197 static const char* U_CALLCONV
ustrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode * ec)198 ustrenum_next(UEnumeration* en,
199               int32_t* resultLength,
200               UErrorCode* ec)
201 {
202     return THIS(en)->next(resultLength, *ec);
203 }
204 
205 /**
206  * Wrapper API to make StringEnumeration look like UEnumeration.
207  */
208 static void U_CALLCONV
ustrenum_reset(UEnumeration * en,UErrorCode * ec)209 ustrenum_reset(UEnumeration* en,
210                UErrorCode* ec)
211 {
212     THIS(en)->reset(*ec);
213 }
214 
215 /**
216  * Pseudo-vtable for UEnumeration wrapper around StringEnumeration.
217  * The StringEnumeration pointer will be stored in 'context'.
218  */
219 static const UEnumeration USTRENUM_VT = {
220     NULL,
221     NULL, // store StringEnumeration pointer here
222     ustrenum_close,
223     ustrenum_count,
224     ustrenum_unext,
225     ustrenum_next,
226     ustrenum_reset
227 };
228 
229 U_CDECL_END
230 
231 /**
232  * Given a StringEnumeration, wrap it in a UEnumeration.  The
233  * StringEnumeration is adopted; after this call, the caller must not
234  * delete it (regardless of error status).
235  */
236 U_CAPI UEnumeration* U_EXPORT2
uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration * adopted,UErrorCode * ec)237 uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration* adopted, UErrorCode* ec) {
238     UEnumeration* result = NULL;
239     if (U_SUCCESS(*ec) && adopted != NULL) {
240         result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
241         if (result == NULL) {
242             *ec = U_MEMORY_ALLOCATION_ERROR;
243         } else {
244             uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT));
245             result->context = adopted;
246         }
247     }
248     if (result == NULL) {
249         delete adopted;
250     }
251     return result;
252 }
253 
254 // C wrapper --------------------------------------------------------------- ***
255 
256 U_CDECL_BEGIN
257 
258 typedef struct UCharStringEnumeration {
259     UEnumeration uenum;
260     int32_t index, count;
261 } UCharStringEnumeration;
262 
263 static void U_CALLCONV
ucharstrenum_close(UEnumeration * en)264 ucharstrenum_close(UEnumeration* en) {
265     uprv_free(en);
266 }
267 
268 static int32_t U_CALLCONV
ucharstrenum_count(UEnumeration * en,UErrorCode *)269 ucharstrenum_count(UEnumeration* en,
270                    UErrorCode* /*ec*/) {
271     return ((UCharStringEnumeration*)en)->count;
272 }
273 
274 static const char* U_CALLCONV
ucharstrenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode *)275 ucharstrenum_next(UEnumeration* en,
276                   int32_t* resultLength,
277                   UErrorCode* /*ec*/) {
278     UCharStringEnumeration *e = (UCharStringEnumeration*) en;
279     if (e->index >= e->count) {
280         return NULL;
281     }
282     const char* result = ((const char**)e->uenum.context)[e->index++];
283     if (resultLength) {
284         *resultLength = (int32_t)uprv_strlen(result);
285     }
286     return result;
287 }
288 
289 static void U_CALLCONV
ucharstrenum_reset(UEnumeration * en,UErrorCode *)290 ucharstrenum_reset(UEnumeration* en,
291                    UErrorCode* /*ec*/) {
292     ((UCharStringEnumeration*)en)->index = 0;
293 }
294 
295 static const UEnumeration UCHARSTRENUM_VT = {
296     NULL,
297     NULL, // store StringEnumeration pointer here
298     ucharstrenum_close,
299     ucharstrenum_count,
300     uenum_unextDefault,
301     ucharstrenum_next,
302     ucharstrenum_reset
303 };
304 
305 U_CDECL_END
306 
307 U_CAPI UEnumeration* U_EXPORT2
uenum_openCharStringsEnumeration(const char * const * strings,int32_t count,UErrorCode * ec)308 uenum_openCharStringsEnumeration(const char* const* strings, int32_t count,
309                                  UErrorCode* ec) {
310     UCharStringEnumeration* result = NULL;
311     if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
312         result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
313         if (result == NULL) {
314             *ec = U_MEMORY_ALLOCATION_ERROR;
315         } else {
316             U_ASSERT((char*)result==(char*)(&result->uenum));
317             uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT));
318             result->uenum.context = (void*)strings;
319             result->index = 0;
320             result->count = count;
321         }
322     }
323     return (UEnumeration*) result;
324 }
325 
326 
327