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