blob: ffb317ddc110931c3771e327b1ecea0e395daedf [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 Aryaab860822015-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
22#include <utils/Log.h>
Kenny Rootba0165b2010-11-09 14:37:23 -080023#include <utils/Unicode.h>
24#include <utils/SharedBuffer.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
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090030/*
31 * Functions outside android is below the namespace android, since they use
32 * functions and constants in android namespace.
33 */
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080034
35// ---------------------------------------------------------------------------
36
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090037namespace android {
38
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080039// Separator used by resource paths. This is not platform dependent contrary
40// to OS_PATH_SEPARATOR.
41#define RES_PATH_SEPARATOR '/'
42
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080043static SharedBuffer* gEmptyStringBuf = NULL;
44static char* gEmptyString = NULL;
45
46extern int gDarwinCantLoadAllObjects;
47int gDarwinIsReallyAnnoying;
48
Mathias Agopian9eb2a3b2013-05-06 20:20:50 -070049void initialize_string8();
50
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080051static inline char* getEmptyString()
52{
53 gEmptyStringBuf->acquire();
54 return gEmptyString;
55}
56
57void initialize_string8()
58{
Dan Egnor88753ae2010-05-06 00:55:09 -070059 // HACK: This dummy dependency forces linking libutils Static.cpp,
60 // which is needed to initialize String8/String16 classes.
61 // These variables are named for Darwin, but are needed elsewhere too,
62 // including static linking on any platform.
63 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090064
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080065 SharedBuffer* buf = SharedBuffer::alloc(1);
66 char* str = (char*)buf->data();
67 *str = 0;
68 gEmptyStringBuf = buf;
69 gEmptyString = str;
70}
71
72void terminate_string8()
73{
74 SharedBuffer::bufferFromData(gEmptyString)->release();
75 gEmptyStringBuf = NULL;
76 gEmptyString = NULL;
77}
78
79// ---------------------------------------------------------------------------
80
81static char* allocFromUTF8(const char* in, size_t len)
82{
83 if (len > 0) {
Sergio Giro14535552015-08-18 14:44:54 +010084 if (len == SIZE_MAX) {
85 return NULL;
86 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080087 SharedBuffer* buf = SharedBuffer::alloc(len+1);
Steve Blockae074452012-01-09 18:35:44 +000088 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080089 if (buf) {
90 char* str = (char*)buf->data();
91 memcpy(str, in, len);
92 str[len] = 0;
93 return str;
94 }
95 return NULL;
96 }
97
98 return getEmptyString();
99}
100
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900101static char* allocFromUTF16(const char16_t* in, size_t len)
102{
Kenny Root9a2d83e2009-12-04 09:38:48 -0800103 if (len == 0) return getEmptyString();
104
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800105 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
106 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800107 return getEmptyString();
108 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800109
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800110 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000111 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800112 if (!buf) {
113 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800114 }
115
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800116 char* resultStr = (char*)buf->data();
117 utf16_to_utf8(in, len, resultStr, resultStrLen);
118 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900119}
120
121static char* allocFromUTF32(const char32_t* in, size_t len)
122{
Kenny Rootba0165b2010-11-09 14:37:23 -0800123 if (len == 0) {
124 return getEmptyString();
125 }
126
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800127 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
128 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800129 return getEmptyString();
130 }
131
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800132 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000133 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800134 if (!buf) {
135 return getEmptyString();
136 }
137
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800138 char* resultStr = (char*) buf->data();
139 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800140
Teow Wan Yeea9de2b92016-08-23 15:27:25 +0800141 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900142}
143
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800144// ---------------------------------------------------------------------------
145
146String8::String8()
147 : mString(getEmptyString())
148{
149}
150
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700151String8::String8(StaticLinkage)
152 : mString(0)
153{
154 // this constructor is used when we can't rely on the static-initializers
155 // having run. In this case we always allocate an empty string. It's less
156 // efficient than using getEmptyString(), but we assume it's uncommon.
157
158 char* data = static_cast<char*>(
159 SharedBuffer::alloc(sizeof(char))->data());
160 data[0] = 0;
161 mString = data;
162}
163
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800164String8::String8(const String8& o)
165 : mString(o.mString)
166{
167 SharedBuffer::bufferFromData(mString)->acquire();
168}
169
170String8::String8(const char* o)
171 : mString(allocFromUTF8(o, strlen(o)))
172{
173 if (mString == NULL) {
174 mString = getEmptyString();
175 }
176}
177
178String8::String8(const char* o, size_t len)
179 : mString(allocFromUTF8(o, len))
180{
181 if (mString == NULL) {
182 mString = getEmptyString();
183 }
184}
185
186String8::String8(const String16& o)
187 : mString(allocFromUTF16(o.string(), o.size()))
188{
189}
190
191String8::String8(const char16_t* o)
192 : mString(allocFromUTF16(o, strlen16(o)))
193{
194}
195
196String8::String8(const char16_t* o, size_t len)
197 : mString(allocFromUTF16(o, len))
198{
199}
200
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900201String8::String8(const char32_t* o)
202 : mString(allocFromUTF32(o, strlen32(o)))
203{
204}
205
206String8::String8(const char32_t* o, size_t len)
207 : mString(allocFromUTF32(o, len))
208{
209}
210
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800211String8::~String8()
212{
213 SharedBuffer::bufferFromData(mString)->release();
214}
215
Jeff Brown1d618d62010-12-02 13:50:46 -0800216String8 String8::format(const char* fmt, ...)
217{
218 va_list args;
219 va_start(args, fmt);
220
221 String8 result(formatV(fmt, args));
222
223 va_end(args);
224 return result;
225}
226
227String8 String8::formatV(const char* fmt, va_list args)
228{
229 String8 result;
230 result.appendFormatV(fmt, args);
231 return result;
232}
233
Jeff Brown48da31b2010-09-12 17:55:08 -0700234void String8::clear() {
235 SharedBuffer::bufferFromData(mString)->release();
236 mString = getEmptyString();
237}
238
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800239void String8::setTo(const String8& other)
240{
241 SharedBuffer::bufferFromData(other.mString)->acquire();
242 SharedBuffer::bufferFromData(mString)->release();
243 mString = other.mString;
244}
245
246status_t String8::setTo(const char* other)
247{
Andreas Huber10e5da52010-06-10 11:14:26 -0700248 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800249 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700250 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800251 if (mString) return NO_ERROR;
252
253 mString = getEmptyString();
254 return NO_MEMORY;
255}
256
257status_t String8::setTo(const char* other, size_t len)
258{
Andreas Huber10e5da52010-06-10 11:14:26 -0700259 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800260 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700261 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800262 if (mString) return NO_ERROR;
263
264 mString = getEmptyString();
265 return NO_MEMORY;
266}
267
268status_t String8::setTo(const char16_t* other, size_t len)
269{
Andreas Huber10e5da52010-06-10 11:14:26 -0700270 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800271 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700272 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800273 if (mString) return NO_ERROR;
274
275 mString = getEmptyString();
276 return NO_MEMORY;
277}
278
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900279status_t String8::setTo(const char32_t* other, size_t len)
280{
Andreas Huber10e5da52010-06-10 11:14:26 -0700281 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900282 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700283 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900284 if (mString) return NO_ERROR;
285
286 mString = getEmptyString();
287 return NO_MEMORY;
288}
289
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800290status_t String8::append(const String8& other)
291{
292 const size_t otherLen = other.bytes();
293 if (bytes() == 0) {
294 setTo(other);
295 return NO_ERROR;
296 } else if (otherLen == 0) {
297 return NO_ERROR;
298 }
299
300 return real_append(other.string(), otherLen);
301}
302
303status_t String8::append(const char* other)
304{
305 return append(other, strlen(other));
306}
307
308status_t String8::append(const char* other, size_t otherLen)
309{
310 if (bytes() == 0) {
311 return setTo(other, otherLen);
312 } else if (otherLen == 0) {
313 return NO_ERROR;
314 }
315
316 return real_append(other, otherLen);
317}
318
Jeff Brown35a154e2010-07-15 23:54:05 -0700319status_t String8::appendFormat(const char* fmt, ...)
320{
Jeff Brown647925d2010-11-10 16:03:06 -0800321 va_list args;
322 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700323
Jeff Brown647925d2010-11-10 16:03:06 -0800324 status_t result = appendFormatV(fmt, args);
325
326 va_end(args);
327 return result;
328}
329
330status_t String8::appendFormatV(const char* fmt, va_list args)
331{
Fengwei Yinfff9d112014-02-27 01:17:09 +0800332 int n, result = NO_ERROR;
333 va_list tmp_args;
334
335 /* args is undefined after vsnprintf.
336 * So we need a copy here to avoid the
337 * second vsnprintf access undefined args.
338 */
339 va_copy(tmp_args, args);
340 n = vsnprintf(NULL, 0, fmt, tmp_args);
341 va_end(tmp_args);
342
Jeff Brown35a154e2010-07-15 23:54:05 -0700343 if (n != 0) {
344 size_t oldLength = length();
345 char* buf = lockBuffer(oldLength + n);
346 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800347 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700348 } else {
349 result = NO_MEMORY;
350 }
351 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700352 return result;
353}
354
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800355status_t String8::real_append(const char* other, size_t otherLen)
356{
357 const size_t myLen = bytes();
358
359 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
360 ->editResize(myLen+otherLen+1);
361 if (buf) {
362 char* str = (char*)buf->data();
363 mString = str;
364 str += myLen;
365 memcpy(str, other, otherLen);
366 str[otherLen] = '\0';
367 return NO_ERROR;
368 }
369 return NO_MEMORY;
370}
371
372char* String8::lockBuffer(size_t size)
373{
374 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
375 ->editResize(size+1);
376 if (buf) {
377 char* str = (char*)buf->data();
378 mString = str;
379 return str;
380 }
381 return NULL;
382}
383
384void String8::unlockBuffer()
385{
386 unlockBuffer(strlen(mString));
387}
388
389status_t String8::unlockBuffer(size_t size)
390{
391 if (size != this->size()) {
392 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
393 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700394 if (! buf) {
395 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800396 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700397
398 char* str = (char*)buf->data();
399 str[size] = 0;
400 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800401 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700402
403 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800404}
405
406ssize_t String8::find(const char* other, size_t start) const
407{
408 size_t len = size();
409 if (start >= len) {
410 return -1;
411 }
412 const char* s = mString+start;
413 const char* p = strstr(s, other);
414 return p ? p-mString : -1;
415}
416
Jeff Brown5ee915a2014-06-06 19:30:15 -0700417bool String8::removeAll(const char* other) {
418 ssize_t index = find(other);
419 if (index < 0) return false;
420
421 char* buf = lockBuffer(size());
422 if (!buf) return false; // out of memory
423
424 size_t skip = strlen(other);
425 size_t len = size();
426 size_t tail = index;
427 while (size_t(index) < len) {
428 ssize_t next = find(other, index + skip);
429 if (next < 0) {
430 next = len;
431 }
432
Andreas Gampecefc1702014-11-13 15:50:17 -0800433 memmove(buf + tail, buf + index + skip, next - index - skip);
Jeff Brown5ee915a2014-06-06 19:30:15 -0700434 tail += next - index - skip;
435 index = next;
436 }
437 unlockBuffer(tail);
438 return true;
439}
440
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800441void String8::toLower()
442{
443 toLower(0, size());
444}
445
446void String8::toLower(size_t start, size_t length)
447{
448 const size_t len = size();
449 if (start >= len) {
450 return;
451 }
452 if (start+length > len) {
453 length = len-start;
454 }
455 char* buf = lockBuffer(len);
456 buf += start;
457 while (length > 0) {
458 *buf = tolower(*buf);
459 buf++;
460 length--;
461 }
462 unlockBuffer(len);
463}
464
465void String8::toUpper()
466{
467 toUpper(0, size());
468}
469
470void String8::toUpper(size_t start, size_t length)
471{
472 const size_t len = size();
473 if (start >= len) {
474 return;
475 }
476 if (start+length > len) {
477 length = len-start;
478 }
479 char* buf = lockBuffer(len);
480 buf += start;
481 while (length > 0) {
482 *buf = toupper(*buf);
483 buf++;
484 length--;
485 }
486 unlockBuffer(len);
487}
488
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900489size_t String8::getUtf32Length() const
490{
Kenny Rootba0165b2010-11-09 14:37:23 -0800491 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900492}
493
494int32_t String8::getUtf32At(size_t index, size_t *next_index) const
495{
Kenny Rootba0165b2010-11-09 14:37:23 -0800496 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900497}
498
Kenny Rootba0165b2010-11-09 14:37:23 -0800499void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900500{
Kenny Rootba0165b2010-11-09 14:37:23 -0800501 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900502}
503
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800504// ---------------------------------------------------------------------------
505// Path functions
506
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800507void String8::setPathName(const char* name)
508{
509 setPathName(name, strlen(name));
510}
511
512void String8::setPathName(const char* name, size_t len)
513{
514 char* buf = lockBuffer(len);
515
516 memcpy(buf, name, len);
517
518 // remove trailing path separator, if present
519 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
520 len--;
521
522 buf[len] = '\0';
523
524 unlockBuffer(len);
525}
526
527String8 String8::getPathLeaf(void) const
528{
529 const char* cp;
530 const char*const buf = mString;
531
532 cp = strrchr(buf, OS_PATH_SEPARATOR);
533 if (cp == NULL)
534 return String8(*this);
535 else
536 return String8(cp+1);
537}
538
539String8 String8::getPathDir(void) const
540{
541 const char* cp;
542 const char*const str = mString;
543
544 cp = strrchr(str, OS_PATH_SEPARATOR);
545 if (cp == NULL)
546 return String8("");
547 else
548 return String8(str, cp - str);
549}
550
551String8 String8::walkPath(String8* outRemains) const
552{
553 const char* cp;
554 const char*const str = mString;
555 const char* buf = str;
556
557 cp = strchr(buf, OS_PATH_SEPARATOR);
558 if (cp == buf) {
559 // don't include a leading '/'.
560 buf = buf+1;
561 cp = strchr(buf, OS_PATH_SEPARATOR);
562 }
563
564 if (cp == NULL) {
565 String8 res = buf != str ? String8(buf) : *this;
566 if (outRemains) *outRemains = String8("");
567 return res;
568 }
569
570 String8 res(buf, cp-buf);
571 if (outRemains) *outRemains = String8(cp+1);
572 return res;
573}
574
575/*
576 * Helper function for finding the start of an extension in a pathname.
577 *
578 * Returns a pointer inside mString, or NULL if no extension was found.
579 */
580char* String8::find_extension(void) const
581{
582 const char* lastSlash;
583 const char* lastDot;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800584 const char* const str = mString;
585
586 // only look at the filename
587 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
588 if (lastSlash == NULL)
589 lastSlash = str;
590 else
591 lastSlash++;
592
593 // find the last dot
594 lastDot = strrchr(lastSlash, '.');
595 if (lastDot == NULL)
596 return NULL;
597
598 // looks good, ship it
599 return const_cast<char*>(lastDot);
600}
601
602String8 String8::getPathExtension(void) const
603{
604 char* ext;
605
606 ext = find_extension();
607 if (ext != NULL)
608 return String8(ext);
609 else
610 return String8("");
611}
612
613String8 String8::getBasePath(void) const
614{
615 char* ext;
616 const char* const str = mString;
617
618 ext = find_extension();
619 if (ext == NULL)
620 return String8(*this);
621 else
622 return String8(str, ext - str);
623}
624
625String8& String8::appendPath(const char* name)
626{
627 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
628 if (name[0] != OS_PATH_SEPARATOR) {
629 if (*name == '\0') {
630 // nothing to do
631 return *this;
632 }
633
634 size_t len = length();
635 if (len == 0) {
636 // no existing filename, just use the new one
637 setPathName(name);
638 return *this;
639 }
640
641 // make room for oldPath + '/' + newPath
642 int newlen = strlen(name);
643
644 char* buf = lockBuffer(len+1+newlen);
645
646 // insert a '/' if needed
647 if (buf[len-1] != OS_PATH_SEPARATOR)
648 buf[len++] = OS_PATH_SEPARATOR;
649
650 memcpy(buf+len, name, newlen+1);
651 len += newlen;
652
653 unlockBuffer(len);
654
655 return *this;
656 } else {
657 setPathName(name);
658 return *this;
659 }
660}
661
662String8& String8::convertToResPath()
663{
664#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
665 size_t len = length();
666 if (len > 0) {
667 char * buf = lockBuffer(len);
668 for (char * end = buf + len; buf < end; ++buf) {
669 if (*buf == OS_PATH_SEPARATOR)
670 *buf = RES_PATH_SEPARATOR;
671 }
672 unlockBuffer(len);
673 }
674#endif
675 return *this;
676}
677
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800678}; // namespace android