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