blob: 28be60fb5c58d0ce3a00f9fef6159ce62125dbfc [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
Elliott Hughes1f8bc862015-07-29 14:02:29 -070019#include <utils/Compat.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080020#include <utils/Log.h>
Kenny Rootba0165b2010-11-09 14:37:23 -080021#include <utils/Unicode.h>
22#include <utils/SharedBuffer.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080023#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080024#include <utils/threads.h>
25
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080026#include <ctype.h>
27
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090028/*
29 * Functions outside android is below the namespace android, since they use
30 * functions and constants in android namespace.
31 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080032
33// ---------------------------------------------------------------------------
34
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090035namespace android {
36
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080037// Separator used by resource paths. This is not platform dependent contrary
38// to OS_PATH_SEPARATOR.
39#define RES_PATH_SEPARATOR '/'
40
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080041static SharedBuffer* gEmptyStringBuf = NULL;
42static char* gEmptyString = NULL;
43
44extern int gDarwinCantLoadAllObjects;
45int gDarwinIsReallyAnnoying;
46
Mathias Agopian9eb2a3b2013-05-06 20:20:50 -070047void initialize_string8();
48
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080049static 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);
Steve Blockae074452012-01-09 18:35:44 +000083 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080084 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);
Steve Blockae074452012-01-09 18:35:44 +0000106 ALOG_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);
Steve Blockae074452012-01-09 18:35:44 +0000128 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800129 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
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700146String8::String8(StaticLinkage)
147 : mString(0)
148{
149 // this constructor is used when we can't rely on the static-initializers
150 // having run. In this case we always allocate an empty string. It's less
151 // efficient than using getEmptyString(), but we assume it's uncommon.
152
153 char* data = static_cast<char*>(
154 SharedBuffer::alloc(sizeof(char))->data());
155 data[0] = 0;
156 mString = data;
157}
158
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800159String8::String8(const String8& o)
160 : mString(o.mString)
161{
162 SharedBuffer::bufferFromData(mString)->acquire();
163}
164
165String8::String8(const char* o)
166 : mString(allocFromUTF8(o, strlen(o)))
167{
168 if (mString == NULL) {
169 mString = getEmptyString();
170 }
171}
172
173String8::String8(const char* o, size_t len)
174 : mString(allocFromUTF8(o, len))
175{
176 if (mString == NULL) {
177 mString = getEmptyString();
178 }
179}
180
181String8::String8(const String16& o)
182 : mString(allocFromUTF16(o.string(), o.size()))
183{
184}
185
186String8::String8(const char16_t* o)
187 : mString(allocFromUTF16(o, strlen16(o)))
188{
189}
190
191String8::String8(const char16_t* o, size_t len)
192 : mString(allocFromUTF16(o, len))
193{
194}
195
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900196String8::String8(const char32_t* o)
197 : mString(allocFromUTF32(o, strlen32(o)))
198{
199}
200
201String8::String8(const char32_t* o, size_t len)
202 : mString(allocFromUTF32(o, len))
203{
204}
205
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800206String8::~String8()
207{
208 SharedBuffer::bufferFromData(mString)->release();
209}
210
Jeff Brown1d618d62010-12-02 13:50:46 -0800211String8 String8::format(const char* fmt, ...)
212{
213 va_list args;
214 va_start(args, fmt);
215
216 String8 result(formatV(fmt, args));
217
218 va_end(args);
219 return result;
220}
221
222String8 String8::formatV(const char* fmt, va_list args)
223{
224 String8 result;
225 result.appendFormatV(fmt, args);
226 return result;
227}
228
Jeff Brown48da31b2010-09-12 17:55:08 -0700229void String8::clear() {
230 SharedBuffer::bufferFromData(mString)->release();
231 mString = getEmptyString();
232}
233
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800234void String8::setTo(const String8& other)
235{
236 SharedBuffer::bufferFromData(other.mString)->acquire();
237 SharedBuffer::bufferFromData(mString)->release();
238 mString = other.mString;
239}
240
241status_t String8::setTo(const char* other)
242{
Andreas Huber10e5da52010-06-10 11:14:26 -0700243 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800244 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700245 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800246 if (mString) return NO_ERROR;
247
248 mString = getEmptyString();
249 return NO_MEMORY;
250}
251
252status_t String8::setTo(const char* other, size_t len)
253{
Andreas Huber10e5da52010-06-10 11:14:26 -0700254 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800255 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700256 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800257 if (mString) return NO_ERROR;
258
259 mString = getEmptyString();
260 return NO_MEMORY;
261}
262
263status_t String8::setTo(const char16_t* other, size_t len)
264{
Andreas Huber10e5da52010-06-10 11:14:26 -0700265 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800266 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700267 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800268 if (mString) return NO_ERROR;
269
270 mString = getEmptyString();
271 return NO_MEMORY;
272}
273
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900274status_t String8::setTo(const char32_t* other, size_t len)
275{
Andreas Huber10e5da52010-06-10 11:14:26 -0700276 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900277 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700278 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900279 if (mString) return NO_ERROR;
280
281 mString = getEmptyString();
282 return NO_MEMORY;
283}
284
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800285status_t String8::append(const String8& other)
286{
287 const size_t otherLen = other.bytes();
288 if (bytes() == 0) {
289 setTo(other);
290 return NO_ERROR;
291 } else if (otherLen == 0) {
292 return NO_ERROR;
293 }
294
295 return real_append(other.string(), otherLen);
296}
297
298status_t String8::append(const char* other)
299{
300 return append(other, strlen(other));
301}
302
303status_t String8::append(const char* other, size_t otherLen)
304{
305 if (bytes() == 0) {
306 return setTo(other, otherLen);
307 } else if (otherLen == 0) {
308 return NO_ERROR;
309 }
310
311 return real_append(other, otherLen);
312}
313
Jeff Brown35a154e2010-07-15 23:54:05 -0700314status_t String8::appendFormat(const char* fmt, ...)
315{
Jeff Brown647925d2010-11-10 16:03:06 -0800316 va_list args;
317 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700318
Jeff Brown647925d2010-11-10 16:03:06 -0800319 status_t result = appendFormatV(fmt, args);
320
321 va_end(args);
322 return result;
323}
324
325status_t String8::appendFormatV(const char* fmt, va_list args)
326{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800327 int n, result = NO_ERROR;
328 va_list tmp_args;
329
330 /* args is undefined after vsnprintf.
331 * So we need a copy here to avoid the
332 * second vsnprintf access undefined args.
333 */
334 va_copy(tmp_args, args);
335 n = vsnprintf(NULL, 0, fmt, tmp_args);
336 va_end(tmp_args);
337
Jeff Brown35a154e2010-07-15 23:54:05 -0700338 if (n != 0) {
339 size_t oldLength = length();
340 char* buf = lockBuffer(oldLength + n);
341 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800342 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700343 } else {
344 result = NO_MEMORY;
345 }
346 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700347 return result;
348}
349
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800350status_t String8::real_append(const char* other, size_t otherLen)
351{
352 const size_t myLen = bytes();
353
354 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
355 ->editResize(myLen+otherLen+1);
356 if (buf) {
357 char* str = (char*)buf->data();
358 mString = str;
359 str += myLen;
360 memcpy(str, other, otherLen);
361 str[otherLen] = '\0';
362 return NO_ERROR;
363 }
364 return NO_MEMORY;
365}
366
367char* String8::lockBuffer(size_t size)
368{
369 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
370 ->editResize(size+1);
371 if (buf) {
372 char* str = (char*)buf->data();
373 mString = str;
374 return str;
375 }
376 return NULL;
377}
378
379void String8::unlockBuffer()
380{
381 unlockBuffer(strlen(mString));
382}
383
384status_t String8::unlockBuffer(size_t size)
385{
386 if (size != this->size()) {
387 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
388 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700389 if (! buf) {
390 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800391 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700392
393 char* str = (char*)buf->data();
394 str[size] = 0;
395 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800396 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700397
398 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800399}
400
401ssize_t String8::find(const char* other, size_t start) const
402{
403 size_t len = size();
404 if (start >= len) {
405 return -1;
406 }
407 const char* s = mString+start;
408 const char* p = strstr(s, other);
409 return p ? p-mString : -1;
410}
411
Jeff Brown5ee915a2014-06-06 19:30:15 -0700412bool String8::removeAll(const char* other) {
413 ssize_t index = find(other);
414 if (index < 0) return false;
415
416 char* buf = lockBuffer(size());
417 if (!buf) return false; // out of memory
418
419 size_t skip = strlen(other);
420 size_t len = size();
421 size_t tail = index;
422 while (size_t(index) < len) {
423 ssize_t next = find(other, index + skip);
424 if (next < 0) {
425 next = len;
426 }
427
Andreas Gampedd060f02014-11-13 15:50:17 -0800428 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700429 tail += next - index - skip;
430 index = next;
431 }
432 unlockBuffer(tail);
433 return true;
434}
435
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800436void String8::toLower()
437{
438 toLower(0, size());
439}
440
441void String8::toLower(size_t start, size_t length)
442{
443 const size_t len = size();
444 if (start >= len) {
445 return;
446 }
447 if (start+length > len) {
448 length = len-start;
449 }
450 char* buf = lockBuffer(len);
451 buf += start;
452 while (length > 0) {
453 *buf = tolower(*buf);
454 buf++;
455 length--;
456 }
457 unlockBuffer(len);
458}
459
460void String8::toUpper()
461{
462 toUpper(0, size());
463}
464
465void String8::toUpper(size_t start, size_t length)
466{
467 const size_t len = size();
468 if (start >= len) {
469 return;
470 }
471 if (start+length > len) {
472 length = len-start;
473 }
474 char* buf = lockBuffer(len);
475 buf += start;
476 while (length > 0) {
477 *buf = toupper(*buf);
478 buf++;
479 length--;
480 }
481 unlockBuffer(len);
482}
483
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900484size_t String8::getUtf32Length() const
485{
Kenny Rootba0165b2010-11-09 14:37:23 -0800486 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900487}
488
489int32_t String8::getUtf32At(size_t index, size_t *next_index) const
490{
Kenny Rootba0165b2010-11-09 14:37:23 -0800491 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900492}
493
Kenny Rootba0165b2010-11-09 14:37:23 -0800494void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900495{
Kenny Rootba0165b2010-11-09 14:37:23 -0800496 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900497}
498
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800499// ---------------------------------------------------------------------------
500// Path functions
501
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800502void String8::setPathName(const char* name)
503{
504 setPathName(name, strlen(name));
505}
506
507void String8::setPathName(const char* name, size_t len)
508{
509 char* buf = lockBuffer(len);
510
511 memcpy(buf, name, len);
512
513 // remove trailing path separator, if present
514 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
515 len--;
516
517 buf[len] = '\0';
518
519 unlockBuffer(len);
520}
521
522String8 String8::getPathLeaf(void) const
523{
524 const char* cp;
525 const char*const buf = mString;
526
527 cp = strrchr(buf, OS_PATH_SEPARATOR);
528 if (cp == NULL)
529 return String8(*this);
530 else
531 return String8(cp+1);
532}
533
534String8 String8::getPathDir(void) const
535{
536 const char* cp;
537 const char*const str = mString;
538
539 cp = strrchr(str, OS_PATH_SEPARATOR);
540 if (cp == NULL)
541 return String8("");
542 else
543 return String8(str, cp - str);
544}
545
546String8 String8::walkPath(String8* outRemains) const
547{
548 const char* cp;
549 const char*const str = mString;
550 const char* buf = str;
551
552 cp = strchr(buf, OS_PATH_SEPARATOR);
553 if (cp == buf) {
554 // don't include a leading '/'.
555 buf = buf+1;
556 cp = strchr(buf, OS_PATH_SEPARATOR);
557 }
558
559 if (cp == NULL) {
560 String8 res = buf != str ? String8(buf) : *this;
561 if (outRemains) *outRemains = String8("");
562 return res;
563 }
564
565 String8 res(buf, cp-buf);
566 if (outRemains) *outRemains = String8(cp+1);
567 return res;
568}
569
570/*
571 * Helper function for finding the start of an extension in a pathname.
572 *
573 * Returns a pointer inside mString, or NULL if no extension was found.
574 */
575char* String8::find_extension(void) const
576{
577 const char* lastSlash;
578 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800579 const char* const str = mString;
580
581 // only look at the filename
582 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
583 if (lastSlash == NULL)
584 lastSlash = str;
585 else
586 lastSlash++;
587
588 // find the last dot
589 lastDot = strrchr(lastSlash, '.');
590 if (lastDot == NULL)
591 return NULL;
592
593 // looks good, ship it
594 return const_cast<char*>(lastDot);
595}
596
597String8 String8::getPathExtension(void) const
598{
599 char* ext;
600
601 ext = find_extension();
602 if (ext != NULL)
603 return String8(ext);
604 else
605 return String8("");
606}
607
608String8 String8::getBasePath(void) const
609{
610 char* ext;
611 const char* const str = mString;
612
613 ext = find_extension();
614 if (ext == NULL)
615 return String8(*this);
616 else
617 return String8(str, ext - str);
618}
619
620String8& String8::appendPath(const char* name)
621{
622 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
623 if (name[0] != OS_PATH_SEPARATOR) {
624 if (*name == '\0') {
625 // nothing to do
626 return *this;
627 }
628
629 size_t len = length();
630 if (len == 0) {
631 // no existing filename, just use the new one
632 setPathName(name);
633 return *this;
634 }
635
636 // make room for oldPath + '/' + newPath
637 int newlen = strlen(name);
638
639 char* buf = lockBuffer(len+1+newlen);
640
641 // insert a '/' if needed
642 if (buf[len-1] != OS_PATH_SEPARATOR)
643 buf[len++] = OS_PATH_SEPARATOR;
644
645 memcpy(buf+len, name, newlen+1);
646 len += newlen;
647
648 unlockBuffer(len);
649
650 return *this;
651 } else {
652 setPathName(name);
653 return *this;
654 }
655}
656
657String8& String8::convertToResPath()
658{
659#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
660 size_t len = length();
661 if (len > 0) {
662 char * buf = lockBuffer(len);
663 for (char * end = buf + len; buf < end; ++buf) {
664 if (*buf == OS_PATH_SEPARATOR)
665 *buf = RES_PATH_SEPARATOR;
666 }
667 unlockBuffer(len);
668 }
669#endif
670 return *this;
671}
672
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800673}; // namespace android