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) 2010-2015, International Business Machines
      6 *   Corporation and others.  All Rights Reserved.
      7 *******************************************************************************
      8 *   file name:  charstr.cpp
      9 *   encoding:   UTF-8
     10 *   tab size:   8 (not used)
     11 *   indentation:4
     12 *
     13 *   created on: 2010may19
     14 *   created by: Markus W. Scherer
     15 */
     16 
     17 #include "unicode/utypes.h"
     18 #include "unicode/putil.h"
     19 #include "charstr.h"
     20 #include "cmemory.h"
     21 #include "cstring.h"
     22 #include "uinvchar.h"
     23 
     24 U_NAMESPACE_BEGIN
     25 
     26 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
     27     if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
     28         len=s.len;
     29         uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
     30     }
     31     return *this;
     32 }
     33 
     34 int32_t CharString::lastIndexOf(char c) const {
     35     for(int32_t i=len; i>0;) {
     36         if(buffer[--i]==c) {
     37             return i;
     38         }
     39     }
     40     return -1;
     41 }
     42 
     43 CharString &CharString::truncate(int32_t newLength) {
     44     if(newLength<0) {
     45         newLength=0;
     46     }
     47     if(newLength<len) {
     48         buffer[len=newLength]=0;
     49     }
     50     return *this;
     51 }
     52 
     53 CharString &CharString::append(char c, UErrorCode &errorCode) {
     54     if(ensureCapacity(len+2, 0, errorCode)) {
     55         buffer[len++]=c;
     56         buffer[len]=0;
     57     }
     58     return *this;
     59 }
     60 
     61 CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
     62     if(U_FAILURE(errorCode)) {
     63         return *this;
     64     }
     65     if(sLength<-1 || (s==NULL && sLength!=0)) {
     66         errorCode=U_ILLEGAL_ARGUMENT_ERROR;
     67         return *this;
     68     }
     69     if(sLength<0) {
     70         sLength=uprv_strlen(s);
     71     }
     72     if(sLength>0) {
     73         if(s==(buffer.getAlias()+len)) {
     74             // The caller wrote into the getAppendBuffer().
     75             if(sLength>=(buffer.getCapacity()-len)) {
     76                 // The caller wrote too much.
     77                 errorCode=U_INTERNAL_PROGRAM_ERROR;
     78             } else {
     79                 buffer[len+=sLength]=0;
     80             }
     81         } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
     82                   sLength>=(buffer.getCapacity()-len)
     83         ) {
     84             // (Part of) this string is appended to itself which requires reallocation,
     85             // so we have to make a copy of the substring and append that.
     86             return append(CharString(s, sLength, errorCode), errorCode);
     87         } else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
     88             uprv_memcpy(buffer.getAlias()+len, s, sLength);
     89             buffer[len+=sLength]=0;
     90         }
     91     }
     92     return *this;
     93 }
     94 
     95 char *CharString::getAppendBuffer(int32_t minCapacity,
     96                                   int32_t desiredCapacityHint,
     97                                   int32_t &resultCapacity,
     98                                   UErrorCode &errorCode) {
     99     if(U_FAILURE(errorCode)) {
    100         resultCapacity=0;
    101         return NULL;
    102     }
    103     int32_t appendCapacity=buffer.getCapacity()-len-1;  // -1 for NUL
    104     if(appendCapacity>=minCapacity) {
    105         resultCapacity=appendCapacity;
    106         return buffer.getAlias()+len;
    107     }
    108     if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
    109         resultCapacity=buffer.getCapacity()-len-1;
    110         return buffer.getAlias()+len;
    111     }
    112     resultCapacity=0;
    113     return NULL;
    114 }
    115 
    116 CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
    117     if(U_FAILURE(errorCode)) {
    118         return *this;
    119     }
    120     if (!uprv_isInvariantUnicodeString(s)) {
    121         errorCode = U_INVARIANT_CONVERSION_ERROR;
    122         return *this;
    123     }
    124     if(ensureCapacity(len+s.length()+1, 0, errorCode)) {
    125         len+=s.extract(0, 0x7fffffff, buffer.getAlias()+len, buffer.getCapacity()-len, US_INV);
    126     }
    127     return *this;
    128 }
    129 
    130 UBool CharString::ensureCapacity(int32_t capacity,
    131                                  int32_t desiredCapacityHint,
    132                                  UErrorCode &errorCode) {
    133     if(U_FAILURE(errorCode)) {
    134         return FALSE;
    135     }
    136     if(capacity>buffer.getCapacity()) {
    137         if(desiredCapacityHint==0) {
    138             desiredCapacityHint=capacity+buffer.getCapacity();
    139         }
    140         if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
    141             buffer.resize(capacity, len+1)==NULL
    142         ) {
    143             errorCode=U_MEMORY_ALLOCATION_ERROR;
    144             return FALSE;
    145         }
    146     }
    147     return TRUE;
    148 }
    149 
    150 CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
    151     if(U_FAILURE(errorCode)) {
    152         return *this;
    153     }
    154     if(s.length()==0) {
    155         return *this;
    156     }
    157     char c;
    158     if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
    159         append(U_FILE_SEP_CHAR, errorCode);
    160     }
    161     append(s, errorCode);
    162     return *this;
    163 }
    164 
    165 CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
    166     char c;
    167     if(U_SUCCESS(errorCode) && len>0 &&
    168             (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
    169         append(U_FILE_SEP_CHAR, errorCode);
    170     }
    171     return *this;
    172 }
    173 
    174 U_NAMESPACE_END
    175