blob: 0bc5aff2216bed1ba322bc68888ae22b91b01c17 [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>
23#include <utils/TextOutput.h>
24#include <utils/threads.h>
25
26#include <private/utils/Static.h>
27
28#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
49static 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) {
82 SharedBuffer* buf = SharedBuffer::alloc(len+1);
83 LOG_ASSERT(buf, "Unable to allocate shared buffer");
84 if (buf) {
85 char* str = (char*)buf->data();
86 memcpy(str, in, len);
87 str[len] = 0;
88 return str;
89 }
90 return NULL;
91 }
92
93 return getEmptyString();
94}
95
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +090096static char* allocFromUTF16(const char16_t* in, size_t len)
97{
Kenny Root9a2d83e2009-12-04 09:38:48 -080098 if (len == 0) return getEmptyString();
99
Kenny Rootba0165b2010-11-09 14:37:23 -0800100 const ssize_t bytes = utf16_to_utf8_length(in, len);
101 if (bytes < 0) {
102 return getEmptyString();
103 }
Kenny Root9a2d83e2009-12-04 09:38:48 -0800104
105 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
106 LOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootba0165b2010-11-09 14:37:23 -0800107 if (!buf) {
108 return getEmptyString();
Kenny Root9a2d83e2009-12-04 09:38:48 -0800109 }
110
Kenny Rootba0165b2010-11-09 14:37:23 -0800111 char* str = (char*)buf->data();
112 utf16_to_utf8(in, len, str);
113 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900114}
115
116static char* allocFromUTF32(const char32_t* in, size_t len)
117{
Kenny Rootba0165b2010-11-09 14:37:23 -0800118 if (len == 0) {
119 return getEmptyString();
120 }
121
122 const ssize_t bytes = utf32_to_utf8_length(in, len);
123 if (bytes < 0) {
124 return getEmptyString();
125 }
126
127 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
128 LOG_ASSERT(buf, "Unable to allocate shared buffer");
129 if (!buf) {
130 return getEmptyString();
131 }
132
133 char* str = (char*) buf->data();
134 utf32_to_utf8(in, len, str);
135
136 return str;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900137}
138
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800139// ---------------------------------------------------------------------------
140
141String8::String8()
142 : mString(getEmptyString())
143{
144}
145
146String8::String8(const String8& o)
147 : mString(o.mString)
148{
149 SharedBuffer::bufferFromData(mString)->acquire();
150}
151
152String8::String8(const char* o)
153 : mString(allocFromUTF8(o, strlen(o)))
154{
155 if (mString == NULL) {
156 mString = getEmptyString();
157 }
158}
159
160String8::String8(const char* o, size_t len)
161 : mString(allocFromUTF8(o, len))
162{
163 if (mString == NULL) {
164 mString = getEmptyString();
165 }
166}
167
168String8::String8(const String16& o)
169 : mString(allocFromUTF16(o.string(), o.size()))
170{
171}
172
173String8::String8(const char16_t* o)
174 : mString(allocFromUTF16(o, strlen16(o)))
175{
176}
177
178String8::String8(const char16_t* o, size_t len)
179 : mString(allocFromUTF16(o, len))
180{
181}
182
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900183String8::String8(const char32_t* o)
184 : mString(allocFromUTF32(o, strlen32(o)))
185{
186}
187
188String8::String8(const char32_t* o, size_t len)
189 : mString(allocFromUTF32(o, len))
190{
191}
192
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800193String8::~String8()
194{
195 SharedBuffer::bufferFromData(mString)->release();
196}
197
Jeff Brown1d618d62010-12-02 13:50:46 -0800198String8 String8::format(const char* fmt, ...)
199{
200 va_list args;
201 va_start(args, fmt);
202
203 String8 result(formatV(fmt, args));
204
205 va_end(args);
206 return result;
207}
208
209String8 String8::formatV(const char* fmt, va_list args)
210{
211 String8 result;
212 result.appendFormatV(fmt, args);
213 return result;
214}
215
Jeff Brown48da31b2010-09-12 17:55:08 -0700216void String8::clear() {
217 SharedBuffer::bufferFromData(mString)->release();
218 mString = getEmptyString();
219}
220
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800221void String8::setTo(const String8& other)
222{
223 SharedBuffer::bufferFromData(other.mString)->acquire();
224 SharedBuffer::bufferFromData(mString)->release();
225 mString = other.mString;
226}
227
228status_t String8::setTo(const char* other)
229{
Andreas Huber10e5da52010-06-10 11:14:26 -0700230 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800231 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700232 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800233 if (mString) return NO_ERROR;
234
235 mString = getEmptyString();
236 return NO_MEMORY;
237}
238
239status_t String8::setTo(const char* other, size_t len)
240{
Andreas Huber10e5da52010-06-10 11:14:26 -0700241 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800242 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700243 mString = newString;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800244 if (mString) return NO_ERROR;
245
246 mString = getEmptyString();
247 return NO_MEMORY;
248}
249
250status_t String8::setTo(const char16_t* other, size_t len)
251{
Andreas Huber10e5da52010-06-10 11:14:26 -0700252 const char *newString = allocFromUTF16(other, len);
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
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900261status_t String8::setTo(const char32_t* other, size_t len)
262{
Andreas Huber10e5da52010-06-10 11:14:26 -0700263 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900264 SharedBuffer::bufferFromData(mString)->release();
Andreas Huber10e5da52010-06-10 11:14:26 -0700265 mString = newString;
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900266 if (mString) return NO_ERROR;
267
268 mString = getEmptyString();
269 return NO_MEMORY;
270}
271
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800272status_t String8::append(const String8& other)
273{
274 const size_t otherLen = other.bytes();
275 if (bytes() == 0) {
276 setTo(other);
277 return NO_ERROR;
278 } else if (otherLen == 0) {
279 return NO_ERROR;
280 }
281
282 return real_append(other.string(), otherLen);
283}
284
285status_t String8::append(const char* other)
286{
287 return append(other, strlen(other));
288}
289
290status_t String8::append(const char* other, size_t otherLen)
291{
292 if (bytes() == 0) {
293 return setTo(other, otherLen);
294 } else if (otherLen == 0) {
295 return NO_ERROR;
296 }
297
298 return real_append(other, otherLen);
299}
300
Jeff Brown35a154e2010-07-15 23:54:05 -0700301status_t String8::appendFormat(const char* fmt, ...)
302{
Jeff Brown647925d2010-11-10 16:03:06 -0800303 va_list args;
304 va_start(args, fmt);
Jeff Brown35a154e2010-07-15 23:54:05 -0700305
Jeff Brown647925d2010-11-10 16:03:06 -0800306 status_t result = appendFormatV(fmt, args);
307
308 va_end(args);
309 return result;
310}
311
312status_t String8::appendFormatV(const char* fmt, va_list args)
313{
Jeff Brown35a154e2010-07-15 23:54:05 -0700314 int result = NO_ERROR;
Jeff Brown647925d2010-11-10 16:03:06 -0800315 int n = vsnprintf(NULL, 0, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700316 if (n != 0) {
317 size_t oldLength = length();
318 char* buf = lockBuffer(oldLength + n);
319 if (buf) {
Jeff Brown647925d2010-11-10 16:03:06 -0800320 vsnprintf(buf + oldLength, n + 1, fmt, args);
Jeff Brown35a154e2010-07-15 23:54:05 -0700321 } else {
322 result = NO_MEMORY;
323 }
324 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700325 return result;
326}
327
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800328status_t String8::real_append(const char* other, size_t otherLen)
329{
330 const size_t myLen = bytes();
331
332 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
333 ->editResize(myLen+otherLen+1);
334 if (buf) {
335 char* str = (char*)buf->data();
336 mString = str;
337 str += myLen;
338 memcpy(str, other, otherLen);
339 str[otherLen] = '\0';
340 return NO_ERROR;
341 }
342 return NO_MEMORY;
343}
344
345char* String8::lockBuffer(size_t size)
346{
347 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
348 ->editResize(size+1);
349 if (buf) {
350 char* str = (char*)buf->data();
351 mString = str;
352 return str;
353 }
354 return NULL;
355}
356
357void String8::unlockBuffer()
358{
359 unlockBuffer(strlen(mString));
360}
361
362status_t String8::unlockBuffer(size_t size)
363{
364 if (size != this->size()) {
365 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
366 ->editResize(size+1);
Jeff Brown35a154e2010-07-15 23:54:05 -0700367 if (! buf) {
368 return NO_MEMORY;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800369 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700370
371 char* str = (char*)buf->data();
372 str[size] = 0;
373 mString = str;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800374 }
Jeff Brown35a154e2010-07-15 23:54:05 -0700375
376 return NO_ERROR;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800377}
378
379ssize_t String8::find(const char* other, size_t start) const
380{
381 size_t len = size();
382 if (start >= len) {
383 return -1;
384 }
385 const char* s = mString+start;
386 const char* p = strstr(s, other);
387 return p ? p-mString : -1;
388}
389
390void String8::toLower()
391{
392 toLower(0, size());
393}
394
395void String8::toLower(size_t start, size_t length)
396{
397 const size_t len = size();
398 if (start >= len) {
399 return;
400 }
401 if (start+length > len) {
402 length = len-start;
403 }
404 char* buf = lockBuffer(len);
405 buf += start;
406 while (length > 0) {
407 *buf = tolower(*buf);
408 buf++;
409 length--;
410 }
411 unlockBuffer(len);
412}
413
414void String8::toUpper()
415{
416 toUpper(0, size());
417}
418
419void String8::toUpper(size_t start, size_t length)
420{
421 const size_t len = size();
422 if (start >= len) {
423 return;
424 }
425 if (start+length > len) {
426 length = len-start;
427 }
428 char* buf = lockBuffer(len);
429 buf += start;
430 while (length > 0) {
431 *buf = toupper(*buf);
432 buf++;
433 length--;
434 }
435 unlockBuffer(len);
436}
437
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900438size_t String8::getUtf32Length() const
439{
Kenny Rootba0165b2010-11-09 14:37:23 -0800440 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900441}
442
443int32_t String8::getUtf32At(size_t index, size_t *next_index) const
444{
Kenny Rootba0165b2010-11-09 14:37:23 -0800445 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900446}
447
Kenny Rootba0165b2010-11-09 14:37:23 -0800448void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900449{
Kenny Rootba0165b2010-11-09 14:37:23 -0800450 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa44dad3e2009-06-30 20:40:42 +0900451}
452
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800453TextOutput& operator<<(TextOutput& to, const String8& val)
454{
455 to << val.string();
456 return to;
457}
458
459// ---------------------------------------------------------------------------
460// Path functions
461
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800462void String8::setPathName(const char* name)
463{
464 setPathName(name, strlen(name));
465}
466
467void String8::setPathName(const char* name, size_t len)
468{
469 char* buf = lockBuffer(len);
470
471 memcpy(buf, name, len);
472
473 // remove trailing path separator, if present
474 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
475 len--;
476
477 buf[len] = '\0';
478
479 unlockBuffer(len);
480}
481
482String8 String8::getPathLeaf(void) const
483{
484 const char* cp;
485 const char*const buf = mString;
486
487 cp = strrchr(buf, OS_PATH_SEPARATOR);
488 if (cp == NULL)
489 return String8(*this);
490 else
491 return String8(cp+1);
492}
493
494String8 String8::getPathDir(void) const
495{
496 const char* cp;
497 const char*const str = mString;
498
499 cp = strrchr(str, OS_PATH_SEPARATOR);
500 if (cp == NULL)
501 return String8("");
502 else
503 return String8(str, cp - str);
504}
505
506String8 String8::walkPath(String8* outRemains) const
507{
508 const char* cp;
509 const char*const str = mString;
510 const char* buf = str;
511
512 cp = strchr(buf, OS_PATH_SEPARATOR);
513 if (cp == buf) {
514 // don't include a leading '/'.
515 buf = buf+1;
516 cp = strchr(buf, OS_PATH_SEPARATOR);
517 }
518
519 if (cp == NULL) {
520 String8 res = buf != str ? String8(buf) : *this;
521 if (outRemains) *outRemains = String8("");
522 return res;
523 }
524
525 String8 res(buf, cp-buf);
526 if (outRemains) *outRemains = String8(cp+1);
527 return res;
528}
529
530/*
531 * Helper function for finding the start of an extension in a pathname.
532 *
533 * Returns a pointer inside mString, or NULL if no extension was found.
534 */
535char* String8::find_extension(void) const
536{
537 const char* lastSlash;
538 const char* lastDot;
539 int extLen;
540 const char* const str = mString;
541
542 // only look at the filename
543 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
544 if (lastSlash == NULL)
545 lastSlash = str;
546 else
547 lastSlash++;
548
549 // find the last dot
550 lastDot = strrchr(lastSlash, '.');
551 if (lastDot == NULL)
552 return NULL;
553
554 // looks good, ship it
555 return const_cast<char*>(lastDot);
556}
557
558String8 String8::getPathExtension(void) const
559{
560 char* ext;
561
562 ext = find_extension();
563 if (ext != NULL)
564 return String8(ext);
565 else
566 return String8("");
567}
568
569String8 String8::getBasePath(void) const
570{
571 char* ext;
572 const char* const str = mString;
573
574 ext = find_extension();
575 if (ext == NULL)
576 return String8(*this);
577 else
578 return String8(str, ext - str);
579}
580
581String8& String8::appendPath(const char* name)
582{
583 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
584 if (name[0] != OS_PATH_SEPARATOR) {
585 if (*name == '\0') {
586 // nothing to do
587 return *this;
588 }
589
590 size_t len = length();
591 if (len == 0) {
592 // no existing filename, just use the new one
593 setPathName(name);
594 return *this;
595 }
596
597 // make room for oldPath + '/' + newPath
598 int newlen = strlen(name);
599
600 char* buf = lockBuffer(len+1+newlen);
601
602 // insert a '/' if needed
603 if (buf[len-1] != OS_PATH_SEPARATOR)
604 buf[len++] = OS_PATH_SEPARATOR;
605
606 memcpy(buf+len, name, newlen+1);
607 len += newlen;
608
609 unlockBuffer(len);
610
611 return *this;
612 } else {
613 setPathName(name);
614 return *this;
615 }
616}
617
618String8& String8::convertToResPath()
619{
620#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
621 size_t len = length();
622 if (len > 0) {
623 char * buf = lockBuffer(len);
624 for (char * end = buf + len; buf < end; ++buf) {
625 if (*buf == OS_PATH_SEPARATOR)
626 *buf = RES_PATH_SEPARATOR;
627 }
628 unlockBuffer(len);
629 }
630#endif
631 return *this;
632}
633
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800634}; // namespace android