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