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