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