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