1/* 2********************************************************************** 3* Copyright (c) 2002-2012, 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 22U_NAMESPACE_BEGIN 23// StringEnumeration implementation ---------------------------------------- *** 24 25StringEnumeration::StringEnumeration() 26 : chars(charsBuffer), charsCapacity(sizeof(charsBuffer)) { 27} 28 29StringEnumeration::~StringEnumeration() { 30 if (chars != NULL && chars != charsBuffer) { 31 uprv_free(chars); 32 } 33} 34 35// StringEnumeration base class clone() default implementation, does not clone 36StringEnumeration * 37StringEnumeration::clone() const { 38 return NULL; 39} 40 41const char * 42StringEnumeration::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 59const UChar * 60StringEnumeration::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 73const UnicodeString * 74StringEnumeration::snext(UErrorCode &status) { 75 int32_t length; 76 const char *s=next(&length, status); 77 return setChars(s, length, status); 78} 79 80void 81StringEnumeration::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 101UnicodeString * 102StringEnumeration::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} 121UBool 122StringEnumeration::operator==(const StringEnumeration& that)const { 123 return typeid(*this) == typeid(that); 124} 125 126UBool 127StringEnumeration::operator!=(const StringEnumeration& that)const { 128 return !operator==(that); 129} 130 131// UStringEnumeration implementation --------------------------------------- *** 132 133UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) : 134 uenum(_uenum) { 135 U_ASSERT(_uenum != 0); 136} 137 138UStringEnumeration::~UStringEnumeration() { 139 uenum_close(uenum); 140} 141 142int32_t UStringEnumeration::count(UErrorCode& status) const { 143 return uenum_count(uenum, &status); 144} 145 146const char *UStringEnumeration::next(int32_t *resultLength, UErrorCode &status) { 147 return uenum_next(uenum, resultLength, &status); 148} 149 150const UnicodeString* UStringEnumeration::snext(UErrorCode& status) { 151 int32_t length; 152 const UChar* str = uenum_unext(uenum, &length, &status); 153 if (str == 0 || U_FAILURE(status)) { 154 return 0; 155 } 156 return &unistr.setTo(str, length); 157} 158 159void UStringEnumeration::reset(UErrorCode& status) { 160 uenum_reset(uenum, &status); 161} 162 163UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration) 164U_NAMESPACE_END 165 166// C wrapper --------------------------------------------------------------- *** 167 168#define THIS(en) ((icu::StringEnumeration*)(en->context)) 169 170U_CDECL_BEGIN 171 172/** 173 * Wrapper API to make StringEnumeration look like UEnumeration. 174 */ 175static void U_CALLCONV 176ustrenum_close(UEnumeration* en) { 177 delete THIS(en); 178 uprv_free(en); 179} 180 181/** 182 * Wrapper API to make StringEnumeration look like UEnumeration. 183 */ 184static int32_t U_CALLCONV 185ustrenum_count(UEnumeration* en, 186 UErrorCode* ec) 187{ 188 return THIS(en)->count(*ec); 189} 190 191/** 192 * Wrapper API to make StringEnumeration look like UEnumeration. 193 */ 194static const UChar* U_CALLCONV 195ustrenum_unext(UEnumeration* en, 196 int32_t* resultLength, 197 UErrorCode* ec) 198{ 199 return THIS(en)->unext(resultLength, *ec); 200} 201 202/** 203 * Wrapper API to make StringEnumeration look like UEnumeration. 204 */ 205static const char* U_CALLCONV 206ustrenum_next(UEnumeration* en, 207 int32_t* resultLength, 208 UErrorCode* ec) 209{ 210 return THIS(en)->next(resultLength, *ec); 211} 212 213/** 214 * Wrapper API to make StringEnumeration look like UEnumeration. 215 */ 216static void U_CALLCONV 217ustrenum_reset(UEnumeration* en, 218 UErrorCode* ec) 219{ 220 THIS(en)->reset(*ec); 221} 222 223/** 224 * Pseudo-vtable for UEnumeration wrapper around StringEnumeration. 225 * The StringEnumeration pointer will be stored in 'context'. 226 */ 227static const UEnumeration USTRENUM_VT = { 228 NULL, 229 NULL, // store StringEnumeration pointer here 230 ustrenum_close, 231 ustrenum_count, 232 ustrenum_unext, 233 ustrenum_next, 234 ustrenum_reset 235}; 236 237U_CDECL_END 238 239/** 240 * Given a StringEnumeration, wrap it in a UEnumeration. The 241 * StringEnumeration is adopted; after this call, the caller must not 242 * delete it (regardless of error status). 243 */ 244U_CAPI UEnumeration* U_EXPORT2 245uenum_openFromStringEnumeration(icu::StringEnumeration* adopted, UErrorCode* ec) { 246 UEnumeration* result = NULL; 247 if (U_SUCCESS(*ec) && adopted != NULL) { 248 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration)); 249 if (result == NULL) { 250 *ec = U_MEMORY_ALLOCATION_ERROR; 251 } else { 252 uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT)); 253 result->context = adopted; 254 } 255 } 256 if (result == NULL) { 257 delete adopted; 258 } 259 return result; 260} 261 262// C wrapper --------------------------------------------------------------- *** 263 264U_CDECL_BEGIN 265 266typedef struct UCharStringEnumeration { 267 UEnumeration uenum; 268 int32_t index, count; 269} UCharStringEnumeration; 270 271static void U_CALLCONV 272ucharstrenum_close(UEnumeration* en) { 273 uprv_free(en); 274} 275 276static int32_t U_CALLCONV 277ucharstrenum_count(UEnumeration* en, 278 UErrorCode* /*ec*/) { 279 return ((UCharStringEnumeration*)en)->count; 280} 281 282static const UChar* U_CALLCONV 283ucharstrenum_unext(UEnumeration* en, 284 int32_t* resultLength, 285 UErrorCode* /*ec*/) { 286 UCharStringEnumeration *e = (UCharStringEnumeration*) en; 287 if (e->index >= e->count) { 288 return NULL; 289 } 290 const UChar* result = ((const UChar**)e->uenum.context)[e->index++]; 291 if (resultLength) { 292 *resultLength = (int32_t)u_strlen(result); 293 } 294 return result; 295} 296 297 298static const char* U_CALLCONV 299ucharstrenum_next(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 char* result = ((const char**)e->uenum.context)[e->index++]; 307 if (resultLength) { 308 *resultLength = (int32_t)uprv_strlen(result); 309 } 310 return result; 311} 312 313static void U_CALLCONV 314ucharstrenum_reset(UEnumeration* en, 315 UErrorCode* /*ec*/) { 316 ((UCharStringEnumeration*)en)->index = 0; 317} 318 319static const UEnumeration UCHARSTRENUM_VT = { 320 NULL, 321 NULL, // store StringEnumeration pointer here 322 ucharstrenum_close, 323 ucharstrenum_count, 324 uenum_unextDefault, 325 ucharstrenum_next, 326 ucharstrenum_reset 327}; 328 329static const UEnumeration UCHARSTRENUM_U_VT = { 330 NULL, 331 NULL, // store StringEnumeration pointer here 332 ucharstrenum_close, 333 ucharstrenum_count, 334 ucharstrenum_unext, 335 uenum_nextDefault, 336 ucharstrenum_reset 337}; 338 339U_CDECL_END 340 341U_CAPI UEnumeration* U_EXPORT2 342uenum_openCharStringsEnumeration(const char* const strings[], int32_t count, 343 UErrorCode* ec) { 344 UCharStringEnumeration* result = NULL; 345 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) { 346 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration)); 347 if (result == NULL) { 348 *ec = U_MEMORY_ALLOCATION_ERROR; 349 } else { 350 U_ASSERT((char*)result==(char*)(&result->uenum)); 351 uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT)); 352 result->uenum.context = (void*)strings; 353 result->index = 0; 354 result->count = count; 355 } 356 } 357 return (UEnumeration*) result; 358} 359 360U_CAPI UEnumeration* U_EXPORT2 361uenum_openUCharStringsEnumeration(const UChar* const strings[], int32_t count, 362 UErrorCode* ec) { 363 UCharStringEnumeration* result = NULL; 364 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) { 365 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration)); 366 if (result == NULL) { 367 *ec = U_MEMORY_ALLOCATION_ERROR; 368 } else { 369 U_ASSERT((char*)result==(char*)(&result->uenum)); 370 uprv_memcpy(result, &UCHARSTRENUM_U_VT, sizeof(UCHARSTRENUM_U_VT)); 371 result->uenum.context = (void*)strings; 372 result->index = 0; 373 result->count = count; 374 } 375 } 376 return (UEnumeration*) result; 377} 378 379 380// end C Wrapper 381