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