|
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 |
|
25 StringEnumeration::StringEnumeration() |
|
26 : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) { |
|
27 } |
|
28 |
|
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 * |
|
37 StringEnumeration::clone() const { |
|
38 return NULL; |
|
39 } |
|
40 |
|
41 const char * |
|
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 * |
|
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 * |
|
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 |
|
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 * |
|
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 |
|
122 StringEnumeration::operator==(const StringEnumeration& that)const { |
|
123 return typeid(*this) == typeid(that); |
|
124 } |
|
125 |
|
126 UBool |
|
127 StringEnumeration::operator!=(const StringEnumeration& that)const { |
|
128 return !operator==(that); |
|
129 } |
|
130 |
|
131 // UStringEnumeration implementation --------------------------------------- *** |
|
132 |
|
133 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) : |
|
134 uenum(_uenum) { |
|
135 U_ASSERT(_uenum != 0); |
|
136 } |
|
137 |
|
138 UStringEnumeration::~UStringEnumeration() { |
|
139 uenum_close(uenum); |
|
140 } |
|
141 |
|
142 int32_t UStringEnumeration::count(UErrorCode& status) const { |
|
143 return uenum_count(uenum, &status); |
|
144 } |
|
145 |
|
146 const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) { |
|
147 return uenum_next(uenum, resultLength, &status); |
|
148 } |
|
149 |
|
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 |
|
159 void UStringEnumeration::reset(UErrorCode& status) { |
|
160 uenum_reset(uenum, &status); |
|
161 } |
|
162 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
272 ucharstrenum_close(UEnumeration* en) { |
|
273 uprv_free(en); |
|
274 } |
|
275 |
|
276 static int32_t U_CALLCONV |
|
277 ucharstrenum_count(UEnumeration* en, |
|
278 UErrorCode* /*ec*/) { |
|
279 return ((UCharStringEnumeration*)en)->count; |
|
280 } |
|
281 |
|
282 static const UChar* U_CALLCONV |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |