1 /*
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 #define __STDC_LIMIT_MACROS
18 #include <stdint.h>
19
20 #include <utils/String8.h>
21
22 #include <utils/Compat.h>
23 #include <utils/Log.h>
24 #include <utils/Unicode.h>
25 #include <utils/String16.h>
26 #include <utils/threads.h>
27
28 #include <ctype.h>
29
30 #include "SharedBuffer.h"
31
32 /*
33 * Functions outside android is below the namespace android, since they use
34 * functions and constants in android namespace.
35 */
36
37 // ---------------------------------------------------------------------------
38
39 namespace android {
40
41 // Separator used by resource paths. This is not platform dependent contrary
42 // to OS_PATH_SEPARATOR.
43 #define RES_PATH_SEPARATOR '/'
44
45 static SharedBuffer* gEmptyStringBuf = NULL;
46 static char* gEmptyString = NULL;
47
48 extern int gDarwinCantLoadAllObjects;
49 int gDarwinIsReallyAnnoying;
50
51 void initialize_string8();
52
getEmptyString()53 static inline char* getEmptyString()
54 {
55 gEmptyStringBuf->acquire();
56 return gEmptyString;
57 }
58
initialize_string8()59 void initialize_string8()
60 {
61 // HACK: This dummy dependency forces linking libutils Static.cpp,
62 // which is needed to initialize String8/String16 classes.
63 // These variables are named for Darwin, but are needed elsewhere too,
64 // including static linking on any platform.
65 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
66
67 SharedBuffer* buf = SharedBuffer::alloc(1);
68 char* str = (char*)buf->data();
69 *str = 0;
70 gEmptyStringBuf = buf;
71 gEmptyString = str;
72 }
73
terminate_string8()74 void terminate_string8()
75 {
76 SharedBuffer::bufferFromData(gEmptyString)->release();
77 gEmptyStringBuf = NULL;
78 gEmptyString = NULL;
79 }
80
81 // ---------------------------------------------------------------------------
82
allocFromUTF8(const char * in,size_t len)83 static char* allocFromUTF8(const char* in, size_t len)
84 {
85 if (len > 0) {
86 if (len == SIZE_MAX) {
87 return NULL;
88 }
89 SharedBuffer* buf = SharedBuffer::alloc(len+1);
90 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
91 if (buf) {
92 char* str = (char*)buf->data();
93 memcpy(str, in, len);
94 str[len] = 0;
95 return str;
96 }
97 return NULL;
98 }
99
100 return getEmptyString();
101 }
102
allocFromUTF16(const char16_t * in,size_t len)103 static char* allocFromUTF16(const char16_t* in, size_t len)
104 {
105 if (len == 0) return getEmptyString();
106
107 const ssize_t bytes = utf16_to_utf8_length(in, len);
108 if (bytes < 0) {
109 return getEmptyString();
110 }
111
112 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
113 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
114 if (!buf) {
115 return getEmptyString();
116 }
117
118 char* str = (char*)buf->data();
119 utf16_to_utf8(in, len, str);
120 return str;
121 }
122
allocFromUTF32(const char32_t * in,size_t len)123 static char* allocFromUTF32(const char32_t* in, size_t len)
124 {
125 if (len == 0) {
126 return getEmptyString();
127 }
128
129 const ssize_t bytes = utf32_to_utf8_length(in, len);
130 if (bytes < 0) {
131 return getEmptyString();
132 }
133
134 SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
135 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
136 if (!buf) {
137 return getEmptyString();
138 }
139
140 char* str = (char*) buf->data();
141 utf32_to_utf8(in, len, str);
142
143 return str;
144 }
145
146 // ---------------------------------------------------------------------------
147
String8()148 String8::String8()
149 : mString(getEmptyString())
150 {
151 }
152
String8(StaticLinkage)153 String8::String8(StaticLinkage)
154 : mString(0)
155 {
156 // this constructor is used when we can't rely on the static-initializers
157 // having run. In this case we always allocate an empty string. It's less
158 // efficient than using getEmptyString(), but we assume it's uncommon.
159
160 char* data = static_cast<char*>(
161 SharedBuffer::alloc(sizeof(char))->data());
162 data[0] = 0;
163 mString = data;
164 }
165
String8(const String8 & o)166 String8::String8(const String8& o)
167 : mString(o.mString)
168 {
169 SharedBuffer::bufferFromData(mString)->acquire();
170 }
171
String8(const char * o)172 String8::String8(const char* o)
173 : mString(allocFromUTF8(o, strlen(o)))
174 {
175 if (mString == NULL) {
176 mString = getEmptyString();
177 }
178 }
179
String8(const char * o,size_t len)180 String8::String8(const char* o, size_t len)
181 : mString(allocFromUTF8(o, len))
182 {
183 if (mString == NULL) {
184 mString = getEmptyString();
185 }
186 }
187
String8(const String16 & o)188 String8::String8(const String16& o)
189 : mString(allocFromUTF16(o.string(), o.size()))
190 {
191 }
192
String8(const char16_t * o)193 String8::String8(const char16_t* o)
194 : mString(allocFromUTF16(o, strlen16(o)))
195 {
196 }
197
String8(const char16_t * o,size_t len)198 String8::String8(const char16_t* o, size_t len)
199 : mString(allocFromUTF16(o, len))
200 {
201 }
202
String8(const char32_t * o)203 String8::String8(const char32_t* o)
204 : mString(allocFromUTF32(o, strlen32(o)))
205 {
206 }
207
String8(const char32_t * o,size_t len)208 String8::String8(const char32_t* o, size_t len)
209 : mString(allocFromUTF32(o, len))
210 {
211 }
212
~String8()213 String8::~String8()
214 {
215 SharedBuffer::bufferFromData(mString)->release();
216 }
217
length() const218 size_t String8::length() const
219 {
220 return SharedBuffer::sizeFromData(mString)-1;
221 }
222
format(const char * fmt,...)223 String8 String8::format(const char* fmt, ...)
224 {
225 va_list args;
226 va_start(args, fmt);
227
228 String8 result(formatV(fmt, args));
229
230 va_end(args);
231 return result;
232 }
233
formatV(const char * fmt,va_list args)234 String8 String8::formatV(const char* fmt, va_list args)
235 {
236 String8 result;
237 result.appendFormatV(fmt, args);
238 return result;
239 }
240
clear()241 void String8::clear() {
242 SharedBuffer::bufferFromData(mString)->release();
243 mString = getEmptyString();
244 }
245
setTo(const String8 & other)246 void String8::setTo(const String8& other)
247 {
248 SharedBuffer::bufferFromData(other.mString)->acquire();
249 SharedBuffer::bufferFromData(mString)->release();
250 mString = other.mString;
251 }
252
setTo(const char * other)253 status_t String8::setTo(const char* other)
254 {
255 const char *newString = allocFromUTF8(other, strlen(other));
256 SharedBuffer::bufferFromData(mString)->release();
257 mString = newString;
258 if (mString) return NO_ERROR;
259
260 mString = getEmptyString();
261 return NO_MEMORY;
262 }
263
setTo(const char * other,size_t len)264 status_t String8::setTo(const char* other, size_t len)
265 {
266 const char *newString = allocFromUTF8(other, len);
267 SharedBuffer::bufferFromData(mString)->release();
268 mString = newString;
269 if (mString) return NO_ERROR;
270
271 mString = getEmptyString();
272 return NO_MEMORY;
273 }
274
setTo(const char16_t * other,size_t len)275 status_t String8::setTo(const char16_t* other, size_t len)
276 {
277 const char *newString = allocFromUTF16(other, len);
278 SharedBuffer::bufferFromData(mString)->release();
279 mString = newString;
280 if (mString) return NO_ERROR;
281
282 mString = getEmptyString();
283 return NO_MEMORY;
284 }
285
setTo(const char32_t * other,size_t len)286 status_t String8::setTo(const char32_t* other, size_t len)
287 {
288 const char *newString = allocFromUTF32(other, len);
289 SharedBuffer::bufferFromData(mString)->release();
290 mString = newString;
291 if (mString) return NO_ERROR;
292
293 mString = getEmptyString();
294 return NO_MEMORY;
295 }
296
append(const String8 & other)297 status_t String8::append(const String8& other)
298 {
299 const size_t otherLen = other.bytes();
300 if (bytes() == 0) {
301 setTo(other);
302 return NO_ERROR;
303 } else if (otherLen == 0) {
304 return NO_ERROR;
305 }
306
307 return real_append(other.string(), otherLen);
308 }
309
append(const char * other)310 status_t String8::append(const char* other)
311 {
312 return append(other, strlen(other));
313 }
314
append(const char * other,size_t otherLen)315 status_t String8::append(const char* other, size_t otherLen)
316 {
317 if (bytes() == 0) {
318 return setTo(other, otherLen);
319 } else if (otherLen == 0) {
320 return NO_ERROR;
321 }
322
323 return real_append(other, otherLen);
324 }
325
appendFormat(const char * fmt,...)326 status_t String8::appendFormat(const char* fmt, ...)
327 {
328 va_list args;
329 va_start(args, fmt);
330
331 status_t result = appendFormatV(fmt, args);
332
333 va_end(args);
334 return result;
335 }
336
appendFormatV(const char * fmt,va_list args)337 status_t String8::appendFormatV(const char* fmt, va_list args)
338 {
339 int n, result = NO_ERROR;
340 va_list tmp_args;
341
342 /* args is undefined after vsnprintf.
343 * So we need a copy here to avoid the
344 * second vsnprintf access undefined args.
345 */
346 va_copy(tmp_args, args);
347 n = vsnprintf(NULL, 0, fmt, tmp_args);
348 va_end(tmp_args);
349
350 if (n != 0) {
351 size_t oldLength = length();
352 char* buf = lockBuffer(oldLength + n);
353 if (buf) {
354 vsnprintf(buf + oldLength, n + 1, fmt, args);
355 } else {
356 result = NO_MEMORY;
357 }
358 }
359 return result;
360 }
361
real_append(const char * other,size_t otherLen)362 status_t String8::real_append(const char* other, size_t otherLen)
363 {
364 const size_t myLen = bytes();
365
366 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
367 ->editResize(myLen+otherLen+1);
368 if (buf) {
369 char* str = (char*)buf->data();
370 mString = str;
371 str += myLen;
372 memcpy(str, other, otherLen);
373 str[otherLen] = '\0';
374 return NO_ERROR;
375 }
376 return NO_MEMORY;
377 }
378
lockBuffer(size_t size)379 char* String8::lockBuffer(size_t size)
380 {
381 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
382 ->editResize(size+1);
383 if (buf) {
384 char* str = (char*)buf->data();
385 mString = str;
386 return str;
387 }
388 return NULL;
389 }
390
unlockBuffer()391 void String8::unlockBuffer()
392 {
393 unlockBuffer(strlen(mString));
394 }
395
unlockBuffer(size_t size)396 status_t String8::unlockBuffer(size_t size)
397 {
398 if (size != this->size()) {
399 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
400 ->editResize(size+1);
401 if (! buf) {
402 return NO_MEMORY;
403 }
404
405 char* str = (char*)buf->data();
406 str[size] = 0;
407 mString = str;
408 }
409
410 return NO_ERROR;
411 }
412
find(const char * other,size_t start) const413 ssize_t String8::find(const char* other, size_t start) const
414 {
415 size_t len = size();
416 if (start >= len) {
417 return -1;
418 }
419 const char* s = mString+start;
420 const char* p = strstr(s, other);
421 return p ? p-mString : -1;
422 }
423
removeAll(const char * other)424 bool String8::removeAll(const char* other) {
425 ssize_t index = find(other);
426 if (index < 0) return false;
427
428 char* buf = lockBuffer(size());
429 if (!buf) return false; // out of memory
430
431 size_t skip = strlen(other);
432 size_t len = size();
433 size_t tail = index;
434 while (size_t(index) < len) {
435 ssize_t next = find(other, index + skip);
436 if (next < 0) {
437 next = len;
438 }
439
440 memmove(buf + tail, buf + index + skip, next - index - skip);
441 tail += next - index - skip;
442 index = next;
443 }
444 unlockBuffer(tail);
445 return true;
446 }
447
toLower()448 void String8::toLower()
449 {
450 toLower(0, size());
451 }
452
toLower(size_t start,size_t length)453 void String8::toLower(size_t start, size_t length)
454 {
455 const size_t len = size();
456 if (start >= len) {
457 return;
458 }
459 if (start+length > len) {
460 length = len-start;
461 }
462 char* buf = lockBuffer(len);
463 buf += start;
464 while (length > 0) {
465 *buf = tolower(*buf);
466 buf++;
467 length--;
468 }
469 unlockBuffer(len);
470 }
471
toUpper()472 void String8::toUpper()
473 {
474 toUpper(0, size());
475 }
476
toUpper(size_t start,size_t length)477 void String8::toUpper(size_t start, size_t length)
478 {
479 const size_t len = size();
480 if (start >= len) {
481 return;
482 }
483 if (start+length > len) {
484 length = len-start;
485 }
486 char* buf = lockBuffer(len);
487 buf += start;
488 while (length > 0) {
489 *buf = toupper(*buf);
490 buf++;
491 length--;
492 }
493 unlockBuffer(len);
494 }
495
getUtf32Length() const496 size_t String8::getUtf32Length() const
497 {
498 return utf8_to_utf32_length(mString, length());
499 }
500
getUtf32At(size_t index,size_t * next_index) const501 int32_t String8::getUtf32At(size_t index, size_t *next_index) const
502 {
503 return utf32_from_utf8_at(mString, length(), index, next_index);
504 }
505
getUtf32(char32_t * dst) const506 void String8::getUtf32(char32_t* dst) const
507 {
508 utf8_to_utf32(mString, length(), dst);
509 }
510
511 // ---------------------------------------------------------------------------
512 // Path functions
513
setPathName(const char * name)514 void String8::setPathName(const char* name)
515 {
516 setPathName(name, strlen(name));
517 }
518
setPathName(const char * name,size_t len)519 void String8::setPathName(const char* name, size_t len)
520 {
521 char* buf = lockBuffer(len);
522
523 memcpy(buf, name, len);
524
525 // remove trailing path separator, if present
526 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
527 len--;
528
529 buf[len] = '\0';
530
531 unlockBuffer(len);
532 }
533
getPathLeaf(void) const534 String8 String8::getPathLeaf(void) const
535 {
536 const char* cp;
537 const char*const buf = mString;
538
539 cp = strrchr(buf, OS_PATH_SEPARATOR);
540 if (cp == NULL)
541 return String8(*this);
542 else
543 return String8(cp+1);
544 }
545
getPathDir(void) const546 String8 String8::getPathDir(void) const
547 {
548 const char* cp;
549 const char*const str = mString;
550
551 cp = strrchr(str, OS_PATH_SEPARATOR);
552 if (cp == NULL)
553 return String8("");
554 else
555 return String8(str, cp - str);
556 }
557
walkPath(String8 * outRemains) const558 String8 String8::walkPath(String8* outRemains) const
559 {
560 const char* cp;
561 const char*const str = mString;
562 const char* buf = str;
563
564 cp = strchr(buf, OS_PATH_SEPARATOR);
565 if (cp == buf) {
566 // don't include a leading '/'.
567 buf = buf+1;
568 cp = strchr(buf, OS_PATH_SEPARATOR);
569 }
570
571 if (cp == NULL) {
572 String8 res = buf != str ? String8(buf) : *this;
573 if (outRemains) *outRemains = String8("");
574 return res;
575 }
576
577 String8 res(buf, cp-buf);
578 if (outRemains) *outRemains = String8(cp+1);
579 return res;
580 }
581
582 /*
583 * Helper function for finding the start of an extension in a pathname.
584 *
585 * Returns a pointer inside mString, or NULL if no extension was found.
586 */
find_extension(void) const587 char* String8::find_extension(void) const
588 {
589 const char* lastSlash;
590 const char* lastDot;
591 const char* const str = mString;
592
593 // only look at the filename
594 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
595 if (lastSlash == NULL)
596 lastSlash = str;
597 else
598 lastSlash++;
599
600 // find the last dot
601 lastDot = strrchr(lastSlash, '.');
602 if (lastDot == NULL)
603 return NULL;
604
605 // looks good, ship it
606 return const_cast<char*>(lastDot);
607 }
608
getPathExtension(void) const609 String8 String8::getPathExtension(void) const
610 {
611 char* ext;
612
613 ext = find_extension();
614 if (ext != NULL)
615 return String8(ext);
616 else
617 return String8("");
618 }
619
getBasePath(void) const620 String8 String8::getBasePath(void) const
621 {
622 char* ext;
623 const char* const str = mString;
624
625 ext = find_extension();
626 if (ext == NULL)
627 return String8(*this);
628 else
629 return String8(str, ext - str);
630 }
631
appendPath(const char * name)632 String8& String8::appendPath(const char* name)
633 {
634 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
635 if (name[0] != OS_PATH_SEPARATOR) {
636 if (*name == '\0') {
637 // nothing to do
638 return *this;
639 }
640
641 size_t len = length();
642 if (len == 0) {
643 // no existing filename, just use the new one
644 setPathName(name);
645 return *this;
646 }
647
648 // make room for oldPath + '/' + newPath
649 int newlen = strlen(name);
650
651 char* buf = lockBuffer(len+1+newlen);
652
653 // insert a '/' if needed
654 if (buf[len-1] != OS_PATH_SEPARATOR)
655 buf[len++] = OS_PATH_SEPARATOR;
656
657 memcpy(buf+len, name, newlen+1);
658 len += newlen;
659
660 unlockBuffer(len);
661
662 return *this;
663 } else {
664 setPathName(name);
665 return *this;
666 }
667 }
668
convertToResPath()669 String8& String8::convertToResPath()
670 {
671 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
672 size_t len = length();
673 if (len > 0) {
674 char * buf = lockBuffer(len);
675 for (char * end = buf + len; buf < end; ++buf) {
676 if (*buf == OS_PATH_SEPARATOR)
677 *buf = RES_PATH_SEPARATOR;
678 }
679 unlockBuffer(len);
680 }
681 #endif
682 return *this;
683 }
684
685 }; // namespace android
686