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