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