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