blob: cad401f7372154df141fff0aaa2b7f9396b02d84 [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
Sergio Giro53473c12016-06-28 18:02:29 +0100105 // Allow for closing '\0'
106 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
107 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800108 return getEmptyString();
109 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800110
Sergio Giro53473c12016-06-28 18:02:29 +0100111 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000112 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800113 if (!buf) {
114 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800115 }
116
Sergio Giro53473c12016-06-28 18:02:29 +0100117 char* resultStr = (char*)buf->data();
118 utf16_to_utf8(in, len, resultStr, resultStrLen);
119 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900120}
121
122static char* allocFromUTF32(const char32_t* in, size_t len)
123{
Kenny Rootba0165b2010-11-09 14:37:23 -0800124 if (len == 0) {
125 return getEmptyString();
126 }
127
Sergio Giro53473c12016-06-28 18:02:29 +0100128 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
129 if (resultStrLen < 1) {
Kenny Rootba0165b2010-11-09 14:37:23 -0800130 return getEmptyString();
131 }
132
Sergio Giro53473c12016-06-28 18:02:29 +0100133 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
Steve Blockae074452012-01-09 18:35:44 +0000134 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800135 if (!buf) {
136 return getEmptyString();
137 }
138
Sergio Giro53473c12016-06-28 18:02:29 +0100139 char* resultStr = (char*) buf->data();
140 utf32_to_utf8(in, len, resultStr, resultStrLen);
Kenny Rootba0165b2010-11-09 14:37:23 -0800141
Sergio Giro53473c12016-06-28 18:02:29 +0100142 return resultStr;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900143}
144
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800145// ---------------------------------------------------------------------------
146
147String8::String8()
148 : mString(getEmptyString())
149{
150}
151
Mathias Agopian4485d0d2013-05-08 16:04:13 -0700152String8::String8(StaticLinkage)
153 : mString(0)
154{
155 // this constructor is used when we can't rely on the static-initializers
156 // having run. In this case we always allocate an empty string. It's less
157 // efficient than using getEmptyString(), but we assume it's uncommon.
158
159 char* data = static_cast<char*>(
160 SharedBuffer::alloc(sizeof(char))->data());
161 data[0] = 0;
162 mString = data;
163}
164
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800165String8::String8(const String8& o)
166 : mString(o.mString)
167{
168 SharedBuffer::bufferFromData(mString)->acquire();
169}
170
171String8::String8(const char* o)
172 : mString(allocFromUTF8(o, strlen(o)))
173{
174 if (mString == NULL) {
175 mString = getEmptyString();
176 }
177}
178
179String8::String8(const char* o, size_t len)
180 : mString(allocFromUTF8(o, len))
181{
182 if (mString == NULL) {
183 mString = getEmptyString();
184 }
185}
186
187String8::String8(const String16& o)
188 : mString(allocFromUTF16(o.string(), o.size()))
189{
190}
191
192String8::String8(const char16_t* o)
193 : mString(allocFromUTF16(o, strlen16(o)))
194{
195}
196
197String8::String8(const char16_t* o, size_t len)
198 : mString(allocFromUTF16(o, len))
199{
200}
201
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900202String8::String8(const char32_t* o)
203 : mString(allocFromUTF32(o, strlen32(o)))
204{
205}
206
207String8::String8(const char32_t* o, size_t len)
208 : mString(allocFromUTF32(o, len))
209{
210}
211
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800212String8::~String8()
213{
214 SharedBuffer::bufferFromData(mString)->release();
215}
216
Jeff Brown1d618d62010-12-02 13:50:46 -0800217String8 String8::format(const char* fmt, ...)
218{
219 va_list args;
220 va_start(args, fmt);
221
222 String8 result(formatV(fmt, args));
223
224 va_end(args);
225 return result;
226}
227
228String8 String8::formatV(const char* fmt, va_list args)
229{
230 String8 result;
231 result.appendFormatV(fmt, args);
232 return result;
233}
234
Jeff Brown48da31b2010-09-12 17:55:08 -0700235void String8::clear() {
236 SharedBuffer::bufferFromData(mString)->release();
237 mString = getEmptyString();
238}
239
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800240void String8::setTo(const String8& other)
241{
242 SharedBuffer::bufferFromData(other.mString)->acquire();
243 SharedBuffer::bufferFromData(mString)->release();
244 mString = other.mString;
245}
246
247status_t String8::setTo(const char* other)
248{
Andreas Huber10e5da52010-06-10 11:14:26 -0700249 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800250 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700251 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800252 if (mString) return NO_ERROR;
253
254 mString = getEmptyString();
255 return NO_MEMORY;
256}
257
258status_t String8::setTo(const char* other, size_t len)
259{
Andreas Huber10e5da52010-06-10 11:14:26 -0700260 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800261 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700262 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800263 if (mString) return NO_ERROR;
264
265 mString = getEmptyString();
266 return NO_MEMORY;
267}
268
269status_t String8::setTo(const char16_t* other, size_t len)
270{
Andreas Huber10e5da52010-06-10 11:14:26 -0700271 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800272 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700273 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800274 if (mString) return NO_ERROR;
275
276 mString = getEmptyString();
277 return NO_MEMORY;
278}
279
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900280status_t String8::setTo(const char32_t* other, size_t len)
281{
Andreas Huber10e5da52010-06-10 11:14:26 -0700282 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900283 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700284 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900285 if (mString) return NO_ERROR;
286
287 mString = getEmptyString();
288 return NO_MEMORY;
289}
290
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800291status_t String8::append(const String8& other)
292{
293 const size_t otherLen = other.bytes();
294 if (bytes() == 0) {
295 setTo(other);
296 return NO_ERROR;
297 } else if (otherLen == 0) {
298 return NO_ERROR;
299 }
300
301 return real_append(other.string(), otherLen);
302}
303
304status_t String8::append(const char* other)
305{
306 return append(other, strlen(other));
307}
308
309status_t String8::append(const char* other, size_t otherLen)
310{
311 if (bytes() == 0) {
312 return setTo(other, otherLen);
313 } else if (otherLen == 0) {
314 return NO_ERROR;
315 }
316
317 return real_append(other, otherLen);
318}
319
Jeff Brown35a154e2010-07-15 23:54:05 -0700320status_t String8::appendFormat(const char* fmt, ...)
321{
Jeff Brown647925d2010-11-10 16:03:06 -0800322 va_list args;
323 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700324
Jeff Brown647925d2010-11-10 16:03:06 -0800325 status_t result = appendFormatV(fmt, args);
326
327 va_end(args);
328 return result;
329}
330
331status_t String8::appendFormatV(const char* fmt, va_list args)
332{
Jeff Brown35a154e2010-07-15 23:54:05 -0700333 int result = NO_ERROR;
Jeff Brown647925d2010-11-10 16:03:06 -0800334 int n = vsnprintf(NULL, 0, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700335 if (n != 0) {
336 size_t oldLength = length();
337 char* buf = lockBuffer(oldLength + n);
338 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800339 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700340 } else {
341 result = NO_MEMORY;
342 }
343 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700344 return result;
345}
346
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800347status_t String8::real_append(const char* other, size_t otherLen)
348{
349 const size_t myLen = bytes();
350
351 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
352 ->editResize(myLen+otherLen+1);
353 if (buf) {
354 char* str = (char*)buf->data();
355 mString = str;
356 str += myLen;
357 memcpy(str, other, otherLen);
358 str[otherLen] = '\0';
359 return NO_ERROR;
360 }
361 return NO_MEMORY;
362}
363
364char* String8::lockBuffer(size_t size)
365{
366 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
367 ->editResize(size+1);
368 if (buf) {
369 char* str = (char*)buf->data();
370 mString = str;
371 return str;
372 }
373 return NULL;
374}
375
376void String8::unlockBuffer()
377{
378 unlockBuffer(strlen(mString));
379}
380
381status_t String8::unlockBuffer(size_t size)
382{
383 if (size != this->size()) {
384 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
385 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700386 if (! buf) {
387 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800388 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700389
390 char* str = (char*)buf->data();
391 str[size] = 0;
392 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800393 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700394
395 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800396}
397
398ssize_t String8::find(const char* other, size_t start) const
399{
400 size_t len = size();
401 if (start >= len) {
402 return -1;
403 }
404 const char* s = mString+start;
405 const char* p = strstr(s, other);
406 return p ? p-mString : -1;
407}
408
409void String8::toLower()
410{
411 toLower(0, size());
412}
413
414void String8::toLower(size_t start, size_t length)
415{
416 const size_t len = size();
417 if (start >= len) {
418 return;
419 }
420 if (start+length > len) {
421 length = len-start;
422 }
423 char* buf = lockBuffer(len);
424 buf += start;
425 while (length > 0) {
426 *buf = tolower(*buf);
427 buf++;
428 length--;
429 }
430 unlockBuffer(len);
431}
432
433void String8::toUpper()
434{
435 toUpper(0, size());
436}
437
438void String8::toUpper(size_t start, size_t length)
439{
440 const size_t len = size();
441 if (start >= len) {
442 return;
443 }
444 if (start+length > len) {
445 length = len-start;
446 }
447 char* buf = lockBuffer(len);
448 buf += start;
449 while (length > 0) {
450 *buf = toupper(*buf);
451 buf++;
452 length--;
453 }
454 unlockBuffer(len);
455}
456
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900457size_t String8::getUtf32Length() const
458{
Kenny Rootba0165b2010-11-09 14:37:23 -0800459 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900460}
461
462int32_t String8::getUtf32At(size_t index, size_t *next_index) const
463{
Kenny Rootba0165b2010-11-09 14:37:23 -0800464 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900465}
466
Kenny Rootba0165b2010-11-09 14:37:23 -0800467void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900468{
Kenny Rootba0165b2010-11-09 14:37:23 -0800469 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900470}
471
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800472// ---------------------------------------------------------------------------
473// Path functions
474
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800475void String8::setPathName(const char* name)
476{
477 setPathName(name, strlen(name));
478}
479
480void String8::setPathName(const char* name, size_t len)
481{
482 char* buf = lockBuffer(len);
483
484 memcpy(buf, name, len);
485
486 // remove trailing path separator, if present
487 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
488 len--;
489
490 buf[len] = '\0';
491
492 unlockBuffer(len);
493}
494
495String8 String8::getPathLeaf(void) const
496{
497 const char* cp;
498 const char*const buf = mString;
499
500 cp = strrchr(buf, OS_PATH_SEPARATOR);
501 if (cp == NULL)
502 return String8(*this);
503 else
504 return String8(cp+1);
505}
506
507String8 String8::getPathDir(void) const
508{
509 const char* cp;
510 const char*const str = mString;
511
512 cp = strrchr(str, OS_PATH_SEPARATOR);
513 if (cp == NULL)
514 return String8("");
515 else
516 return String8(str, cp - str);
517}
518
519String8 String8::walkPath(String8* outRemains) const
520{
521 const char* cp;
522 const char*const str = mString;
523 const char* buf = str;
524
525 cp = strchr(buf, OS_PATH_SEPARATOR);
526 if (cp == buf) {
527 // don't include a leading '/'.
528 buf = buf+1;
529 cp = strchr(buf, OS_PATH_SEPARATOR);
530 }
531
532 if (cp == NULL) {
533 String8 res = buf != str ? String8(buf) : *this;
534 if (outRemains) *outRemains = String8("");
535 return res;
536 }
537
538 String8 res(buf, cp-buf);
539 if (outRemains) *outRemains = String8(cp+1);
540 return res;
541}
542
543/*
544 * Helper function for finding the start of an extension in a pathname.
545 *
546 * Returns a pointer inside mString, or NULL if no extension was found.
547 */
548char* String8::find_extension(void) const
549{
550 const char* lastSlash;
551 const char* lastDot;
552 int extLen;
553 const char* const str = mString;
554
555 // only look at the filename
556 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
557 if (lastSlash == NULL)
558 lastSlash = str;
559 else
560 lastSlash++;
561
562 // find the last dot
563 lastDot = strrchr(lastSlash, '.');
564 if (lastDot == NULL)
565 return NULL;
566
567 // looks good, ship it
568 return const_cast<char*>(lastDot);
569}
570
571String8 String8::getPathExtension(void) const
572{
573 char* ext;
574
575 ext = find_extension();
576 if (ext != NULL)
577 return String8(ext);
578 else
579 return String8("");
580}
581
582String8 String8::getBasePath(void) const
583{
584 char* ext;
585 const char* const str = mString;
586
587 ext = find_extension();
588 if (ext == NULL)
589 return String8(*this);
590 else
591 return String8(str, ext - str);
592}
593
594String8& String8::appendPath(const char* name)
595{
596 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
597 if (name[0] != OS_PATH_SEPARATOR) {
598 if (*name == '\0') {
599 // nothing to do
600 return *this;
601 }
602
603 size_t len = length();
604 if (len == 0) {
605 // no existing filename, just use the new one
606 setPathName(name);
607 return *this;
608 }
609
610 // make room for oldPath + '/' + newPath
611 int newlen = strlen(name);
612
613 char* buf = lockBuffer(len+1+newlen);
614
615 // insert a '/' if needed
616 if (buf[len-1] != OS_PATH_SEPARATOR)
617 buf[len++] = OS_PATH_SEPARATOR;
618
619 memcpy(buf+len, name, newlen+1);
620 len += newlen;
621
622 unlockBuffer(len);
623
624 return *this;
625 } else {
626 setPathName(name);
627 return *this;
628 }
629}
630
631String8& String8::convertToResPath()
632{
633#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
634 size_t len = length();
635 if (len > 0) {
636 char * buf = lockBuffer(len);
637 for (char * end = buf + len; buf < end; ++buf) {
638 if (*buf == OS_PATH_SEPARATOR)
639 *buf = RES_PATH_SEPARATOR;
640 }
641 unlockBuffer(len);
642 }
643#endif
644 return *this;
645}
646
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800647}; // namespace android