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