blob: 749bfcbb510df8fab611af524f2959c072931e2c [file] [log] [blame]
The Android Open Source Projectcbb10112009-03-03 19:31:44 -08001/*
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
Abhishek Aryae0dce902015-08-20 17:38:16 -070017#define __STDC_LIMIT_MACROS
18#include <stdint.h>
19
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080020#include <utils/String8.h>
21
Steven Moreland066e6252023-10-07 00:29:44 +000022#include <log/log.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080023#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080024
Steven Morelandd21cfab2017-03-10 08:58:36 -080025#include <ctype.h>
26
Biswapriyo Nath9e25bf02022-10-21 10:26:01 +053027#include <limits>
Elliott Hughes4b7b4d62021-04-15 15:18:54 -070028#include <string>
29
Sergio Girod2529f22015-09-23 16:22:59 +010030#include "SharedBuffer.h"
31
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090032/*
33 * Functions outside android is below the namespace android, since they use
34 * functions and constants in android namespace.
35 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080036
37// ---------------------------------------------------------------------------
38
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090039namespace android {
40
Steven Moreland241b93c2018-03-06 09:11:29 -080041static inline char* getEmptyString() {
42 static SharedBuffer* gEmptyStringBuf = [] {
43 SharedBuffer* buf = SharedBuffer::alloc(1);
44 char* str = static_cast<char*>(buf->data());
45 *str = 0;
46 return buf;
47 }();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080048
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080049 gEmptyStringBuf->acquire();
Steven Moreland241b93c2018-03-06 09:11:29 -080050 return static_cast<char*>(gEmptyStringBuf->data());
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080051}
52
53// ---------------------------------------------------------------------------
54
55static char* allocFromUTF8(const char* in, size_t len)
56{
57 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010058 if (len == SIZE_MAX) {
Yi Konge1731a42018-07-16 18:11:34 -070059 return nullptr;
Sergio Giroebabef22015-08-18 14:44:54 +010060 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080061 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000062 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080063 if (buf) {
64 char* str = (char*)buf->data();
65 memcpy(str, in, len);
66 str[len] = 0;
67 return str;
68 }
Yi Konge1731a42018-07-16 18:11:34 -070069 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080070 }
71
72 return getEmptyString();
73}
74
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090075static char* allocFromUTF16(const char16_t* in, size_t len)
76{
Kenny Root9a2d83e2009-12-04 09:38:48 -080077 if (len == 0) return getEmptyString();
78
Sergio Giroc4966a32016-06-28 18:02:29 +010079 // Allow for closing '\0'
80 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
81 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -080082 return getEmptyString();
83 }
Kenny Root9a2d83e2009-12-04 09:38:48 -080084
Sergio Giroc4966a32016-06-28 18:02:29 +010085 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +000086 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -080087 if (!buf) {
88 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -080089 }
90
Sergio Giroc4966a32016-06-28 18:02:29 +010091 char* resultStr = (char*)buf->data();
92 utf16_to_utf8(in, len, resultStr, resultStrLen);
93 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090094}
95
96static char* allocFromUTF32(const char32_t* in, size_t len)
97{
Kenny Rootba0165b2010-11-09 14:37:23 -080098 if (len == 0) {
99 return getEmptyString();
100 }
101
Sergio Giroc4966a32016-06-28 18:02:29 +0100102 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
103 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800104 return getEmptyString();
105 }
106
Sergio Giroc4966a32016-06-28 18:02:29 +0100107 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000108 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800109 if (!buf) {
110 return getEmptyString();
111 }
112
Sergio Giroc4966a32016-06-28 18:02:29 +0100113 char* resultStr = (char*) buf->data();
114 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800115
Sergio Giroc4966a32016-06-28 18:02:29 +0100116 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900117}
118
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800119// ---------------------------------------------------------------------------
120
121String8::String8()
122 : mString(getEmptyString())
123{
124}
125
126String8::String8(const String8& o)
127 : mString(o.mString)
128{
129 SharedBuffer::bufferFromData(mString)->acquire();
130}
131
132String8::String8(const char* o)
133 : mString(allocFromUTF8(o, strlen(o)))
134{
Yi Konge1731a42018-07-16 18:11:34 -0700135 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800136 mString = getEmptyString();
137 }
138}
139
140String8::String8(const char* o, size_t len)
141 : mString(allocFromUTF8(o, len))
142{
Yi Konge1731a42018-07-16 18:11:34 -0700143 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800144 mString = getEmptyString();
145 }
146}
147
Tomasz Wasilczyk90af4152023-08-11 02:12:16 +0000148String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800149
150String8::String8(const char16_t* o)
151 : mString(allocFromUTF16(o, strlen16(o)))
152{
153}
154
155String8::String8(const char16_t* o, size_t len)
156 : mString(allocFromUTF16(o, len))
157{
158}
159
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900160String8::String8(const char32_t* o)
Elliott Hughes4b7b4d62021-04-15 15:18:54 -0700161 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900162
163String8::String8(const char32_t* o, size_t len)
164 : mString(allocFromUTF32(o, len))
165{
166}
167
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800168String8::~String8()
169{
170 SharedBuffer::bufferFromData(mString)->release();
171}
172
Sergio Girod2529f22015-09-23 16:22:59 +0100173size_t String8::length() const
174{
175 return SharedBuffer::sizeFromData(mString)-1;
176}
177
Jeff Brown1d618d62010-12-02 13:50:46 -0800178String8 String8::format(const char* fmt, ...)
179{
180 va_list args;
181 va_start(args, fmt);
182
183 String8 result(formatV(fmt, args));
184
185 va_end(args);
186 return result;
187}
188
189String8 String8::formatV(const char* fmt, va_list args)
190{
191 String8 result;
192 result.appendFormatV(fmt, args);
193 return result;
194}
195
Jeff Brown48da31b2010-09-12 17:55:08 -0700196void String8::clear() {
197 SharedBuffer::bufferFromData(mString)->release();
198 mString = getEmptyString();
199}
200
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800201void String8::setTo(const String8& other)
202{
203 SharedBuffer::bufferFromData(other.mString)->acquire();
204 SharedBuffer::bufferFromData(mString)->release();
205 mString = other.mString;
206}
207
208status_t String8::setTo(const char* other)
209{
Andreas Huber10e5da52010-06-10 11:14:26 -0700210 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800211 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700212 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700213 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800214
215 mString = getEmptyString();
216 return NO_MEMORY;
217}
218
219status_t String8::setTo(const char* other, size_t len)
220{
Andreas Huber10e5da52010-06-10 11:14:26 -0700221 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800222 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700223 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700224 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800225
226 mString = getEmptyString();
227 return NO_MEMORY;
228}
229
230status_t String8::setTo(const char16_t* other, size_t len)
231{
Andreas Huber10e5da52010-06-10 11:14:26 -0700232 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800233 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700234 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700235 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800236
237 mString = getEmptyString();
238 return NO_MEMORY;
239}
240
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900241status_t String8::setTo(const char32_t* other, size_t len)
242{
Andreas Huber10e5da52010-06-10 11:14:26 -0700243 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900244 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700245 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700246 if (mString) return OK;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900247
248 mString = getEmptyString();
249 return NO_MEMORY;
250}
251
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800252status_t String8::append(const String8& other)
253{
254 const size_t otherLen = other.bytes();
255 if (bytes() == 0) {
256 setTo(other);
Elliott Hughes643268f2018-10-08 11:10:11 -0700257 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800258 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700259 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800260 }
261
Tomasz Wasilczyk90af4152023-08-11 02:12:16 +0000262 return real_append(other.c_str(), otherLen);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800263}
264
265status_t String8::append(const char* other)
266{
267 return append(other, strlen(other));
268}
269
270status_t String8::append(const char* other, size_t otherLen)
271{
272 if (bytes() == 0) {
273 return setTo(other, otherLen);
274 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700275 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800276 }
277
278 return real_append(other, otherLen);
279}
280
Jeff Brown35a154e2010-07-15 23:54:05 -0700281status_t String8::appendFormat(const char* fmt, ...)
282{
Jeff Brown647925d2010-11-10 16:03:06 -0800283 va_list args;
284 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700285
Jeff Brown647925d2010-11-10 16:03:06 -0800286 status_t result = appendFormatV(fmt, args);
287
288 va_end(args);
289 return result;
290}
291
292status_t String8::appendFormatV(const char* fmt, va_list args)
293{
Elliott Hughes643268f2018-10-08 11:10:11 -0700294 int n, result = OK;
Fengwei Yinfff9d112014-02-27 01:17:09 +0800295 va_list tmp_args;
296
297 /* args is undefined after vsnprintf.
298 * So we need a copy here to avoid the
299 * second vsnprintf access undefined args.
300 */
301 va_copy(tmp_args, args);
Yi Konge1731a42018-07-16 18:11:34 -0700302 n = vsnprintf(nullptr, 0, fmt, tmp_args);
Fengwei Yinfff9d112014-02-27 01:17:09 +0800303 va_end(tmp_args);
304
Steven Moreland0f0cb952020-07-28 21:41:54 +0000305 if (n < 0) return UNKNOWN_ERROR;
306
307 if (n > 0) {
Jeff Brown35a154e2010-07-15 23:54:05 -0700308 size_t oldLength = length();
Andrei Homescu1a867dc2022-03-29 00:30:34 +0000309 if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
Steven Moreland0f0cb952020-07-28 21:41:54 +0000310 oldLength > std::numeric_limits<size_t>::max() - n - 1) {
311 return NO_MEMORY;
312 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700313 char* buf = lockBuffer(oldLength + n);
314 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800315 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700316 } else {
317 result = NO_MEMORY;
318 }
319 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700320 return result;
321}
322
Elliott Hughes59682762021-06-10 16:42:20 -0700323status_t String8::real_append(const char* other, size_t otherLen) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800324 const size_t myLen = bytes();
Samuel Tan95fd5272016-02-18 16:56:21 -0800325
Elliott Hughes59682762021-06-10 16:42:20 -0700326 SharedBuffer* buf;
327 size_t newLen;
328 if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
329 __builtin_add_overflow(newLen, 1, &newLen) ||
330 (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
331 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800332 }
Elliott Hughes59682762021-06-10 16:42:20 -0700333
334 char* str = (char*)buf->data();
335 mString = str;
336 str += myLen;
337 memcpy(str, other, otherLen);
338 str[otherLen] = '\0';
339 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800340}
341
342char* String8::lockBuffer(size_t size)
343{
344 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
345 ->editResize(size+1);
346 if (buf) {
347 char* str = (char*)buf->data();
348 mString = str;
349 return str;
350 }
Yi Konge1731a42018-07-16 18:11:34 -0700351 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800352}
353
354void String8::unlockBuffer()
355{
356 unlockBuffer(strlen(mString));
357}
358
359status_t String8::unlockBuffer(size_t size)
360{
361 if (size != this->size()) {
362 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
363 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700364 if (! buf) {
365 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800366 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700367
368 char* str = (char*)buf->data();
369 str[size] = 0;
370 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800371 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700372
Elliott Hughes643268f2018-10-08 11:10:11 -0700373 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800374}
375
376ssize_t String8::find(const char* other, size_t start) const
377{
378 size_t len = size();
379 if (start >= len) {
380 return -1;
381 }
382 const char* s = mString+start;
383 const char* p = strstr(s, other);
384 return p ? p-mString : -1;
385}
386
Jeff Brown5ee915a2014-06-06 19:30:15 -0700387bool String8::removeAll(const char* other) {
Eric Miaoc6ce48e2023-07-14 16:35:09 -0700388 ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
389
390 if (*other == '\0')
391 return true;
392
Jeff Brown5ee915a2014-06-06 19:30:15 -0700393 ssize_t index = find(other);
394 if (index < 0) return false;
395
396 char* buf = lockBuffer(size());
397 if (!buf) return false; // out of memory
398
399 size_t skip = strlen(other);
400 size_t len = size();
401 size_t tail = index;
402 while (size_t(index) < len) {
403 ssize_t next = find(other, index + skip);
404 if (next < 0) {
405 next = len;
406 }
407
Andreas Gampedd060f02014-11-13 15:50:17 -0800408 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700409 tail += next - index - skip;
410 index = next;
411 }
412 unlockBuffer(tail);
413 return true;
414}
415
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800416void String8::toLower()
417{
Elliott Hughesa8583952021-04-08 13:26:49 -0700418 const size_t length = size();
419 if (length == 0) return;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800420
Elliott Hughesa8583952021-04-08 13:26:49 -0700421 char* buf = lockBuffer(length);
422 for (size_t i = length; i > 0; --i) {
Steven Morelandfdbc5652020-07-13 23:31:45 +0000423 *buf = static_cast<char>(tolower(*buf));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800424 buf++;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800425 }
Elliott Hughesa8583952021-04-08 13:26:49 -0700426 unlockBuffer(length);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800427}
428
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800429// ---------------------------------------------------------------------------
430// Path functions
431
Steven Morelandc7383702023-10-21 00:43:52 +0000432// TODO: we should remove all the path functions from String8
433#if defined(_WIN32)
434#define OS_PATH_SEPARATOR '\\'
435#else
436#define OS_PATH_SEPARATOR '/'
437#endif
438
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800439String8 String8::getPathDir(void) const
440{
441 const char* cp;
442 const char*const str = mString;
443
444 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700445 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800446 return String8("");
447 else
448 return String8(str, cp - str);
449}
450
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000451/*
452 * Helper function for finding the start of an extension in a pathname.
453 *
454 * Returns a pointer inside mString, or NULL if no extension was found.
455 */
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000456static const char* find_extension(const char* str) {
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000457 const char* lastSlash;
458 const char* lastDot;
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000459
460 // only look at the filename
461 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
462 if (lastSlash == nullptr)
463 lastSlash = str;
464 else
465 lastSlash++;
466
467 // find the last dot
468 lastDot = strrchr(lastSlash, '.');
469 if (lastDot == nullptr)
470 return nullptr;
471
472 // looks good, ship it
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000473 return lastDot;
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000474}
475
476String8 String8::getPathExtension(void) const
477{
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000478 auto ext = find_extension(mString);
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000479 if (ext != nullptr)
480 return String8(ext);
481 else
482 return String8("");
483}
484
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800485}; // namespace android