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