blob: 8d312b57ce2b767d758676c7de4e4d19ce1fe07b [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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080042// Separator used by resource paths. This is not platform dependent contrary
43// to OS_PATH_SEPARATOR.
44#define RES_PATH_SEPARATOR '/'
45
Steven Moreland241b93c2018-03-06 09:11:29 -080046static inline char* getEmptyString() {
47 static SharedBuffer* gEmptyStringBuf = [] {
48 SharedBuffer* buf = SharedBuffer::alloc(1);
49 char* str = static_cast<char*>(buf->data());
50 *str = 0;
51 return buf;
52 }();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080053
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080054 gEmptyStringBuf->acquire();
Steven Moreland241b93c2018-03-06 09:11:29 -080055 return static_cast<char*>(gEmptyStringBuf->data());
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080056}
57
58// ---------------------------------------------------------------------------
59
60static char* allocFromUTF8(const char* in, size_t len)
61{
62 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010063 if (len == SIZE_MAX) {
Yi Konge1731a42018-07-16 18:11:34 -070064 return nullptr;
Sergio Giroebabef22015-08-18 14:44:54 +010065 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080066 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000067 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080068 if (buf) {
69 char* str = (char*)buf->data();
70 memcpy(str, in, len);
71 str[len] = 0;
72 return str;
73 }
Yi Konge1731a42018-07-16 18:11:34 -070074 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080075 }
76
77 return getEmptyString();
78}
79
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090080static char* allocFromUTF16(const char16_t* in, size_t len)
81{
Kenny Root9a2d83e2009-12-04 09:38:48 -080082 if (len == 0) return getEmptyString();
83
Sergio Giroc4966a32016-06-28 18:02:29 +010084 // Allow for closing '\0'
85 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
86 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -080087 return getEmptyString();
88 }
Kenny Root9a2d83e2009-12-04 09:38:48 -080089
Sergio Giroc4966a32016-06-28 18:02:29 +010090 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +000091 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -080092 if (!buf) {
93 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -080094 }
95
Sergio Giroc4966a32016-06-28 18:02:29 +010096 char* resultStr = (char*)buf->data();
97 utf16_to_utf8(in, len, resultStr, resultStrLen);
98 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090099}
100
101static char* allocFromUTF32(const char32_t* in, size_t len)
102{
Kenny Rootba0165b2010-11-09 14:37:23 -0800103 if (len == 0) {
104 return getEmptyString();
105 }
106
Sergio Giroc4966a32016-06-28 18:02:29 +0100107 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
108 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800109 return getEmptyString();
110 }
111
Sergio Giroc4966a32016-06-28 18:02:29 +0100112 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000113 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800114 if (!buf) {
115 return getEmptyString();
116 }
117
Sergio Giroc4966a32016-06-28 18:02:29 +0100118 char* resultStr = (char*) buf->data();
119 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800120
Sergio Giroc4966a32016-06-28 18:02:29 +0100121 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900122}
123
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800124// ---------------------------------------------------------------------------
125
126String8::String8()
127 : mString(getEmptyString())
128{
129}
130
131String8::String8(const String8& o)
132 : mString(o.mString)
133{
134 SharedBuffer::bufferFromData(mString)->acquire();
135}
136
137String8::String8(const char* o)
138 : mString(allocFromUTF8(o, strlen(o)))
139{
Yi Konge1731a42018-07-16 18:11:34 -0700140 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800141 mString = getEmptyString();
142 }
143}
144
145String8::String8(const char* o, size_t len)
146 : mString(allocFromUTF8(o, len))
147{
Yi Konge1731a42018-07-16 18:11:34 -0700148 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800149 mString = getEmptyString();
150 }
151}
152
153String8::String8(const String16& o)
154 : mString(allocFromUTF16(o.string(), o.size()))
155{
156}
157
158String8::String8(const char16_t* o)
159 : mString(allocFromUTF16(o, strlen16(o)))
160{
161}
162
163String8::String8(const char16_t* o, size_t len)
164 : mString(allocFromUTF16(o, len))
165{
166}
167
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900168String8::String8(const char32_t* o)
Elliott Hughes4b7b4d62021-04-15 15:18:54 -0700169 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900170
171String8::String8(const char32_t* o, size_t len)
172 : mString(allocFromUTF32(o, len))
173{
174}
175
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800176String8::~String8()
177{
178 SharedBuffer::bufferFromData(mString)->release();
179}
180
Sergio Girod2529f22015-09-23 16:22:59 +0100181size_t String8::length() const
182{
183 return SharedBuffer::sizeFromData(mString)-1;
184}
185
Jeff Brown1d618d62010-12-02 13:50:46 -0800186String8 String8::format(const char* fmt, ...)
187{
188 va_list args;
189 va_start(args, fmt);
190
191 String8 result(formatV(fmt, args));
192
193 va_end(args);
194 return result;
195}
196
197String8 String8::formatV(const char* fmt, va_list args)
198{
199 String8 result;
200 result.appendFormatV(fmt, args);
201 return result;
202}
203
Jeff Brown48da31b2010-09-12 17:55:08 -0700204void String8::clear() {
205 SharedBuffer::bufferFromData(mString)->release();
206 mString = getEmptyString();
207}
208
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800209void String8::setTo(const String8& other)
210{
211 SharedBuffer::bufferFromData(other.mString)->acquire();
212 SharedBuffer::bufferFromData(mString)->release();
213 mString = other.mString;
214}
215
216status_t String8::setTo(const char* other)
217{
Andreas Huber10e5da52010-06-10 11:14:26 -0700218 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800219 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700220 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700221 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800222
223 mString = getEmptyString();
224 return NO_MEMORY;
225}
226
227status_t String8::setTo(const char* other, size_t len)
228{
Andreas Huber10e5da52010-06-10 11:14:26 -0700229 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800230 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700231 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700232 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800233
234 mString = getEmptyString();
235 return NO_MEMORY;
236}
237
238status_t String8::setTo(const char16_t* other, size_t len)
239{
Andreas Huber10e5da52010-06-10 11:14:26 -0700240 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800241 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700242 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700243 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800244
245 mString = getEmptyString();
246 return NO_MEMORY;
247}
248
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900249status_t String8::setTo(const char32_t* other, size_t len)
250{
Andreas Huber10e5da52010-06-10 11:14:26 -0700251 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900252 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700253 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700254 if (mString) return OK;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900255
256 mString = getEmptyString();
257 return NO_MEMORY;
258}
259
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800260status_t String8::append(const String8& other)
261{
262 const size_t otherLen = other.bytes();
263 if (bytes() == 0) {
264 setTo(other);
Elliott Hughes643268f2018-10-08 11:10:11 -0700265 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800266 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700267 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800268 }
269
270 return real_append(other.string(), otherLen);
271}
272
273status_t String8::append(const char* other)
274{
275 return append(other, strlen(other));
276}
277
278status_t String8::append(const char* other, size_t otherLen)
279{
280 if (bytes() == 0) {
281 return setTo(other, otherLen);
282 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700283 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800284 }
285
286 return real_append(other, otherLen);
287}
288
Jeff Brown35a154e2010-07-15 23:54:05 -0700289status_t String8::appendFormat(const char* fmt, ...)
290{
Jeff Brown647925d2010-11-10 16:03:06 -0800291 va_list args;
292 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700293
Jeff Brown647925d2010-11-10 16:03:06 -0800294 status_t result = appendFormatV(fmt, args);
295
296 va_end(args);
297 return result;
298}
299
300status_t String8::appendFormatV(const char* fmt, va_list args)
301{
Elliott Hughes643268f2018-10-08 11:10:11 -0700302 int n, result = OK;
Fengwei Yinfff9d112014-02-27 01:17:09 +0800303 va_list tmp_args;
304
305 /* args is undefined after vsnprintf.
306 * So we need a copy here to avoid the
307 * second vsnprintf access undefined args.
308 */
309 va_copy(tmp_args, args);
Yi Konge1731a42018-07-16 18:11:34 -0700310 n = vsnprintf(nullptr, 0, fmt, tmp_args);
Fengwei Yinfff9d112014-02-27 01:17:09 +0800311 va_end(tmp_args);
312
Steven Moreland0f0cb952020-07-28 21:41:54 +0000313 if (n < 0) return UNKNOWN_ERROR;
314
315 if (n > 0) {
Jeff Brown35a154e2010-07-15 23:54:05 -0700316 size_t oldLength = length();
Andrei Homescu1a867dc2022-03-29 00:30:34 +0000317 if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
Steven Moreland0f0cb952020-07-28 21:41:54 +0000318 oldLength > std::numeric_limits<size_t>::max() - n - 1) {
319 return NO_MEMORY;
320 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700321 char* buf = lockBuffer(oldLength + n);
322 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800323 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700324 } else {
325 result = NO_MEMORY;
326 }
327 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700328 return result;
329}
330
Elliott Hughes59682762021-06-10 16:42:20 -0700331status_t String8::real_append(const char* other, size_t otherLen) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800332 const size_t myLen = bytes();
Samuel Tan95fd5272016-02-18 16:56:21 -0800333
Elliott Hughes59682762021-06-10 16:42:20 -0700334 SharedBuffer* buf;
335 size_t newLen;
336 if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
337 __builtin_add_overflow(newLen, 1, &newLen) ||
338 (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
339 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800340 }
Elliott Hughes59682762021-06-10 16:42:20 -0700341
342 char* str = (char*)buf->data();
343 mString = str;
344 str += myLen;
345 memcpy(str, other, otherLen);
346 str[otherLen] = '\0';
347 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800348}
349
350char* String8::lockBuffer(size_t size)
351{
352 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
353 ->editResize(size+1);
354 if (buf) {
355 char* str = (char*)buf->data();
356 mString = str;
357 return str;
358 }
Yi Konge1731a42018-07-16 18:11:34 -0700359 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800360}
361
362void String8::unlockBuffer()
363{
364 unlockBuffer(strlen(mString));
365}
366
367status_t String8::unlockBuffer(size_t size)
368{
369 if (size != this->size()) {
370 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
371 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700372 if (! buf) {
373 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800374 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700375
376 char* str = (char*)buf->data();
377 str[size] = 0;
378 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800379 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700380
Elliott Hughes643268f2018-10-08 11:10:11 -0700381 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800382}
383
384ssize_t String8::find(const char* other, size_t start) const
385{
386 size_t len = size();
387 if (start >= len) {
388 return -1;
389 }
390 const char* s = mString+start;
391 const char* p = strstr(s, other);
392 return p ? p-mString : -1;
393}
394
Jeff Brown5ee915a2014-06-06 19:30:15 -0700395bool String8::removeAll(const char* other) {
Eric Miaoc6ce48e2023-07-14 16:35:09 -0700396 ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
397
398 if (*other == '\0')
399 return true;
400
Jeff Brown5ee915a2014-06-06 19:30:15 -0700401 ssize_t index = find(other);
402 if (index < 0) return false;
403
404 char* buf = lockBuffer(size());
405 if (!buf) return false; // out of memory
406
407 size_t skip = strlen(other);
408 size_t len = size();
409 size_t tail = index;
410 while (size_t(index) < len) {
411 ssize_t next = find(other, index + skip);
412 if (next < 0) {
413 next = len;
414 }
415
Andreas Gampedd060f02014-11-13 15:50:17 -0800416 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700417 tail += next - index - skip;
418 index = next;
419 }
420 unlockBuffer(tail);
421 return true;
422}
423
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800424void String8::toLower()
425{
Elliott Hughesa8583952021-04-08 13:26:49 -0700426 const size_t length = size();
427 if (length == 0) return;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800428
Elliott Hughesa8583952021-04-08 13:26:49 -0700429 char* buf = lockBuffer(length);
430 for (size_t i = length; i > 0; --i) {
Steven Morelandfdbc5652020-07-13 23:31:45 +0000431 *buf = static_cast<char>(tolower(*buf));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800432 buf++;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800433 }
Elliott Hughesa8583952021-04-08 13:26:49 -0700434 unlockBuffer(length);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800435}
436
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800437// ---------------------------------------------------------------------------
438// Path functions
439
Greg Kaiserd03851e2021-07-19 20:19:44 +0000440static void setPathName(String8& s, const char* name) {
441 size_t len = strlen(name);
442 char* buf = s.lockBuffer(len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800443
444 memcpy(buf, name, len);
445
446 // remove trailing path separator, if present
Greg Kaiserd03851e2021-07-19 20:19:44 +0000447 if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800448 buf[len] = '\0';
449
Greg Kaiserd03851e2021-07-19 20:19:44 +0000450 s.unlockBuffer(len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800451}
452
453String8 String8::getPathLeaf(void) const
454{
455 const char* cp;
456 const char*const buf = mString;
457
458 cp = strrchr(buf, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700459 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800460 return String8(*this);
461 else
462 return String8(cp+1);
463}
464
465String8 String8::getPathDir(void) const
466{
467 const char* cp;
468 const char*const str = mString;
469
470 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700471 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800472 return String8("");
473 else
474 return String8(str, cp - str);
475}
476
477String8 String8::walkPath(String8* outRemains) const
478{
479 const char* cp;
480 const char*const str = mString;
481 const char* buf = str;
482
483 cp = strchr(buf, OS_PATH_SEPARATOR);
484 if (cp == buf) {
485 // don't include a leading '/'.
486 buf = buf+1;
487 cp = strchr(buf, OS_PATH_SEPARATOR);
488 }
489
Yi Konge1731a42018-07-16 18:11:34 -0700490 if (cp == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800491 String8 res = buf != str ? String8(buf) : *this;
492 if (outRemains) *outRemains = String8("");
493 return res;
494 }
495
496 String8 res(buf, cp-buf);
497 if (outRemains) *outRemains = String8(cp+1);
498 return res;
499}
500
501/*
502 * Helper function for finding the start of an extension in a pathname.
503 *
504 * Returns a pointer inside mString, or NULL if no extension was found.
505 */
506char* String8::find_extension(void) const
507{
508 const char* lastSlash;
509 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800510 const char* const str = mString;
511
512 // only look at the filename
513 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700514 if (lastSlash == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800515 lastSlash = str;
516 else
517 lastSlash++;
518
519 // find the last dot
520 lastDot = strrchr(lastSlash, '.');
Yi Konge1731a42018-07-16 18:11:34 -0700521 if (lastDot == nullptr)
522 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800523
524 // looks good, ship it
525 return const_cast<char*>(lastDot);
526}
527
528String8 String8::getPathExtension(void) const
529{
530 char* ext;
531
532 ext = find_extension();
Yi Konge1731a42018-07-16 18:11:34 -0700533 if (ext != nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800534 return String8(ext);
535 else
536 return String8("");
537}
538
539String8 String8::getBasePath(void) const
540{
541 char* ext;
542 const char* const str = mString;
543
544 ext = find_extension();
Yi Konge1731a42018-07-16 18:11:34 -0700545 if (ext == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800546 return String8(*this);
547 else
548 return String8(str, ext - str);
549}
550
551String8& String8::appendPath(const char* name)
552{
553 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
554 if (name[0] != OS_PATH_SEPARATOR) {
555 if (*name == '\0') {
556 // nothing to do
557 return *this;
558 }
559
560 size_t len = length();
561 if (len == 0) {
562 // no existing filename, just use the new one
Greg Kaiserd03851e2021-07-19 20:19:44 +0000563 setPathName(*this, name);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800564 return *this;
565 }
566
567 // make room for oldPath + '/' + newPath
568 int newlen = strlen(name);
569
570 char* buf = lockBuffer(len+1+newlen);
571
572 // insert a '/' if needed
573 if (buf[len-1] != OS_PATH_SEPARATOR)
574 buf[len++] = OS_PATH_SEPARATOR;
575
576 memcpy(buf+len, name, newlen+1);
577 len += newlen;
578
579 unlockBuffer(len);
580
581 return *this;
582 } else {
Greg Kaiserd03851e2021-07-19 20:19:44 +0000583 setPathName(*this, name);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800584 return *this;
585 }
586}
587
588String8& String8::convertToResPath()
589{
590#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
591 size_t len = length();
592 if (len > 0) {
593 char * buf = lockBuffer(len);
594 for (char * end = buf + len; buf < end; ++buf) {
595 if (*buf == OS_PATH_SEPARATOR)
596 *buf = RES_PATH_SEPARATOR;
597 }
598 unlockBuffer(len);
599 }
600#endif
601 return *this;
602}
603
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800604}; // namespace android