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