blob: d13548e4c5d927f9e2393e46488523d7c700ee19 [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
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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080039// Separator used by resource paths. This is not platform dependent contrary
40// to OS_PATH_SEPARATOR.
41#define RES_PATH_SEPARATOR '/'
42
Steven Moreland241b93c2018-03-06 09:11:29 -080043static inline char* getEmptyString() {
44 static SharedBuffer* gEmptyStringBuf = [] {
45 SharedBuffer* buf = SharedBuffer::alloc(1);
46 char* str = static_cast<char*>(buf->data());
47 *str = 0;
48 return buf;
49 }();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080050
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080051 gEmptyStringBuf->acquire();
Steven Moreland241b93c2018-03-06 09:11:29 -080052 return static_cast<char*>(gEmptyStringBuf->data());
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080053}
54
55// ---------------------------------------------------------------------------
56
57static char* allocFromUTF8(const char* in, size_t len)
58{
59 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010060 if (len == SIZE_MAX) {
Yi Konge1731a42018-07-16 18:11:34 -070061 return nullptr;
Sergio Giroebabef22015-08-18 14:44:54 +010062 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080063 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000064 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080065 if (buf) {
66 char* str = (char*)buf->data();
67 memcpy(str, in, len);
68 str[len] = 0;
69 return str;
70 }
Yi Konge1731a42018-07-16 18:11:34 -070071 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080072 }
73
74 return getEmptyString();
75}
76
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090077static char* allocFromUTF16(const char16_t* in, size_t len)
78{
Kenny Root9a2d83e2009-12-04 09:38:48 -080079 if (len == 0) return getEmptyString();
80
Sergio Giroc4966a32016-06-28 18:02:29 +010081 // Allow for closing '\0'
82 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
83 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -080084 return getEmptyString();
85 }
Kenny Root9a2d83e2009-12-04 09:38:48 -080086
Sergio Giroc4966a32016-06-28 18:02:29 +010087 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +000088 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -080089 if (!buf) {
90 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -080091 }
92
Sergio Giroc4966a32016-06-28 18:02:29 +010093 char* resultStr = (char*)buf->data();
94 utf16_to_utf8(in, len, resultStr, resultStrLen);
95 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090096}
97
98static char* allocFromUTF32(const char32_t* in, size_t len)
99{
Kenny Rootba0165b2010-11-09 14:37:23 -0800100 if (len == 0) {
101 return getEmptyString();
102 }
103
Sergio Giroc4966a32016-06-28 18:02:29 +0100104 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
105 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800106 return getEmptyString();
107 }
108
Sergio Giroc4966a32016-06-28 18:02:29 +0100109 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000110 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800111 if (!buf) {
112 return getEmptyString();
113 }
114
Sergio Giroc4966a32016-06-28 18:02:29 +0100115 char* resultStr = (char*) buf->data();
116 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800117
Sergio Giroc4966a32016-06-28 18:02:29 +0100118 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900119}
120
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800121// ---------------------------------------------------------------------------
122
123String8::String8()
124 : mString(getEmptyString())
125{
126}
127
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700128String8::String8(StaticLinkage)
Yi Konge1731a42018-07-16 18:11:34 -0700129 : mString(nullptr)
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700130{
131 // this constructor is used when we can't rely on the static-initializers
132 // having run. In this case we always allocate an empty string. It's less
133 // efficient than using getEmptyString(), but we assume it's uncommon.
134
135 char* data = static_cast<char*>(
136 SharedBuffer::alloc(sizeof(char))->data());
137 data[0] = 0;
138 mString = data;
139}
140
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800141String8::String8(const String8& o)
142 : mString(o.mString)
143{
144 SharedBuffer::bufferFromData(mString)->acquire();
145}
146
147String8::String8(const char* o)
148 : mString(allocFromUTF8(o, strlen(o)))
149{
Yi Konge1731a42018-07-16 18:11:34 -0700150 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800151 mString = getEmptyString();
152 }
153}
154
155String8::String8(const char* o, size_t len)
156 : mString(allocFromUTF8(o, len))
157{
Yi Konge1731a42018-07-16 18:11:34 -0700158 if (mString == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800159 mString = getEmptyString();
160 }
161}
162
163String8::String8(const String16& o)
164 : mString(allocFromUTF16(o.string(), o.size()))
165{
166}
167
168String8::String8(const char16_t* o)
169 : mString(allocFromUTF16(o, strlen16(o)))
170{
171}
172
173String8::String8(const char16_t* o, size_t len)
174 : mString(allocFromUTF16(o, len))
175{
176}
177
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900178String8::String8(const char32_t* o)
179 : mString(allocFromUTF32(o, strlen32(o)))
180{
181}
182
183String8::String8(const char32_t* o, size_t len)
184 : mString(allocFromUTF32(o, len))
185{
186}
187
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800188String8::~String8()
189{
190 SharedBuffer::bufferFromData(mString)->release();
191}
192
Sergio Girod2529f22015-09-23 16:22:59 +0100193size_t String8::length() const
194{
195 return SharedBuffer::sizeFromData(mString)-1;
196}
197
Jeff Brown1d618d62010-12-02 13:50:46 -0800198String8 String8::format(const char* fmt, ...)
199{
200 va_list args;
201 va_start(args, fmt);
202
203 String8 result(formatV(fmt, args));
204
205 va_end(args);
206 return result;
207}
208
209String8 String8::formatV(const char* fmt, va_list args)
210{
211 String8 result;
212 result.appendFormatV(fmt, args);
213 return result;
214}
215
Jeff Brown48da31b2010-09-12 17:55:08 -0700216void String8::clear() {
217 SharedBuffer::bufferFromData(mString)->release();
218 mString = getEmptyString();
219}
220
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800221void String8::setTo(const String8& other)
222{
223 SharedBuffer::bufferFromData(other.mString)->acquire();
224 SharedBuffer::bufferFromData(mString)->release();
225 mString = other.mString;
226}
227
228status_t String8::setTo(const char* other)
229{
Andreas Huber10e5da52010-06-10 11:14:26 -0700230 const char *newString = allocFromUTF8(other, strlen(other));
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
239status_t String8::setTo(const char* other, size_t len)
240{
Andreas Huber10e5da52010-06-10 11:14:26 -0700241 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800242 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;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800245
246 mString = getEmptyString();
247 return NO_MEMORY;
248}
249
250status_t String8::setTo(const char16_t* other, size_t len)
251{
Andreas Huber10e5da52010-06-10 11:14:26 -0700252 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800253 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700254 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700255 if (mString) return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800256
257 mString = getEmptyString();
258 return NO_MEMORY;
259}
260
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900261status_t String8::setTo(const char32_t* other, size_t len)
262{
Andreas Huber10e5da52010-06-10 11:14:26 -0700263 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900264 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700265 mString = newString;
Elliott Hughes643268f2018-10-08 11:10:11 -0700266 if (mString) return OK;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900267
268 mString = getEmptyString();
269 return NO_MEMORY;
270}
271
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800272status_t String8::append(const String8& other)
273{
274 const size_t otherLen = other.bytes();
275 if (bytes() == 0) {
276 setTo(other);
Elliott Hughes643268f2018-10-08 11:10:11 -0700277 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800278 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700279 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800280 }
281
282 return real_append(other.string(), otherLen);
283}
284
285status_t String8::append(const char* other)
286{
287 return append(other, strlen(other));
288}
289
290status_t String8::append(const char* other, size_t otherLen)
291{
292 if (bytes() == 0) {
293 return setTo(other, otherLen);
294 } else if (otherLen == 0) {
Elliott Hughes643268f2018-10-08 11:10:11 -0700295 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800296 }
297
298 return real_append(other, otherLen);
299}
300
Jeff Brown35a154e2010-07-15 23:54:05 -0700301status_t String8::appendFormat(const char* fmt, ...)
302{
Jeff Brown647925d2010-11-10 16:03:06 -0800303 va_list args;
304 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700305
Jeff Brown647925d2010-11-10 16:03:06 -0800306 status_t result = appendFormatV(fmt, args);
307
308 va_end(args);
309 return result;
310}
311
312status_t String8::appendFormatV(const char* fmt, va_list args)
313{
Elliott Hughes643268f2018-10-08 11:10:11 -0700314 int n, result = OK;
Fengwei Yinfff9d112014-02-27 01:17:09 +0800315 va_list tmp_args;
316
317 /* args is undefined after vsnprintf.
318 * So we need a copy here to avoid the
319 * second vsnprintf access undefined args.
320 */
321 va_copy(tmp_args, args);
Yi Konge1731a42018-07-16 18:11:34 -0700322 n = vsnprintf(nullptr, 0, fmt, tmp_args);
Fengwei Yinfff9d112014-02-27 01:17:09 +0800323 va_end(tmp_args);
324
Jeff Brown35a154e2010-07-15 23:54:05 -0700325 if (n != 0) {
326 size_t oldLength = length();
327 char* buf = lockBuffer(oldLength + n);
328 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800329 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700330 } else {
331 result = NO_MEMORY;
332 }
333 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700334 return result;
335}
336
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800337status_t String8::real_append(const char* other, size_t otherLen)
338{
339 const size_t myLen = bytes();
Samuel Tan95fd5272016-02-18 16:56:21 -0800340
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800341 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
342 ->editResize(myLen+otherLen+1);
343 if (buf) {
344 char* str = (char*)buf->data();
345 mString = str;
346 str += myLen;
347 memcpy(str, other, otherLen);
348 str[otherLen] = '\0';
Elliott Hughes643268f2018-10-08 11:10:11 -0700349 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800350 }
351 return NO_MEMORY;
352}
353
354char* String8::lockBuffer(size_t size)
355{
356 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
357 ->editResize(size+1);
358 if (buf) {
359 char* str = (char*)buf->data();
360 mString = str;
361 return str;
362 }
Yi Konge1731a42018-07-16 18:11:34 -0700363 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800364}
365
366void String8::unlockBuffer()
367{
368 unlockBuffer(strlen(mString));
369}
370
371status_t String8::unlockBuffer(size_t size)
372{
373 if (size != this->size()) {
374 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
375 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700376 if (! buf) {
377 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800378 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700379
380 char* str = (char*)buf->data();
381 str[size] = 0;
382 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800383 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700384
Elliott Hughes643268f2018-10-08 11:10:11 -0700385 return OK;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800386}
387
388ssize_t String8::find(const char* other, size_t start) const
389{
390 size_t len = size();
391 if (start >= len) {
392 return -1;
393 }
394 const char* s = mString+start;
395 const char* p = strstr(s, other);
396 return p ? p-mString : -1;
397}
398
Jeff Brown5ee915a2014-06-06 19:30:15 -0700399bool String8::removeAll(const char* other) {
400 ssize_t index = find(other);
401 if (index < 0) return false;
402
403 char* buf = lockBuffer(size());
404 if (!buf) return false; // out of memory
405
406 size_t skip = strlen(other);
407 size_t len = size();
408 size_t tail = index;
409 while (size_t(index) < len) {
410 ssize_t next = find(other, index + skip);
411 if (next < 0) {
412 next = len;
413 }
414
Andreas Gampedd060f02014-11-13 15:50:17 -0800415 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700416 tail += next - index - skip;
417 index = next;
418 }
419 unlockBuffer(tail);
420 return true;
421}
422
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800423void String8::toLower()
424{
425 toLower(0, size());
426}
427
428void String8::toLower(size_t start, size_t length)
429{
430 const size_t len = size();
431 if (start >= len) {
432 return;
433 }
434 if (start+length > len) {
435 length = len-start;
436 }
437 char* buf = lockBuffer(len);
438 buf += start;
439 while (length > 0) {
440 *buf = tolower(*buf);
441 buf++;
442 length--;
443 }
444 unlockBuffer(len);
445}
446
447void String8::toUpper()
448{
449 toUpper(0, size());
450}
451
452void String8::toUpper(size_t start, size_t length)
453{
454 const size_t len = size();
455 if (start >= len) {
456 return;
457 }
458 if (start+length > len) {
459 length = len-start;
460 }
461 char* buf = lockBuffer(len);
462 buf += start;
463 while (length > 0) {
464 *buf = toupper(*buf);
465 buf++;
466 length--;
467 }
468 unlockBuffer(len);
469}
470
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800471// ---------------------------------------------------------------------------
472// Path functions
473
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800474void String8::setPathName(const char* name)
475{
476 setPathName(name, strlen(name));
477}
478
479void String8::setPathName(const char* name, size_t len)
480{
481 char* buf = lockBuffer(len);
482
483 memcpy(buf, name, len);
484
485 // remove trailing path separator, if present
486 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
487 len--;
488
489 buf[len] = '\0';
490
491 unlockBuffer(len);
492}
493
494String8 String8::getPathLeaf(void) const
495{
496 const char* cp;
497 const char*const buf = mString;
498
499 cp = strrchr(buf, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700500 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800501 return String8(*this);
502 else
503 return String8(cp+1);
504}
505
506String8 String8::getPathDir(void) const
507{
508 const char* cp;
509 const char*const str = mString;
510
511 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700512 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800513 return String8("");
514 else
515 return String8(str, cp - str);
516}
517
518String8 String8::walkPath(String8* outRemains) const
519{
520 const char* cp;
521 const char*const str = mString;
522 const char* buf = str;
523
524 cp = strchr(buf, OS_PATH_SEPARATOR);
525 if (cp == buf) {
526 // don't include a leading '/'.
527 buf = buf+1;
528 cp = strchr(buf, OS_PATH_SEPARATOR);
529 }
530
Yi Konge1731a42018-07-16 18:11:34 -0700531 if (cp == nullptr) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800532 String8 res = buf != str ? String8(buf) : *this;
533 if (outRemains) *outRemains = String8("");
534 return res;
535 }
536
537 String8 res(buf, cp-buf);
538 if (outRemains) *outRemains = String8(cp+1);
539 return res;
540}
541
542/*
543 * Helper function for finding the start of an extension in a pathname.
544 *
545 * Returns a pointer inside mString, or NULL if no extension was found.
546 */
547char* String8::find_extension(void) const
548{
549 const char* lastSlash;
550 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800551 const char* const str = mString;
552
553 // only look at the filename
554 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700555 if (lastSlash == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800556 lastSlash = str;
557 else
558 lastSlash++;
559
560 // find the last dot
561 lastDot = strrchr(lastSlash, '.');
Yi Konge1731a42018-07-16 18:11:34 -0700562 if (lastDot == nullptr)
563 return nullptr;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800564
565 // looks good, ship it
566 return const_cast<char*>(lastDot);
567}
568
569String8 String8::getPathExtension(void) const
570{
571 char* ext;
572
573 ext = find_extension();
Yi Konge1731a42018-07-16 18:11:34 -0700574 if (ext != nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800575 return String8(ext);
576 else
577 return String8("");
578}
579
580String8 String8::getBasePath(void) const
581{
582 char* ext;
583 const char* const str = mString;
584
585 ext = find_extension();
Yi Konge1731a42018-07-16 18:11:34 -0700586 if (ext == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800587 return String8(*this);
588 else
589 return String8(str, ext - str);
590}
591
592String8& String8::appendPath(const char* name)
593{
594 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
595 if (name[0] != OS_PATH_SEPARATOR) {
596 if (*name == '\0') {
597 // nothing to do
598 return *this;
599 }
600
601 size_t len = length();
602 if (len == 0) {
603 // no existing filename, just use the new one
604 setPathName(name);
605 return *this;
606 }
607
608 // make room for oldPath + '/' + newPath
609 int newlen = strlen(name);
610
611 char* buf = lockBuffer(len+1+newlen);
612
613 // insert a '/' if needed
614 if (buf[len-1] != OS_PATH_SEPARATOR)
615 buf[len++] = OS_PATH_SEPARATOR;
616
617 memcpy(buf+len, name, newlen+1);
618 len += newlen;
619
620 unlockBuffer(len);
621
622 return *this;
623 } else {
624 setPathName(name);
625 return *this;
626 }
627}
628
629String8& String8::convertToResPath()
630{
631#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
632 size_t len = length();
633 if (len > 0) {
634 char * buf = lockBuffer(len);
635 for (char * end = buf + len; buf < end; ++buf) {
636 if (*buf == OS_PATH_SEPARATOR)
637 *buf = RES_PATH_SEPARATOR;
638 }
639 unlockBuffer(len);
640 }
641#endif
642 return *this;
643}
644
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800645}; // namespace android