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