blob: 69313ead7cfe2c99809c78b5a8b86033f04af0be [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) {
Sergio Giro4eeacbe2015-08-18 14:44:54 +010082 if (len == SIZE_MAX) {
83 return NULL;
84 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080085 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000086 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080087 if (buf) {
88 char* str = (char*)buf->data();
89 memcpy(str, in, len);
90 str[len] = 0;
91 return str;
92 }
93 return NULL;
94 }
95
96 return getEmptyString();
97}
98
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090099static char* allocFromUTF16(const char16_t* in, size_t len)
100{
Kenny Root9a2d83e2009-12-04 09:38:48 -0800101 if (len == 0) return getEmptyString();
102
Kenny Rootba0165b2010-11-09 14:37:23 -0800103 const ssize_t bytes = utf16_to_utf8_length(in, len);
104 if (bytes < 0) {
105 return getEmptyString();
106 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800107
108 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
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();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800112 }
113
Kenny Rootba0165b2010-11-09 14:37:23 -0800114 char* str = (char*)buf->data();
115 utf16_to_utf8(in, len, str);
116 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900117}
118
119static char* allocFromUTF32(const char32_t* in, size_t len)
120{
Kenny Rootba0165b2010-11-09 14:37:23 -0800121 if (len == 0) {
122 return getEmptyString();
123 }
124
125 const ssize_t bytes = utf32_to_utf8_length(in, len);
126 if (bytes < 0) {
127 return getEmptyString();
128 }
129
130 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000131 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800132 if (!buf) {
133 return getEmptyString();
134 }
135
136 char* str = (char*) buf->data();
137 utf32_to_utf8(in, len, str);
138
139 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900140}
141
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800142// ---------------------------------------------------------------------------
143
144String8::String8()
145 : mString(getEmptyString())
146{
147}
148
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700149String8::String8(StaticLinkage)
150 : mString(0)
151{
152 // this constructor is used when we can't rely on the static-initializers
153 // having run. In this case we always allocate an empty string. It's less
154 // efficient than using getEmptyString(), but we assume it's uncommon.
155
156 char* data = static_cast<char*>(
157 SharedBuffer::alloc(sizeof(char))->data());
158 data[0] = 0;
159 mString = data;
160}
161
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800162String8::String8(const String8& o)
163 : mString(o.mString)
164{
165 SharedBuffer::bufferFromData(mString)->acquire();
166}
167
168String8::String8(const char* o)
169 : mString(allocFromUTF8(o, strlen(o)))
170{
171 if (mString == NULL) {
172 mString = getEmptyString();
173 }
174}
175
176String8::String8(const char* o, size_t len)
177 : mString(allocFromUTF8(o, len))
178{
179 if (mString == NULL) {
180 mString = getEmptyString();
181 }
182}
183
184String8::String8(const String16& o)
185 : mString(allocFromUTF16(o.string(), o.size()))
186{
187}
188
189String8::String8(const char16_t* o)
190 : mString(allocFromUTF16(o, strlen16(o)))
191{
192}
193
194String8::String8(const char16_t* o, size_t len)
195 : mString(allocFromUTF16(o, len))
196{
197}
198
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900199String8::String8(const char32_t* o)
200 : mString(allocFromUTF32(o, strlen32(o)))
201{
202}
203
204String8::String8(const char32_t* o, size_t len)
205 : mString(allocFromUTF32(o, len))
206{
207}
208
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800209String8::~String8()
210{
211 SharedBuffer::bufferFromData(mString)->release();
212}
213
Jeff Brown1d618d62010-12-02 13:50:46 -0800214String8 String8::format(const char* fmt, ...)
215{
216 va_list args;
217 va_start(args, fmt);
218
219 String8 result(formatV(fmt, args));
220
221 va_end(args);
222 return result;
223}
224
225String8 String8::formatV(const char* fmt, va_list args)
226{
227 String8 result;
228 result.appendFormatV(fmt, args);
229 return result;
230}
231
Jeff Brown48da31b2010-09-12 17:55:08 -0700232void String8::clear() {
233 SharedBuffer::bufferFromData(mString)->release();
234 mString = getEmptyString();
235}
236
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800237void String8::setTo(const String8& other)
238{
239 SharedBuffer::bufferFromData(other.mString)->acquire();
240 SharedBuffer::bufferFromData(mString)->release();
241 mString = other.mString;
242}
243
244status_t String8::setTo(const char* other)
245{
Andreas Huber10e5da52010-06-10 11:14:26 -0700246 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800247 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700248 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800249 if (mString) return NO_ERROR;
250
251 mString = getEmptyString();
252 return NO_MEMORY;
253}
254
255status_t String8::setTo(const char* other, size_t len)
256{
Andreas Huber10e5da52010-06-10 11:14:26 -0700257 const char *newString = allocFromUTF8(other, len);
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 char16_t* other, size_t len)
267{
Andreas Huber10e5da52010-06-10 11:14:26 -0700268 const char *newString = allocFromUTF16(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
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900277status_t String8::setTo(const char32_t* other, size_t len)
278{
Andreas Huber10e5da52010-06-10 11:14:26 -0700279 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900280 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700281 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900282 if (mString) return NO_ERROR;
283
284 mString = getEmptyString();
285 return NO_MEMORY;
286}
287
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800288status_t String8::append(const String8& other)
289{
290 const size_t otherLen = other.bytes();
291 if (bytes() == 0) {
292 setTo(other);
293 return NO_ERROR;
294 } else if (otherLen == 0) {
295 return NO_ERROR;
296 }
297
298 return real_append(other.string(), otherLen);
299}
300
301status_t String8::append(const char* other)
302{
303 return append(other, strlen(other));
304}
305
306status_t String8::append(const char* other, size_t otherLen)
307{
308 if (bytes() == 0) {
309 return setTo(other, otherLen);
310 } else if (otherLen == 0) {
311 return NO_ERROR;
312 }
313
314 return real_append(other, otherLen);
315}
316
Jeff Brown35a154e2010-07-15 23:54:05 -0700317status_t String8::appendFormat(const char* fmt, ...)
318{
Jeff Brown647925d2010-11-10 16:03:06 -0800319 va_list args;
320 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700321
Jeff Brown647925d2010-11-10 16:03:06 -0800322 status_t result = appendFormatV(fmt, args);
323
324 va_end(args);
325 return result;
326}
327
328status_t String8::appendFormatV(const char* fmt, va_list args)
329{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800330 int n, result = NO_ERROR;
331 va_list tmp_args;
332
333 /* args is undefined after vsnprintf.
334 * So we need a copy here to avoid the
335 * second vsnprintf access undefined args.
336 */
337 va_copy(tmp_args, args);
338 n = vsnprintf(NULL, 0, fmt, tmp_args);
339 va_end(tmp_args);
340
Jeff Brown35a154e2010-07-15 23:54:05 -0700341 if (n != 0) {
342 size_t oldLength = length();
343 char* buf = lockBuffer(oldLength + n);
344 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800345 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700346 } else {
347 result = NO_MEMORY;
348 }
349 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700350 return result;
351}
352
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800353status_t String8::real_append(const char* other, size_t otherLen)
354{
355 const size_t myLen = bytes();
356
357 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
358 ->editResize(myLen+otherLen+1);
359 if (buf) {
360 char* str = (char*)buf->data();
361 mString = str;
362 str += myLen;
363 memcpy(str, other, otherLen);
364 str[otherLen] = '\0';
365 return NO_ERROR;
366 }
367 return NO_MEMORY;
368}
369
370char* String8::lockBuffer(size_t size)
371{
372 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
373 ->editResize(size+1);
374 if (buf) {
375 char* str = (char*)buf->data();
376 mString = str;
377 return str;
378 }
379 return NULL;
380}
381
382void String8::unlockBuffer()
383{
384 unlockBuffer(strlen(mString));
385}
386
387status_t String8::unlockBuffer(size_t size)
388{
389 if (size != this->size()) {
390 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
391 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700392 if (! buf) {
393 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800394 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700395
396 char* str = (char*)buf->data();
397 str[size] = 0;
398 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800399 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700400
401 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800402}
403
404ssize_t String8::find(const char* other, size_t start) const
405{
406 size_t len = size();
407 if (start >= len) {
408 return -1;
409 }
410 const char* s = mString+start;
411 const char* p = strstr(s, other);
412 return p ? p-mString : -1;
413}
414
Jeff Brown5ee915a2014-06-06 19:30:15 -0700415bool String8::removeAll(const char* other) {
416 ssize_t index = find(other);
417 if (index < 0) return false;
418
419 char* buf = lockBuffer(size());
420 if (!buf) return false; // out of memory
421
422 size_t skip = strlen(other);
423 size_t len = size();
424 size_t tail = index;
425 while (size_t(index) < len) {
426 ssize_t next = find(other, index + skip);
427 if (next < 0) {
428 next = len;
429 }
430
Andreas Gampedd060f02014-11-13 15:50:17 -0800431 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700432 tail += next - index - skip;
433 index = next;
434 }
435 unlockBuffer(tail);
436 return true;
437}
438
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800439void String8::toLower()
440{
441 toLower(0, size());
442}
443
444void String8::toLower(size_t start, size_t length)
445{
446 const size_t len = size();
447 if (start >= len) {
448 return;
449 }
450 if (start+length > len) {
451 length = len-start;
452 }
453 char* buf = lockBuffer(len);
454 buf += start;
455 while (length > 0) {
456 *buf = tolower(*buf);
457 buf++;
458 length--;
459 }
460 unlockBuffer(len);
461}
462
463void String8::toUpper()
464{
465 toUpper(0, size());
466}
467
468void String8::toUpper(size_t start, size_t length)
469{
470 const size_t len = size();
471 if (start >= len) {
472 return;
473 }
474 if (start+length > len) {
475 length = len-start;
476 }
477 char* buf = lockBuffer(len);
478 buf += start;
479 while (length > 0) {
480 *buf = toupper(*buf);
481 buf++;
482 length--;
483 }
484 unlockBuffer(len);
485}
486
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900487size_t String8::getUtf32Length() const
488{
Kenny Rootba0165b2010-11-09 14:37:23 -0800489 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900490}
491
492int32_t String8::getUtf32At(size_t index, size_t *next_index) const
493{
Kenny Rootba0165b2010-11-09 14:37:23 -0800494 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900495}
496
Kenny Rootba0165b2010-11-09 14:37:23 -0800497void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900498{
Kenny Rootba0165b2010-11-09 14:37:23 -0800499 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900500}
501
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800502// ---------------------------------------------------------------------------
503// Path functions
504
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800505void String8::setPathName(const char* name)
506{
507 setPathName(name, strlen(name));
508}
509
510void String8::setPathName(const char* name, size_t len)
511{
512 char* buf = lockBuffer(len);
513
514 memcpy(buf, name, len);
515
516 // remove trailing path separator, if present
517 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
518 len--;
519
520 buf[len] = '\0';
521
522 unlockBuffer(len);
523}
524
525String8 String8::getPathLeaf(void) const
526{
527 const char* cp;
528 const char*const buf = mString;
529
530 cp = strrchr(buf, OS_PATH_SEPARATOR);
531 if (cp == NULL)
532 return String8(*this);
533 else
534 return String8(cp+1);
535}
536
537String8 String8::getPathDir(void) const
538{
539 const char* cp;
540 const char*const str = mString;
541
542 cp = strrchr(str, OS_PATH_SEPARATOR);
543 if (cp == NULL)
544 return String8("");
545 else
546 return String8(str, cp - str);
547}
548
549String8 String8::walkPath(String8* outRemains) const
550{
551 const char* cp;
552 const char*const str = mString;
553 const char* buf = str;
554
555 cp = strchr(buf, OS_PATH_SEPARATOR);
556 if (cp == buf) {
557 // don't include a leading '/'.
558 buf = buf+1;
559 cp = strchr(buf, OS_PATH_SEPARATOR);
560 }
561
562 if (cp == NULL) {
563 String8 res = buf != str ? String8(buf) : *this;
564 if (outRemains) *outRemains = String8("");
565 return res;
566 }
567
568 String8 res(buf, cp-buf);
569 if (outRemains) *outRemains = String8(cp+1);
570 return res;
571}
572
573/*
574 * Helper function for finding the start of an extension in a pathname.
575 *
576 * Returns a pointer inside mString, or NULL if no extension was found.
577 */
578char* String8::find_extension(void) const
579{
580 const char* lastSlash;
581 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800582 const char* const str = mString;
583
584 // only look at the filename
585 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
586 if (lastSlash == NULL)
587 lastSlash = str;
588 else
589 lastSlash++;
590
591 // find the last dot
592 lastDot = strrchr(lastSlash, '.');
593 if (lastDot == NULL)
594 return NULL;
595
596 // looks good, ship it
597 return const_cast<char*>(lastDot);
598}
599
600String8 String8::getPathExtension(void) const
601{
602 char* ext;
603
604 ext = find_extension();
605 if (ext != NULL)
606 return String8(ext);
607 else
608 return String8("");
609}
610
611String8 String8::getBasePath(void) const
612{
613 char* ext;
614 const char* const str = mString;
615
616 ext = find_extension();
617 if (ext == NULL)
618 return String8(*this);
619 else
620 return String8(str, ext - str);
621}
622
623String8& String8::appendPath(const char* name)
624{
625 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
626 if (name[0] != OS_PATH_SEPARATOR) {
627 if (*name == '\0') {
628 // nothing to do
629 return *this;
630 }
631
632 size_t len = length();
633 if (len == 0) {
634 // no existing filename, just use the new one
635 setPathName(name);
636 return *this;
637 }
638
639 // make room for oldPath + '/' + newPath
640 int newlen = strlen(name);
641
642 char* buf = lockBuffer(len+1+newlen);
643
644 // insert a '/' if needed
645 if (buf[len-1] != OS_PATH_SEPARATOR)
646 buf[len++] = OS_PATH_SEPARATOR;
647
648 memcpy(buf+len, name, newlen+1);
649 len += newlen;
650
651 unlockBuffer(len);
652
653 return *this;
654 } else {
655 setPathName(name);
656 return *this;
657 }
658}
659
660String8& String8::convertToResPath()
661{
662#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
663 size_t len = length();
664 if (len > 0) {
665 char * buf = lockBuffer(len);
666 for (char * end = buf + len; buf < end; ++buf) {
667 if (*buf == OS_PATH_SEPARATOR)
668 *buf = RES_PATH_SEPARATOR;
669 }
670 unlockBuffer(len);
671 }
672#endif
673 return *this;
674}
675
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800676}; // namespace android