Home | History | Annotate | Download | only in common
      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