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