blob: 1de9e8b1736253a348f0feb92c889d0cafea4b3b [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
17#include <utils/String8.h>
18
Steven Moreland066e6252023-10-07 00:29:44 +000019#include <log/log.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080020#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080021
Steven Morelandd21cfab2017-03-10 08:58:36 -080022#include <ctype.h>
Elliott Hughes29cd0712024-02-09 16:40:02 +000023#include <stdint.h>
Steven Morelandd21cfab2017-03-10 08:58:36 -080024
Biswapriyo Nath9e25bf02022-10-21 10:26:01 +053025#include <limits>
Elliott Hughes4b7b4d62021-04-15 15:18:54 -070026#include <string>
27
Sergio Girod2529f22015-09-23 16:22:59 +010028#include "SharedBuffer.h"
29
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090030/*
31 * Functions outside android is below the namespace android, since they use
32 * functions and constants in android namespace.
33 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080034
35// ---------------------------------------------------------------------------
36
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090037namespace android {
38
Steven Moreland241b93c2018-03-06 09:11:29 -080039static 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 }();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080046
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080047 gEmptyStringBuf->acquire();
Steven Moreland241b93c2018-03-06 09:11:29 -080048 return static_cast<char*>(gEmptyStringBuf->data());
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080049}
50
51// ---------------------------------------------------------------------------
52
53static char* allocFromUTF8(const char* in, size_t len)
54{
55 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010056 if (len == SIZE_MAX) {
Yi Konge1731a42018-07-16 18:11:34 -070057 return nullptr;
Sergio Giroebabef22015-08-18 14:44:54 +010058 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080059 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000060 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080061 if (buf) {
62 char* str = (char*)buf->data();
63 memcpy(str, in, len);
64 str[len] = 0;
65 return str;
66 }
Yi Konge1731a42018-07-16 18:11:34 -070067 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080068 }
69
70 return getEmptyString();
71}
72
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090073static char* allocFromUTF16(const char16_t* in, size_t len)
74{
Kenny Root9a2d83e2009-12-04 09:38:48 -080075 if (len == 0) return getEmptyString();
76
Sergio Giroc4966a32016-06-28 18:02:29 +010077 // Allow for closing '\0'
78 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
79 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -080080 return getEmptyString();
81 }
Kenny Root9a2d83e2009-12-04 09:38:48 -080082
Sergio Giroc4966a32016-06-28 18:02:29 +010083 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +000084 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -080085 if (!buf) {
86 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -080087 }
88
Sergio Giroc4966a32016-06-28 18:02:29 +010089 char* resultStr = (char*)buf->data();
90 utf16_to_utf8(in, len, resultStr, resultStrLen);
91 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090092}
93
94static char* allocFromUTF32(const char32_t* in, size_t len)
95{
Kenny Rootba0165b2010-11-09 14:37:23 -080096 if (len == 0) {
97 return getEmptyString();
98 }
99
Sergio Giroc4966a32016-06-28 18:02:29 +0100100 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
101 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800102 return getEmptyString();
103 }
104
Sergio Giroc4966a32016-06-28 18:02:29 +0100105 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000106 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800107 if (!buf) {
108 return getEmptyString();
109 }
110
Sergio Giroc4966a32016-06-28 18:02:29 +0100111 char* resultStr = (char*) buf->data();
112 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800113
Sergio Giroc4966a32016-06-28 18:02:29 +0100114 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900115}
116
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800117// ---------------------------------------------------------------------------
118
119String8::String8()
120 : mString(getEmptyString())
121{
122}
123
124String8::String8(const String8& o)
125 : mString(o.mString)
126{
127 SharedBuffer::bufferFromData(mString)->acquire();
128}
129
130String8::String8(const char* o)
131 : mString(allocFromUTF8(o, strlen(o)))
132{
Yi Konge1731a42018-07-16 18:11:34 -0700133 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800134 mString = getEmptyString();
135 }
136}
137
138String8::String8(const char* o, size_t len)
139 : mString(allocFromUTF8(o, len))
140{
Yi Konge1731a42018-07-16 18:11:34 -0700141 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800142 mString = getEmptyString();
143 }
144}
145
Tomasz Wasilczyk90af4152023-08-11 02:12:16 +0000146String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800147
148String8::String8(const char16_t* o)
149 : mString(allocFromUTF16(o, strlen16(o)))
150{
151}
152
153String8::String8(const char16_t* o, size_t len)
154 : mString(allocFromUTF16(o, len))
155{
156}
157
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900158String8::String8(const char32_t* o)
Elliott Hughes4b7b4d62021-04-15 15:18:54 -0700159 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900160
161String8::String8(const char32_t* o, size_t len)
162 : mString(allocFromUTF32(o, len))
163{
164}
165
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800166String8::~String8()
167{
168 SharedBuffer::bufferFromData(mString)->release();
169}
170
Sergio Girod2529f22015-09-23 16:22:59 +0100171size_t String8::length() const
172{
173 return SharedBuffer::sizeFromData(mString)-1;
174}
175
Jeff Brown1d618d62010-12-02 13:50:46 -0800176String8 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
187String8 String8::formatV(const char* fmt, va_list args)
188{
189 String8 result;
190 result.appendFormatV(fmt, args);
191 return result;
192}
193
Jeff Brown48da31b2010-09-12 17:55:08 -0700194void String8::clear() {
195 SharedBuffer::bufferFromData(mString)->release();
196 mString = getEmptyString();
197}
198
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800199void String8::setTo(const String8& other)
200{
201 SharedBuffer::bufferFromData(other.mString)->acquire();
202 SharedBuffer::bufferFromData(mString)->release();
203 mString = other.mString;
204}
205
206status_t String8::setTo(const char* other)
207{
Andreas Huber10e5da52010-06-10 11:14:26 -0700208 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800209 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700210 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700211 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800212
213 mString = getEmptyString();
214 return NO_MEMORY;
215}
216
217status_t String8::setTo(const char* other, size_t len)
218{
Andreas Huber10e5da52010-06-10 11:14:26 -0700219 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800220 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700221 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700222 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800223
224 mString = getEmptyString();
225 return NO_MEMORY;
226}
227
228status_t String8::setTo(const char16_t* other, size_t len)
229{
Andreas Huber10e5da52010-06-10 11:14:26 -0700230 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800231 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700232 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700233 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800234
235 mString = getEmptyString();
236 return NO_MEMORY;
237}
238
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900239status_t String8::setTo(const char32_t* other, size_t len)
240{
Andreas Huber10e5da52010-06-10 11:14:26 -0700241 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900242 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700243 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700244 if (mString) return OK;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900245
246 mString = getEmptyString();
247 return NO_MEMORY;
248}
249
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800250status_t String8::append(const String8& other)
251{
252 const size_t otherLen = other.bytes();
253 if (bytes() == 0) {
254 setTo(other);
Elliott Hughes643268f2018-10-08 11:10:11 -0700255 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800256 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700257 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800258 }
259
Tomasz Wasilczyk90af4152023-08-11 02:12:16 +0000260 return real_append(other.c_str(), otherLen);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800261}
262
263status_t String8::append(const char* other)
264{
265 return append(other, strlen(other));
266}
267
268status_t String8::append(const char* other, size_t otherLen)
269{
270 if (bytes() == 0) {
271 return setTo(other, otherLen);
272 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700273 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800274 }
275
276 return real_append(other, otherLen);
277}
278
Jeff Brown35a154e2010-07-15 23:54:05 -0700279status_t String8::appendFormat(const char* fmt, ...)
280{
Jeff Brown647925d2010-11-10 16:03:06 -0800281 va_list args;
282 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700283
Jeff Brown647925d2010-11-10 16:03:06 -0800284 status_t result = appendFormatV(fmt, args);
285
286 va_end(args);
287 return result;
288}
289
290status_t String8::appendFormatV(const char* fmt, va_list args)
291{
Elliott Hughes643268f2018-10-08 11:10:11 -0700292 int n, result = OK;
Fengwei Yinfff9d112014-02-27 01:17:09 +0800293 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);
Yi Konge1731a42018-07-16 18:11:34 -0700300 n = vsnprintf(nullptr, 0, fmt, tmp_args);
Fengwei Yinfff9d112014-02-27 01:17:09 +0800301 va_end(tmp_args);
302
Steven Moreland0f0cb952020-07-28 21:41:54 +0000303 if (n < 0) return UNKNOWN_ERROR;
304
305 if (n > 0) {
Jeff Brown35a154e2010-07-15 23:54:05 -0700306 size_t oldLength = length();
Andrei Homescu1a867dc2022-03-29 00:30:34 +0000307 if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
Steven Moreland0f0cb952020-07-28 21:41:54 +0000308 oldLength > std::numeric_limits<size_t>::max() - n - 1) {
309 return NO_MEMORY;
310 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700311 char* buf = lockBuffer(oldLength + n);
312 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800313 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700314 } else {
315 result = NO_MEMORY;
316 }
317 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700318 return result;
319}
320
Elliott Hughes59682762021-06-10 16:42:20 -0700321status_t String8::real_append(const char* other, size_t otherLen) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800322 const size_t myLen = bytes();
Samuel Tan95fd5272016-02-18 16:56:21 -0800323
Elliott Hughes59682762021-06-10 16:42:20 -0700324 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;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800330 }
Elliott Hughes59682762021-06-10 16:42:20 -0700331
332 char* str = (char*)buf->data();
333 mString = str;
334 str += myLen;
335 memcpy(str, other, otherLen);
336 str[otherLen] = '\0';
337 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800338}
339
340char* 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 }
Yi Konge1731a42018-07-16 18:11:34 -0700349 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800350}
351
352void String8::unlockBuffer()
353{
354 unlockBuffer(strlen(mString));
355}
356
357status_t String8::unlockBuffer(size_t size)
358{
359 if (size != this->size()) {
360 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
361 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700362 if (! buf) {
363 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800364 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700365
366 char* str = (char*)buf->data();
367 str[size] = 0;
368 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800369 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700370
Elliott Hughes643268f2018-10-08 11:10:11 -0700371 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800372}
373
374ssize_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
Jeff Brown5ee915a2014-06-06 19:30:15 -0700385bool String8::removeAll(const char* other) {
Eric Miaoc6ce48e2023-07-14 16:35:09 -0700386 ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
387
388 if (*other == '\0')
389 return true;
390
Jeff Brown5ee915a2014-06-06 19:30:15 -0700391 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
Andreas Gampedd060f02014-11-13 15:50:17 -0800406 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700407 tail += next - index - skip;
408 index = next;
409 }
410 unlockBuffer(tail);
411 return true;
412}
413
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800414void String8::toLower()
415{
Elliott Hughesa8583952021-04-08 13:26:49 -0700416 const size_t length = size();
417 if (length == 0) return;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800418
Elliott Hughesa8583952021-04-08 13:26:49 -0700419 char* buf = lockBuffer(length);
420 for (size_t i = length; i > 0; --i) {
Steven Morelandfdbc5652020-07-13 23:31:45 +0000421 *buf = static_cast<char>(tolower(*buf));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800422 buf++;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800423 }
Elliott Hughesa8583952021-04-08 13:26:49 -0700424 unlockBuffer(length);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800425}
426
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800427// ---------------------------------------------------------------------------
428// Path functions
429
Steven Morelandc7383702023-10-21 00:43:52 +0000430// 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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800437String8 String8::getPathDir(void) const
438{
439 const char* cp;
440 const char*const str = mString;
441
442 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700443 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800444 return String8("");
445 else
446 return String8(str, cp - str);
447}
448
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000449/*
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 */
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000454static const char* find_extension(const char* str) {
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000455 const char* lastSlash;
456 const char* lastDot;
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000457
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
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000471 return lastDot;
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000472}
473
474String8 String8::getPathExtension(void) const
475{
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000476 auto ext = find_extension(mString);
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000477 if (ext != nullptr)
478 return String8(ext);
479 else
480 return String8("");
481}
482
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800483}; // namespace android