blob: 2b72847e52bd77a28c2e0f16deba4c21dae7a708 [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
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000433static void setPathName(String8& s, const char* name) {
434 size_t len = strlen(name);
435 char* buf = s.lockBuffer(len);
436
437 memcpy(buf, name, len);
438
439 // remove trailing path separator, if present
440 if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
441 buf[len] = '\0';
442
443 s.unlockBuffer(len);
444}
445
446String8 String8::getPathLeaf(void) const
447{
448 const char* cp;
449 const char*const buf = mString;
450
451 cp = strrchr(buf, OS_PATH_SEPARATOR);
452 if (cp == nullptr)
453 return String8(*this);
454 else
455 return String8(cp+1);
456}
457
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800458String8 String8::getPathDir(void) const
459{
460 const char* cp;
461 const char*const str = mString;
462
463 cp = strrchr(str, OS_PATH_SEPARATOR);
Yi Konge1731a42018-07-16 18:11:34 -0700464 if (cp == nullptr)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800465 return String8("");
466 else
467 return String8(str, cp - str);
468}
469
Tomasz Wasilczykcff2e402023-09-08 17:08:39 +0000470String8 String8::walkPath(String8* outRemains) const
471{
472 const char* cp;
473 const char*const str = mString;
474 const char* buf = str;
475
476 cp = strchr(buf, OS_PATH_SEPARATOR);
477 if (cp == buf) {
478 // don't include a leading '/'.
479 buf = buf+1;
480 cp = strchr(buf, OS_PATH_SEPARATOR);
481 }
482
483 if (cp == nullptr) {
484 String8 res = buf != str ? String8(buf) : *this;
485 if (outRemains) *outRemains = String8("");
486 return res;
487 }
488
489 String8 res(buf, cp-buf);
490 if (outRemains) *outRemains = String8(cp+1);
491 return res;
492}
493
494/*
495 * Helper function for finding the start of an extension in a pathname.
496 *
497 * Returns a pointer inside mString, or NULL if no extension was found.
498 */
499char* String8::find_extension(void) const
500{
501 const char* lastSlash;
502 const char* lastDot;
503 const char* const str = mString;
504
505 // only look at the filename
506 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
507 if (lastSlash == nullptr)
508 lastSlash = str;
509 else
510 lastSlash++;
511
512 // find the last dot
513 lastDot = strrchr(lastSlash, '.');
514 if (lastDot == nullptr)
515 return nullptr;
516
517 // looks good, ship it
518 return const_cast<char*>(lastDot);
519}
520
521String8 String8::getPathExtension(void) const
522{
523 char* ext;
524
525 ext = find_extension();
526 if (ext != nullptr)
527 return String8(ext);
528 else
529 return String8("");
530}
531
532String8 String8::getBasePath(void) const
533{
534 char* ext;
535 const char* const str = mString;
536
537 ext = find_extension();
538 if (ext == nullptr)
539 return String8(*this);
540 else
541 return String8(str, ext - str);
542}
543
544String8& String8::appendPath(const char* name)
545{
546 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
547 if (name[0] != OS_PATH_SEPARATOR) {
548 if (*name == '\0') {
549 // nothing to do
550 return *this;
551 }
552
553 size_t len = length();
554 if (len == 0) {
555 // no existing filename, just use the new one
556 setPathName(*this, name);
557 return *this;
558 }
559
560 // make room for oldPath + '/' + newPath
561 int newlen = strlen(name);
562
563 char* buf = lockBuffer(len+1+newlen);
564
565 // insert a '/' if needed
566 if (buf[len-1] != OS_PATH_SEPARATOR)
567 buf[len++] = OS_PATH_SEPARATOR;
568
569 memcpy(buf+len, name, newlen+1);
570 len += newlen;
571
572 unlockBuffer(len);
573
574 return *this;
575 } else {
576 setPathName(*this, name);
577 return *this;
578 }
579}
580
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800581}; // namespace android