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