blob: 0ac39f9190e9150d7bf84c3838388f7d0e77bc47 [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>
24#include <utils/String16.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080025
Sergio Girod2529f22015-09-23 16:22:59 +010026#include "SharedBuffer.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 Giroebabef22015-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
Sergio Giroc4966a32016-06-28 18:02:29 +0100103 // Allow for closing '\0'
104 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
105 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800106 return getEmptyString();
107 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800108
Sergio Giroc4966a32016-06-28 18:02:29 +0100109 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
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
Sergio Giroc4966a32016-06-28 18:02:29 +0100115 char* resultStr = (char*)buf->data();
116 utf16_to_utf8(in, len, resultStr, resultStrLen);
117 return resultStr;
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
Sergio Giroc4966a32016-06-28 18:02:29 +0100126 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
127 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800128 return getEmptyString();
129 }
130
Sergio Giroc4966a32016-06-28 18:02:29 +0100131 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
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
Sergio Giroc4966a32016-06-28 18:02:29 +0100137 char* resultStr = (char*) buf->data();
138 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800139
Sergio Giroc4966a32016-06-28 18:02:29 +0100140 return resultStr;
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
Jeff Brown1d618d62010-12-02 13:50:46 -0800220String8 String8::format(const char* fmt, ...)
221{
222 va_list args;
223 va_start(args, fmt);
224
225 String8 result(formatV(fmt, args));
226
227 va_end(args);
228 return result;
229}
230
231String8 String8::formatV(const char* fmt, va_list args)
232{
233 String8 result;
234 result.appendFormatV(fmt, args);
235 return result;
236}
237
Jeff Brown48da31b2010-09-12 17:55:08 -0700238void String8::clear() {
239 SharedBuffer::bufferFromData(mString)->release();
240 mString = getEmptyString();
241}
242
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800243void String8::setTo(const String8& other)
244{
245 SharedBuffer::bufferFromData(other.mString)->acquire();
246 SharedBuffer::bufferFromData(mString)->release();
247 mString = other.mString;
248}
249
250status_t String8::setTo(const char* other)
251{
Andreas Huber10e5da52010-06-10 11:14:26 -0700252 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800253 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700254 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800255 if (mString) return NO_ERROR;
256
257 mString = getEmptyString();
258 return NO_MEMORY;
259}
260
261status_t String8::setTo(const char* other, size_t len)
262{
Andreas Huber10e5da52010-06-10 11:14:26 -0700263 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800264 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700265 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800266 if (mString) return NO_ERROR;
267
268 mString = getEmptyString();
269 return NO_MEMORY;
270}
271
272status_t String8::setTo(const char16_t* other, size_t len)
273{
Andreas Huber10e5da52010-06-10 11:14:26 -0700274 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800275 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700276 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800277 if (mString) return NO_ERROR;
278
279 mString = getEmptyString();
280 return NO_MEMORY;
281}
282
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900283status_t String8::setTo(const char32_t* other, size_t len)
284{
Andreas Huber10e5da52010-06-10 11:14:26 -0700285 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900286 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700287 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900288 if (mString) return NO_ERROR;
289
290 mString = getEmptyString();
291 return NO_MEMORY;
292}
293
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800294status_t String8::append(const String8& other)
295{
296 const size_t otherLen = other.bytes();
297 if (bytes() == 0) {
298 setTo(other);
299 return NO_ERROR;
300 } else if (otherLen == 0) {
301 return NO_ERROR;
302 }
303
304 return real_append(other.string(), otherLen);
305}
306
307status_t String8::append(const char* other)
308{
309 return append(other, strlen(other));
310}
311
312status_t String8::append(const char* other, size_t otherLen)
313{
314 if (bytes() == 0) {
315 return setTo(other, otherLen);
316 } else if (otherLen == 0) {
317 return NO_ERROR;
318 }
319
320 return real_append(other, otherLen);
321}
322
Jeff Brown35a154e2010-07-15 23:54:05 -0700323status_t String8::appendFormat(const char* fmt, ...)
324{
Jeff Brown647925d2010-11-10 16:03:06 -0800325 va_list args;
326 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700327
Jeff Brown647925d2010-11-10 16:03:06 -0800328 status_t result = appendFormatV(fmt, args);
329
330 va_end(args);
331 return result;
332}
333
334status_t String8::appendFormatV(const char* fmt, va_list args)
335{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800336 int n, result = NO_ERROR;
337 va_list tmp_args;
338
339 /* args is undefined after vsnprintf.
340 * So we need a copy here to avoid the
341 * second vsnprintf access undefined args.
342 */
343 va_copy(tmp_args, args);
344 n = vsnprintf(NULL, 0, fmt, tmp_args);
345 va_end(tmp_args);
346
Jeff Brown35a154e2010-07-15 23:54:05 -0700347 if (n != 0) {
348 size_t oldLength = length();
349 char* buf = lockBuffer(oldLength + n);
350 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800351 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700352 } else {
353 result = NO_MEMORY;
354 }
355 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700356 return result;
357}
358
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800359status_t String8::real_append(const char* other, size_t otherLen)
360{
361 const size_t myLen = bytes();
Samuel Tan95fd5272016-02-18 16:56:21 -0800362
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800363 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
364 ->editResize(myLen+otherLen+1);
365 if (buf) {
366 char* str = (char*)buf->data();
367 mString = str;
368 str += myLen;
369 memcpy(str, other, otherLen);
370 str[otherLen] = '\0';
371 return NO_ERROR;
372 }
373 return NO_MEMORY;
374}
375
376char* String8::lockBuffer(size_t size)
377{
378 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
379 ->editResize(size+1);
380 if (buf) {
381 char* str = (char*)buf->data();
382 mString = str;
383 return str;
384 }
385 return NULL;
386}
387
388void String8::unlockBuffer()
389{
390 unlockBuffer(strlen(mString));
391}
392
393status_t String8::unlockBuffer(size_t size)
394{
395 if (size != this->size()) {
396 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
397 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700398 if (! buf) {
399 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800400 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700401
402 char* str = (char*)buf->data();
403 str[size] = 0;
404 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800405 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700406
407 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800408}
409
410ssize_t String8::find(const char* other, size_t start) const
411{
412 size_t len = size();
413 if (start >= len) {
414 return -1;
415 }
416 const char* s = mString+start;
417 const char* p = strstr(s, other);
418 return p ? p-mString : -1;
419}
420
Jeff Brown5ee915a2014-06-06 19:30:15 -0700421bool String8::removeAll(const char* other) {
422 ssize_t index = find(other);
423 if (index < 0) return false;
424
425 char* buf = lockBuffer(size());
426 if (!buf) return false; // out of memory
427
428 size_t skip = strlen(other);
429 size_t len = size();
430 size_t tail = index;
431 while (size_t(index) < len) {
432 ssize_t next = find(other, index + skip);
433 if (next < 0) {
434 next = len;
435 }
436
Andreas Gampedd060f02014-11-13 15:50:17 -0800437 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700438 tail += next - index - skip;
439 index = next;
440 }
441 unlockBuffer(tail);
442 return true;
443}
444
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800445void String8::toLower()
446{
447 toLower(0, size());
448}
449
450void String8::toLower(size_t start, size_t length)
451{
452 const size_t len = size();
453 if (start >= len) {
454 return;
455 }
456 if (start+length > len) {
457 length = len-start;
458 }
459 char* buf = lockBuffer(len);
460 buf += start;
461 while (length > 0) {
462 *buf = tolower(*buf);
463 buf++;
464 length--;
465 }
466 unlockBuffer(len);
467}
468
469void String8::toUpper()
470{
471 toUpper(0, size());
472}
473
474void String8::toUpper(size_t start, size_t length)
475{
476 const size_t len = size();
477 if (start >= len) {
478 return;
479 }
480 if (start+length > len) {
481 length = len-start;
482 }
483 char* buf = lockBuffer(len);
484 buf += start;
485 while (length > 0) {
486 *buf = toupper(*buf);
487 buf++;
488 length--;
489 }
490 unlockBuffer(len);
491}
492
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900493size_t String8::getUtf32Length() const
494{
Kenny Rootba0165b2010-11-09 14:37:23 -0800495 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900496}
497
498int32_t String8::getUtf32At(size_t index, size_t *next_index) const
499{
Kenny Rootba0165b2010-11-09 14:37:23 -0800500 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900501}
502
Kenny Rootba0165b2010-11-09 14:37:23 -0800503void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900504{
Kenny Rootba0165b2010-11-09 14:37:23 -0800505 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900506}
507
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800508// ---------------------------------------------------------------------------
509// Path functions
510
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800511void String8::setPathName(const char* name)
512{
513 setPathName(name, strlen(name));
514}
515
516void String8::setPathName(const char* name, size_t len)
517{
518 char* buf = lockBuffer(len);
519
520 memcpy(buf, name, len);
521
522 // remove trailing path separator, if present
523 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
524 len--;
525
526 buf[len] = '\0';
527
528 unlockBuffer(len);
529}
530
531String8 String8::getPathLeaf(void) const
532{
533 const char* cp;
534 const char*const buf = mString;
535
536 cp = strrchr(buf, OS_PATH_SEPARATOR);
537 if (cp == NULL)
538 return String8(*this);
539 else
540 return String8(cp+1);
541}
542
543String8 String8::getPathDir(void) const
544{
545 const char* cp;
546 const char*const str = mString;
547
548 cp = strrchr(str, OS_PATH_SEPARATOR);
549 if (cp == NULL)
550 return String8("");
551 else
552 return String8(str, cp - str);
553}
554
555String8 String8::walkPath(String8* outRemains) const
556{
557 const char* cp;
558 const char*const str = mString;
559 const char* buf = str;
560
561 cp = strchr(buf, OS_PATH_SEPARATOR);
562 if (cp == buf) {
563 // don't include a leading '/'.
564 buf = buf+1;
565 cp = strchr(buf, OS_PATH_SEPARATOR);
566 }
567
568 if (cp == NULL) {
569 String8 res = buf != str ? String8(buf) : *this;
570 if (outRemains) *outRemains = String8("");
571 return res;
572 }
573
574 String8 res(buf, cp-buf);
575 if (outRemains) *outRemains = String8(cp+1);
576 return res;
577}
578
579/*
580 * Helper function for finding the start of an extension in a pathname.
581 *
582 * Returns a pointer inside mString, or NULL if no extension was found.
583 */
584char* String8::find_extension(void) const
585{
586 const char* lastSlash;
587 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800588 const char* const str = mString;
589
590 // only look at the filename
591 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
592 if (lastSlash == NULL)
593 lastSlash = str;
594 else
595 lastSlash++;
596
597 // find the last dot
598 lastDot = strrchr(lastSlash, '.');
599 if (lastDot == NULL)
600 return NULL;
601
602 // looks good, ship it
603 return const_cast<char*>(lastDot);
604}
605
606String8 String8::getPathExtension(void) const
607{
608 char* ext;
609
610 ext = find_extension();
611 if (ext != NULL)
612 return String8(ext);
613 else
614 return String8("");
615}
616
617String8 String8::getBasePath(void) const
618{
619 char* ext;
620 const char* const str = mString;
621
622 ext = find_extension();
623 if (ext == NULL)
624 return String8(*this);
625 else
626 return String8(str, ext - str);
627}
628
629String8& String8::appendPath(const char* name)
630{
631 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
632 if (name[0] != OS_PATH_SEPARATOR) {
633 if (*name == '\0') {
634 // nothing to do
635 return *this;
636 }
637
638 size_t len = length();
639 if (len == 0) {
640 // no existing filename, just use the new one
641 setPathName(name);
642 return *this;
643 }
644
645 // make room for oldPath + '/' + newPath
646 int newlen = strlen(name);
647
648 char* buf = lockBuffer(len+1+newlen);
649
650 // insert a '/' if needed
651 if (buf[len-1] != OS_PATH_SEPARATOR)
652 buf[len++] = OS_PATH_SEPARATOR;
653
654 memcpy(buf+len, name, newlen+1);
655 len += newlen;
656
657 unlockBuffer(len);
658
659 return *this;
660 } else {
661 setPathName(name);
662 return *this;
663 }
664}
665
666String8& String8::convertToResPath()
667{
668#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
669 size_t len = length();
670 if (len > 0) {
671 char * buf = lockBuffer(len);
672 for (char * end = buf + len; buf < end; ++buf) {
673 if (*buf == OS_PATH_SEPARATOR)
674 *buf = RES_PATH_SEPARATOR;
675 }
676 unlockBuffer(len);
677 }
678#endif
679 return *this;
680}
681
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800682}; // namespace android