blob: 5e8552049cf1462efc29a865361a0ee69dc48493 [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>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080022#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080023#include <utils/threads.h>
24
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080025#include <ctype.h>
26
Sergio Girod2529f22015-09-23 16:22:59 +010027#include "SharedBuffer.h"
28
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090029/*
30 * Functions outside android is below the namespace android, since they use
31 * functions and constants in android namespace.
32 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080033
34// ---------------------------------------------------------------------------
35
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090036namespace android {
37
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080038// Separator used by resource paths. This is not platform dependent contrary
39// to OS_PATH_SEPARATOR.
40#define RES_PATH_SEPARATOR '/'
41
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080042static SharedBuffer* gEmptyStringBuf = NULL;
43static char* gEmptyString = NULL;
44
45extern int gDarwinCantLoadAllObjects;
46int gDarwinIsReallyAnnoying;
47
Mathias Agopian9eb2a3b2013-05-06 20:20:50 -070048void initialize_string8();
49
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080050static inline char* getEmptyString()
51{
52 gEmptyStringBuf->acquire();
53 return gEmptyString;
54}
55
56void initialize_string8()
57{
Dan Egnor88753ae2010-05-06 00:55:09 -070058 // HACK: This dummy dependency forces linking libutils Static.cpp,
59 // which is needed to initialize String8/String16 classes.
60 // These variables are named for Darwin, but are needed elsewhere too,
61 // including static linking on any platform.
62 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090063
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080064 SharedBuffer* buf = SharedBuffer::alloc(1);
65 char* str = (char*)buf->data();
66 *str = 0;
67 gEmptyStringBuf = buf;
68 gEmptyString = str;
69}
70
71void terminate_string8()
72{
73 SharedBuffer::bufferFromData(gEmptyString)->release();
74 gEmptyStringBuf = NULL;
75 gEmptyString = NULL;
76}
77
78// ---------------------------------------------------------------------------
79
80static char* allocFromUTF8(const char* in, size_t len)
81{
82 if (len > 0) {
Sergio Giro4eeacbe2015-08-18 14:44:54 +010083 if (len == SIZE_MAX) {
84 return NULL;
85 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080086 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000087 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080088 if (buf) {
89 char* str = (char*)buf->data();
90 memcpy(str, in, len);
91 str[len] = 0;
92 return str;
93 }
94 return NULL;
95 }
96
97 return getEmptyString();
98}
99
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900100static char* allocFromUTF16(const char16_t* in, size_t len)
101{
Kenny Root9a2d83e2009-12-04 09:38:48 -0800102 if (len == 0) return getEmptyString();
103
Kenny Rootba0165b2010-11-09 14:37:23 -0800104 const ssize_t bytes = utf16_to_utf8_length(in, len);
105 if (bytes < 0) {
106 return getEmptyString();
107 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800108
109 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
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();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800113 }
114
Kenny Rootba0165b2010-11-09 14:37:23 -0800115 char* str = (char*)buf->data();
116 utf16_to_utf8(in, len, str);
117 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900118}
119
120static char* allocFromUTF32(const char32_t* in, size_t len)
121{
Kenny Rootba0165b2010-11-09 14:37:23 -0800122 if (len == 0) {
123 return getEmptyString();
124 }
125
126 const ssize_t bytes = utf32_to_utf8_length(in, len);
127 if (bytes < 0) {
128 return getEmptyString();
129 }
130
131 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000132 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800133 if (!buf) {
134 return getEmptyString();
135 }
136
137 char* str = (char*) buf->data();
138 utf32_to_utf8(in, len, str);
139
140 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900141}
142
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800143// ---------------------------------------------------------------------------
144
145String8::String8()
146 : mString(getEmptyString())
147{
148}
149
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700150String8::String8(StaticLinkage)
151 : mString(0)
152{
153 // this constructor is used when we can't rely on the static-initializers
154 // having run. In this case we always allocate an empty string. It's less
155 // efficient than using getEmptyString(), but we assume it's uncommon.
156
157 char* data = static_cast<char*>(
158 SharedBuffer::alloc(sizeof(char))->data());
159 data[0] = 0;
160 mString = data;
161}
162
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800163String8::String8(const String8& o)
164 : mString(o.mString)
165{
166 SharedBuffer::bufferFromData(mString)->acquire();
167}
168
169String8::String8(const char* o)
170 : mString(allocFromUTF8(o, strlen(o)))
171{
172 if (mString == NULL) {
173 mString = getEmptyString();
174 }
175}
176
177String8::String8(const char* o, size_t len)
178 : mString(allocFromUTF8(o, len))
179{
180 if (mString == NULL) {
181 mString = getEmptyString();
182 }
183}
184
185String8::String8(const String16& o)
186 : mString(allocFromUTF16(o.string(), o.size()))
187{
188}
189
190String8::String8(const char16_t* o)
191 : mString(allocFromUTF16(o, strlen16(o)))
192{
193}
194
195String8::String8(const char16_t* o, size_t len)
196 : mString(allocFromUTF16(o, len))
197{
198}
199
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900200String8::String8(const char32_t* o)
201 : mString(allocFromUTF32(o, strlen32(o)))
202{
203}
204
205String8::String8(const char32_t* o, size_t len)
206 : mString(allocFromUTF32(o, len))
207{
208}
209
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800210String8::~String8()
211{
212 SharedBuffer::bufferFromData(mString)->release();
213}
214
Sergio Girod2529f22015-09-23 16:22:59 +0100215size_t String8::length() const
216{
217 return SharedBuffer::sizeFromData(mString)-1;
218}
219
220const SharedBuffer* String8::sharedBuffer() const
221{
222 return SharedBuffer::bufferFromData(mString);
223}
224
Jeff Brown1d618d62010-12-02 13:50:46 -0800225String8 String8::format(const char* fmt, ...)
226{
227 va_list args;
228 va_start(args, fmt);
229
230 String8 result(formatV(fmt, args));
231
232 va_end(args);
233 return result;
234}
235
236String8 String8::formatV(const char* fmt, va_list args)
237{
238 String8 result;
239 result.appendFormatV(fmt, args);
240 return result;
241}
242
Jeff Brown48da31b2010-09-12 17:55:08 -0700243void String8::clear() {
244 SharedBuffer::bufferFromData(mString)->release();
245 mString = getEmptyString();
246}
247
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800248void String8::setTo(const String8& other)
249{
250 SharedBuffer::bufferFromData(other.mString)->acquire();
251 SharedBuffer::bufferFromData(mString)->release();
252 mString = other.mString;
253}
254
255status_t String8::setTo(const char* other)
256{
Andreas Huber10e5da52010-06-10 11:14:26 -0700257 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800258 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700259 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800260 if (mString) return NO_ERROR;
261
262 mString = getEmptyString();
263 return NO_MEMORY;
264}
265
266status_t String8::setTo(const char* other, size_t len)
267{
Andreas Huber10e5da52010-06-10 11:14:26 -0700268 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800269 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700270 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800271 if (mString) return NO_ERROR;
272
273 mString = getEmptyString();
274 return NO_MEMORY;
275}
276
277status_t String8::setTo(const char16_t* other, size_t len)
278{
Andreas Huber10e5da52010-06-10 11:14:26 -0700279 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800280 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700281 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800282 if (mString) return NO_ERROR;
283
284 mString = getEmptyString();
285 return NO_MEMORY;
286}
287
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900288status_t String8::setTo(const char32_t* other, size_t len)
289{
Andreas Huber10e5da52010-06-10 11:14:26 -0700290 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900291 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700292 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900293 if (mString) return NO_ERROR;
294
295 mString = getEmptyString();
296 return NO_MEMORY;
297}
298
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800299status_t String8::append(const String8& other)
300{
301 const size_t otherLen = other.bytes();
302 if (bytes() == 0) {
303 setTo(other);
304 return NO_ERROR;
305 } else if (otherLen == 0) {
306 return NO_ERROR;
307 }
308
309 return real_append(other.string(), otherLen);
310}
311
312status_t String8::append(const char* other)
313{
314 return append(other, strlen(other));
315}
316
317status_t String8::append(const char* other, size_t otherLen)
318{
319 if (bytes() == 0) {
320 return setTo(other, otherLen);
321 } else if (otherLen == 0) {
322 return NO_ERROR;
323 }
324
325 return real_append(other, otherLen);
326}
327
Jeff Brown35a154e2010-07-15 23:54:05 -0700328status_t String8::appendFormat(const char* fmt, ...)
329{
Jeff Brown647925d2010-11-10 16:03:06 -0800330 va_list args;
331 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700332
Jeff Brown647925d2010-11-10 16:03:06 -0800333 status_t result = appendFormatV(fmt, args);
334
335 va_end(args);
336 return result;
337}
338
339status_t String8::appendFormatV(const char* fmt, va_list args)
340{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800341 int n, result = NO_ERROR;
342 va_list tmp_args;
343
344 /* args is undefined after vsnprintf.
345 * So we need a copy here to avoid the
346 * second vsnprintf access undefined args.
347 */
348 va_copy(tmp_args, args);
349 n = vsnprintf(NULL, 0, fmt, tmp_args);
350 va_end(tmp_args);
351
Jeff Brown35a154e2010-07-15 23:54:05 -0700352 if (n != 0) {
353 size_t oldLength = length();
354 char* buf = lockBuffer(oldLength + n);
355 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800356 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700357 } else {
358 result = NO_MEMORY;
359 }
360 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700361 return result;
362}
363
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800364status_t String8::real_append(const char* other, size_t otherLen)
365{
366 const size_t myLen = bytes();
367
368 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
369 ->editResize(myLen+otherLen+1);
370 if (buf) {
371 char* str = (char*)buf->data();
372 mString = str;
373 str += myLen;
374 memcpy(str, other, otherLen);
375 str[otherLen] = '\0';
376 return NO_ERROR;
377 }
378 return NO_MEMORY;
379}
380
381char* String8::lockBuffer(size_t size)
382{
383 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
384 ->editResize(size+1);
385 if (buf) {
386 char* str = (char*)buf->data();
387 mString = str;
388 return str;
389 }
390 return NULL;
391}
392
393void String8::unlockBuffer()
394{
395 unlockBuffer(strlen(mString));
396}
397
398status_t String8::unlockBuffer(size_t size)
399{
400 if (size != this->size()) {
401 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
402 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700403 if (! buf) {
404 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800405 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700406
407 char* str = (char*)buf->data();
408 str[size] = 0;
409 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800410 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700411
412 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800413}
414
415ssize_t String8::find(const char* other, size_t start) const
416{
417 size_t len = size();
418 if (start >= len) {
419 return -1;
420 }
421 const char* s = mString+start;
422 const char* p = strstr(s, other);
423 return p ? p-mString : -1;
424}
425
Jeff Brown5ee915a2014-06-06 19:30:15 -0700426bool String8::removeAll(const char* other) {
427 ssize_t index = find(other);
428 if (index < 0) return false;
429
430 char* buf = lockBuffer(size());
431 if (!buf) return false; // out of memory
432
433 size_t skip = strlen(other);
434 size_t len = size();
435 size_t tail = index;
436 while (size_t(index) < len) {
437 ssize_t next = find(other, index + skip);
438 if (next < 0) {
439 next = len;
440 }
441
Andreas Gampedd060f02014-11-13 15:50:17 -0800442 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700443 tail += next - index - skip;
444 index = next;
445 }
446 unlockBuffer(tail);
447 return true;
448}
449
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800450void String8::toLower()
451{
452 toLower(0, size());
453}
454
455void String8::toLower(size_t start, size_t length)
456{
457 const size_t len = size();
458 if (start >= len) {
459 return;
460 }
461 if (start+length > len) {
462 length = len-start;
463 }
464 char* buf = lockBuffer(len);
465 buf += start;
466 while (length > 0) {
467 *buf = tolower(*buf);
468 buf++;
469 length--;
470 }
471 unlockBuffer(len);
472}
473
474void String8::toUpper()
475{
476 toUpper(0, size());
477}
478
479void String8::toUpper(size_t start, size_t length)
480{
481 const size_t len = size();
482 if (start >= len) {
483 return;
484 }
485 if (start+length > len) {
486 length = len-start;
487 }
488 char* buf = lockBuffer(len);
489 buf += start;
490 while (length > 0) {
491 *buf = toupper(*buf);
492 buf++;
493 length--;
494 }
495 unlockBuffer(len);
496}
497
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900498size_t String8::getUtf32Length() const
499{
Kenny Rootba0165b2010-11-09 14:37:23 -0800500 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900501}
502
503int32_t String8::getUtf32At(size_t index, size_t *next_index) const
504{
Kenny Rootba0165b2010-11-09 14:37:23 -0800505 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900506}
507
Kenny Rootba0165b2010-11-09 14:37:23 -0800508void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900509{
Kenny Rootba0165b2010-11-09 14:37:23 -0800510 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900511}
512
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800513// ---------------------------------------------------------------------------
514// Path functions
515
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800516void String8::setPathName(const char* name)
517{
518 setPathName(name, strlen(name));
519}
520
521void String8::setPathName(const char* name, size_t len)
522{
523 char* buf = lockBuffer(len);
524
525 memcpy(buf, name, len);
526
527 // remove trailing path separator, if present
528 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
529 len--;
530
531 buf[len] = '\0';
532
533 unlockBuffer(len);
534}
535
536String8 String8::getPathLeaf(void) const
537{
538 const char* cp;
539 const char*const buf = mString;
540
541 cp = strrchr(buf, OS_PATH_SEPARATOR);
542 if (cp == NULL)
543 return String8(*this);
544 else
545 return String8(cp+1);
546}
547
548String8 String8::getPathDir(void) const
549{
550 const char* cp;
551 const char*const str = mString;
552
553 cp = strrchr(str, OS_PATH_SEPARATOR);
554 if (cp == NULL)
555 return String8("");
556 else
557 return String8(str, cp - str);
558}
559
560String8 String8::walkPath(String8* outRemains) const
561{
562 const char* cp;
563 const char*const str = mString;
564 const char* buf = str;
565
566 cp = strchr(buf, OS_PATH_SEPARATOR);
567 if (cp == buf) {
568 // don't include a leading '/'.
569 buf = buf+1;
570 cp = strchr(buf, OS_PATH_SEPARATOR);
571 }
572
573 if (cp == NULL) {
574 String8 res = buf != str ? String8(buf) : *this;
575 if (outRemains) *outRemains = String8("");
576 return res;
577 }
578
579 String8 res(buf, cp-buf);
580 if (outRemains) *outRemains = String8(cp+1);
581 return res;
582}
583
584/*
585 * Helper function for finding the start of an extension in a pathname.
586 *
587 * Returns a pointer inside mString, or NULL if no extension was found.
588 */
589char* String8::find_extension(void) const
590{
591 const char* lastSlash;
592 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800593 const char* const str = mString;
594
595 // only look at the filename
596 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
597 if (lastSlash == NULL)
598 lastSlash = str;
599 else
600 lastSlash++;
601
602 // find the last dot
603 lastDot = strrchr(lastSlash, '.');
604 if (lastDot == NULL)
605 return NULL;
606
607 // looks good, ship it
608 return const_cast<char*>(lastDot);
609}
610
611String8 String8::getPathExtension(void) const
612{
613 char* ext;
614
615 ext = find_extension();
616 if (ext != NULL)
617 return String8(ext);
618 else
619 return String8("");
620}
621
622String8 String8::getBasePath(void) const
623{
624 char* ext;
625 const char* const str = mString;
626
627 ext = find_extension();
628 if (ext == NULL)
629 return String8(*this);
630 else
631 return String8(str, ext - str);
632}
633
634String8& String8::appendPath(const char* name)
635{
636 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
637 if (name[0] != OS_PATH_SEPARATOR) {
638 if (*name == '\0') {
639 // nothing to do
640 return *this;
641 }
642
643 size_t len = length();
644 if (len == 0) {
645 // no existing filename, just use the new one
646 setPathName(name);
647 return *this;
648 }
649
650 // make room for oldPath + '/' + newPath
651 int newlen = strlen(name);
652
653 char* buf = lockBuffer(len+1+newlen);
654
655 // insert a '/' if needed
656 if (buf[len-1] != OS_PATH_SEPARATOR)
657 buf[len++] = OS_PATH_SEPARATOR;
658
659 memcpy(buf+len, name, newlen+1);
660 len += newlen;
661
662 unlockBuffer(len);
663
664 return *this;
665 } else {
666 setPathName(name);
667 return *this;
668 }
669}
670
671String8& String8::convertToResPath()
672{
673#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
674 size_t len = length();
675 if (len > 0) {
676 char * buf = lockBuffer(len);
677 for (char * end = buf + len; buf < end; ++buf) {
678 if (*buf == OS_PATH_SEPARATOR)
679 *buf = RES_PATH_SEPARATOR;
680 }
681 unlockBuffer(len);
682 }
683#endif
684 return *this;
685}
686
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800687}; // namespace android