blob: bb068256b0526c11b4b0a416b93f0520abf5bbb6 [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
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 Giro5b85b1d2015-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
Kenny Rootba0165b2010-11-09 14:37:23 -0800105 const ssize_t bytes = utf16_to_utf8_length(in, len);
106 if (bytes < 0) {
107 return getEmptyString();
108 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800109
110 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
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
Kenny Rootba0165b2010-11-09 14:37:23 -0800116 char* str = (char*)buf->data();
117 utf16_to_utf8(in, len, str);
118 return str;
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
127 const ssize_t bytes = utf32_to_utf8_length(in, len);
128 if (bytes < 0) {
129 return getEmptyString();
130 }
131
132 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
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
138 char* str = (char*) buf->data();
139 utf32_to_utf8(in, len, str);
140
141 return str;
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{
Jeff Brown35a154e2010-07-15 23:54:05 -0700332 int result = NO_ERROR;
Jeff Brown647925d2010-11-10 16:03:06 -0800333 int n = vsnprintf(NULL, 0, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700334 if (n != 0) {
335 size_t oldLength = length();
336 char* buf = lockBuffer(oldLength + n);
337 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800338 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700339 } else {
340 result = NO_MEMORY;
341 }
342 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700343 return result;
344}
345
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800346status_t String8::real_append(const char* other, size_t otherLen)
347{
348 const size_t myLen = bytes();
349
350 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
351 ->editResize(myLen+otherLen+1);
352 if (buf) {
353 char* str = (char*)buf->data();
354 mString = str;
355 str += myLen;
356 memcpy(str, other, otherLen);
357 str[otherLen] = '\0';
358 return NO_ERROR;
359 }
360 return NO_MEMORY;
361}
362
363char* String8::lockBuffer(size_t size)
364{
365 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
366 ->editResize(size+1);
367 if (buf) {
368 char* str = (char*)buf->data();
369 mString = str;
370 return str;
371 }
372 return NULL;
373}
374
375void String8::unlockBuffer()
376{
377 unlockBuffer(strlen(mString));
378}
379
380status_t String8::unlockBuffer(size_t size)
381{
382 if (size != this->size()) {
383 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
384 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700385 if (! buf) {
386 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800387 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700388
389 char* str = (char*)buf->data();
390 str[size] = 0;
391 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800392 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700393
394 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800395}
396
397ssize_t String8::find(const char* other, size_t start) const
398{
399 size_t len = size();
400 if (start >= len) {
401 return -1;
402 }
403 const char* s = mString+start;
404 const char* p = strstr(s, other);
405 return p ? p-mString : -1;
406}
407
408void String8::toLower()
409{
410 toLower(0, size());
411}
412
413void String8::toLower(size_t start, size_t length)
414{
415 const size_t len = size();
416 if (start >= len) {
417 return;
418 }
419 if (start+length > len) {
420 length = len-start;
421 }
422 char* buf = lockBuffer(len);
423 buf += start;
424 while (length > 0) {
425 *buf = tolower(*buf);
426 buf++;
427 length--;
428 }
429 unlockBuffer(len);
430}
431
432void String8::toUpper()
433{
434 toUpper(0, size());
435}
436
437void String8::toUpper(size_t start, size_t length)
438{
439 const size_t len = size();
440 if (start >= len) {
441 return;
442 }
443 if (start+length > len) {
444 length = len-start;
445 }
446 char* buf = lockBuffer(len);
447 buf += start;
448 while (length > 0) {
449 *buf = toupper(*buf);
450 buf++;
451 length--;
452 }
453 unlockBuffer(len);
454}
455
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900456size_t String8::getUtf32Length() const
457{
Kenny Rootba0165b2010-11-09 14:37:23 -0800458 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900459}
460
461int32_t String8::getUtf32At(size_t index, size_t *next_index) const
462{
Kenny Rootba0165b2010-11-09 14:37:23 -0800463 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900464}
465
Kenny Rootba0165b2010-11-09 14:37:23 -0800466void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900467{
Kenny Rootba0165b2010-11-09 14:37:23 -0800468 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900469}
470
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800471// ---------------------------------------------------------------------------
472// Path functions
473
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800474void String8::setPathName(const char* name)
475{
476 setPathName(name, strlen(name));
477}
478
479void String8::setPathName(const char* name, size_t len)
480{
481 char* buf = lockBuffer(len);
482
483 memcpy(buf, name, len);
484
485 // remove trailing path separator, if present
486 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
487 len--;
488
489 buf[len] = '\0';
490
491 unlockBuffer(len);
492}
493
494String8 String8::getPathLeaf(void) const
495{
496 const char* cp;
497 const char*const buf = mString;
498
499 cp = strrchr(buf, OS_PATH_SEPARATOR);
500 if (cp == NULL)
501 return String8(*this);
502 else
503 return String8(cp+1);
504}
505
506String8 String8::getPathDir(void) const
507{
508 const char* cp;
509 const char*const str = mString;
510
511 cp = strrchr(str, OS_PATH_SEPARATOR);
512 if (cp == NULL)
513 return String8("");
514 else
515 return String8(str, cp - str);
516}
517
518String8 String8::walkPath(String8* outRemains) const
519{
520 const char* cp;
521 const char*const str = mString;
522 const char* buf = str;
523
524 cp = strchr(buf, OS_PATH_SEPARATOR);
525 if (cp == buf) {
526 // don't include a leading '/'.
527 buf = buf+1;
528 cp = strchr(buf, OS_PATH_SEPARATOR);
529 }
530
531 if (cp == NULL) {
532 String8 res = buf != str ? String8(buf) : *this;
533 if (outRemains) *outRemains = String8("");
534 return res;
535 }
536
537 String8 res(buf, cp-buf);
538 if (outRemains) *outRemains = String8(cp+1);
539 return res;
540}
541
542/*
543 * Helper function for finding the start of an extension in a pathname.
544 *
545 * Returns a pointer inside mString, or NULL if no extension was found.
546 */
547char* String8::find_extension(void) const
548{
549 const char* lastSlash;
550 const char* lastDot;
551 int extLen;
552 const char* const str = mString;
553
554 // only look at the filename
555 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
556 if (lastSlash == NULL)
557 lastSlash = str;
558 else
559 lastSlash++;
560
561 // find the last dot
562 lastDot = strrchr(lastSlash, '.');
563 if (lastDot == NULL)
564 return NULL;
565
566 // looks good, ship it
567 return const_cast<char*>(lastDot);
568}
569
570String8 String8::getPathExtension(void) const
571{
572 char* ext;
573
574 ext = find_extension();
575 if (ext != NULL)
576 return String8(ext);
577 else
578 return String8("");
579}
580
581String8 String8::getBasePath(void) const
582{
583 char* ext;
584 const char* const str = mString;
585
586 ext = find_extension();
587 if (ext == NULL)
588 return String8(*this);
589 else
590 return String8(str, ext - str);
591}
592
593String8& String8::appendPath(const char* name)
594{
595 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
596 if (name[0] != OS_PATH_SEPARATOR) {
597 if (*name == '\0') {
598 // nothing to do
599 return *this;
600 }
601
602 size_t len = length();
603 if (len == 0) {
604 // no existing filename, just use the new one
605 setPathName(name);
606 return *this;
607 }
608
609 // make room for oldPath + '/' + newPath
610 int newlen = strlen(name);
611
612 char* buf = lockBuffer(len+1+newlen);
613
614 // insert a '/' if needed
615 if (buf[len-1] != OS_PATH_SEPARATOR)
616 buf[len++] = OS_PATH_SEPARATOR;
617
618 memcpy(buf+len, name, newlen+1);
619 len += newlen;
620
621 unlockBuffer(len);
622
623 return *this;
624 } else {
625 setPathName(name);
626 return *this;
627 }
628}
629
630String8& String8::convertToResPath()
631{
632#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
633 size_t len = length();
634 if (len > 0) {
635 char * buf = lockBuffer(len);
636 for (char * end = buf + len; buf < end; ++buf) {
637 if (*buf == OS_PATH_SEPARATOR)
638 *buf = RES_PATH_SEPARATOR;
639 }
640 unlockBuffer(len);
641 }
642#endif
643 return *this;
644}
645
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800646}; // namespace android