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