blob: 771d312668bddb0cb3fcf7bf8444c61cfac02cf7 [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>
Kenny Rootba0165b2010-11-09 14:37:23 -080024#include <utils/Unicode.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080025#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080026#include <utils/threads.h>
27
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080028#include <ctype.h>
29
Sergio Girod2529f22015-09-23 16:22:59 +010030#include "SharedBuffer.h"
31
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090032/*
33 * Functions outside android is below the namespace android, since they use
34 * functions and constants in android namespace.
35 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080036
37// ---------------------------------------------------------------------------
38
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090039namespace android {
40
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080041// Separator used by resource paths. This is not platform dependent contrary
42// to OS_PATH_SEPARATOR.
43#define RES_PATH_SEPARATOR '/'
44
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080045static SharedBuffer* gEmptyStringBuf = NULL;
46static char* gEmptyString = NULL;
47
48extern int gDarwinCantLoadAllObjects;
49int gDarwinIsReallyAnnoying;
50
Mathias Agopian9eb2a3b2013-05-06 20:20:50 -070051void initialize_string8();
52
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080053static inline char* getEmptyString()
54{
55 gEmptyStringBuf->acquire();
56 return gEmptyString;
57}
58
59void initialize_string8()
60{
Dan Egnor88753ae2010-05-06 00:55:09 -070061 // HACK: This dummy dependency forces linking libutils Static.cpp,
62 // which is needed to initialize String8/String16 classes.
63 // These variables are named for Darwin, but are needed elsewhere too,
64 // including static linking on any platform.
65 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090066
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080067 SharedBuffer* buf = SharedBuffer::alloc(1);
68 char* str = (char*)buf->data();
69 *str = 0;
70 gEmptyStringBuf = buf;
71 gEmptyString = str;
72}
73
74void terminate_string8()
75{
76 SharedBuffer::bufferFromData(gEmptyString)->release();
77 gEmptyStringBuf = NULL;
78 gEmptyString = NULL;
79}
80
81// ---------------------------------------------------------------------------
82
83static char* allocFromUTF8(const char* in, size_t len)
84{
85 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010086 if (len == SIZE_MAX) {
87 return NULL;
88 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080089 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000090 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080091 if (buf) {
92 char* str = (char*)buf->data();
93 memcpy(str, in, len);
94 str[len] = 0;
95 return str;
96 }
97 return NULL;
98 }
99
100 return getEmptyString();
101}
102
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900103static char* allocFromUTF16(const char16_t* in, size_t len)
104{
Kenny Root9a2d83e2009-12-04 09:38:48 -0800105 if (len == 0) return getEmptyString();
106
Kenny Rootba0165b2010-11-09 14:37:23 -0800107 const ssize_t bytes = utf16_to_utf8_length(in, len);
108 if (bytes < 0) {
109 return getEmptyString();
110 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800111
112 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000113 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800114 if (!buf) {
115 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800116 }
117
Kenny Rootba0165b2010-11-09 14:37:23 -0800118 char* str = (char*)buf->data();
119 utf16_to_utf8(in, len, str);
120 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900121}
122
123static char* allocFromUTF32(const char32_t* in, size_t len)
124{
Kenny Rootba0165b2010-11-09 14:37:23 -0800125 if (len == 0) {
126 return getEmptyString();
127 }
128
129 const ssize_t bytes = utf32_to_utf8_length(in, len);
130 if (bytes < 0) {
131 return getEmptyString();
132 }
133
134 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000135 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800136 if (!buf) {
137 return getEmptyString();
138 }
139
140 char* str = (char*) buf->data();
141 utf32_to_utf8(in, len, str);
142
143 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900144}
145
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800146// ---------------------------------------------------------------------------
147
148String8::String8()
149 : mString(getEmptyString())
150{
151}
152
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700153String8::String8(StaticLinkage)
154 : mString(0)
155{
156 // this constructor is used when we can't rely on the static-initializers
157 // having run. In this case we always allocate an empty string. It's less
158 // efficient than using getEmptyString(), but we assume it's uncommon.
159
160 char* data = static_cast<char*>(
161 SharedBuffer::alloc(sizeof(char))->data());
162 data[0] = 0;
163 mString = data;
164}
165
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800166String8::String8(const String8& o)
167 : mString(o.mString)
168{
169 SharedBuffer::bufferFromData(mString)->acquire();
170}
171
172String8::String8(const char* o)
173 : mString(allocFromUTF8(o, strlen(o)))
174{
175 if (mString == NULL) {
176 mString = getEmptyString();
177 }
178}
179
180String8::String8(const char* o, size_t len)
181 : mString(allocFromUTF8(o, len))
182{
183 if (mString == NULL) {
184 mString = getEmptyString();
185 }
186}
187
188String8::String8(const String16& o)
189 : mString(allocFromUTF16(o.string(), o.size()))
190{
191}
192
193String8::String8(const char16_t* o)
194 : mString(allocFromUTF16(o, strlen16(o)))
195{
196}
197
198String8::String8(const char16_t* o, size_t len)
199 : mString(allocFromUTF16(o, len))
200{
201}
202
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900203String8::String8(const char32_t* o)
204 : mString(allocFromUTF32(o, strlen32(o)))
205{
206}
207
208String8::String8(const char32_t* o, size_t len)
209 : mString(allocFromUTF32(o, len))
210{
211}
212
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800213String8::~String8()
214{
215 SharedBuffer::bufferFromData(mString)->release();
216}
217
Sergio Girod2529f22015-09-23 16:22:59 +0100218size_t String8::length() const
219{
220 return SharedBuffer::sizeFromData(mString)-1;
221}
222
Jeff Brown1d618d62010-12-02 13:50:46 -0800223String8 String8::format(const char* fmt, ...)
224{
225 va_list args;
226 va_start(args, fmt);
227
228 String8 result(formatV(fmt, args));
229
230 va_end(args);
231 return result;
232}
233
234String8 String8::formatV(const char* fmt, va_list args)
235{
236 String8 result;
237 result.appendFormatV(fmt, args);
238 return result;
239}
240
Jeff Brown48da31b2010-09-12 17:55:08 -0700241void String8::clear() {
242 SharedBuffer::bufferFromData(mString)->release();
243 mString = getEmptyString();
244}
245
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800246void String8::setTo(const String8& other)
247{
248 SharedBuffer::bufferFromData(other.mString)->acquire();
249 SharedBuffer::bufferFromData(mString)->release();
250 mString = other.mString;
251}
252
253status_t String8::setTo(const char* other)
254{
Andreas Huber10e5da52010-06-10 11:14:26 -0700255 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800256 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700257 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800258 if (mString) return NO_ERROR;
259
260 mString = getEmptyString();
261 return NO_MEMORY;
262}
263
264status_t String8::setTo(const char* other, size_t len)
265{
Andreas Huber10e5da52010-06-10 11:14:26 -0700266 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800267 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700268 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800269 if (mString) return NO_ERROR;
270
271 mString = getEmptyString();
272 return NO_MEMORY;
273}
274
275status_t String8::setTo(const char16_t* other, size_t len)
276{
Andreas Huber10e5da52010-06-10 11:14:26 -0700277 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800278 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700279 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800280 if (mString) return NO_ERROR;
281
282 mString = getEmptyString();
283 return NO_MEMORY;
284}
285
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900286status_t String8::setTo(const char32_t* other, size_t len)
287{
Andreas Huber10e5da52010-06-10 11:14:26 -0700288 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900289 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700290 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900291 if (mString) return NO_ERROR;
292
293 mString = getEmptyString();
294 return NO_MEMORY;
295}
296
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800297status_t String8::append(const String8& other)
298{
299 const size_t otherLen = other.bytes();
300 if (bytes() == 0) {
301 setTo(other);
302 return NO_ERROR;
303 } else if (otherLen == 0) {
304 return NO_ERROR;
305 }
306
307 return real_append(other.string(), otherLen);
308}
309
310status_t String8::append(const char* other)
311{
312 return append(other, strlen(other));
313}
314
315status_t String8::append(const char* other, size_t otherLen)
316{
317 if (bytes() == 0) {
318 return setTo(other, otherLen);
319 } else if (otherLen == 0) {
320 return NO_ERROR;
321 }
322
323 return real_append(other, otherLen);
324}
325
Jeff Brown35a154e2010-07-15 23:54:05 -0700326status_t String8::appendFormat(const char* fmt, ...)
327{
Jeff Brown647925d2010-11-10 16:03:06 -0800328 va_list args;
329 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700330
Jeff Brown647925d2010-11-10 16:03:06 -0800331 status_t result = appendFormatV(fmt, args);
332
333 va_end(args);
334 return result;
335}
336
337status_t String8::appendFormatV(const char* fmt, va_list args)
338{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800339 int n, result = NO_ERROR;
340 va_list tmp_args;
341
342 /* args is undefined after vsnprintf.
343 * So we need a copy here to avoid the
344 * second vsnprintf access undefined args.
345 */
346 va_copy(tmp_args, args);
347 n = vsnprintf(NULL, 0, fmt, tmp_args);
348 va_end(tmp_args);
349
Jeff Brown35a154e2010-07-15 23:54:05 -0700350 if (n != 0) {
351 size_t oldLength = length();
352 char* buf = lockBuffer(oldLength + n);
353 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800354 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700355 } else {
356 result = NO_MEMORY;
357 }
358 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700359 return result;
360}
361
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800362status_t String8::real_append(const char* other, size_t otherLen)
363{
364 const size_t myLen = bytes();
365
366 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
367 ->editResize(myLen+otherLen+1);
368 if (buf) {
369 char* str = (char*)buf->data();
370 mString = str;
371 str += myLen;
372 memcpy(str, other, otherLen);
373 str[otherLen] = '\0';
374 return NO_ERROR;
375 }
376 return NO_MEMORY;
377}
378
379char* String8::lockBuffer(size_t size)
380{
381 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
382 ->editResize(size+1);
383 if (buf) {
384 char* str = (char*)buf->data();
385 mString = str;
386 return str;
387 }
388 return NULL;
389}
390
391void String8::unlockBuffer()
392{
393 unlockBuffer(strlen(mString));
394}
395
396status_t String8::unlockBuffer(size_t size)
397{
398 if (size != this->size()) {
399 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
400 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700401 if (! buf) {
402 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800403 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700404
405 char* str = (char*)buf->data();
406 str[size] = 0;
407 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800408 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700409
410 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800411}
412
413ssize_t String8::find(const char* other, size_t start) const
414{
415 size_t len = size();
416 if (start >= len) {
417 return -1;
418 }
419 const char* s = mString+start;
420 const char* p = strstr(s, other);
421 return p ? p-mString : -1;
422}
423
Jeff Brown5ee915a2014-06-06 19:30:15 -0700424bool String8::removeAll(const char* other) {
425 ssize_t index = find(other);
426 if (index < 0) return false;
427
428 char* buf = lockBuffer(size());
429 if (!buf) return false; // out of memory
430
431 size_t skip = strlen(other);
432 size_t len = size();
433 size_t tail = index;
434 while (size_t(index) < len) {
435 ssize_t next = find(other, index + skip);
436 if (next < 0) {
437 next = len;
438 }
439
Andreas Gampedd060f02014-11-13 15:50:17 -0800440 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700441 tail += next - index - skip;
442 index = next;
443 }
444 unlockBuffer(tail);
445 return true;
446}
447
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800448void String8::toLower()
449{
450 toLower(0, size());
451}
452
453void String8::toLower(size_t start, size_t length)
454{
455 const size_t len = size();
456 if (start >= len) {
457 return;
458 }
459 if (start+length > len) {
460 length = len-start;
461 }
462 char* buf = lockBuffer(len);
463 buf += start;
464 while (length > 0) {
465 *buf = tolower(*buf);
466 buf++;
467 length--;
468 }
469 unlockBuffer(len);
470}
471
472void String8::toUpper()
473{
474 toUpper(0, size());
475}
476
477void String8::toUpper(size_t start, size_t length)
478{
479 const size_t len = size();
480 if (start >= len) {
481 return;
482 }
483 if (start+length > len) {
484 length = len-start;
485 }
486 char* buf = lockBuffer(len);
487 buf += start;
488 while (length > 0) {
489 *buf = toupper(*buf);
490 buf++;
491 length--;
492 }
493 unlockBuffer(len);
494}
495
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900496size_t String8::getUtf32Length() const
497{
Kenny Rootba0165b2010-11-09 14:37:23 -0800498 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900499}
500
501int32_t String8::getUtf32At(size_t index, size_t *next_index) const
502{
Kenny Rootba0165b2010-11-09 14:37:23 -0800503 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900504}
505
Kenny Rootba0165b2010-11-09 14:37:23 -0800506void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900507{
Kenny Rootba0165b2010-11-09 14:37:23 -0800508 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900509}
510
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800511// ---------------------------------------------------------------------------
512// Path functions
513
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800514void String8::setPathName(const char* name)
515{
516 setPathName(name, strlen(name));
517}
518
519void String8::setPathName(const char* name, size_t len)
520{
521 char* buf = lockBuffer(len);
522
523 memcpy(buf, name, len);
524
525 // remove trailing path separator, if present
526 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
527 len--;
528
529 buf[len] = '\0';
530
531 unlockBuffer(len);
532}
533
534String8 String8::getPathLeaf(void) const
535{
536 const char* cp;
537 const char*const buf = mString;
538
539 cp = strrchr(buf, OS_PATH_SEPARATOR);
540 if (cp == NULL)
541 return String8(*this);
542 else
543 return String8(cp+1);
544}
545
546String8 String8::getPathDir(void) const
547{
548 const char* cp;
549 const char*const str = mString;
550
551 cp = strrchr(str, OS_PATH_SEPARATOR);
552 if (cp == NULL)
553 return String8("");
554 else
555 return String8(str, cp - str);
556}
557
558String8 String8::walkPath(String8* outRemains) const
559{
560 const char* cp;
561 const char*const str = mString;
562 const char* buf = str;
563
564 cp = strchr(buf, OS_PATH_SEPARATOR);
565 if (cp == buf) {
566 // don't include a leading '/'.
567 buf = buf+1;
568 cp = strchr(buf, OS_PATH_SEPARATOR);
569 }
570
571 if (cp == NULL) {
572 String8 res = buf != str ? String8(buf) : *this;
573 if (outRemains) *outRemains = String8("");
574 return res;
575 }
576
577 String8 res(buf, cp-buf);
578 if (outRemains) *outRemains = String8(cp+1);
579 return res;
580}
581
582/*
583 * Helper function for finding the start of an extension in a pathname.
584 *
585 * Returns a pointer inside mString, or NULL if no extension was found.
586 */
587char* String8::find_extension(void) const
588{
589 const char* lastSlash;
590 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800591 const char* const str = mString;
592
593 // only look at the filename
594 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
595 if (lastSlash == NULL)
596 lastSlash = str;
597 else
598 lastSlash++;
599
600 // find the last dot
601 lastDot = strrchr(lastSlash, '.');
602 if (lastDot == NULL)
603 return NULL;
604
605 // looks good, ship it
606 return const_cast<char*>(lastDot);
607}
608
609String8 String8::getPathExtension(void) const
610{
611 char* ext;
612
613 ext = find_extension();
614 if (ext != NULL)
615 return String8(ext);
616 else
617 return String8("");
618}
619
620String8 String8::getBasePath(void) const
621{
622 char* ext;
623 const char* const str = mString;
624
625 ext = find_extension();
626 if (ext == NULL)
627 return String8(*this);
628 else
629 return String8(str, ext - str);
630}
631
632String8& String8::appendPath(const char* name)
633{
634 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
635 if (name[0] != OS_PATH_SEPARATOR) {
636 if (*name == '\0') {
637 // nothing to do
638 return *this;
639 }
640
641 size_t len = length();
642 if (len == 0) {
643 // no existing filename, just use the new one
644 setPathName(name);
645 return *this;
646 }
647
648 // make room for oldPath + '/' + newPath
649 int newlen = strlen(name);
650
651 char* buf = lockBuffer(len+1+newlen);
652
653 // insert a '/' if needed
654 if (buf[len-1] != OS_PATH_SEPARATOR)
655 buf[len++] = OS_PATH_SEPARATOR;
656
657 memcpy(buf+len, name, newlen+1);
658 len += newlen;
659
660 unlockBuffer(len);
661
662 return *this;
663 } else {
664 setPathName(name);
665 return *this;
666 }
667}
668
669String8& String8::convertToResPath()
670{
671#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
672 size_t len = length();
673 if (len > 0) {
674 char * buf = lockBuffer(len);
675 for (char * end = buf + len; buf < end; ++buf) {
676 if (*buf == OS_PATH_SEPARATOR)
677 *buf = RES_PATH_SEPARATOR;
678 }
679 unlockBuffer(len);
680 }
681#endif
682 return *this;
683}
684
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800685}; // namespace android