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
24U_NAMESPACE_BEGIN
25// StringEnumeration implementation ---------------------------------------- ***
26
27StringEnumeration::StringEnumeration()
28 : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) {
29}
30
31StringEnumeration::~StringEnumeration() {
32 if (chars != nullptr && chars != charsBuffer) {
33 uprv_free(chars);
34 }
35}
36
37// StringEnumeration base class clone() default implementation, does not clone
38StringEnumeration *
39StringEnumeration::clone() const {
40 return nullptr;
41}
42
43const char *
44StringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
45 const UnicodeString *s=snext(status);
46 if(U_SUCCESS(status) && s!=nullptr) {
47 unistr=*s;
48 ensureCharsCapacity(unistr.length()+1, status);
49 if(U_SUCCESS(status)) {
50 if(resultLength!=nullptr) {
51 *resultLength=unistr.length();
52 }
53 unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV);
54 return chars;
55 }
56 }
57
58 return nullptr;
59}
60
61const char16_t *
62StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) {
63 const UnicodeString *s=snext(status);
64 if(U_SUCCESS(status) && s!=nullptr) {
65 unistr=*s;
66 if(resultLength!=nullptr) {
67 *resultLength=unistr.length();
68 }
69 return unistr.getTerminatedBuffer();
70 }
71
72 return nullptr;
73}
74
75const UnicodeString *
76StringEnumeration::snext(UErrorCode &status) {
77 int32_t length;
78 const char *s=next(&length, status);
79 return setChars(s, length, status);
80}
81
82void
83StringEnumeration::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==nullptr) {
94 chars=charsBuffer;
95 charsCapacity=sizeof(charsBuffer);
96 status=U_MEMORY_ALLOCATION_ERROR;
97 } else {
98 charsCapacity=capacity;
99 }
100 }
101}
102
103UnicodeString *
104StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) {
105 if(U_SUCCESS(status) && s!=nullptr) {
106 if(length<0) {
107 length=(int32_t)uprv_strlen(s);
108 }
109
110 char16_t *buffer=unistr.getBuffer(length+1);
111 if(buffer!=nullptr) {
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 nullptr;
122}
123bool
124StringEnumeration::operator==(const StringEnumeration& that)const {
125 return typeid(*this) == typeid(that);
126}
127
128bool
129StringEnumeration::operator!=(const StringEnumeration& that)const {
130 return !operator==(that);
131}
132
133// UStringEnumeration implementation --------------------------------------- ***
134
135UStringEnumeration * U_EXPORT2
136UStringEnumeration::fromUEnumeration(
137 UEnumeration *uenumToAdopt, UErrorCode &status) {
138 if (U_FAILURE(status)) {
139 uenum_close(uenumToAdopt);
140 return nullptr;
141 }
142 UStringEnumeration *result = new UStringEnumeration(uenumToAdopt);
143 if (result == nullptr) {
144 status = U_MEMORY_ALLOCATION_ERROR;
145 uenum_close(uenumToAdopt);
146 return nullptr;
147 }
148 return result;
149}
150
151UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) :
152 uenum(_uenum) {
153 U_ASSERT(_uenum != 0);
154}
155
156UStringEnumeration::~UStringEnumeration() {
157 uenum_close(uenum);
158}
159
160int32_t UStringEnumeration::count(UErrorCode& status) const {
161 return uenum_count(uenum, &status);
162}
163
164const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) {
165 return uenum_next(uenum, resultLength, &status);
166}
167
168const UnicodeString* UStringEnumeration::snext(UErrorCode& status) {
169 int32_t length;
170 const char16_t* 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
177void UStringEnumeration::reset(UErrorCode& status) {
178 uenum_reset(uenum, &status);
179}
180
181UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration)
182U_NAMESPACE_END
183
184// C wrapper --------------------------------------------------------------- ***
185
186#define THIS(en) ((icu::StringEnumeration*)(en->context))
187
188U_CDECL_BEGIN
189
190/**
191 * Wrapper API to make StringEnumeration look like UEnumeration.
192 */
193static void U_CALLCONV
194ustrenum_close(UEnumeration* en) {
195 delete THIS(en);
196 uprv_free(en);
197}
198
199/**
200 * Wrapper API to make StringEnumeration look like UEnumeration.
201 */
202static int32_t U_CALLCONV
203ustrenum_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 */
212static const char16_t* U_CALLCONV
213ustrenum_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 */
223static const char* U_CALLCONV
224ustrenum_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 */
234static void U_CALLCONV
235ustrenum_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 */
245static const UEnumeration USTRENUM_VT = {
246 nullptr,
247 nullptr, // store StringEnumeration pointer here
248 ustrenum_close,
249 ustrenum_count,
250 ustrenum_unext,
251 ustrenum_next,
252 ustrenum_reset
253};
254
255U_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 */
262U_CAPI UEnumeration* U_EXPORT2
263uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) {
264 UEnumeration* result = nullptr;
265 if (U_SUCCESS(*ec) && adopted != nullptr) {
266 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration));
267 if (result == nullptr) {
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 == nullptr) {
275 delete adopted;
276 }
277 return result;
278}
279
280// C wrapper --------------------------------------------------------------- ***
281
282U_CDECL_BEGIN
283
284typedef struct UCharStringEnumeration {
285 UEnumeration uenum;
286 int32_t index, count;
287} UCharStringEnumeration;
288
289static void U_CALLCONV
290ucharstrenum_close(UEnumeration* en) {
291 uprv_free(en);
292}
293
294static int32_t U_CALLCONV
295ucharstrenum_count(UEnumeration* en,
296 UErrorCode* /*ec*/) {
297 return ((UCharStringEnumeration*)en)->count;
298}
299
300static const char16_t* U_CALLCONV
301ucharstrenum_unext(UEnumeration* en,
302 int32_t* resultLength,
303 UErrorCode* /*ec*/) {
304 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
305 if (e->index >= e->count) {
306 return nullptr;
307 }
308 const char16_t* result = ((const char16_t**)e->uenum.context)[e->index++];
309 if (resultLength) {
310 *resultLength = (int32_t)u_strlen(result);
311 }
312 return result;
313}
314
315
316static const char* U_CALLCONV
317ucharstrenum_next(UEnumeration* en,
318 int32_t* resultLength,
319 UErrorCode* /*ec*/) {
320 UCharStringEnumeration *e = (UCharStringEnumeration*) en;
321 if (e->index >= e->count) {
322 return nullptr;
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
331static void U_CALLCONV
332ucharstrenum_reset(UEnumeration* en,
333 UErrorCode* /*ec*/) {
334 ((UCharStringEnumeration*)en)->index = 0;
335}
336
337static const UEnumeration UCHARSTRENUM_VT = {
338 nullptr,
339 nullptr, // store StringEnumeration pointer here
340 ucharstrenum_close,
341 ucharstrenum_count,
342 uenum_unextDefault,
343 ucharstrenum_next,
344 ucharstrenum_reset
345};
346
347static const UEnumeration UCHARSTRENUM_U_VT = {
348 nullptr,
349 nullptr, // store StringEnumeration pointer here
350 ucharstrenum_close,
351 ucharstrenum_count,
352 ucharstrenum_unext,
353 uenum_nextDefault,
354 ucharstrenum_reset
355};
356
357U_CDECL_END
358
359U_CAPI UEnumeration* U_EXPORT2
360uenum_openCharStringsEnumeration(const char* const strings[], int32_t count,
361 UErrorCode* ec) {
362 UCharStringEnumeration* result = nullptr;
363 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
364 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
365 if (result == nullptr) {
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
378U_CAPI UEnumeration* U_EXPORT2
379uenum_openUCharStringsEnumeration(const char16_t* const strings[], int32_t count,
380 UErrorCode* ec) {
381 UCharStringEnumeration* result = nullptr;
382 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) {
383 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration));
384 if (result == nullptr) {
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