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