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