1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 *******************************************************************************
5 *
6 *   Copyright (C) 2002-2012, International Business Machines
7 *   Corporation and others.  All Rights Reserved.
8 *
9 *******************************************************************************
10 *   file name:  uenum.c
11 *   encoding:   UTF-8
12 *   tab size:   8 (not used)
13 *   indentation:2
14 *
15 *   created on: 2002jul08
16 *   created by: Vladimir Weinstein
17 */
18 
19 #include "unicode/putil.h"
20 #include "uenumimp.h"
21 #include "cmemory.h"
22 
23 /* Layout of the baseContext buffer. */
24 typedef struct {
25     int32_t len;  /* number of bytes available starting at 'data' */
26     char    data; /* actual data starts here */
27 } _UEnumBuffer;
28 
29 /* Extra bytes to allocate in the baseContext buffer. */
30 static const int32_t PAD = 8;
31 
32 /* Return a pointer to the baseContext buffer, possibly allocating
33    or reallocating it if at least 'capacity' bytes are not available. */
_getBuffer(UEnumeration * en,int32_t capacity)34 static void* _getBuffer(UEnumeration* en, int32_t capacity) {
35 
36     if (en->baseContext != NULL) {
37         if (((_UEnumBuffer*) en->baseContext)->len < capacity) {
38             capacity += PAD;
39             en->baseContext = uprv_realloc(en->baseContext,
40                                            sizeof(int32_t) + capacity);
41             if (en->baseContext == NULL) {
42                 return NULL;
43             }
44             ((_UEnumBuffer*) en->baseContext)->len = capacity;
45         }
46     } else {
47         capacity += PAD;
48         en->baseContext = uprv_malloc(sizeof(int32_t) + capacity);
49         if (en->baseContext == NULL) {
50             return NULL;
51         }
52         ((_UEnumBuffer*) en->baseContext)->len = capacity;
53     }
54 
55     return (void*) & ((_UEnumBuffer*) en->baseContext)->data;
56 }
57 
58 U_CAPI void U_EXPORT2
uenum_close(UEnumeration * en)59 uenum_close(UEnumeration* en)
60 {
61     if (en) {
62         if (en->close != NULL) {
63             if (en->baseContext) {
64                 uprv_free(en->baseContext);
65             }
66             en->close(en);
67         } else { /* this seems dangerous, but we better kill the object */
68             uprv_free(en);
69         }
70     }
71 }
72 
73 U_CAPI int32_t U_EXPORT2
uenum_count(UEnumeration * en,UErrorCode * status)74 uenum_count(UEnumeration* en, UErrorCode* status)
75 {
76     if (!en || U_FAILURE(*status)) {
77         return -1;
78     }
79     if (en->count != NULL) {
80         return en->count(en, status);
81     } else {
82         *status = U_UNSUPPORTED_ERROR;
83         return -1;
84     }
85 }
86 
87 /* Don't call this directly. Only uenum_unext should be calling this. */
88 U_CAPI const UChar* U_EXPORT2
uenum_unextDefault(UEnumeration * en,int32_t * resultLength,UErrorCode * status)89 uenum_unextDefault(UEnumeration* en,
90             int32_t* resultLength,
91             UErrorCode* status)
92 {
93     UChar *ustr = NULL;
94     int32_t len = 0;
95     if (en->next != NULL) {
96         const char *cstr = en->next(en, &len, status);
97         if (cstr != NULL) {
98             ustr = (UChar*) _getBuffer(en, (len+1) * sizeof(UChar));
99             if (ustr == NULL) {
100                 *status = U_MEMORY_ALLOCATION_ERROR;
101             } else {
102                 u_charsToUChars(cstr, ustr, len+1);
103             }
104         }
105     } else {
106         *status = U_UNSUPPORTED_ERROR;
107     }
108     if (resultLength) {
109         *resultLength = len;
110     }
111     return ustr;
112 }
113 
114 /* Don't call this directly. Only uenum_next should be calling this. */
115 U_CAPI const char* U_EXPORT2
uenum_nextDefault(UEnumeration * en,int32_t * resultLength,UErrorCode * status)116 uenum_nextDefault(UEnumeration* en,
117             int32_t* resultLength,
118             UErrorCode* status)
119 {
120     if (en->uNext != NULL) {
121         char *tempCharVal;
122         const UChar *tempUCharVal = en->uNext(en, resultLength, status);
123         if (tempUCharVal == NULL) {
124             return NULL;
125         }
126         tempCharVal = (char*)
127             _getBuffer(en, (*resultLength+1) * sizeof(char));
128         if (!tempCharVal) {
129             *status = U_MEMORY_ALLOCATION_ERROR;
130             return NULL;
131         }
132         u_UCharsToChars(tempUCharVal, tempCharVal, *resultLength + 1);
133         return tempCharVal;
134     } else {
135         *status = U_UNSUPPORTED_ERROR;
136         return NULL;
137     }
138 }
139 
140 U_CAPI const UChar* U_EXPORT2
uenum_unext(UEnumeration * en,int32_t * resultLength,UErrorCode * status)141 uenum_unext(UEnumeration* en,
142             int32_t* resultLength,
143             UErrorCode* status)
144 {
145     if (!en || U_FAILURE(*status)) {
146         return NULL;
147     }
148     if (en->uNext != NULL) {
149         return en->uNext(en, resultLength, status);
150     } else {
151         *status = U_UNSUPPORTED_ERROR;
152         return NULL;
153     }
154 }
155 
156 U_CAPI const char* U_EXPORT2
uenum_next(UEnumeration * en,int32_t * resultLength,UErrorCode * status)157 uenum_next(UEnumeration* en,
158           int32_t* resultLength,
159           UErrorCode* status)
160 {
161     if (!en || U_FAILURE(*status)) {
162         return NULL;
163     }
164     if (en->next != NULL) {
165         if (resultLength != NULL) {
166             return en->next(en, resultLength, status);
167         }
168         else {
169             int32_t dummyLength=0;
170             return en->next(en, &dummyLength, status);
171         }
172     } else {
173         *status = U_UNSUPPORTED_ERROR;
174         return NULL;
175     }
176 }
177 
178 U_CAPI void U_EXPORT2
uenum_reset(UEnumeration * en,UErrorCode * status)179 uenum_reset(UEnumeration* en, UErrorCode* status)
180 {
181     if (!en || U_FAILURE(*status)) {
182         return;
183     }
184     if (en->reset != NULL) {
185         en->reset(en, status);
186     } else {
187         *status = U_UNSUPPORTED_ERROR;
188     }
189 }
190