blob: 82f5cb682b475fa089dfd54070cbd7c94b3829fd [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) {
396 ssize_t index = find(other);
397 if (index < 0) return false;
398
399 char* buf = lockBuffer(size());
400 if (!buf) return false; // out of memory
401
402 size_t skip = strlen(other);
403 size_t len = size();
404 size_t tail = index;
405 while (size_t(index) < len) {
406 ssize_t next = find(other, index + skip);
407 if (next < 0) {
408 next = len;
409 }
410
Andreas Gampedd060f02014-11-13 15:50:17 -0800411 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700412 tail += next - index - skip;
413 index = next;
414 }
415 unlockBuffer(tail);
416 return true;
417}
418
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800419void String8::toLower()
420{
Elliott Hughesa8583952021-04-08 13:26:49 -0700421 const size_t length = size();
422 if (length == 0) return;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800423
Elliott Hughesa8583952021-04-08 13:26:49 -0700424 char* buf = lockBuffer(length);
425 for (size_t i = length; i > 0; --i) {
Steven Morelandfdbc5652020-07-13 23:31:45 +0000426 *buf = static_cast<char>(tolower(*buf));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800427 buf++;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800428 }
Elliott Hughesa8583952021-04-08 13:26:49 -0700429 unlockBuffer(length);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800430}
431
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800432// ---------------------------------------------------------------------------
433// Path functions
434
Greg Kaiserd03851e2021-07-19 20:19:44 +0000435static void setPathName(String8& s, const char* name) {
436 size_t len = strlen(name);
437 char* buf = s.lockBuffer(len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800438
439 memcpy(buf, name, len);
440
441 // remove trailing path separator, if present
Greg Kaiserd03851e2021-07-19 20:19:44 +0000442 if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800443 buf[len] = '\0';
444
Greg Kaiserd03851e2021-07-19 20:19:44 +0000445 s.unlockBuffer(len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800446}
447
448String8 String8::getPathLeaf(void) const
449{
450 const char* cp;
451 const char*const buf = mString;
452
453 cp = strrchr(buf, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700454 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800455 return String8(*this);
456 else
457 return String8(cp+1);
458}
459
460String8 String8::getPathDir(void) const
461{
462 const char* cp;
463 const char*const str = mString;
464
465 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700466 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800467 return String8("");
468 else
469 return String8(str, cp - str);
470}
471
472String8 String8::walkPath(String8* outRemains) const
473{
474 const char* cp;
475 const char*const str = mString;
476 const char* buf = str;
477
478 cp = strchr(buf, OS_PATH_SEPARATOR);
479 if (cp == buf) {
480 // don't include a leading '/'.
481 buf = buf+1;
482 cp = strchr(buf, OS_PATH_SEPARATOR);
483 }
484
Yi Konge1731a42018-07-16 18:11:34 -0700485 if (cp == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800486 String8 res = buf != str ? String8(buf) : *this;
487 if (outRemains) *outRemains = String8("");
488 return res;
489 }
490
491 String8 res(buf, cp-buf);
492 if (outRemains) *outRemains = String8(cp+1);
493 return res;
494}
495
496/*
497 * Helper function for finding the start of an extension in a pathname.
498 *
499 * Returns a pointer inside mString, or NULL if no extension was found.
500 */
501char* String8::find_extension(void) const
502{
503 const char* lastSlash;
504 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800505 const char* const str = mString;
506
507 // only look at the filename
508 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700509 if (lastSlash == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800510 lastSlash = str;
511 else
512 lastSlash++;
513
514 // find the last dot
515 lastDot = strrchr(lastSlash, '.');
Yi Konge1731a42018-07-16 18:11:34 -0700516 if (lastDot == nullptr)
517 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800518
519 // looks good, ship it
520 return const_cast<char*>(lastDot);
521}
522
523String8 String8::getPathExtension(void) const
524{
525 char* ext;
526
527 ext = find_extension();
Yi Konge1731a42018-07-16 18:11:34 -0700528 if (ext != nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800529 return String8(ext);
530 else
531 return String8("");
532}
533
534String8 String8::getBasePath(void) const
535{
536 char* ext;
537 const char* const str = mString;
538
539 ext = find_extension();
Yi Konge1731a42018-07-16 18:11:34 -0700540 if (ext == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800541 return String8(*this);
542 else
543 return String8(str, ext - str);
544}
545
546String8& String8::appendPath(const char* name)
547{
548 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
549 if (name[0] != OS_PATH_SEPARATOR) {
550 if (*name == '\0') {
551 // nothing to do
552 return *this;
553 }
554
555 size_t len = length();
556 if (len == 0) {
557 // no existing filename, just use the new one
Greg Kaiserd03851e2021-07-19 20:19:44 +0000558 setPathName(*this, name);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800559 return *this;
560 }
561
562 // make room for oldPath + '/' + newPath
563 int newlen = strlen(name);
564
565 char* buf = lockBuffer(len+1+newlen);
566
567 // insert a '/' if needed
568 if (buf[len-1] != OS_PATH_SEPARATOR)
569 buf[len++] = OS_PATH_SEPARATOR;
570
571 memcpy(buf+len, name, newlen+1);
572 len += newlen;
573
574 unlockBuffer(len);
575
576 return *this;
577 } else {
Greg Kaiserd03851e2021-07-19 20:19:44 +0000578 setPathName(*this, name);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800579 return *this;
580 }
581}
582
583String8& String8::convertToResPath()
584{
585#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
586 size_t len = length();
587 if (len > 0) {
588 char * buf = lockBuffer(len);
589 for (char * end = buf + len; buf < end; ++buf) {
590 if (*buf == OS_PATH_SEPARATOR)
591 *buf = RES_PATH_SEPARATOR;
592 }
593 unlockBuffer(len);
594 }
595#endif
596 return *this;
597}
598
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800599}; // namespace android