blob: 14966023121f840b20cb3a327e589e69eda78f0b [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>
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
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090027/*
28 * Functions outside android is below the namespace android, since they use
29 * functions and constants in android namespace.
30 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080031
32// ---------------------------------------------------------------------------
33
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090034namespace android {
35
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080036// Separator used by resource paths. This is not platform dependent contrary
37// to OS_PATH_SEPARATOR.
38#define RES_PATH_SEPARATOR '/'
39
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080040static SharedBuffer* gEmptyStringBuf = NULL;
41static char* gEmptyString = NULL;
42
43extern int gDarwinCantLoadAllObjects;
44int gDarwinIsReallyAnnoying;
45
Mathias Agopian9eb2a3b2013-05-06 20:20:50 -070046void initialize_string8();
47
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080048static inline char* getEmptyString()
49{
50 gEmptyStringBuf->acquire();
51 return gEmptyString;
52}
53
54void initialize_string8()
55{
Dan Egnor88753ae2010-05-06 00:55:09 -070056 // HACK: This dummy dependency forces linking libutils Static.cpp,
57 // which is needed to initialize String8/String16 classes.
58 // These variables are named for Darwin, but are needed elsewhere too,
59 // including static linking on any platform.
60 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090061
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080062 SharedBuffer* buf = SharedBuffer::alloc(1);
63 char* str = (char*)buf->data();
64 *str = 0;
65 gEmptyStringBuf = buf;
66 gEmptyString = str;
67}
68
69void terminate_string8()
70{
71 SharedBuffer::bufferFromData(gEmptyString)->release();
72 gEmptyStringBuf = NULL;
73 gEmptyString = NULL;
74}
75
76// ---------------------------------------------------------------------------
77
78static char* allocFromUTF8(const char* in, size_t len)
79{
80 if (len > 0) {
Sergio Giroebabef22015-08-18 14:44:54 +010081 if (len == SIZE_MAX) {
82 return NULL;
83 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080084 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000085 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080086 if (buf) {
87 char* str = (char*)buf->data();
88 memcpy(str, in, len);
89 str[len] = 0;
90 return str;
91 }
92 return NULL;
93 }
94
95 return getEmptyString();
96}
97
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090098static char* allocFromUTF16(const char16_t* in, size_t len)
99{
Kenny Root9a2d83e2009-12-04 09:38:48 -0800100 if (len == 0) return getEmptyString();
101
Kenny Rootba0165b2010-11-09 14:37:23 -0800102 const ssize_t bytes = utf16_to_utf8_length(in, len);
103 if (bytes < 0) {
104 return getEmptyString();
105 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800106
107 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000108 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800109 if (!buf) {
110 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800111 }
112
Kenny Rootba0165b2010-11-09 14:37:23 -0800113 char* str = (char*)buf->data();
114 utf16_to_utf8(in, len, str);
115 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900116}
117
118static char* allocFromUTF32(const char32_t* in, size_t len)
119{
Kenny Rootba0165b2010-11-09 14:37:23 -0800120 if (len == 0) {
121 return getEmptyString();
122 }
123
124 const ssize_t bytes = utf32_to_utf8_length(in, len);
125 if (bytes < 0) {
126 return getEmptyString();
127 }
128
129 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000130 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800131 if (!buf) {
132 return getEmptyString();
133 }
134
135 char* str = (char*) buf->data();
136 utf32_to_utf8(in, len, str);
137
138 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900139}
140
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800141// ---------------------------------------------------------------------------
142
143String8::String8()
144 : mString(getEmptyString())
145{
146}
147
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700148String8::String8(StaticLinkage)
149 : mString(0)
150{
151 // this constructor is used when we can't rely on the static-initializers
152 // having run. In this case we always allocate an empty string. It's less
153 // efficient than using getEmptyString(), but we assume it's uncommon.
154
155 char* data = static_cast<char*>(
156 SharedBuffer::alloc(sizeof(char))->data());
157 data[0] = 0;
158 mString = data;
159}
160
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800161String8::String8(const String8& o)
162 : mString(o.mString)
163{
164 SharedBuffer::bufferFromData(mString)->acquire();
165}
166
167String8::String8(const char* o)
168 : mString(allocFromUTF8(o, strlen(o)))
169{
170 if (mString == NULL) {
171 mString = getEmptyString();
172 }
173}
174
175String8::String8(const char* o, size_t len)
176 : mString(allocFromUTF8(o, len))
177{
178 if (mString == NULL) {
179 mString = getEmptyString();
180 }
181}
182
183String8::String8(const String16& o)
184 : mString(allocFromUTF16(o.string(), o.size()))
185{
186}
187
188String8::String8(const char16_t* o)
189 : mString(allocFromUTF16(o, strlen16(o)))
190{
191}
192
193String8::String8(const char16_t* o, size_t len)
194 : mString(allocFromUTF16(o, len))
195{
196}
197
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900198String8::String8(const char32_t* o)
199 : mString(allocFromUTF32(o, strlen32(o)))
200{
201}
202
203String8::String8(const char32_t* o, size_t len)
204 : mString(allocFromUTF32(o, len))
205{
206}
207
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800208String8::~String8()
209{
210 SharedBuffer::bufferFromData(mString)->release();
211}
212
Jeff Brown1d618d62010-12-02 13:50:46 -0800213String8 String8::format(const char* fmt, ...)
214{
215 va_list args;
216 va_start(args, fmt);
217
218 String8 result(formatV(fmt, args));
219
220 va_end(args);
221 return result;
222}
223
224String8 String8::formatV(const char* fmt, va_list args)
225{
226 String8 result;
227 result.appendFormatV(fmt, args);
228 return result;
229}
230
Jeff Brown48da31b2010-09-12 17:55:08 -0700231void String8::clear() {
232 SharedBuffer::bufferFromData(mString)->release();
233 mString = getEmptyString();
234}
235
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800236void String8::setTo(const String8& other)
237{
238 SharedBuffer::bufferFromData(other.mString)->acquire();
239 SharedBuffer::bufferFromData(mString)->release();
240 mString = other.mString;
241}
242
243status_t String8::setTo(const char* other)
244{
Andreas Huber10e5da52010-06-10 11:14:26 -0700245 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800246 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700247 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800248 if (mString) return NO_ERROR;
249
250 mString = getEmptyString();
251 return NO_MEMORY;
252}
253
254status_t String8::setTo(const char* other, size_t len)
255{
Andreas Huber10e5da52010-06-10 11:14:26 -0700256 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800257 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700258 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800259 if (mString) return NO_ERROR;
260
261 mString = getEmptyString();
262 return NO_MEMORY;
263}
264
265status_t String8::setTo(const char16_t* other, size_t len)
266{
Andreas Huber10e5da52010-06-10 11:14:26 -0700267 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800268 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700269 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800270 if (mString) return NO_ERROR;
271
272 mString = getEmptyString();
273 return NO_MEMORY;
274}
275
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900276status_t String8::setTo(const char32_t* other, size_t len)
277{
Andreas Huber10e5da52010-06-10 11:14:26 -0700278 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900279 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700280 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900281 if (mString) return NO_ERROR;
282
283 mString = getEmptyString();
284 return NO_MEMORY;
285}
286
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800287status_t String8::append(const String8& other)
288{
289 const size_t otherLen = other.bytes();
290 if (bytes() == 0) {
291 setTo(other);
292 return NO_ERROR;
293 } else if (otherLen == 0) {
294 return NO_ERROR;
295 }
296
297 return real_append(other.string(), otherLen);
298}
299
300status_t String8::append(const char* other)
301{
302 return append(other, strlen(other));
303}
304
305status_t String8::append(const char* other, size_t otherLen)
306{
307 if (bytes() == 0) {
308 return setTo(other, otherLen);
309 } else if (otherLen == 0) {
310 return NO_ERROR;
311 }
312
313 return real_append(other, otherLen);
314}
315
Jeff Brown35a154e2010-07-15 23:54:05 -0700316status_t String8::appendFormat(const char* fmt, ...)
317{
Jeff Brown647925d2010-11-10 16:03:06 -0800318 va_list args;
319 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700320
Jeff Brown647925d2010-11-10 16:03:06 -0800321 status_t result = appendFormatV(fmt, args);
322
323 va_end(args);
324 return result;
325}
326
327status_t String8::appendFormatV(const char* fmt, va_list args)
328{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800329 int n, result = NO_ERROR;
330 va_list tmp_args;
331
332 /* args is undefined after vsnprintf.
333 * So we need a copy here to avoid the
334 * second vsnprintf access undefined args.
335 */
336 va_copy(tmp_args, args);
337 n = vsnprintf(NULL, 0, fmt, tmp_args);
338 va_end(tmp_args);
339
Jeff Brown35a154e2010-07-15 23:54:05 -0700340 if (n != 0) {
341 size_t oldLength = length();
342 char* buf = lockBuffer(oldLength + n);
343 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800344 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700345 } else {
346 result = NO_MEMORY;
347 }
348 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700349 return result;
350}
351
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800352status_t String8::real_append(const char* other, size_t otherLen)
353{
354 const size_t myLen = bytes();
355
356 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
357 ->editResize(myLen+otherLen+1);
358 if (buf) {
359 char* str = (char*)buf->data();
360 mString = str;
361 str += myLen;
362 memcpy(str, other, otherLen);
363 str[otherLen] = '\0';
364 return NO_ERROR;
365 }
366 return NO_MEMORY;
367}
368
369char* String8::lockBuffer(size_t size)
370{
371 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
372 ->editResize(size+1);
373 if (buf) {
374 char* str = (char*)buf->data();
375 mString = str;
376 return str;
377 }
378 return NULL;
379}
380
381void String8::unlockBuffer()
382{
383 unlockBuffer(strlen(mString));
384}
385
386status_t String8::unlockBuffer(size_t size)
387{
388 if (size != this->size()) {
389 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
390 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700391 if (! buf) {
392 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800393 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700394
395 char* str = (char*)buf->data();
396 str[size] = 0;
397 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800398 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700399
400 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800401}
402
403ssize_t String8::find(const char* other, size_t start) const
404{
405 size_t len = size();
406 if (start >= len) {
407 return -1;
408 }
409 const char* s = mString+start;
410 const char* p = strstr(s, other);
411 return p ? p-mString : -1;
412}
413
Jeff Brown5ee915a2014-06-06 19:30:15 -0700414bool String8::removeAll(const char* other) {
415 ssize_t index = find(other);
416 if (index < 0) return false;
417
418 char* buf = lockBuffer(size());
419 if (!buf) return false; // out of memory
420
421 size_t skip = strlen(other);
422 size_t len = size();
423 size_t tail = index;
424 while (size_t(index) < len) {
425 ssize_t next = find(other, index + skip);
426 if (next < 0) {
427 next = len;
428 }
429
Andreas Gampedd060f02014-11-13 15:50:17 -0800430 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700431 tail += next - index - skip;
432 index = next;
433 }
434 unlockBuffer(tail);
435 return true;
436}
437
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800438void String8::toLower()
439{
440 toLower(0, size());
441}
442
443void String8::toLower(size_t start, size_t length)
444{
445 const size_t len = size();
446 if (start >= len) {
447 return;
448 }
449 if (start+length > len) {
450 length = len-start;
451 }
452 char* buf = lockBuffer(len);
453 buf += start;
454 while (length > 0) {
455 *buf = tolower(*buf);
456 buf++;
457 length--;
458 }
459 unlockBuffer(len);
460}
461
462void String8::toUpper()
463{
464 toUpper(0, size());
465}
466
467void String8::toUpper(size_t start, size_t length)
468{
469 const size_t len = size();
470 if (start >= len) {
471 return;
472 }
473 if (start+length > len) {
474 length = len-start;
475 }
476 char* buf = lockBuffer(len);
477 buf += start;
478 while (length > 0) {
479 *buf = toupper(*buf);
480 buf++;
481 length--;
482 }
483 unlockBuffer(len);
484}
485
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900486size_t String8::getUtf32Length() const
487{
Kenny Rootba0165b2010-11-09 14:37:23 -0800488 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900489}
490
491int32_t String8::getUtf32At(size_t index, size_t *next_index) const
492{
Kenny Rootba0165b2010-11-09 14:37:23 -0800493 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900494}
495
Kenny Rootba0165b2010-11-09 14:37:23 -0800496void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900497{
Kenny Rootba0165b2010-11-09 14:37:23 -0800498 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900499}
500
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800501// ---------------------------------------------------------------------------
502// Path functions
503
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800504void String8::setPathName(const char* name)
505{
506 setPathName(name, strlen(name));
507}
508
509void String8::setPathName(const char* name, size_t len)
510{
511 char* buf = lockBuffer(len);
512
513 memcpy(buf, name, len);
514
515 // remove trailing path separator, if present
516 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
517 len--;
518
519 buf[len] = '\0';
520
521 unlockBuffer(len);
522}
523
524String8 String8::getPathLeaf(void) const
525{
526 const char* cp;
527 const char*const buf = mString;
528
529 cp = strrchr(buf, OS_PATH_SEPARATOR);
530 if (cp == NULL)
531 return String8(*this);
532 else
533 return String8(cp+1);
534}
535
536String8 String8::getPathDir(void) const
537{
538 const char* cp;
539 const char*const str = mString;
540
541 cp = strrchr(str, OS_PATH_SEPARATOR);
542 if (cp == NULL)
543 return String8("");
544 else
545 return String8(str, cp - str);
546}
547
548String8 String8::walkPath(String8* outRemains) const
549{
550 const char* cp;
551 const char*const str = mString;
552 const char* buf = str;
553
554 cp = strchr(buf, OS_PATH_SEPARATOR);
555 if (cp == buf) {
556 // don't include a leading '/'.
557 buf = buf+1;
558 cp = strchr(buf, OS_PATH_SEPARATOR);
559 }
560
561 if (cp == NULL) {
562 String8 res = buf != str ? String8(buf) : *this;
563 if (outRemains) *outRemains = String8("");
564 return res;
565 }
566
567 String8 res(buf, cp-buf);
568 if (outRemains) *outRemains = String8(cp+1);
569 return res;
570}
571
572/*
573 * Helper function for finding the start of an extension in a pathname.
574 *
575 * Returns a pointer inside mString, or NULL if no extension was found.
576 */
577char* String8::find_extension(void) const
578{
579 const char* lastSlash;
580 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800581 const char* const str = mString;
582
583 // only look at the filename
584 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
585 if (lastSlash == NULL)
586 lastSlash = str;
587 else
588 lastSlash++;
589
590 // find the last dot
591 lastDot = strrchr(lastSlash, '.');
592 if (lastDot == NULL)
593 return NULL;
594
595 // looks good, ship it
596 return const_cast<char*>(lastDot);
597}
598
599String8 String8::getPathExtension(void) const
600{
601 char* ext;
602
603 ext = find_extension();
604 if (ext != NULL)
605 return String8(ext);
606 else
607 return String8("");
608}
609
610String8 String8::getBasePath(void) const
611{
612 char* ext;
613 const char* const str = mString;
614
615 ext = find_extension();
616 if (ext == NULL)
617 return String8(*this);
618 else
619 return String8(str, ext - str);
620}
621
622String8& String8::appendPath(const char* name)
623{
624 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
625 if (name[0] != OS_PATH_SEPARATOR) {
626 if (*name == '\0') {
627 // nothing to do
628 return *this;
629 }
630
631 size_t len = length();
632 if (len == 0) {
633 // no existing filename, just use the new one
634 setPathName(name);
635 return *this;
636 }
637
638 // make room for oldPath + '/' + newPath
639 int newlen = strlen(name);
640
641 char* buf = lockBuffer(len+1+newlen);
642
643 // insert a '/' if needed
644 if (buf[len-1] != OS_PATH_SEPARATOR)
645 buf[len++] = OS_PATH_SEPARATOR;
646
647 memcpy(buf+len, name, newlen+1);
648 len += newlen;
649
650 unlockBuffer(len);
651
652 return *this;
653 } else {
654 setPathName(name);
655 return *this;
656 }
657}
658
659String8& String8::convertToResPath()
660{
661#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
662 size_t len = length();
663 if (len > 0) {
664 char * buf = lockBuffer(len);
665 for (char * end = buf + len; buf < end; ++buf) {
666 if (*buf == OS_PATH_SEPARATOR)
667 *buf = RES_PATH_SEPARATOR;
668 }
669 unlockBuffer(len);
670 }
671#endif
672 return *this;
673}
674
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800675}; // namespace android