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