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