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/String16.h>
25
26 #include <ctype.h>
27
28 #include "SharedBuffer.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
length() const217 size_t String8::length() const
218 {
219 return SharedBuffer::sizeFromData(mString)-1;
220 }
221
format(const char * fmt,...)222 String8 String8::format(const char* fmt, ...)
223 {
224 va_list args;
225 va_start(args, fmt);
226
227 String8 result(formatV(fmt, args));
228
229 va_end(args);
230 return result;
231 }
232
formatV(const char * fmt,va_list args)233 String8 String8::formatV(const char* fmt, va_list args)
234 {
235 String8 result;
236 result.appendFormatV(fmt, args);
237 return result;
238 }
239
clear()240 void String8::clear() {
241 SharedBuffer::bufferFromData(mString)->release();
242 mString = getEmptyString();
243 }
244
setTo(const String8 & other)245 void String8::setTo(const String8& other)
246 {
247 SharedBuffer::bufferFromData(other.mString)->acquire();
248 SharedBuffer::bufferFromData(mString)->release();
249 mString = other.mString;
250 }
251
setTo(const char * other)252 status_t String8::setTo(const char* other)
253 {
254 const char *newString = allocFromUTF8(other, strlen(other));
255 SharedBuffer::bufferFromData(mString)->release();
256 mString = newString;
257 if (mString) return NO_ERROR;
258
259 mString = getEmptyString();
260 return NO_MEMORY;
261 }
262
setTo(const char * other,size_t len)263 status_t String8::setTo(const char* other, size_t len)
264 {
265 const char *newString = allocFromUTF8(other, len);
266 SharedBuffer::bufferFromData(mString)->release();
267 mString = newString;
268 if (mString) return NO_ERROR;
269
270 mString = getEmptyString();
271 return NO_MEMORY;
272 }
273
setTo(const char16_t * other,size_t len)274 status_t String8::setTo(const char16_t* other, size_t len)
275 {
276 const char *newString = allocFromUTF16(other, len);
277 SharedBuffer::bufferFromData(mString)->release();
278 mString = newString;
279 if (mString) return NO_ERROR;
280
281 mString = getEmptyString();
282 return NO_MEMORY;
283 }
284
setTo(const char32_t * other,size_t len)285 status_t String8::setTo(const char32_t* other, size_t len)
286 {
287 const char *newString = allocFromUTF32(other, len);
288 SharedBuffer::bufferFromData(mString)->release();
289 mString = newString;
290 if (mString) return NO_ERROR;
291
292 mString = getEmptyString();
293 return NO_MEMORY;
294 }
295
append(const String8 & other)296 status_t String8::append(const String8& other)
297 {
298 const size_t otherLen = other.bytes();
299 if (bytes() == 0) {
300 setTo(other);
301 return NO_ERROR;
302 } else if (otherLen == 0) {
303 return NO_ERROR;
304 }
305
306 return real_append(other.string(), otherLen);
307 }
308
append(const char * other)309 status_t String8::append(const char* other)
310 {
311 return append(other, strlen(other));
312 }
313
append(const char * other,size_t otherLen)314 status_t String8::append(const char* other, size_t otherLen)
315 {
316 if (bytes() == 0) {
317 return setTo(other, otherLen);
318 } else if (otherLen == 0) {
319 return NO_ERROR;
320 }
321
322 return real_append(other, otherLen);
323 }
324
appendFormat(const char * fmt,...)325 status_t String8::appendFormat(const char* fmt, ...)
326 {
327 va_list args;
328 va_start(args, fmt);
329
330 status_t result = appendFormatV(fmt, args);
331
332 va_end(args);
333 return result;
334 }
335
appendFormatV(const char * fmt,va_list args)336 status_t String8::appendFormatV(const char* fmt, va_list args)
337 {
338 int n, result = NO_ERROR;
339 va_list tmp_args;
340
341 /* args is undefined after vsnprintf.
342 * So we need a copy here to avoid the
343 * second vsnprintf access undefined args.
344 */
345 va_copy(tmp_args, args);
346 n = vsnprintf(NULL, 0, fmt, tmp_args);
347 va_end(tmp_args);
348
349 if (n != 0) {
350 size_t oldLength = length();
351 char* buf = lockBuffer(oldLength + n);
352 if (buf) {
353 vsnprintf(buf + oldLength, n + 1, fmt, args);
354 } else {
355 result = NO_MEMORY;
356 }
357 }
358 return result;
359 }
360
real_append(const char * other,size_t otherLen)361 status_t String8::real_append(const char* other, size_t otherLen)
362 {
363 const size_t myLen = bytes();
364
365 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
366 ->editResize(myLen+otherLen+1);
367 if (buf) {
368 char* str = (char*)buf->data();
369 mString = str;
370 str += myLen;
371 memcpy(str, other, otherLen);
372 str[otherLen] = '\0';
373 return NO_ERROR;
374 }
375 return NO_MEMORY;
376 }
377
lockBuffer(size_t size)378 char* String8::lockBuffer(size_t size)
379 {
380 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
381 ->editResize(size+1);
382 if (buf) {
383 char* str = (char*)buf->data();
384 mString = str;
385 return str;
386 }
387 return NULL;
388 }
389
unlockBuffer()390 void String8::unlockBuffer()
391 {
392 unlockBuffer(strlen(mString));
393 }
394
unlockBuffer(size_t size)395 status_t String8::unlockBuffer(size_t size)
396 {
397 if (size != this->size()) {
398 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
399 ->editResize(size+1);
400 if (! buf) {
401 return NO_MEMORY;
402 }
403
404 char* str = (char*)buf->data();
405 str[size] = 0;
406 mString = str;
407 }
408
409 return NO_ERROR;
410 }
411
find(const char * other,size_t start) const412 ssize_t String8::find(const char* other, size_t start) const
413 {
414 size_t len = size();
415 if (start >= len) {
416 return -1;
417 }
418 const char* s = mString+start;
419 const char* p = strstr(s, other);
420 return p ? p-mString : -1;
421 }
422
removeAll(const char * other)423 bool String8::removeAll(const char* other) {
424 ssize_t index = find(other);
425 if (index < 0) return false;
426
427 char* buf = lockBuffer(size());
428 if (!buf) return false; // out of memory
429
430 size_t skip = strlen(other);
431 size_t len = size();
432 size_t tail = index;
433 while (size_t(index) < len) {
434 ssize_t next = find(other, index + skip);
435 if (next < 0) {
436 next = len;
437 }
438
439 memmove(buf + tail, buf + index + skip, next - index - skip);
440 tail += next - index - skip;
441 index = next;
442 }
443 unlockBuffer(tail);
444 return true;
445 }
446
toLower()447 void String8::toLower()
448 {
449 toLower(0, size());
450 }
451
toLower(size_t start,size_t length)452 void String8::toLower(size_t start, size_t length)
453 {
454 const size_t len = size();
455 if (start >= len) {
456 return;
457 }
458 if (start+length > len) {
459 length = len-start;
460 }
461 char* buf = lockBuffer(len);
462 buf += start;
463 while (length > 0) {
464 *buf = tolower(*buf);
465 buf++;
466 length--;
467 }
468 unlockBuffer(len);
469 }
470
toUpper()471 void String8::toUpper()
472 {
473 toUpper(0, size());
474 }
475
toUpper(size_t start,size_t length)476 void String8::toUpper(size_t start, size_t length)
477 {
478 const size_t len = size();
479 if (start >= len) {
480 return;
481 }
482 if (start+length > len) {
483 length = len-start;
484 }
485 char* buf = lockBuffer(len);
486 buf += start;
487 while (length > 0) {
488 *buf = toupper(*buf);
489 buf++;
490 length--;
491 }
492 unlockBuffer(len);
493 }
494
getUtf32Length() const495 size_t String8::getUtf32Length() const
496 {
497 return utf8_to_utf32_length(mString, length());
498 }
499
getUtf32At(size_t index,size_t * next_index) const500 int32_t String8::getUtf32At(size_t index, size_t *next_index) const
501 {
502 return utf32_from_utf8_at(mString, length(), index, next_index);
503 }
504
getUtf32(char32_t * dst) const505 void String8::getUtf32(char32_t* dst) const
506 {
507 utf8_to_utf32(mString, length(), dst);
508 }
509
510 // ---------------------------------------------------------------------------
511 // Path functions
512
setPathName(const char * name)513 void String8::setPathName(const char* name)
514 {
515 setPathName(name, strlen(name));
516 }
517
setPathName(const char * name,size_t len)518 void String8::setPathName(const char* name, size_t len)
519 {
520 char* buf = lockBuffer(len);
521
522 memcpy(buf, name, len);
523
524 // remove trailing path separator, if present
525 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
526 len--;
527
528 buf[len] = '\0';
529
530 unlockBuffer(len);
531 }
532
getPathLeaf(void) const533 String8 String8::getPathLeaf(void) const
534 {
535 const char* cp;
536 const char*const buf = mString;
537
538 cp = strrchr(buf, OS_PATH_SEPARATOR);
539 if (cp == NULL)
540 return String8(*this);
541 else
542 return String8(cp+1);
543 }
544
getPathDir(void) const545 String8 String8::getPathDir(void) const
546 {
547 const char* cp;
548 const char*const str = mString;
549
550 cp = strrchr(str, OS_PATH_SEPARATOR);
551 if (cp == NULL)
552 return String8("");
553 else
554 return String8(str, cp - str);
555 }
556
walkPath(String8 * outRemains) const557 String8 String8::walkPath(String8* outRemains) const
558 {
559 const char* cp;
560 const char*const str = mString;
561 const char* buf = str;
562
563 cp = strchr(buf, OS_PATH_SEPARATOR);
564 if (cp == buf) {
565 // don't include a leading '/'.
566 buf = buf+1;
567 cp = strchr(buf, OS_PATH_SEPARATOR);
568 }
569
570 if (cp == NULL) {
571 String8 res = buf != str ? String8(buf) : *this;
572 if (outRemains) *outRemains = String8("");
573 return res;
574 }
575
576 String8 res(buf, cp-buf);
577 if (outRemains) *outRemains = String8(cp+1);
578 return res;
579 }
580
581 /*
582 * Helper function for finding the start of an extension in a pathname.
583 *
584 * Returns a pointer inside mString, or NULL if no extension was found.
585 */
find_extension(void) const586 char* String8::find_extension(void) const
587 {
588 const char* lastSlash;
589 const char* lastDot;
590 const char* const str = mString;
591
592 // only look at the filename
593 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
594 if (lastSlash == NULL)
595 lastSlash = str;
596 else
597 lastSlash++;
598
599 // find the last dot
600 lastDot = strrchr(lastSlash, '.');
601 if (lastDot == NULL)
602 return NULL;
603
604 // looks good, ship it
605 return const_cast<char*>(lastDot);
606 }
607
getPathExtension(void) const608 String8 String8::getPathExtension(void) const
609 {
610 char* ext;
611
612 ext = find_extension();
613 if (ext != NULL)
614 return String8(ext);
615 else
616 return String8("");
617 }
618
getBasePath(void) const619 String8 String8::getBasePath(void) const
620 {
621 char* ext;
622 const char* const str = mString;
623
624 ext = find_extension();
625 if (ext == NULL)
626 return String8(*this);
627 else
628 return String8(str, ext - str);
629 }
630
appendPath(const char * name)631 String8& String8::appendPath(const char* name)
632 {
633 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
634 if (name[0] != OS_PATH_SEPARATOR) {
635 if (*name == '\0') {
636 // nothing to do
637 return *this;
638 }
639
640 size_t len = length();
641 if (len == 0) {
642 // no existing filename, just use the new one
643 setPathName(name);
644 return *this;
645 }
646
647 // make room for oldPath + '/' + newPath
648 int newlen = strlen(name);
649
650 char* buf = lockBuffer(len+1+newlen);
651
652 // insert a '/' if needed
653 if (buf[len-1] != OS_PATH_SEPARATOR)
654 buf[len++] = OS_PATH_SEPARATOR;
655
656 memcpy(buf+len, name, newlen+1);
657 len += newlen;
658
659 unlockBuffer(len);
660
661 return *this;
662 } else {
663 setPathName(name);
664 return *this;
665 }
666 }
667
convertToResPath()668 String8& String8::convertToResPath()
669 {
670 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
671 size_t len = length();
672 if (len > 0) {
673 char * buf = lockBuffer(len);
674 for (char * end = buf + len; buf < end; ++buf) {
675 if (*buf == OS_PATH_SEPARATOR)
676 *buf = RES_PATH_SEPARATOR;
677 }
678 unlockBuffer(len);
679 }
680 #endif
681 return *this;
682 }
683
684 }; // namespace android
685