blob: c8dc0838dc7230746f103663d51cace85b3dcb59 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-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 Rootc412dcb2010-11-09 14:37:23 -080020#include <utils/Unicode.h>
21#include <utils/SharedBuffer.h>
The Android Open Source Projectedbf3b62009-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 Miyakawa9f220242009-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 Projectedbf3b62009-03-03 19:31:44 -080034
35// ---------------------------------------------------------------------------
36
Daisuke Miyakawa9f220242009-06-30 20:40:42 +090037namespace android {
38
The Android Open Source Projectedbf3b62009-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 Projectedbf3b62009-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 Egnor386a3322010-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 Miyakawa9f220242009-06-30 20:40:42 +090062
The Android Open Source Projectedbf3b62009-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 Miyakawa9f220242009-06-30 20:40:42 +090096static char* allocFromUTF16(const char16_t* in, size_t len)
97{
Kenny Root92f59842009-12-04 09:38:48 -080098 if (len == 0) return getEmptyString();
99
Kenny Rootc412dcb2010-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 Root92f59842009-12-04 09:38:48 -0800104
105 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
106 LOG_ASSERT(buf, "Unable to allocate shared buffer");
Kenny Rootc412dcb2010-11-09 14:37:23 -0800107 if (!buf) {
108 return getEmptyString();
Kenny Root92f59842009-12-04 09:38:48 -0800109 }
110
Kenny Rootc412dcb2010-11-09 14:37:23 -0800111 char* str = (char*)buf->data();
112 utf16_to_utf8(in, len, str);
113 return str;
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900114}
115
116static char* allocFromUTF32(const char32_t* in, size_t len)
117{
Kenny Rootc412dcb2010-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 Miyakawa9f220242009-06-30 20:40:42 +0900137}
138
The Android Open Source Projectedbf3b62009-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 Miyakawa9f220242009-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 Projectedbf3b62009-03-03 19:31:44 -0800193String8::~String8()
194{
195 SharedBuffer::bufferFromData(mString)->release();
196}
197
Jeff Brown6a817e22010-09-12 17:55:08 -0700198void String8::clear() {
199 SharedBuffer::bufferFromData(mString)->release();
200 mString = getEmptyString();
201}
202
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800203void String8::setTo(const String8& other)
204{
205 SharedBuffer::bufferFromData(other.mString)->acquire();
206 SharedBuffer::bufferFromData(mString)->release();
207 mString = other.mString;
208}
209
210status_t String8::setTo(const char* other)
211{
Andreas Hubera637eb42010-06-10 11:14:26 -0700212 const char *newString = allocFromUTF8(other, strlen(other));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800213 SharedBuffer::bufferFromData(mString)->release();
Andreas Hubera637eb42010-06-10 11:14:26 -0700214 mString = newString;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800215 if (mString) return NO_ERROR;
216
217 mString = getEmptyString();
218 return NO_MEMORY;
219}
220
221status_t String8::setTo(const char* other, size_t len)
222{
Andreas Hubera637eb42010-06-10 11:14:26 -0700223 const char *newString = allocFromUTF8(other, len);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800224 SharedBuffer::bufferFromData(mString)->release();
Andreas Hubera637eb42010-06-10 11:14:26 -0700225 mString = newString;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800226 if (mString) return NO_ERROR;
227
228 mString = getEmptyString();
229 return NO_MEMORY;
230}
231
232status_t String8::setTo(const char16_t* other, size_t len)
233{
Andreas Hubera637eb42010-06-10 11:14:26 -0700234 const char *newString = allocFromUTF16(other, len);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800235 SharedBuffer::bufferFromData(mString)->release();
Andreas Hubera637eb42010-06-10 11:14:26 -0700236 mString = newString;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800237 if (mString) return NO_ERROR;
238
239 mString = getEmptyString();
240 return NO_MEMORY;
241}
242
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900243status_t String8::setTo(const char32_t* other, size_t len)
244{
Andreas Hubera637eb42010-06-10 11:14:26 -0700245 const char *newString = allocFromUTF32(other, len);
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900246 SharedBuffer::bufferFromData(mString)->release();
Andreas Hubera637eb42010-06-10 11:14:26 -0700247 mString = newString;
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900248 if (mString) return NO_ERROR;
249
250 mString = getEmptyString();
251 return NO_MEMORY;
252}
253
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800254status_t String8::append(const String8& other)
255{
256 const size_t otherLen = other.bytes();
257 if (bytes() == 0) {
258 setTo(other);
259 return NO_ERROR;
260 } else if (otherLen == 0) {
261 return NO_ERROR;
262 }
263
264 return real_append(other.string(), otherLen);
265}
266
267status_t String8::append(const char* other)
268{
269 return append(other, strlen(other));
270}
271
272status_t String8::append(const char* other, size_t otherLen)
273{
274 if (bytes() == 0) {
275 return setTo(other, otherLen);
276 } else if (otherLen == 0) {
277 return NO_ERROR;
278 }
279
280 return real_append(other, otherLen);
281}
282
Jeff Brown0a128e32010-07-15 23:54:05 -0700283status_t String8::appendFormat(const char* fmt, ...)
284{
285 va_list ap;
286 va_start(ap, fmt);
287
288 int result = NO_ERROR;
289 int n = vsnprintf(NULL, 0, fmt, ap);
290 if (n != 0) {
291 size_t oldLength = length();
292 char* buf = lockBuffer(oldLength + n);
293 if (buf) {
294 vsnprintf(buf + oldLength, n + 1, fmt, ap);
295 } else {
296 result = NO_MEMORY;
297 }
298 }
299
300 va_end(ap);
301 return result;
302}
303
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800304status_t String8::real_append(const char* other, size_t otherLen)
305{
306 const size_t myLen = bytes();
307
308 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
309 ->editResize(myLen+otherLen+1);
310 if (buf) {
311 char* str = (char*)buf->data();
312 mString = str;
313 str += myLen;
314 memcpy(str, other, otherLen);
315 str[otherLen] = '\0';
316 return NO_ERROR;
317 }
318 return NO_MEMORY;
319}
320
321char* String8::lockBuffer(size_t size)
322{
323 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
324 ->editResize(size+1);
325 if (buf) {
326 char* str = (char*)buf->data();
327 mString = str;
328 return str;
329 }
330 return NULL;
331}
332
333void String8::unlockBuffer()
334{
335 unlockBuffer(strlen(mString));
336}
337
338status_t String8::unlockBuffer(size_t size)
339{
340 if (size != this->size()) {
341 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
342 ->editResize(size+1);
Jeff Brown0a128e32010-07-15 23:54:05 -0700343 if (! buf) {
344 return NO_MEMORY;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800345 }
Jeff Brown0a128e32010-07-15 23:54:05 -0700346
347 char* str = (char*)buf->data();
348 str[size] = 0;
349 mString = str;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800350 }
Jeff Brown0a128e32010-07-15 23:54:05 -0700351
352 return NO_ERROR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800353}
354
355ssize_t String8::find(const char* other, size_t start) const
356{
357 size_t len = size();
358 if (start >= len) {
359 return -1;
360 }
361 const char* s = mString+start;
362 const char* p = strstr(s, other);
363 return p ? p-mString : -1;
364}
365
366void String8::toLower()
367{
368 toLower(0, size());
369}
370
371void String8::toLower(size_t start, size_t length)
372{
373 const size_t len = size();
374 if (start >= len) {
375 return;
376 }
377 if (start+length > len) {
378 length = len-start;
379 }
380 char* buf = lockBuffer(len);
381 buf += start;
382 while (length > 0) {
383 *buf = tolower(*buf);
384 buf++;
385 length--;
386 }
387 unlockBuffer(len);
388}
389
390void String8::toUpper()
391{
392 toUpper(0, size());
393}
394
395void String8::toUpper(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 = toupper(*buf);
408 buf++;
409 length--;
410 }
411 unlockBuffer(len);
412}
413
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900414size_t String8::getUtf32Length() const
415{
Kenny Rootc412dcb2010-11-09 14:37:23 -0800416 return utf8_to_utf32_length(mString, length());
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900417}
418
419int32_t String8::getUtf32At(size_t index, size_t *next_index) const
420{
Kenny Rootc412dcb2010-11-09 14:37:23 -0800421 return utf32_from_utf8_at(mString, length(), index, next_index);
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900422}
423
Kenny Rootc412dcb2010-11-09 14:37:23 -0800424void String8::getUtf32(char32_t* dst) const
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900425{
Kenny Rootc412dcb2010-11-09 14:37:23 -0800426 utf8_to_utf32(mString, length(), dst);
Daisuke Miyakawa9f220242009-06-30 20:40:42 +0900427}
428
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800429TextOutput& operator<<(TextOutput& to, const String8& val)
430{
431 to << val.string();
432 return to;
433}
434
435// ---------------------------------------------------------------------------
436// Path functions
437
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800438void String8::setPathName(const char* name)
439{
440 setPathName(name, strlen(name));
441}
442
443void String8::setPathName(const char* name, size_t len)
444{
445 char* buf = lockBuffer(len);
446
447 memcpy(buf, name, len);
448
449 // remove trailing path separator, if present
450 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
451 len--;
452
453 buf[len] = '\0';
454
455 unlockBuffer(len);
456}
457
458String8 String8::getPathLeaf(void) const
459{
460 const char* cp;
461 const char*const buf = mString;
462
463 cp = strrchr(buf, OS_PATH_SEPARATOR);
464 if (cp == NULL)
465 return String8(*this);
466 else
467 return String8(cp+1);
468}
469
470String8 String8::getPathDir(void) const
471{
472 const char* cp;
473 const char*const str = mString;
474
475 cp = strrchr(str, OS_PATH_SEPARATOR);
476 if (cp == NULL)
477 return String8("");
478 else
479 return String8(str, cp - str);
480}
481
482String8 String8::walkPath(String8* outRemains) const
483{
484 const char* cp;
485 const char*const str = mString;
486 const char* buf = str;
487
488 cp = strchr(buf, OS_PATH_SEPARATOR);
489 if (cp == buf) {
490 // don't include a leading '/'.
491 buf = buf+1;
492 cp = strchr(buf, OS_PATH_SEPARATOR);
493 }
494
495 if (cp == NULL) {
496 String8 res = buf != str ? String8(buf) : *this;
497 if (outRemains) *outRemains = String8("");
498 return res;
499 }
500
501 String8 res(buf, cp-buf);
502 if (outRemains) *outRemains = String8(cp+1);
503 return res;
504}
505
506/*
507 * Helper function for finding the start of an extension in a pathname.
508 *
509 * Returns a pointer inside mString, or NULL if no extension was found.
510 */
511char* String8::find_extension(void) const
512{
513 const char* lastSlash;
514 const char* lastDot;
515 int extLen;
516 const char* const str = mString;
517
518 // only look at the filename
519 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
520 if (lastSlash == NULL)
521 lastSlash = str;
522 else
523 lastSlash++;
524
525 // find the last dot
526 lastDot = strrchr(lastSlash, '.');
527 if (lastDot == NULL)
528 return NULL;
529
530 // looks good, ship it
531 return const_cast<char*>(lastDot);
532}
533
534String8 String8::getPathExtension(void) const
535{
536 char* ext;
537
538 ext = find_extension();
539 if (ext != NULL)
540 return String8(ext);
541 else
542 return String8("");
543}
544
545String8 String8::getBasePath(void) const
546{
547 char* ext;
548 const char* const str = mString;
549
550 ext = find_extension();
551 if (ext == NULL)
552 return String8(*this);
553 else
554 return String8(str, ext - str);
555}
556
557String8& String8::appendPath(const char* name)
558{
559 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
560 if (name[0] != OS_PATH_SEPARATOR) {
561 if (*name == '\0') {
562 // nothing to do
563 return *this;
564 }
565
566 size_t len = length();
567 if (len == 0) {
568 // no existing filename, just use the new one
569 setPathName(name);
570 return *this;
571 }
572
573 // make room for oldPath + '/' + newPath
574 int newlen = strlen(name);
575
576 char* buf = lockBuffer(len+1+newlen);
577
578 // insert a '/' if needed
579 if (buf[len-1] != OS_PATH_SEPARATOR)
580 buf[len++] = OS_PATH_SEPARATOR;
581
582 memcpy(buf+len, name, newlen+1);
583 len += newlen;
584
585 unlockBuffer(len);
586
587 return *this;
588 } else {
589 setPathName(name);
590 return *this;
591 }
592}
593
594String8& String8::convertToResPath()
595{
596#if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
597 size_t len = length();
598 if (len > 0) {
599 char * buf = lockBuffer(len);
600 for (char * end = buf + len; buf < end; ++buf) {
601 if (*buf == OS_PATH_SEPARATOR)
602 *buf = RES_PATH_SEPARATOR;
603 }
604 unlockBuffer(len);
605 }
606#endif
607 return *this;
608}
609
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800610}; // namespace android