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