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. */
24typedef 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. */
30static 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. */
34static void* _getBuffer(UEnumeration* en, int32_t capacity) {
35
36 if (en->baseContext != nullptr) {
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 == nullptr) {
42 return nullptr;
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 == nullptr) {
50 return nullptr;
51 }
52 ((_UEnumBuffer*) en->baseContext)->len = capacity;
53 }
54
55 return (void*) & ((_UEnumBuffer*) en->baseContext)->data;
56}
57
58U_CAPI void U_EXPORT2
59uenum_close(UEnumeration* en)
60{
61 if (en) {
62 if (en->close != nullptr) {
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
73U_CAPI int32_t U_EXPORT2
74uenum_count(UEnumeration* en, UErrorCode* status)
75{
76 if (!en || U_FAILURE(*status)) {
77 return -1;
78 }
79 if (en->count != nullptr) {
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. */
88U_CAPI const char16_t* U_EXPORT2
89uenum_unextDefault(UEnumeration* en,
90 int32_t* resultLength,
91 UErrorCode* status)
92{
93 char16_t *ustr = nullptr;
94 int32_t len = 0;
95 if (en->next != nullptr) {
96 const char *cstr = en->next(en, &len, status);
97 if (cstr != nullptr) {
98 ustr = (char16_t*) _getBuffer(en, (len+1) * sizeof(char16_t));
99 if (ustr == nullptr) {
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. */
115U_CAPI const char* U_EXPORT2
116uenum_nextDefault(UEnumeration* en,
117 int32_t* resultLength,
118 UErrorCode* status)
119{
120 if (en->uNext != nullptr) {
121 char *tempCharVal;
122 const char16_t *tempUCharVal = en->uNext(en, resultLength, status);
123 if (tempUCharVal == nullptr) {
124 return nullptr;
125 }
126 tempCharVal = (char*)
127 _getBuffer(en, (*resultLength+1) * sizeof(char));
128 if (!tempCharVal) {
129 *status = U_MEMORY_ALLOCATION_ERROR;
130 return nullptr;
131 }
132 u_UCharsToChars(tempUCharVal, tempCharVal, *resultLength + 1);
133 return tempCharVal;
134 } else {
135 *status = U_UNSUPPORTED_ERROR;
136 return nullptr;
137 }
138}
139
140U_CAPI const char16_t* U_EXPORT2
141uenum_unext(UEnumeration* en,
142 int32_t* resultLength,
143 UErrorCode* status)
144{
145 if (!en || U_FAILURE(*status)) {
146 return nullptr;
147 }
148 if (en->uNext != nullptr) {
149 return en->uNext(en, resultLength, status);
150 } else {
151 *status = U_UNSUPPORTED_ERROR;
152 return nullptr;
153 }
154}
155
156U_CAPI const char* U_EXPORT2
157uenum_next(UEnumeration* en,
158 int32_t* resultLength,
159 UErrorCode* status)
160{
161 if (!en || U_FAILURE(*status)) {
162 return nullptr;
163 }
164 if (en->next != nullptr) {
165 if (resultLength != nullptr) {
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 nullptr;
175 }
176}
177
178U_CAPI void U_EXPORT2
179uenum_reset(UEnumeration* en, UErrorCode* status)
180{
181 if (!en || U_FAILURE(*status)) {
182 return;
183 }
184 if (en->reset != nullptr) {
185 en->reset(en, status);
186 } else {
187 *status = U_UNSUPPORTED_ERROR;
188 }
189}
190