charstr.cpp (8479B)
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 <cstdlib> 18 19 #include "unicode/utypes.h" 20 #include "unicode/putil.h" 21 #include "charstr.h" 22 #include "cmemory.h" 23 #include "cstring.h" 24 #include "uinvchar.h" 25 #include "ustr_imp.h" 26 27 U_NAMESPACE_BEGIN 28 29 CharString::CharString(CharString&& src) noexcept 30 : buffer(std::move(src.buffer)), len(src.len) { 31 src.len = 0; // not strictly necessary because we make no guarantees on the source string 32 } 33 34 CharString& CharString::operator=(CharString&& src) noexcept { 35 buffer = std::move(src.buffer); 36 len = src.len; 37 src.len = 0; // not strictly necessary because we make no guarantees on the source string 38 return *this; 39 } 40 41 char *CharString::cloneData(UErrorCode &errorCode) const { 42 if (U_FAILURE(errorCode)) { return nullptr; } 43 char *p = static_cast<char *>(uprv_malloc(len + 1)); 44 if (p == nullptr) { 45 errorCode = U_MEMORY_ALLOCATION_ERROR; 46 return nullptr; 47 } 48 uprv_memcpy(p, buffer.getAlias(), len + 1); 49 return p; 50 } 51 52 int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const { 53 if (U_FAILURE(errorCode)) { return len; } 54 if (capacity < 0 || (capacity > 0 && dest == nullptr)) { 55 errorCode = U_ILLEGAL_ARGUMENT_ERROR; 56 return len; 57 } 58 const char *src = buffer.getAlias(); 59 if (0 < len && len <= capacity && src != dest) { 60 uprv_memcpy(dest, src, len); 61 } 62 return u_terminateChars(dest, capacity, len, &errorCode); 63 } 64 65 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) { 66 if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) { 67 len=s.len; 68 uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1); 69 } 70 return *this; 71 } 72 73 CharString &CharString::copyFrom(StringPiece s, UErrorCode &errorCode) { 74 if (U_FAILURE(errorCode)) { 75 return *this; 76 } 77 len = 0; 78 append(s, errorCode); 79 return *this; 80 } 81 82 int32_t CharString::lastIndexOf(char c) const { 83 for(int32_t i=len; i>0;) { 84 if(buffer[--i]==c) { 85 return i; 86 } 87 } 88 return -1; 89 } 90 91 bool CharString::contains(StringPiece s) const { 92 if (s.empty()) { return false; } 93 const char *p = buffer.getAlias(); 94 int32_t lastStart = len - s.length(); 95 for (int32_t i = 0; i <= lastStart; ++i) { 96 if (uprv_memcmp(p + i, s.data(), s.length()) == 0) { 97 return true; 98 } 99 } 100 return false; 101 } 102 103 CharString &CharString::truncate(int32_t newLength) { 104 if(newLength<0) { 105 newLength=0; 106 } 107 if(newLength<len) { 108 buffer[len=newLength]=0; 109 } 110 return *this; 111 } 112 113 CharString &CharString::append(char c, UErrorCode &errorCode) { 114 if(ensureCapacity(len+2, 0, errorCode)) { 115 buffer[len++]=c; 116 buffer[len]=0; 117 } 118 return *this; 119 } 120 121 CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) { 122 if(U_FAILURE(errorCode)) { 123 return *this; 124 } 125 if(sLength<-1 || (s==nullptr && sLength!=0)) { 126 errorCode=U_ILLEGAL_ARGUMENT_ERROR; 127 return *this; 128 } 129 if(sLength<0) { 130 sLength= static_cast<int32_t>(uprv_strlen(s)); 131 } 132 if(sLength>0) { 133 if(s==(buffer.getAlias()+len)) { 134 // The caller wrote into the getAppendBuffer(). 135 if(sLength>=(buffer.getCapacity()-len)) { 136 // The caller wrote too much. 137 errorCode=U_INTERNAL_PROGRAM_ERROR; 138 } else { 139 buffer[len+=sLength]=0; 140 } 141 } else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) && 142 sLength>=(buffer.getCapacity()-len) 143 ) { 144 // (Part of) this string is appended to itself which requires reallocation, 145 // so we have to make a copy of the substring and append that. 146 return append(CharString(s, sLength, errorCode), errorCode); 147 } else if(ensureCapacity(len+sLength+1, 0, errorCode)) { 148 uprv_memcpy(buffer.getAlias()+len, s, sLength); 149 buffer[len+=sLength]=0; 150 } 151 } 152 return *this; 153 } 154 155 CharString &CharString::appendNumber(int64_t number, UErrorCode &status) { 156 if (number < 0) { 157 this->append('-', status); 158 if (U_FAILURE(status)) { 159 return *this; 160 } 161 } 162 163 if (number == 0) { 164 this->append('0', status); 165 return *this; 166 } 167 168 int32_t numLen = 0; 169 while (number != 0) { 170 int32_t residue = number % 10; 171 number /= 10; 172 this->append(std::abs(residue) + '0', status); 173 numLen++; 174 if (U_FAILURE(status)) { 175 return *this; 176 } 177 } 178 179 int32_t start = this->length() - numLen, end = this->length() - 1; 180 while(start < end) { 181 std::swap(this->data()[start++], this->data()[end--]); 182 } 183 184 return *this; 185 } 186 187 char *CharString::getAppendBuffer(int32_t minCapacity, 188 int32_t desiredCapacityHint, 189 int32_t &resultCapacity, 190 UErrorCode &errorCode) { 191 if(U_FAILURE(errorCode)) { 192 resultCapacity=0; 193 return nullptr; 194 } 195 int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL 196 if(appendCapacity>=minCapacity) { 197 resultCapacity=appendCapacity; 198 return buffer.getAlias()+len; 199 } 200 if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) { 201 resultCapacity=buffer.getCapacity()-len-1; 202 return buffer.getAlias()+len; 203 } 204 resultCapacity=0; 205 return nullptr; 206 } 207 208 CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) { 209 return appendInvariantChars(s.getBuffer(), s.length(), errorCode); 210 } 211 212 CharString &CharString::appendInvariantChars(const char16_t* uchars, int32_t ucharsLen, UErrorCode &errorCode) { 213 if(U_FAILURE(errorCode)) { 214 return *this; 215 } 216 if (!uprv_isInvariantUString(uchars, ucharsLen)) { 217 errorCode = U_INVARIANT_CONVERSION_ERROR; 218 return *this; 219 } 220 if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) { 221 u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen); 222 len += ucharsLen; 223 buffer[len] = 0; 224 } 225 return *this; 226 } 227 228 UBool CharString::ensureCapacity(int32_t capacity, 229 int32_t desiredCapacityHint, 230 UErrorCode &errorCode) { 231 if(U_FAILURE(errorCode)) { 232 return false; 233 } 234 if(capacity>buffer.getCapacity()) { 235 if(desiredCapacityHint==0) { 236 desiredCapacityHint=capacity+buffer.getCapacity(); 237 } 238 if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==nullptr) && 239 buffer.resize(capacity, len+1)==nullptr 240 ) { 241 errorCode=U_MEMORY_ALLOCATION_ERROR; 242 return false; 243 } 244 } 245 return true; 246 } 247 248 CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) { 249 if(U_FAILURE(errorCode)) { 250 return *this; 251 } 252 if(s.length()==0) { 253 return *this; 254 } 255 char c; 256 if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) { 257 append(getDirSepChar(), errorCode); 258 } 259 append(s, errorCode); 260 return *this; 261 } 262 263 CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) { 264 char c; 265 if(U_SUCCESS(errorCode) && len>0 && 266 (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) { 267 append(getDirSepChar(), errorCode); 268 } 269 return *this; 270 } 271 272 char CharString::getDirSepChar() const { 273 char dirSepChar = U_FILE_SEP_CHAR; 274 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR) 275 // We may need to return a different directory separator when building for Cygwin or MSYS2. 276 if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR)) 277 dirSepChar = U_FILE_ALT_SEP_CHAR; 278 #endif 279 return dirSepChar; 280 } 281 282 U_NAMESPACE_END