blob: 413928abb34e99333bf20cb7e736edba07fce31e [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{
Todd Poynord9ad7d82013-05-02 15:41:35 -070050 if (!gEmptyStringBuf) initialize_string8();
51
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080052 gEmptyStringBuf->acquire();
53 return gEmptyString;
54}
55
56void initialize_string8()
57{
Todd Poynord9ad7d82013-05-02 15:41:35 -070058 if (gEmptyStringBuf) return;
59
Dan Egnor88753ae2010-05-06 00:55:09 -070060 // HACK: This dummy dependency forces linking libutils Static.cpp,
61 // which is needed to initialize String8/String16 classes.
62 // These variables are named for Darwin, but are needed elsewhere too,
63 // including static linking on any platform.
64 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090065
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080066 SharedBuffer* buf = SharedBuffer::alloc(1);
67 char* str = (char*)buf->data();
68 *str = 0;
69 gEmptyStringBuf = buf;
70 gEmptyString = str;
71}
72
73void terminate_string8()
74{
75 SharedBuffer::bufferFromData(gEmptyString)->release();
76 gEmptyStringBuf = NULL;
77 gEmptyString = NULL;
78}
79
80// ---------------------------------------------------------------------------
81
82static char* allocFromUTF8(const char* in, size_t len)
83{
84 if (len > 0) {
85 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
Kenny Rootba0165b2010-11-09 14:37:23 -0800103 const ssize_t bytes = utf16_to_utf8_length(in, len);
104 if (bytes < 0) {
105 return getEmptyString();
106 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800107
108 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000109 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800110 if (!buf) {
111 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800112 }
113
Kenny Rootba0165b2010-11-09 14:37:23 -0800114 char* str = (char*)buf->data();
115 utf16_to_utf8(in, len, str);
116 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900117}
118
119static char* allocFromUTF32(const char32_t* in, size_t len)
120{
Kenny Rootba0165b2010-11-09 14:37:23 -0800121 if (len == 0) {
122 return getEmptyString();
123 }
124
125 const ssize_t bytes = utf32_to_utf8_length(in, len);
126 if (bytes < 0) {
127 return getEmptyString();
128 }
129
130 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
Steve Blockae074452012-01-09 18:35:44 +0000131 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800132 if (!buf) {
133 return getEmptyString();
134 }
135
136 char* str = (char*) buf->data();
137 utf32_to_utf8(in, len, str);
138
139 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900140}
141
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800142// ---------------------------------------------------------------------------
143
144String8::String8()
145 : mString(getEmptyString())
146{
147}
148
149String8::String8(const String8& o)
150 : mString(o.mString)
151{
152 SharedBuffer::bufferFromData(mString)->acquire();
153}
154
155String8::String8(const char* o)
156 : mString(allocFromUTF8(o, strlen(o)))
157{
158 if (mString == NULL) {
159 mString = getEmptyString();
160 }
161}
162
163String8::String8(const char* o, size_t len)
164 : mString(allocFromUTF8(o, len))
165{
166 if (mString == NULL) {
167 mString = getEmptyString();
168 }
169}
170
171String8::String8(const String16& o)
172 : mString(allocFromUTF16(o.string(), o.size()))
173{
174}
175
176String8::String8(const char16_t* o)
177 : mString(allocFromUTF16(o, strlen16(o)))
178{
179}
180
181String8::String8(const char16_t* o, size_t len)
182 : mString(allocFromUTF16(o, len))
183{
184}
185
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900186String8::String8(const char32_t* o)
187 : mString(allocFromUTF32(o, strlen32(o)))
188{
189}
190
191String8::String8(const char32_t* o, size_t len)
192 : mString(allocFromUTF32(o, len))
193{
194}
195
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800196String8::~String8()
197{
198 SharedBuffer::bufferFromData(mString)->release();
199}
200
Jeff Brown1d618d62010-12-02 13:50:46 -0800201String8 String8::format(const char* fmt, ...)
202{
203 va_list args;
204 va_start(args, fmt);
205
206 String8 result(formatV(fmt, args));
207
208 va_end(args);
209 return result;
210}
211
212String8 String8::formatV(const char* fmt, va_list args)
213{
214 String8 result;
215 result.appendFormatV(fmt, args);
216 return result;
217}
218
Jeff Brown48da31b2010-09-12 17:55:08 -0700219void String8::clear() {
220 SharedBuffer::bufferFromData(mString)->release();
221 mString = getEmptyString();
222}
223
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800224void String8::setTo(const String8& other)
225{
226 SharedBuffer::bufferFromData(other.mString)->acquire();
227 SharedBuffer::bufferFromData(mString)->release();
228 mString = other.mString;
229}
230
231status_t String8::setTo(const char* other)
232{
Andreas Huber10e5da52010-06-10 11:14:26 -0700233 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800234 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700235 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800236 if (mString) return NO_ERROR;
237
238 mString = getEmptyString();
239 return NO_MEMORY;
240}
241
242status_t String8::setTo(const char* other, size_t len)
243{
Andreas Huber10e5da52010-06-10 11:14:26 -0700244 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800245 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700246 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800247 if (mString) return NO_ERROR;
248
249 mString = getEmptyString();
250 return NO_MEMORY;
251}
252
253status_t String8::setTo(const char16_t* other, size_t len)
254{
Andreas Huber10e5da52010-06-10 11:14:26 -0700255 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800256 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700257 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800258 if (mString) return NO_ERROR;
259
260 mString = getEmptyString();
261 return NO_MEMORY;
262}
263
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900264status_t String8::setTo(const char32_t* other, size_t len)
265{
Andreas Huber10e5da52010-06-10 11:14:26 -0700266 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900267 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700268 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900269 if (mString) return NO_ERROR;
270
271 mString = getEmptyString();
272 return NO_MEMORY;
273}
274
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800275status_t String8::append(const String8& other)
276{
277 const size_t otherLen = other.bytes();
278 if (bytes() == 0) {
279 setTo(other);
280 return NO_ERROR;
281 } else if (otherLen == 0) {
282 return NO_ERROR;
283 }
284
285 return real_append(other.string(), otherLen);
286}
287
288status_t String8::append(const char* other)
289{
290 return append(other, strlen(other));
291}
292
293status_t String8::append(const char* other, size_t otherLen)
294{
295 if (bytes() == 0) {
296 return setTo(other, otherLen);
297 } else if (otherLen == 0) {
298 return NO_ERROR;
299 }
300
301 return real_append(other, otherLen);
302}
303
Jeff Brown35a154e2010-07-15 23:54:05 -0700304status_t String8::appendFormat(const char* fmt, ...)
305{
Jeff Brown647925d2010-11-10 16:03:06 -0800306 va_list args;
307 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700308
Jeff Brown647925d2010-11-10 16:03:06 -0800309 status_t result = appendFormatV(fmt, args);
310
311 va_end(args);
312 return result;
313}
314
315status_t String8::appendFormatV(const char* fmt, va_list args)
316{
Jeff Brown35a154e2010-07-15 23:54:05 -0700317 int result = NO_ERROR;
Jeff Brown647925d2010-11-10 16:03:06 -0800318 int n = vsnprintf(NULL, 0, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700319 if (n != 0) {
320 size_t oldLength = length();
321 char* buf = lockBuffer(oldLength + n);
322 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800323 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700324 } else {
325 result = NO_MEMORY;
326 }
327 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700328 return result;
329}
330
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800331status_t String8::real_append(const char* other, size_t otherLen)
332{
333 const size_t myLen = bytes();
334
335 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
336 ->editResize(myLen+otherLen+1);
337 if (buf) {
338 char* str = (char*)buf->data();
339 mString = str;
340 str += myLen;
341 memcpy(str, other, otherLen);
342 str[otherLen] = '\0';
343 return NO_ERROR;
344 }
345 return NO_MEMORY;
346}
347
348char* String8::lockBuffer(size_t size)
349{
350 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
351 ->editResize(size+1);
352 if (buf) {
353 char* str = (char*)buf->data();
354 mString = str;
355 return str;
356 }
357 return NULL;
358}
359
360void String8::unlockBuffer()
361{
362 unlockBuffer(strlen(mString));
363}
364
365status_t String8::unlockBuffer(size_t size)
366{
367 if (size != this->size()) {
368 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
369 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700370 if (! buf) {
371 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800372 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700373
374 char* str = (char*)buf->data();
375 str[size] = 0;
376 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800377 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700378
379 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800380}
381
382ssize_t String8::find(const char* other, size_t start) const
383{
384 size_t len = size();
385 if (start >= len) {
386 return -1;
387 }
388 const char* s = mString+start;
389 const char* p = strstr(s, other);
390 return p ? p-mString : -1;
391}
392
393void String8::toLower()
394{
395 toLower(0, size());
396}
397
398void String8::toLower(size_t start, size_t length)
399{
400 const size_t len = size();
401 if (start >= len) {
402 return;
403 }
404 if (start+length > len) {
405 length = len-start;
406 }
407 char* buf = lockBuffer(len);
408 buf += start;
409 while (length > 0) {
410 *buf = tolower(*buf);
411 buf++;
412 length--;
413 }
414 unlockBuffer(len);
415}
416
417void String8::toUpper()
418{
419 toUpper(0, size());
420}
421
422void String8::toUpper(size_t start, size_t length)
423{
424 const size_t len = size();
425 if (start >= len) {
426 return;
427 }
428 if (start+length > len) {
429 length = len-start;
430 }
431 char* buf = lockBuffer(len);
432 buf += start;
433 while (length > 0) {
434 *buf = toupper(*buf);
435 buf++;
436 length--;
437 }
438 unlockBuffer(len);
439}
440
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900441size_t String8::getUtf32Length() const
442{
Kenny Rootba0165b2010-11-09 14:37:23 -0800443 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900444}
445
446int32_t String8::getUtf32At(size_t index, size_t *next_index) const
447{
Kenny Rootba0165b2010-11-09 14:37:23 -0800448 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900449}
450
Kenny Rootba0165b2010-11-09 14:37:23 -0800451void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900452{
Kenny Rootba0165b2010-11-09 14:37:23 -0800453 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900454}
455
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800456// ---------------------------------------------------------------------------
457// Path functions
458
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800459void String8::setPathName(const char* name)
460{
461 setPathName(name, strlen(name));
462}
463
464void String8::setPathName(const char* name, size_t len)
465{
466 char* buf = lockBuffer(len);
467
468 memcpy(buf, name, len);
469
470 // remove trailing path separator, if present
471 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
472 len--;
473
474 buf[len] = '\0';
475
476 unlockBuffer(len);
477}
478
479String8 String8::getPathLeaf(void) const
480{
481 const char* cp;
482 const char*const buf = mString;
483
484 cp = strrchr(buf, OS_PATH_SEPARATOR);
485 if (cp == NULL)
486 return String8(*this);
487 else
488 return String8(cp+1);
489}
490
491String8 String8::getPathDir(void) const
492{
493 const char* cp;
494 const char*const str = mString;
495
496 cp = strrchr(str, OS_PATH_SEPARATOR);
497 if (cp == NULL)
498 return String8("");
499 else
500 return String8(str, cp - str);
501}
502
503String8 String8::walkPath(String8* outRemains) const
504{
505 const char* cp;
506 const char*const str = mString;
507 const char* buf = str;
508
509 cp = strchr(buf, OS_PATH_SEPARATOR);
510 if (cp == buf) {
511 // don't include a leading '/'.
512 buf = buf+1;
513 cp = strchr(buf, OS_PATH_SEPARATOR);
514 }
515
516 if (cp == NULL) {
517 String8 res = buf != str ? String8(buf) : *this;
518 if (outRemains) *outRemains = String8("");
519 return res;
520 }
521
522 String8 res(buf, cp-buf);
523 if (outRemains) *outRemains = String8(cp+1);
524 return res;
525}
526
527/*
528 * Helper function for finding the start of an extension in a pathname.
529 *
530 * Returns a pointer inside mString, or NULL if no extension was found.
531 */
532char* String8::find_extension(void) const
533{
534 const char* lastSlash;
535 const char* lastDot;
536 int extLen;
537 const char* const str = mString;
538
539 // only look at the filename
540 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
541 if (lastSlash == NULL)
542 lastSlash = str;
543 else
544 lastSlash++;
545
546 // find the last dot
547 lastDot = strrchr(lastSlash, '.');
548 if (lastDot == NULL)
549 return NULL;
550
551 // looks good, ship it
552 return const_cast<char*>(lastDot);
553}
554
555String8 String8::getPathExtension(void) const
556{
557 char* ext;
558
559 ext = find_extension();
560 if (ext != NULL)
561 return String8(ext);
562 else
563 return String8("");
564}
565
566String8 String8::getBasePath(void) const
567{
568 char* ext;
569 const char* const str = mString;
570
571 ext = find_extension();
572 if (ext == NULL)
573 return String8(*this);
574 else
575 return String8(str, ext - str);
576}
577
578String8& String8::appendPath(const char* name)
579{
580 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
581 if (name[0] != OS_PATH_SEPARATOR) {
582 if (*name == '\0') {
583 // nothing to do
584 return *this;
585 }
586
587 size_t len = length();
588 if (len == 0) {
589 // no existing filename, just use the new one
590 setPathName(name);
591 return *this;
592 }
593
594 // make room for oldPath + '/' + newPath
595 int newlen = strlen(name);
596
597 char* buf = lockBuffer(len+1+newlen);
598
599 // insert a '/' if needed
600 if (buf[len-1] != OS_PATH_SEPARATOR)
601 buf[len++] = OS_PATH_SEPARATOR;
602
603 memcpy(buf+len, name, newlen+1);
604 len += newlen;
605
606 unlockBuffer(len);
607
608 return *this;
609 } else {
610 setPathName(name);
611 return *this;
612 }
613}
614
615String8& String8::convertToResPath()
616{
617#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
618 size_t len = length();
619 if (len > 0) {
620 char * buf = lockBuffer(len);
621 for (char * end = buf + len; buf < end; ++buf) {
622 if (*buf == OS_PATH_SEPARATOR)
623 *buf = RES_PATH_SEPARATOR;
624 }
625 unlockBuffer(len);
626 }
627#endif
628 return *this;
629}
630
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800631}; // namespace android