blob: 4301f0ea3a77e1811333ae792966644cb9d27bbe [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
Elliott Hughes1f8bc862015-07-29 14:02:29 -070022#include <utils/Compat.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080023#include <utils/Log.h>
24#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080025
Steven Morelandd21cfab2017-03-10 08:58:36 -080026#include <ctype.h>
27
Biswapriyo Nath9e25bf02022-10-21 10:26:01 +053028#include <limits>
Elliott Hughes4b7b4d62021-04-15 15:18:54 -070029#include <string>
30
Sergio Girod2529f22015-09-23 16:22:59 +010031#include "SharedBuffer.h"
32
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090033/*
34 * Functions outside android is below the namespace android, since they use
35 * functions and constants in android namespace.
36 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080037
38// ---------------------------------------------------------------------------
39
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090040namespace android {
41
Steven Moreland241b93c2018-03-06 09:11:29 -080042static inline char* getEmptyString() {
43 static SharedBuffer* gEmptyStringBuf = [] {
44 SharedBuffer* buf = SharedBuffer::alloc(1);
45 char* str = static_cast<char*>(buf->data());
46 *str = 0;
47 return buf;
48 }();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080049
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080050 gEmptyStringBuf->acquire();
Steven Moreland241b93c2018-03-06 09:11:29 -080051 return static_cast<char*>(gEmptyStringBuf->data());
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080052}
53
54// ---------------------------------------------------------------------------
55
56static char* allocFromUTF8(const char* in, size_t len)
57{
58 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010059 if (len == SIZE_MAX) {
Yi Konge1731a42018-07-16 18:11:34 -070060 return nullptr;
Sergio Giroebabef22015-08-18 14:44:54 +010061 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080062 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000063 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080064 if (buf) {
65 char* str = (char*)buf->data();
66 memcpy(str, in, len);
67 str[len] = 0;
68 return str;
69 }
Yi Konge1731a42018-07-16 18:11:34 -070070 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080071 }
72
73 return getEmptyString();
74}
75
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090076static char* allocFromUTF16(const char16_t* in, size_t len)
77{
Kenny Root9a2d83e2009-12-04 09:38:48 -080078 if (len == 0) return getEmptyString();
79
Sergio Giroc4966a32016-06-28 18:02:29 +010080 // Allow for closing '\0'
81 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
82 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -080083 return getEmptyString();
84 }
Kenny Root9a2d83e2009-12-04 09:38:48 -080085
Sergio Giroc4966a32016-06-28 18:02:29 +010086 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +000087 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -080088 if (!buf) {
89 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -080090 }
91
Sergio Giroc4966a32016-06-28 18:02:29 +010092 char* resultStr = (char*)buf->data();
93 utf16_to_utf8(in, len, resultStr, resultStrLen);
94 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090095}
96
97static char* allocFromUTF32(const char32_t* in, size_t len)
98{
Kenny Rootba0165b2010-11-09 14:37:23 -080099 if (len == 0) {
100 return getEmptyString();
101 }
102
Sergio Giroc4966a32016-06-28 18:02:29 +0100103 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
104 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800105 return getEmptyString();
106 }
107
Sergio Giroc4966a32016-06-28 18:02:29 +0100108 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000109 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800110 if (!buf) {
111 return getEmptyString();
112 }
113
Sergio Giroc4966a32016-06-28 18:02:29 +0100114 char* resultStr = (char*) buf->data();
115 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800116
Sergio Giroc4966a32016-06-28 18:02:29 +0100117 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900118}
119
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800120// ---------------------------------------------------------------------------
121
122String8::String8()
123 : mString(getEmptyString())
124{
125}
126
127String8::String8(const String8& o)
128 : mString(o.mString)
129{
130 SharedBuffer::bufferFromData(mString)->acquire();
131}
132
133String8::String8(const char* o)
134 : mString(allocFromUTF8(o, strlen(o)))
135{
Yi Konge1731a42018-07-16 18:11:34 -0700136 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800137 mString = getEmptyString();
138 }
139}
140
141String8::String8(const char* o, size_t len)
142 : mString(allocFromUTF8(o, len))
143{
Yi Konge1731a42018-07-16 18:11:34 -0700144 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800145 mString = getEmptyString();
146 }
147}
148
Tomasz Wasilczyk90af4152023-08-11 02:12:16 +0000149String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800150
151String8::String8(const char16_t* o)
152 : mString(allocFromUTF16(o, strlen16(o)))
153{
154}
155
156String8::String8(const char16_t* o, size_t len)
157 : mString(allocFromUTF16(o, len))
158{
159}
160
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900161String8::String8(const char32_t* o)
Elliott Hughes4b7b4d62021-04-15 15:18:54 -0700162 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900163
164String8::String8(const char32_t* o, size_t len)
165 : mString(allocFromUTF32(o, len))
166{
167}
168
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800169String8::~String8()
170{
171 SharedBuffer::bufferFromData(mString)->release();
172}
173
Sergio Girod2529f22015-09-23 16:22:59 +0100174size_t String8::length() const
175{
176 return SharedBuffer::sizeFromData(mString)-1;
177}
178
Jeff Brown1d618d62010-12-02 13:50:46 -0800179String8 String8::format(const char* fmt, ...)
180{
181 va_list args;
182 va_start(args, fmt);
183
184 String8 result(formatV(fmt, args));
185
186 va_end(args);
187 return result;
188}
189
190String8 String8::formatV(const char* fmt, va_list args)
191{
192 String8 result;
193 result.appendFormatV(fmt, args);
194 return result;
195}
196
Jeff Brown48da31b2010-09-12 17:55:08 -0700197void String8::clear() {
198 SharedBuffer::bufferFromData(mString)->release();
199 mString = getEmptyString();
200}
201
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800202void String8::setTo(const String8& other)
203{
204 SharedBuffer::bufferFromData(other.mString)->acquire();
205 SharedBuffer::bufferFromData(mString)->release();
206 mString = other.mString;
207}
208
209status_t String8::setTo(const char* other)
210{
Andreas Huber10e5da52010-06-10 11:14:26 -0700211 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800212 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700213 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700214 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800215
216 mString = getEmptyString();
217 return NO_MEMORY;
218}
219
220status_t String8::setTo(const char* other, size_t len)
221{
Andreas Huber10e5da52010-06-10 11:14:26 -0700222 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800223 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700224 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700225 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800226
227 mString = getEmptyString();
228 return NO_MEMORY;
229}
230
231status_t String8::setTo(const char16_t* other, size_t len)
232{
Andreas Huber10e5da52010-06-10 11:14:26 -0700233 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800234 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700235 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700236 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800237
238 mString = getEmptyString();
239 return NO_MEMORY;
240}
241
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900242status_t String8::setTo(const char32_t* other, size_t len)
243{
Andreas Huber10e5da52010-06-10 11:14:26 -0700244 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900245 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700246 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700247 if (mString) return OK;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900248
249 mString = getEmptyString();
250 return NO_MEMORY;
251}
252
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800253status_t String8::append(const String8& other)
254{
255 const size_t otherLen = other.bytes();
256 if (bytes() == 0) {
257 setTo(other);
Elliott Hughes643268f2018-10-08 11:10:11 -0700258 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800259 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700260 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800261 }
262
Tomasz Wasilczyk90af4152023-08-11 02:12:16 +0000263 return real_append(other.c_str(), otherLen);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800264}
265
266status_t String8::append(const char* other)
267{
268 return append(other, strlen(other));
269}
270
271status_t String8::append(const char* other, size_t otherLen)
272{
273 if (bytes() == 0) {
274 return setTo(other, otherLen);
275 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700276 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800277 }
278
279 return real_append(other, otherLen);
280}
281
Jeff Brown35a154e2010-07-15 23:54:05 -0700282status_t String8::appendFormat(const char* fmt, ...)
283{
Jeff Brown647925d2010-11-10 16:03:06 -0800284 va_list args;
285 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700286
Jeff Brown647925d2010-11-10 16:03:06 -0800287 status_t result = appendFormatV(fmt, args);
288
289 va_end(args);
290 return result;
291}
292
293status_t String8::appendFormatV(const char* fmt, va_list args)
294{
Elliott Hughes643268f2018-10-08 11:10:11 -0700295 int n, result = OK;
Fengwei Yinfff9d112014-02-27 01:17:09 +0800296 va_list tmp_args;
297
298 /* args is undefined after vsnprintf.
299 * So we need a copy here to avoid the
300 * second vsnprintf access undefined args.
301 */
302 va_copy(tmp_args, args);
Yi Konge1731a42018-07-16 18:11:34 -0700303 n = vsnprintf(nullptr, 0, fmt, tmp_args);
Fengwei Yinfff9d112014-02-27 01:17:09 +0800304 va_end(tmp_args);
305
Steven Moreland0f0cb952020-07-28 21:41:54 +0000306 if (n < 0) return UNKNOWN_ERROR;
307
308 if (n > 0) {
Jeff Brown35a154e2010-07-15 23:54:05 -0700309 size_t oldLength = length();
Andrei Homescu1a867dc2022-03-29 00:30:34 +0000310 if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
Steven Moreland0f0cb952020-07-28 21:41:54 +0000311 oldLength > std::numeric_limits<size_t>::max() - n - 1) {
312 return NO_MEMORY;
313 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700314 char* buf = lockBuffer(oldLength + n);
315 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800316 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700317 } else {
318 result = NO_MEMORY;
319 }
320 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700321 return result;
322}
323
Elliott Hughes59682762021-06-10 16:42:20 -0700324status_t String8::real_append(const char* other, size_t otherLen) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800325 const size_t myLen = bytes();
Samuel Tan95fd5272016-02-18 16:56:21 -0800326
Elliott Hughes59682762021-06-10 16:42:20 -0700327 SharedBuffer* buf;
328 size_t newLen;
329 if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
330 __builtin_add_overflow(newLen, 1, &newLen) ||
331 (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
332 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800333 }
Elliott Hughes59682762021-06-10 16:42:20 -0700334
335 char* str = (char*)buf->data();
336 mString = str;
337 str += myLen;
338 memcpy(str, other, otherLen);
339 str[otherLen] = '\0';
340 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800341}
342
343char* String8::lockBuffer(size_t size)
344{
345 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
346 ->editResize(size+1);
347 if (buf) {
348 char* str = (char*)buf->data();
349 mString = str;
350 return str;
351 }
Yi Konge1731a42018-07-16 18:11:34 -0700352 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800353}
354
355void String8::unlockBuffer()
356{
357 unlockBuffer(strlen(mString));
358}
359
360status_t String8::unlockBuffer(size_t size)
361{
362 if (size != this->size()) {
363 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
364 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700365 if (! buf) {
366 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800367 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700368
369 char* str = (char*)buf->data();
370 str[size] = 0;
371 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800372 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700373
Elliott Hughes643268f2018-10-08 11:10:11 -0700374 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800375}
376
377ssize_t String8::find(const char* other, size_t start) const
378{
379 size_t len = size();
380 if (start >= len) {
381 return -1;
382 }
383 const char* s = mString+start;
384 const char* p = strstr(s, other);
385 return p ? p-mString : -1;
386}
387
Jeff Brown5ee915a2014-06-06 19:30:15 -0700388bool String8::removeAll(const char* other) {
Eric Miaoc6ce48e2023-07-14 16:35:09 -0700389 ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
390
391 if (*other == '\0')
392 return true;
393
Jeff Brown5ee915a2014-06-06 19:30:15 -0700394 ssize_t index = find(other);
395 if (index < 0) return false;
396
397 char* buf = lockBuffer(size());
398 if (!buf) return false; // out of memory
399
400 size_t skip = strlen(other);
401 size_t len = size();
402 size_t tail = index;
403 while (size_t(index) < len) {
404 ssize_t next = find(other, index + skip);
405 if (next < 0) {
406 next = len;
407 }
408
Andreas Gampedd060f02014-11-13 15:50:17 -0800409 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700410 tail += next - index - skip;
411 index = next;
412 }
413 unlockBuffer(tail);
414 return true;
415}
416
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800417void String8::toLower()
418{
Elliott Hughesa8583952021-04-08 13:26:49 -0700419 const size_t length = size();
420 if (length == 0) return;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800421
Elliott Hughesa8583952021-04-08 13:26:49 -0700422 char* buf = lockBuffer(length);
423 for (size_t i = length; i > 0; --i) {
Steven Morelandfdbc5652020-07-13 23:31:45 +0000424 *buf = static_cast<char>(tolower(*buf));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800425 buf++;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800426 }
Elliott Hughesa8583952021-04-08 13:26:49 -0700427 unlockBuffer(length);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800428}
429
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800430// ---------------------------------------------------------------------------
431// Path functions
432
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800433String8 String8::getPathDir(void) const
434{
435 const char* cp;
436 const char*const str = mString;
437
438 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700439 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800440 return String8("");
441 else
442 return String8(str, cp - str);
443}
444
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000445/*
446 * Helper function for finding the start of an extension in a pathname.
447 *
448 * Returns a pointer inside mString, or NULL if no extension was found.
449 */
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000450static const char* find_extension(const char* str) {
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000451 const char* lastSlash;
452 const char* lastDot;
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000453
454 // only look at the filename
455 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
456 if (lastSlash == nullptr)
457 lastSlash = str;
458 else
459 lastSlash++;
460
461 // find the last dot
462 lastDot = strrchr(lastSlash, '.');
463 if (lastDot == nullptr)
464 return nullptr;
465
466 // looks good, ship it
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000467 return lastDot;
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000468}
469
470String8 String8::getPathExtension(void) const
471{
Tomasz Wasilczyka1853512023-09-11 17:45:16 +0000472 auto ext = find_extension(mString);
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000473 if (ext != nullptr)
474 return String8(ext);
475 else
476 return String8("");
477}
478
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800479}; // namespace android