• 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 
477 // ---------------------------------------------------------------------------
478 // Path functions
479 
setPathName(const char * name)480 void String8::setPathName(const char* name)
481 {
482     setPathName(name, strlen(name));
483 }
484 
setPathName(const char * name,size_t len)485 void String8::setPathName(const char* name, size_t len)
486 {
487     char* buf = lockBuffer(len);
488 
489     memcpy(buf, name, len);
490 
491     // remove trailing path separator, if present
492     if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
493         len--;
494 
495     buf[len] = '\0';
496 
497     unlockBuffer(len);
498 }
499 
getPathLeaf(void) const500 String8 String8::getPathLeaf(void) const
501 {
502     const char* cp;
503     const char*const buf = mString;
504 
505     cp = strrchr(buf, OS_PATH_SEPARATOR);
506     if (cp == nullptr)
507         return String8(*this);
508     else
509         return String8(cp+1);
510 }
511 
getPathDir(void) const512 String8 String8::getPathDir(void) const
513 {
514     const char* cp;
515     const char*const str = mString;
516 
517     cp = strrchr(str, OS_PATH_SEPARATOR);
518     if (cp == nullptr)
519         return String8("");
520     else
521         return String8(str, cp - str);
522 }
523 
walkPath(String8 * outRemains) const524 String8 String8::walkPath(String8* outRemains) const
525 {
526     const char* cp;
527     const char*const str = mString;
528     const char* buf = str;
529 
530     cp = strchr(buf, OS_PATH_SEPARATOR);
531     if (cp == buf) {
532         // don't include a leading '/'.
533         buf = buf+1;
534         cp = strchr(buf, OS_PATH_SEPARATOR);
535     }
536 
537     if (cp == nullptr) {
538         String8 res = buf != str ? String8(buf) : *this;
539         if (outRemains) *outRemains = String8("");
540         return res;
541     }
542 
543     String8 res(buf, cp-buf);
544     if (outRemains) *outRemains = String8(cp+1);
545     return res;
546 }
547 
548 /*
549  * Helper function for finding the start of an extension in a pathname.
550  *
551  * Returns a pointer inside mString, or NULL if no extension was found.
552  */
find_extension(void) const553 char* String8::find_extension(void) const
554 {
555     const char* lastSlash;
556     const char* lastDot;
557     const char* const str = mString;
558 
559     // only look at the filename
560     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
561     if (lastSlash == nullptr)
562         lastSlash = str;
563     else
564         lastSlash++;
565 
566     // find the last dot
567     lastDot = strrchr(lastSlash, '.');
568     if (lastDot == nullptr)
569         return nullptr;
570 
571     // looks good, ship it
572     return const_cast<char*>(lastDot);
573 }
574 
getPathExtension(void) const575 String8 String8::getPathExtension(void) const
576 {
577     char* ext;
578 
579     ext = find_extension();
580     if (ext != nullptr)
581         return String8(ext);
582     else
583         return String8("");
584 }
585 
getBasePath(void) const586 String8 String8::getBasePath(void) const
587 {
588     char* ext;
589     const char* const str = mString;
590 
591     ext = find_extension();
592     if (ext == nullptr)
593         return String8(*this);
594     else
595         return String8(str, ext - str);
596 }
597 
appendPath(const char * name)598 String8& String8::appendPath(const char* name)
599 {
600     // TODO: The test below will fail for Win32 paths. Fix later or ignore.
601     if (name[0] != OS_PATH_SEPARATOR) {
602         if (*name == '\0') {
603             // nothing to do
604             return *this;
605         }
606 
607         size_t len = length();
608         if (len == 0) {
609             // no existing filename, just use the new one
610             setPathName(name);
611             return *this;
612         }
613 
614         // make room for oldPath + '/' + newPath
615         int newlen = strlen(name);
616 
617         char* buf = lockBuffer(len+1+newlen);
618 
619         // insert a '/' if needed
620         if (buf[len-1] != OS_PATH_SEPARATOR)
621             buf[len++] = OS_PATH_SEPARATOR;
622 
623         memcpy(buf+len, name, newlen+1);
624         len += newlen;
625 
626         unlockBuffer(len);
627 
628         return *this;
629     } else {
630         setPathName(name);
631         return *this;
632     }
633 }
634 
convertToResPath()635 String8& String8::convertToResPath()
636 {
637 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
638     size_t len = length();
639     if (len > 0) {
640         char * buf = lockBuffer(len);
641         for (char * end = buf + len; buf < end; ++buf) {
642             if (*buf == OS_PATH_SEPARATOR)
643                 *buf = RES_PATH_SEPARATOR;
644         }
645         unlockBuffer(len);
646     }
647 #endif
648     return *this;
649 }
650 
651 }; // namespace android
652