blob: e531a2a0f0ceedb68015752901ee85b554e8e6ec [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
17#include <utils/String8.h>
18
19#include <utils/Log.h>
Kenny Rootba0165b2010-11-09 14:37:23 -080020#include <utils/Unicode.h>
21#include <utils/SharedBuffer.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080022#include <utils/String16.h>
23#include <utils/TextOutput.h>
24#include <utils/threads.h>
25
26#include <private/utils/Static.h>
27
28#include <ctype.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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080043static SharedBuffer* gEmptyStringBuf = NULL;
44static char* gEmptyString = NULL;
45
46extern int gDarwinCantLoadAllObjects;
47int gDarwinIsReallyAnnoying;
48
49static inline char* getEmptyString()
50{
51 gEmptyStringBuf->acquire();
52 return gEmptyString;
53}
54
55void initialize_string8()
56{
Dan Egnor88753ae2010-05-06 00:55:09 -070057 // HACK: This dummy dependency forces linking libutils Static.cpp,
58 // which is needed to initialize String8/String16 classes.
59 // These variables are named for Darwin, but are needed elsewhere too,
60 // including static linking on any platform.
61 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090062
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080063 SharedBuffer* buf = SharedBuffer::alloc(1);
64 char* str = (char*)buf->data();
65 *str = 0;
66 gEmptyStringBuf = buf;
67 gEmptyString = str;
68}
69
70void terminate_string8()
71{
72 SharedBuffer::bufferFromData(gEmptyString)->release();
73 gEmptyStringBuf = NULL;
74 gEmptyString = NULL;
75}
76
77// ---------------------------------------------------------------------------
78
79static char* allocFromUTF8(const char* in, size_t len)
80{
81 if (len > 0) {
82 SharedBuffer* buf = SharedBuffer::alloc(len+1);
83 LOG_ASSERT(buf, "Unable to allocate shared buffer");
84 if (buf) {
85 char* str = (char*)buf->data();
86 memcpy(str, in, len);
87 str[len] = 0;
88 return str;
89 }
90 return NULL;
91 }
92
93 return getEmptyString();
94}
95
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090096static char* allocFromUTF16(const char16_t* in, size_t len)
97{
Kenny Root9a2d83e2009-12-04 09:38:48 -080098 if (len == 0) return getEmptyString();
99
Kenny Rootba0165b2010-11-09 14:37:23 -0800100 const ssize_t bytes = utf16_to_utf8_length(in, len);
101 if (bytes < 0) {
102 return getEmptyString();
103 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800104
105 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
106 LOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800107 if (!buf) {
108 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800109 }
110
Kenny Rootba0165b2010-11-09 14:37:23 -0800111 char* str = (char*)buf->data();
112 utf16_to_utf8(in, len, str);
113 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900114}
115
116static char* allocFromUTF32(const char32_t* in, size_t len)
117{
Kenny Rootba0165b2010-11-09 14:37:23 -0800118 if (len == 0) {
119 return getEmptyString();
120 }
121
122 const ssize_t bytes = utf32_to_utf8_length(in, len);
123 if (bytes < 0) {
124 return getEmptyString();
125 }
126
127 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
128 LOG_ASSERT(buf, "Unable to allocate shared buffer");
129 if (!buf) {
130 return getEmptyString();
131 }
132
133 char* str = (char*) buf->data();
134 utf32_to_utf8(in, len, str);
135
136 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900137}
138
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800139// ---------------------------------------------------------------------------
140
141String8::String8()
142 : mString(getEmptyString())
143{
144}
145
146String8::String8(const String8& o)
147 : mString(o.mString)
148{
149 SharedBuffer::bufferFromData(mString)->acquire();
150}
151
152String8::String8(const char* o)
153 : mString(allocFromUTF8(o, strlen(o)))
154{
155 if (mString == NULL) {
156 mString = getEmptyString();
157 }
158}
159
160String8::String8(const char* o, size_t len)
161 : mString(allocFromUTF8(o, len))
162{
163 if (mString == NULL) {
164 mString = getEmptyString();
165 }
166}
167
168String8::String8(const String16& o)
169 : mString(allocFromUTF16(o.string(), o.size()))
170{
171}
172
173String8::String8(const char16_t* o)
174 : mString(allocFromUTF16(o, strlen16(o)))
175{
176}
177
178String8::String8(const char16_t* o, size_t len)
179 : mString(allocFromUTF16(o, len))
180{
181}
182
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900183String8::String8(const char32_t* o)
184 : mString(allocFromUTF32(o, strlen32(o)))
185{
186}
187
188String8::String8(const char32_t* o, size_t len)
189 : mString(allocFromUTF32(o, len))
190{
191}
192
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800193String8::~String8()
194{
195 SharedBuffer::bufferFromData(mString)->release();
196}
197
Jeff Brown48da31b2010-09-12 17:55:08 -0700198void String8::clear() {
199 SharedBuffer::bufferFromData(mString)->release();
200 mString = getEmptyString();
201}
202
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800203void String8::setTo(const String8& other)
204{
205 SharedBuffer::bufferFromData(other.mString)->acquire();
206 SharedBuffer::bufferFromData(mString)->release();
207 mString = other.mString;
208}
209
210status_t String8::setTo(const char* other)
211{
Andreas Huber10e5da52010-06-10 11:14:26 -0700212 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800213 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700214 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800215 if (mString) return NO_ERROR;
216
217 mString = getEmptyString();
218 return NO_MEMORY;
219}
220
221status_t String8::setTo(const char* other, size_t len)
222{
Andreas Huber10e5da52010-06-10 11:14:26 -0700223 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800224 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700225 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800226 if (mString) return NO_ERROR;
227
228 mString = getEmptyString();
229 return NO_MEMORY;
230}
231
232status_t String8::setTo(const char16_t* other, size_t len)
233{
Andreas Huber10e5da52010-06-10 11:14:26 -0700234 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800235 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700236 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800237 if (mString) return NO_ERROR;
238
239 mString = getEmptyString();
240 return NO_MEMORY;
241}
242
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900243status_t String8::setTo(const char32_t* other, size_t len)
244{
Andreas Huber10e5da52010-06-10 11:14:26 -0700245 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900246 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700247 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900248 if (mString) return NO_ERROR;
249
250 mString = getEmptyString();
251 return NO_MEMORY;
252}
253
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800254status_t String8::append(const String8& other)
255{
256 const size_t otherLen = other.bytes();
257 if (bytes() == 0) {
258 setTo(other);
259 return NO_ERROR;
260 } else if (otherLen == 0) {
261 return NO_ERROR;
262 }
263
264 return real_append(other.string(), otherLen);
265}
266
267status_t String8::append(const char* other)
268{
269 return append(other, strlen(other));
270}
271
272status_t String8::append(const char* other, size_t otherLen)
273{
274 if (bytes() == 0) {
275 return setTo(other, otherLen);
276 } else if (otherLen == 0) {
277 return NO_ERROR;
278 }
279
280 return real_append(other, otherLen);
281}
282
Jeff Brown35a154e2010-07-15 23:54:05 -0700283status_t String8::appendFormat(const char* fmt, ...)
284{
Jeff Brown647925d2010-11-10 16:03:06 -0800285 va_list args;
286 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700287
Jeff Brown647925d2010-11-10 16:03:06 -0800288 status_t result = appendFormatV(fmt, args);
289
290 va_end(args);
291 return result;
292}
293
294status_t String8::appendFormatV(const char* fmt, va_list args)
295{
Jeff Brown35a154e2010-07-15 23:54:05 -0700296 int result = NO_ERROR;
Jeff Brown647925d2010-11-10 16:03:06 -0800297 int n = vsnprintf(NULL, 0, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700298 if (n != 0) {
299 size_t oldLength = length();
300 char* buf = lockBuffer(oldLength + n);
301 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800302 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700303 } else {
304 result = NO_MEMORY;
305 }
306 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700307 return result;
308}
309
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800310status_t String8::real_append(const char* other, size_t otherLen)
311{
312 const size_t myLen = bytes();
313
314 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
315 ->editResize(myLen+otherLen+1);
316 if (buf) {
317 char* str = (char*)buf->data();
318 mString = str;
319 str += myLen;
320 memcpy(str, other, otherLen);
321 str[otherLen] = '\0';
322 return NO_ERROR;
323 }
324 return NO_MEMORY;
325}
326
327char* String8::lockBuffer(size_t size)
328{
329 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
330 ->editResize(size+1);
331 if (buf) {
332 char* str = (char*)buf->data();
333 mString = str;
334 return str;
335 }
336 return NULL;
337}
338
339void String8::unlockBuffer()
340{
341 unlockBuffer(strlen(mString));
342}
343
344status_t String8::unlockBuffer(size_t size)
345{
346 if (size != this->size()) {
347 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
348 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700349 if (! buf) {
350 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800351 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700352
353 char* str = (char*)buf->data();
354 str[size] = 0;
355 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800356 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700357
358 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800359}
360
361ssize_t String8::find(const char* other, size_t start) const
362{
363 size_t len = size();
364 if (start >= len) {
365 return -1;
366 }
367 const char* s = mString+start;
368 const char* p = strstr(s, other);
369 return p ? p-mString : -1;
370}
371
372void String8::toLower()
373{
374 toLower(0, size());
375}
376
377void String8::toLower(size_t start, size_t length)
378{
379 const size_t len = size();
380 if (start >= len) {
381 return;
382 }
383 if (start+length > len) {
384 length = len-start;
385 }
386 char* buf = lockBuffer(len);
387 buf += start;
388 while (length > 0) {
389 *buf = tolower(*buf);
390 buf++;
391 length--;
392 }
393 unlockBuffer(len);
394}
395
396void String8::toUpper()
397{
398 toUpper(0, size());
399}
400
401void String8::toUpper(size_t start, size_t length)
402{
403 const size_t len = size();
404 if (start >= len) {
405 return;
406 }
407 if (start+length > len) {
408 length = len-start;
409 }
410 char* buf = lockBuffer(len);
411 buf += start;
412 while (length > 0) {
413 *buf = toupper(*buf);
414 buf++;
415 length--;
416 }
417 unlockBuffer(len);
418}
419
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900420size_t String8::getUtf32Length() const
421{
Kenny Rootba0165b2010-11-09 14:37:23 -0800422 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900423}
424
425int32_t String8::getUtf32At(size_t index, size_t *next_index) const
426{
Kenny Rootba0165b2010-11-09 14:37:23 -0800427 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900428}
429
Kenny Rootba0165b2010-11-09 14:37:23 -0800430void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900431{
Kenny Rootba0165b2010-11-09 14:37:23 -0800432 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900433}
434
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800435TextOutput& operator<<(TextOutput& to, const String8& val)
436{
437 to << val.string();
438 return to;
439}
440
441// ---------------------------------------------------------------------------
442// Path functions
443
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800444void String8::setPathName(const char* name)
445{
446 setPathName(name, strlen(name));
447}
448
449void String8::setPathName(const char* name, size_t len)
450{
451 char* buf = lockBuffer(len);
452
453 memcpy(buf, name, len);
454
455 // remove trailing path separator, if present
456 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
457 len--;
458
459 buf[len] = '\0';
460
461 unlockBuffer(len);
462}
463
464String8 String8::getPathLeaf(void) const
465{
466 const char* cp;
467 const char*const buf = mString;
468
469 cp = strrchr(buf, OS_PATH_SEPARATOR);
470 if (cp == NULL)
471 return String8(*this);
472 else
473 return String8(cp+1);
474}
475
476String8 String8::getPathDir(void) const
477{
478 const char* cp;
479 const char*const str = mString;
480
481 cp = strrchr(str, OS_PATH_SEPARATOR);
482 if (cp == NULL)
483 return String8("");
484 else
485 return String8(str, cp - str);
486}
487
488String8 String8::walkPath(String8* outRemains) const
489{
490 const char* cp;
491 const char*const str = mString;
492 const char* buf = str;
493
494 cp = strchr(buf, OS_PATH_SEPARATOR);
495 if (cp == buf) {
496 // don't include a leading '/'.
497 buf = buf+1;
498 cp = strchr(buf, OS_PATH_SEPARATOR);
499 }
500
501 if (cp == NULL) {
502 String8 res = buf != str ? String8(buf) : *this;
503 if (outRemains) *outRemains = String8("");
504 return res;
505 }
506
507 String8 res(buf, cp-buf);
508 if (outRemains) *outRemains = String8(cp+1);
509 return res;
510}
511
512/*
513 * Helper function for finding the start of an extension in a pathname.
514 *
515 * Returns a pointer inside mString, or NULL if no extension was found.
516 */
517char* String8::find_extension(void) const
518{
519 const char* lastSlash;
520 const char* lastDot;
521 int extLen;
522 const char* const str = mString;
523
524 // only look at the filename
525 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
526 if (lastSlash == NULL)
527 lastSlash = str;
528 else
529 lastSlash++;
530
531 // find the last dot
532 lastDot = strrchr(lastSlash, '.');
533 if (lastDot == NULL)
534 return NULL;
535
536 // looks good, ship it
537 return const_cast<char*>(lastDot);
538}
539
540String8 String8::getPathExtension(void) const
541{
542 char* ext;
543
544 ext = find_extension();
545 if (ext != NULL)
546 return String8(ext);
547 else
548 return String8("");
549}
550
551String8 String8::getBasePath(void) const
552{
553 char* ext;
554 const char* const str = mString;
555
556 ext = find_extension();
557 if (ext == NULL)
558 return String8(*this);
559 else
560 return String8(str, ext - str);
561}
562
563String8& String8::appendPath(const char* name)
564{
565 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
566 if (name[0] != OS_PATH_SEPARATOR) {
567 if (*name == '\0') {
568 // nothing to do
569 return *this;
570 }
571
572 size_t len = length();
573 if (len == 0) {
574 // no existing filename, just use the new one
575 setPathName(name);
576 return *this;
577 }
578
579 // make room for oldPath + '/' + newPath
580 int newlen = strlen(name);
581
582 char* buf = lockBuffer(len+1+newlen);
583
584 // insert a '/' if needed
585 if (buf[len-1] != OS_PATH_SEPARATOR)
586 buf[len++] = OS_PATH_SEPARATOR;
587
588 memcpy(buf+len, name, newlen+1);
589 len += newlen;
590
591 unlockBuffer(len);
592
593 return *this;
594 } else {
595 setPathName(name);
596 return *this;
597 }
598}
599
600String8& String8::convertToResPath()
601{
602#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
603 size_t len = length();
604 if (len > 0) {
605 char * buf = lockBuffer(len);
606 for (char * end = buf + len; buf < end; ++buf) {
607 if (*buf == OS_PATH_SEPARATOR)
608 *buf = RES_PATH_SEPARATOR;
609 }
610 unlockBuffer(len);
611 }
612#endif
613 return *this;
614}
615
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800616}; // namespace android