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. */ 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 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 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 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 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 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 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 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