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