1 /* 2 ********************************************************************** 3 * Copyright (c) 2002-2009, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ********************************************************************** 6 * Author: Alan Liu 7 * Created: November 11 2002 8 * Since: ICU 2.4 9 ********************************************************************** 10 */ 11 #include "unicode/ustring.h" 12 #include "unicode/strenum.h" 13 #include "unicode/putil.h" 14 #include "uenumimp.h" 15 #include "ustrenum.h" 16 #include "cstring.h" 17 #include "cmemory.h" 18 #include "uassert.h" 19 20 U_NAMESPACE_BEGIN 21 // StringEnumeration implementation ---------------------------------------- *** 22 23 StringEnumeration::StringEnumeration() 24 : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) { 25 } 26 27 StringEnumeration::~StringEnumeration() { 28 if (chars != NULL && chars != charsBuffer) { 29 uprv_free(chars); 30 } 31 } 32 33 // StringEnumeration base class clone() default implementation, does not clone 34 StringEnumeration * 35 StringEnumeration::clone() const { 36 return NULL; 37 } 38 39 const char * 40 StringEnumeration::next(int32_t *resultLength, UErrorCode &status) { 41 const UnicodeString *s=snext(status); 42 if(s!=NULL) { 43 unistr=*s; 44 ensureCharsCapacity(unistr.length()+1, status); 45 if(U_SUCCESS(status)) { 46 if(resultLength!=NULL) { 47 *resultLength=unistr.length(); 48 } 49 unistr.extract(0, INT32_MAX, chars, charsCapacity, US_INV); 50 return chars; 51 } 52 } 53 54 return NULL; 55 } 56 57 const UChar * 58 StringEnumeration::unext(int32_t *resultLength, UErrorCode &status) { 59 const UnicodeString *s=snext(status); 60 if(s!=NULL) { 61 unistr=*s; 62 if(U_SUCCESS(status)) { 63 if(resultLength!=NULL) { 64 *resultLength=unistr.length(); 65 } 66 return unistr.getTerminatedBuffer(); 67 } 68 } 69 70 return NULL; 71 } 72 73 void 74 StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) { 75 if(U_SUCCESS(status) && capacity>charsCapacity) { 76 if(capacity<(charsCapacity+charsCapacity/2)) { 77 // avoid allocation thrashing 78 capacity=charsCapacity+charsCapacity/2; 79 } 80 if(chars!=charsBuffer) { 81 uprv_free(chars); 82 } 83 chars=(char *)uprv_malloc(capacity); 84 if(chars==NULL) { 85 chars=charsBuffer; 86 charsCapacity=sizeof(charsBuffer); 87 status=U_MEMORY_ALLOCATION_ERROR; 88 } else { 89 charsCapacity=capacity; 90 } 91 } 92 } 93 94 UnicodeString * 95 StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) { 96 if(U_SUCCESS(status) && s!=NULL) { 97 if(length<0) { 98 length=(int32_t)uprv_strlen(s); 99 } 100 101 UChar *buffer=unistr.getBuffer(length+1); 102 if(buffer!=NULL) { 103 u_charsToUChars(s, buffer, length); 104 buffer[length]=0; 105 unistr.releaseBuffer(length); 106 return &unistr; 107 } else { 108 status=U_MEMORY_ALLOCATION_ERROR; 109 } 110 } 111 112 return NULL; 113 } 114 UBool 115 StringEnumeration::operator==(const StringEnumeration& that)const { 116 return getDynamicClassID() == that.getDynamicClassID(); 117 } 118 119 UBool 120 StringEnumeration::operator!=(const StringEnumeration& that)const { 121 return !operator==(that); 122 } 123 124 // UStringEnumeration implementation --------------------------------------- *** 125 126 UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) : 127 uenum(_uenum) { 128 U_ASSERT(_uenum != 0); 129 } 130 131 UStringEnumeration::~UStringEnumeration() { 132 uenum_close(uenum); 133 } 134 135 int32_t UStringEnumeration::count(UErrorCode& status) const { 136 return uenum_count(uenum, &status); 137 } 138 139 const UnicodeString* UStringEnumeration::snext(UErrorCode& status) { 140 int32_t length; 141 const UChar* str = uenum_unext(uenum, &length, &status); 142 if (str == 0 || U_FAILURE(status)) { 143 return 0; 144 } 145 return &unistr.setTo(str, length); 146 } 147 148 void UStringEnumeration::reset(UErrorCode& status) { 149 uenum_reset(uenum, &status); 150 } 151 152 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration) 153 U_NAMESPACE_END 154 155 // C wrapper --------------------------------------------------------------- *** 156 157 #define THIS(en) ((U_NAMESPACE_QUALIFIER StringEnumeration*)(en->context)) 158 159 U_CDECL_BEGIN 160 161 /** 162 * Wrapper API to make StringEnumeration look like UEnumeration. 163 */ 164 static void U_CALLCONV 165 ustrenum_close(UEnumeration* en) { 166 delete THIS(en); 167 uprv_free(en); 168 } 169 170 /** 171 * Wrapper API to make StringEnumeration look like UEnumeration. 172 */ 173 static int32_t U_CALLCONV 174 ustrenum_count(UEnumeration* en, 175 UErrorCode* ec) 176 { 177 return THIS(en)->count(*ec); 178 } 179 180 /** 181 * Wrapper API to make StringEnumeration look like UEnumeration. 182 */ 183 static const UChar* U_CALLCONV 184 ustrenum_unext(UEnumeration* en, 185 int32_t* resultLength, 186 UErrorCode* ec) 187 { 188 return THIS(en)->unext(resultLength, *ec); 189 } 190 191 /** 192 * Wrapper API to make StringEnumeration look like UEnumeration. 193 */ 194 static const char* U_CALLCONV 195 ustrenum_next(UEnumeration* en, 196 int32_t* resultLength, 197 UErrorCode* ec) 198 { 199 return THIS(en)->next(resultLength, *ec); 200 } 201 202 /** 203 * Wrapper API to make StringEnumeration look like UEnumeration. 204 */ 205 static void U_CALLCONV 206 ustrenum_reset(UEnumeration* en, 207 UErrorCode* ec) 208 { 209 THIS(en)->reset(*ec); 210 } 211 212 /** 213 * Pseudo-vtable for UEnumeration wrapper around StringEnumeration. 214 * The StringEnumeration pointer will be stored in 'context'. 215 */ 216 static const UEnumeration USTRENUM_VT = { 217 NULL, 218 NULL, // store StringEnumeration pointer here 219 ustrenum_close, 220 ustrenum_count, 221 ustrenum_unext, 222 ustrenum_next, 223 ustrenum_reset 224 }; 225 226 U_CDECL_END 227 228 /** 229 * Given a StringEnumeration, wrap it in a UEnumeration. The 230 * StringEnumeration is adopted; after this call, the caller must not 231 * delete it (regardless of error status). 232 */ 233 U_CAPI UEnumeration* U_EXPORT2 234 uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration* adopted, UErrorCode* ec) { 235 UEnumeration* result = NULL; 236 if (U_SUCCESS(*ec) && adopted != NULL) { 237 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration)); 238 if (result == NULL) { 239 *ec = U_MEMORY_ALLOCATION_ERROR; 240 } else { 241 uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT)); 242 result->context = adopted; 243 } 244 } 245 if (result == NULL) { 246 delete adopted; 247 } 248 return result; 249 } 250 251 // C wrapper --------------------------------------------------------------- *** 252 253 U_CDECL_BEGIN 254 255 typedef struct UCharStringEnumeration { 256 UEnumeration uenum; 257 int32_t index, count; 258 } UCharStringEnumeration; 259 260 static void U_CALLCONV 261 ucharstrenum_close(UEnumeration* en) { 262 uprv_free(en); 263 } 264 265 static int32_t U_CALLCONV 266 ucharstrenum_count(UEnumeration* en, 267 UErrorCode* /*ec*/) { 268 return ((UCharStringEnumeration*)en)->count; 269 } 270 271 static const char* U_CALLCONV 272 ucharstrenum_next(UEnumeration* en, 273 int32_t* resultLength, 274 UErrorCode* /*ec*/) { 275 UCharStringEnumeration *e = (UCharStringEnumeration*) en; 276 if (e->index >= e->count) { 277 return NULL; 278 } 279 const char* result = ((const char**)e->uenum.context)[e->index++]; 280 if (resultLength) { 281 *resultLength = (int32_t)uprv_strlen(result); 282 } 283 return result; 284 } 285 286 static void U_CALLCONV 287 ucharstrenum_reset(UEnumeration* en, 288 UErrorCode* /*ec*/) { 289 ((UCharStringEnumeration*)en)->index = 0; 290 } 291 292 static const UEnumeration UCHARSTRENUM_VT = { 293 NULL, 294 NULL, // store StringEnumeration pointer here 295 ucharstrenum_close, 296 ucharstrenum_count, 297 uenum_unextDefault, 298 ucharstrenum_next, 299 ucharstrenum_reset 300 }; 301 302 U_CDECL_END 303 304 U_CAPI UEnumeration* U_EXPORT2 305 uenum_openCharStringsEnumeration(const char* const* strings, int32_t count, 306 UErrorCode* ec) { 307 UCharStringEnumeration* result = NULL; 308 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) { 309 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration)); 310 if (result == NULL) { 311 *ec = U_MEMORY_ALLOCATION_ERROR; 312 } else { 313 U_ASSERT((char*)result==(char*)(&result->uenum)); 314 uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT)); 315 result->uenum.context = (void*)strings; 316 result->index = 0; 317 result->count = count; 318 } 319 } 320 return (UEnumeration*) result; 321 } 322 323 324