1/* 2********************************************************************** 3* Copyright (c) 2002-2010, 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 <typeinfo> // 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(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(s!=NULL) { 63 unistr=*s; 64 if(U_SUCCESS(status)) { 65 if(resultLength!=NULL) { 66 *resultLength=unistr.length(); 67 } 68 return unistr.getTerminatedBuffer(); 69 } 70 } 71 72 return NULL; 73} 74 75void 76StringEnumeration::ensureCharsCapacity(int32_t capacity, UErrorCode &status) { 77 if(U_SUCCESS(status) && capacity>charsCapacity) { 78 if(capacity<(charsCapacity+charsCapacity/2)) { 79 // avoid allocation thrashing 80 capacity=charsCapacity+charsCapacity/2; 81 } 82 if(chars!=charsBuffer) { 83 uprv_free(chars); 84 } 85 chars=(char *)uprv_malloc(capacity); 86 if(chars==NULL) { 87 chars=charsBuffer; 88 charsCapacity=sizeof(charsBuffer); 89 status=U_MEMORY_ALLOCATION_ERROR; 90 } else { 91 charsCapacity=capacity; 92 } 93 } 94} 95 96UnicodeString * 97StringEnumeration::setChars(const char *s, int32_t length, UErrorCode &status) { 98 if(U_SUCCESS(status) && s!=NULL) { 99 if(length<0) { 100 length=(int32_t)uprv_strlen(s); 101 } 102 103 UChar *buffer=unistr.getBuffer(length+1); 104 if(buffer!=NULL) { 105 u_charsToUChars(s, buffer, length); 106 buffer[length]=0; 107 unistr.releaseBuffer(length); 108 return &unistr; 109 } else { 110 status=U_MEMORY_ALLOCATION_ERROR; 111 } 112 } 113 114 return NULL; 115} 116UBool 117StringEnumeration::operator==(const StringEnumeration& that)const { 118 return typeid(*this) == typeid(that); 119 120} 121 122UBool 123StringEnumeration::operator!=(const StringEnumeration& that)const { 124 return !operator==(that); 125} 126 127// UStringEnumeration implementation --------------------------------------- *** 128 129UStringEnumeration::UStringEnumeration(UEnumeration* _uenum) : 130 uenum(_uenum) { 131 U_ASSERT(_uenum != 0); 132} 133 134UStringEnumeration::~UStringEnumeration() { 135 uenum_close(uenum); 136} 137 138int32_t UStringEnumeration::count(UErrorCode& status) const { 139 return uenum_count(uenum, &status); 140} 141 142const UnicodeString* UStringEnumeration::snext(UErrorCode& status) { 143 int32_t length; 144 const UChar* str = uenum_unext(uenum, &length, &status); 145 if (str == 0 || U_FAILURE(status)) { 146 return 0; 147 } 148 return &unistr.setTo(str, length); 149} 150 151void UStringEnumeration::reset(UErrorCode& status) { 152 uenum_reset(uenum, &status); 153} 154 155UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UStringEnumeration) 156U_NAMESPACE_END 157 158// C wrapper --------------------------------------------------------------- *** 159 160#define THIS(en) ((U_NAMESPACE_QUALIFIER StringEnumeration*)(en->context)) 161 162U_CDECL_BEGIN 163 164/** 165 * Wrapper API to make StringEnumeration look like UEnumeration. 166 */ 167static void U_CALLCONV 168ustrenum_close(UEnumeration* en) { 169 delete THIS(en); 170 uprv_free(en); 171} 172 173/** 174 * Wrapper API to make StringEnumeration look like UEnumeration. 175 */ 176static int32_t U_CALLCONV 177ustrenum_count(UEnumeration* en, 178 UErrorCode* ec) 179{ 180 return THIS(en)->count(*ec); 181} 182 183/** 184 * Wrapper API to make StringEnumeration look like UEnumeration. 185 */ 186static const UChar* U_CALLCONV 187ustrenum_unext(UEnumeration* en, 188 int32_t* resultLength, 189 UErrorCode* ec) 190{ 191 return THIS(en)->unext(resultLength, *ec); 192} 193 194/** 195 * Wrapper API to make StringEnumeration look like UEnumeration. 196 */ 197static const char* U_CALLCONV 198ustrenum_next(UEnumeration* en, 199 int32_t* resultLength, 200 UErrorCode* ec) 201{ 202 return THIS(en)->next(resultLength, *ec); 203} 204 205/** 206 * Wrapper API to make StringEnumeration look like UEnumeration. 207 */ 208static void U_CALLCONV 209ustrenum_reset(UEnumeration* en, 210 UErrorCode* ec) 211{ 212 THIS(en)->reset(*ec); 213} 214 215/** 216 * Pseudo-vtable for UEnumeration wrapper around StringEnumeration. 217 * The StringEnumeration pointer will be stored in 'context'. 218 */ 219static const UEnumeration USTRENUM_VT = { 220 NULL, 221 NULL, // store StringEnumeration pointer here 222 ustrenum_close, 223 ustrenum_count, 224 ustrenum_unext, 225 ustrenum_next, 226 ustrenum_reset 227}; 228 229U_CDECL_END 230 231/** 232 * Given a StringEnumeration, wrap it in a UEnumeration. The 233 * StringEnumeration is adopted; after this call, the caller must not 234 * delete it (regardless of error status). 235 */ 236U_CAPI UEnumeration* U_EXPORT2 237uenum_openFromStringEnumeration(U_NAMESPACE_QUALIFIER StringEnumeration* adopted, UErrorCode* ec) { 238 UEnumeration* result = NULL; 239 if (U_SUCCESS(*ec) && adopted != NULL) { 240 result = (UEnumeration*) uprv_malloc(sizeof(UEnumeration)); 241 if (result == NULL) { 242 *ec = U_MEMORY_ALLOCATION_ERROR; 243 } else { 244 uprv_memcpy(result, &USTRENUM_VT, sizeof(USTRENUM_VT)); 245 result->context = adopted; 246 } 247 } 248 if (result == NULL) { 249 delete adopted; 250 } 251 return result; 252} 253 254// C wrapper --------------------------------------------------------------- *** 255 256U_CDECL_BEGIN 257 258typedef struct UCharStringEnumeration { 259 UEnumeration uenum; 260 int32_t index, count; 261} UCharStringEnumeration; 262 263static void U_CALLCONV 264ucharstrenum_close(UEnumeration* en) { 265 uprv_free(en); 266} 267 268static int32_t U_CALLCONV 269ucharstrenum_count(UEnumeration* en, 270 UErrorCode* /*ec*/) { 271 return ((UCharStringEnumeration*)en)->count; 272} 273 274static const char* U_CALLCONV 275ucharstrenum_next(UEnumeration* en, 276 int32_t* resultLength, 277 UErrorCode* /*ec*/) { 278 UCharStringEnumeration *e = (UCharStringEnumeration*) en; 279 if (e->index >= e->count) { 280 return NULL; 281 } 282 const char* result = ((const char**)e->uenum.context)[e->index++]; 283 if (resultLength) { 284 *resultLength = (int32_t)uprv_strlen(result); 285 } 286 return result; 287} 288 289static void U_CALLCONV 290ucharstrenum_reset(UEnumeration* en, 291 UErrorCode* /*ec*/) { 292 ((UCharStringEnumeration*)en)->index = 0; 293} 294 295static const UEnumeration UCHARSTRENUM_VT = { 296 NULL, 297 NULL, // store StringEnumeration pointer here 298 ucharstrenum_close, 299 ucharstrenum_count, 300 uenum_unextDefault, 301 ucharstrenum_next, 302 ucharstrenum_reset 303}; 304 305U_CDECL_END 306 307U_CAPI UEnumeration* U_EXPORT2 308uenum_openCharStringsEnumeration(const char* const* strings, int32_t count, 309 UErrorCode* ec) { 310 UCharStringEnumeration* result = NULL; 311 if (U_SUCCESS(*ec) && count >= 0 && (count == 0 || strings != 0)) { 312 result = (UCharStringEnumeration*) uprv_malloc(sizeof(UCharStringEnumeration)); 313 if (result == NULL) { 314 *ec = U_MEMORY_ALLOCATION_ERROR; 315 } else { 316 U_ASSERT((char*)result==(char*)(&result->uenum)); 317 uprv_memcpy(result, &UCHARSTRENUM_VT, sizeof(UCHARSTRENUM_VT)); 318 result->uenum.context = (void*)strings; 319 result->index = 0; 320 result->count = count; 321 } 322 } 323 return (UEnumeration*) result; 324} 325 326 327