1 /*
2 * Copyright (C) 2005 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <utils/String8.h>
18
19 #include <log/log.h>
20 #include <utils/String16.h>
21
22 #include <ctype.h>
23 #include <stdint.h>
24
25 #include <limits>
26 #include <string>
27
28 #include "SharedBuffer.h"
29
30 /*
31 * Functions outside android is below the namespace android, since they use
32 * functions and constants in android namespace.
33 */
34
35 // ---------------------------------------------------------------------------
36
37 namespace android {
38
getEmptyString()39 static inline char* getEmptyString() {
40 static SharedBuffer* gEmptyStringBuf = [] {
41 SharedBuffer* buf = SharedBuffer::alloc(1);
42 char* str = static_cast<char*>(buf->data());
43 *str = 0;
44 return buf;
45 }();
46
47 gEmptyStringBuf->acquire();
48 return static_cast<char*>(gEmptyStringBuf->data());
49 }
50
51 // ---------------------------------------------------------------------------
52
allocFromUTF8(const char * in,size_t len)53 static char* allocFromUTF8(const char* in, size_t len)
54 {
55 if (len > 0) {
56 if (len == SIZE_MAX) {
57 return nullptr;
58 }
59 SharedBuffer* buf = SharedBuffer::alloc(len+1);
60 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
61 if (buf) {
62 char* str = (char*)buf->data();
63 memcpy(str, in, len);
64 str[len] = 0;
65 return str;
66 }
67 return nullptr;
68 }
69
70 return getEmptyString();
71 }
72
allocFromUTF16(const char16_t * in,size_t len)73 static char* allocFromUTF16(const char16_t* in, size_t len)
74 {
75 if (len == 0) return getEmptyString();
76
77 // Allow for closing '\0'
78 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
79 if (resultStrLen < 1) {
80 return getEmptyString();
81 }
82
83 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
84 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
85 if (!buf) {
86 return getEmptyString();
87 }
88
89 char* resultStr = (char*)buf->data();
90 utf16_to_utf8(in, len, resultStr, resultStrLen);
91 return resultStr;
92 }
93
allocFromUTF32(const char32_t * in,size_t len)94 static char* allocFromUTF32(const char32_t* in, size_t len)
95 {
96 if (len == 0) {
97 return getEmptyString();
98 }
99
100 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
101 if (resultStrLen < 1) {
102 return getEmptyString();
103 }
104
105 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
106 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
107 if (!buf) {
108 return getEmptyString();
109 }
110
111 char* resultStr = (char*) buf->data();
112 utf32_to_utf8(in, len, resultStr, resultStrLen);
113
114 return resultStr;
115 }
116
117 // ---------------------------------------------------------------------------
118
String8()119 String8::String8()
120 : mString(getEmptyString())
121 {
122 }
123
String8(const String8 & o)124 String8::String8(const String8& o)
125 : mString(o.mString)
126 {
127 SharedBuffer::bufferFromData(mString)->acquire();
128 }
129
String8(const char * o)130 String8::String8(const char* o)
131 : mString(allocFromUTF8(o, strlen(o)))
132 {
133 if (mString == nullptr) {
134 mString = getEmptyString();
135 }
136 }
137
String8(const char * o,size_t len)138 String8::String8(const char* o, size_t len)
139 : mString(allocFromUTF8(o, len))
140 {
141 if (mString == nullptr) {
142 mString = getEmptyString();
143 }
144 }
145
String8(const String16 & o)146 String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
147
String8(const char16_t * o)148 String8::String8(const char16_t* o)
149 : mString(allocFromUTF16(o, strlen16(o)))
150 {
151 }
152
String8(const char16_t * o,size_t len)153 String8::String8(const char16_t* o, size_t len)
154 : mString(allocFromUTF16(o, len))
155 {
156 }
157
String8(const char32_t * o)158 String8::String8(const char32_t* o)
159 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
160
String8(const char32_t * o,size_t len)161 String8::String8(const char32_t* o, size_t len)
162 : mString(allocFromUTF32(o, len))
163 {
164 }
165
~String8()166 String8::~String8()
167 {
168 SharedBuffer::bufferFromData(mString)->release();
169 }
170
length() const171 size_t String8::length() const
172 {
173 return SharedBuffer::sizeFromData(mString)-1;
174 }
175
format(const char * fmt,...)176 String8 String8::format(const char* fmt, ...)
177 {
178 va_list args;
179 va_start(args, fmt);
180
181 String8 result(formatV(fmt, args));
182
183 va_end(args);
184 return result;
185 }
186
formatV(const char * fmt,va_list args)187 String8 String8::formatV(const char* fmt, va_list args)
188 {
189 String8 result;
190 result.appendFormatV(fmt, args);
191 return result;
192 }
193
clear()194 void String8::clear() {
195 SharedBuffer::bufferFromData(mString)->release();
196 mString = getEmptyString();
197 }
198
setTo(const String8 & other)199 void String8::setTo(const String8& other)
200 {
201 SharedBuffer::bufferFromData(other.mString)->acquire();
202 SharedBuffer::bufferFromData(mString)->release();
203 mString = other.mString;
204 }
205
setTo(const char * other)206 status_t String8::setTo(const char* other)
207 {
208 const char *newString = allocFromUTF8(other, strlen(other));
209 SharedBuffer::bufferFromData(mString)->release();
210 mString = newString;
211 if (mString) return OK;
212
213 mString = getEmptyString();
214 return NO_MEMORY;
215 }
216
setTo(const char * other,size_t len)217 status_t String8::setTo(const char* other, size_t len)
218 {
219 const char *newString = allocFromUTF8(other, len);
220 SharedBuffer::bufferFromData(mString)->release();
221 mString = newString;
222 if (mString) return OK;
223
224 mString = getEmptyString();
225 return NO_MEMORY;
226 }
227
setTo(const char16_t * other,size_t len)228 status_t String8::setTo(const char16_t* other, size_t len)
229 {
230 const char *newString = allocFromUTF16(other, len);
231 SharedBuffer::bufferFromData(mString)->release();
232 mString = newString;
233 if (mString) return OK;
234
235 mString = getEmptyString();
236 return NO_MEMORY;
237 }
238
setTo(const char32_t * other,size_t len)239 status_t String8::setTo(const char32_t* other, size_t len)
240 {
241 const char *newString = allocFromUTF32(other, len);
242 SharedBuffer::bufferFromData(mString)->release();
243 mString = newString;
244 if (mString) return OK;
245
246 mString = getEmptyString();
247 return NO_MEMORY;
248 }
249
append(const String8 & other)250 status_t String8::append(const String8& other)
251 {
252 const size_t otherLen = other.bytes();
253 if (bytes() == 0) {
254 setTo(other);
255 return OK;
256 } else if (otherLen == 0) {
257 return OK;
258 }
259
260 return real_append(other.c_str(), otherLen);
261 }
262
append(const char * other)263 status_t String8::append(const char* other)
264 {
265 return append(other, strlen(other));
266 }
267
append(const char * other,size_t otherLen)268 status_t String8::append(const char* other, size_t otherLen)
269 {
270 if (bytes() == 0) {
271 return setTo(other, otherLen);
272 } else if (otherLen == 0) {
273 return OK;
274 }
275
276 return real_append(other, otherLen);
277 }
278
appendFormat(const char * fmt,...)279 status_t String8::appendFormat(const char* fmt, ...)
280 {
281 va_list args;
282 va_start(args, fmt);
283
284 status_t result = appendFormatV(fmt, args);
285
286 va_end(args);
287 return result;
288 }
289
appendFormatV(const char * fmt,va_list args)290 status_t String8::appendFormatV(const char* fmt, va_list args)
291 {
292 int n, result = OK;
293 va_list tmp_args;
294
295 /* args is undefined after vsnprintf.
296 * So we need a copy here to avoid the
297 * second vsnprintf access undefined args.
298 */
299 va_copy(tmp_args, args);
300 n = vsnprintf(nullptr, 0, fmt, tmp_args);
301 va_end(tmp_args);
302
303 if (n < 0) return UNKNOWN_ERROR;
304
305 if (n > 0) {
306 size_t oldLength = length();
307 if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
308 oldLength > std::numeric_limits<size_t>::max() - n - 1) {
309 return NO_MEMORY;
310 }
311 char* buf = lockBuffer(oldLength + n);
312 if (buf) {
313 vsnprintf(buf + oldLength, n + 1, fmt, args);
314 } else {
315 result = NO_MEMORY;
316 }
317 }
318 return result;
319 }
320
real_append(const char * other,size_t otherLen)321 status_t String8::real_append(const char* other, size_t otherLen) {
322 const size_t myLen = bytes();
323
324 SharedBuffer* buf;
325 size_t newLen;
326 if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
327 __builtin_add_overflow(newLen, 1, &newLen) ||
328 (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
329 return NO_MEMORY;
330 }
331
332 char* str = (char*)buf->data();
333 mString = str;
334 str += myLen;
335 memcpy(str, other, otherLen);
336 str[otherLen] = '\0';
337 return OK;
338 }
339
lockBuffer(size_t size)340 char* String8::lockBuffer(size_t size)
341 {
342 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
343 ->editResize(size+1);
344 if (buf) {
345 char* str = (char*)buf->data();
346 mString = str;
347 return str;
348 }
349 return nullptr;
350 }
351
unlockBuffer()352 void String8::unlockBuffer()
353 {
354 unlockBuffer(strlen(mString));
355 }
356
unlockBuffer(size_t size)357 status_t String8::unlockBuffer(size_t size)
358 {
359 if (size != this->size()) {
360 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
361 ->editResize(size+1);
362 if (! buf) {
363 return NO_MEMORY;
364 }
365
366 char* str = (char*)buf->data();
367 str[size] = 0;
368 mString = str;
369 }
370
371 return OK;
372 }
373
find(const char * other,size_t start) const374 ssize_t String8::find(const char* other, size_t start) const
375 {
376 size_t len = size();
377 if (start >= len) {
378 return -1;
379 }
380 const char* s = mString+start;
381 const char* p = strstr(s, other);
382 return p ? p-mString : -1;
383 }
384
removeAll(const char * other)385 bool String8::removeAll(const char* other) {
386 ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
387
388 if (*other == '\0')
389 return true;
390
391 ssize_t index = find(other);
392 if (index < 0) return false;
393
394 char* buf = lockBuffer(size());
395 if (!buf) return false; // out of memory
396
397 size_t skip = strlen(other);
398 size_t len = size();
399 size_t tail = index;
400 while (size_t(index) < len) {
401 ssize_t next = find(other, index + skip);
402 if (next < 0) {
403 next = len;
404 }
405
406 memmove(buf + tail, buf + index + skip, next - index - skip);
407 tail += next - index - skip;
408 index = next;
409 }
410 unlockBuffer(tail);
411 return true;
412 }
413
toLower()414 void String8::toLower()
415 {
416 const size_t length = size();
417 if (length == 0) return;
418
419 char* buf = lockBuffer(length);
420 for (size_t i = length; i > 0; --i) {
421 *buf = static_cast<char>(tolower(*buf));
422 buf++;
423 }
424 unlockBuffer(length);
425 }
426
427 // ---------------------------------------------------------------------------
428 // Path functions
429
430 // TODO: we should remove all the path functions from String8
431 #if defined(_WIN32)
432 #define OS_PATH_SEPARATOR '\\'
433 #else
434 #define OS_PATH_SEPARATOR '/'
435 #endif
436
getPathDir(void) const437 String8 String8::getPathDir(void) const
438 {
439 const char* cp;
440 const char*const str = mString;
441
442 cp = strrchr(str, OS_PATH_SEPARATOR);
443 if (cp == nullptr)
444 return String8("");
445 else
446 return String8(str, cp - str);
447 }
448
449 /*
450 * Helper function for finding the start of an extension in a pathname.
451 *
452 * Returns a pointer inside mString, or NULL if no extension was found.
453 */
find_extension(const char * str)454 static const char* find_extension(const char* str) {
455 const char* lastSlash;
456 const char* lastDot;
457
458 // only look at the filename
459 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
460 if (lastSlash == nullptr)
461 lastSlash = str;
462 else
463 lastSlash++;
464
465 // find the last dot
466 lastDot = strrchr(lastSlash, '.');
467 if (lastDot == nullptr)
468 return nullptr;
469
470 // looks good, ship it
471 return lastDot;
472 }
473
getPathExtension(void) const474 String8 String8::getPathExtension(void) const
475 {
476 auto ext = find_extension(mString);
477 if (ext != nullptr)
478 return String8(ext);
479 else
480 return String8("");
481 }
482
483 }; // namespace android
484