• 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 #include <utils/String8.h>
18 
19 #include <log/log.h>
20 #include <utils/String16.h>
21 
22 #include <ctype.h>
23 #include <stdint.h>
24 
25 #include <limits>
26 #include <string>
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 
getEmptyString()39 static inline char* getEmptyString() {
40     static SharedBuffer* gEmptyStringBuf = [] {
41         SharedBuffer* buf = SharedBuffer::alloc(1);
42         char* str = static_cast<char*>(buf->data());
43         *str = 0;
44         return buf;
45     }();
46 
47     gEmptyStringBuf->acquire();
48     return static_cast<char*>(gEmptyStringBuf->data());
49 }
50 
51 // ---------------------------------------------------------------------------
52 
allocFromUTF8(const char * in,size_t len)53 static char* allocFromUTF8(const char* in, size_t len)
54 {
55     if (len > 0) {
56         if (len == SIZE_MAX) {
57             return nullptr;
58         }
59         SharedBuffer* buf = SharedBuffer::alloc(len+1);
60         ALOG_ASSERT(buf, "Unable to allocate shared buffer");
61         if (buf) {
62             char* str = (char*)buf->data();
63             memcpy(str, in, len);
64             str[len] = 0;
65             return str;
66         }
67         return nullptr;
68     }
69 
70     return getEmptyString();
71 }
72 
allocFromUTF16(const char16_t * in,size_t len)73 static char* allocFromUTF16(const char16_t* in, size_t len)
74 {
75     if (len == 0) return getEmptyString();
76 
77      // Allow for closing '\0'
78     const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
79     if (resultStrLen < 1) {
80         return getEmptyString();
81     }
82 
83     SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
84     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
85     if (!buf) {
86         return getEmptyString();
87     }
88 
89     char* resultStr = (char*)buf->data();
90     utf16_to_utf8(in, len, resultStr, resultStrLen);
91     return resultStr;
92 }
93 
allocFromUTF32(const char32_t * in,size_t len)94 static char* allocFromUTF32(const char32_t* in, size_t len)
95 {
96     if (len == 0) {
97         return getEmptyString();
98     }
99 
100     const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
101     if (resultStrLen < 1) {
102         return getEmptyString();
103     }
104 
105     SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
106     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
107     if (!buf) {
108         return getEmptyString();
109     }
110 
111     char* resultStr = (char*) buf->data();
112     utf32_to_utf8(in, len, resultStr, resultStrLen);
113 
114     return resultStr;
115 }
116 
117 // ---------------------------------------------------------------------------
118 
String8()119 String8::String8()
120     : mString(getEmptyString())
121 {
122 }
123 
String8(const String8 & o)124 String8::String8(const String8& o)
125     : mString(o.mString)
126 {
127     SharedBuffer::bufferFromData(mString)->acquire();
128 }
129 
String8(const char * o)130 String8::String8(const char* o)
131     : mString(allocFromUTF8(o, strlen(o)))
132 {
133     if (mString == nullptr) {
134         mString = getEmptyString();
135     }
136 }
137 
String8(const char * o,size_t len)138 String8::String8(const char* o, size_t len)
139     : mString(allocFromUTF8(o, len))
140 {
141     if (mString == nullptr) {
142         mString = getEmptyString();
143     }
144 }
145 
String8(const String16 & o)146 String8::String8(const String16& o) : mString(allocFromUTF16(o.c_str(), o.size())) {}
147 
String8(const char16_t * o)148 String8::String8(const char16_t* o)
149     : mString(allocFromUTF16(o, strlen16(o)))
150 {
151 }
152 
String8(const char16_t * o,size_t len)153 String8::String8(const char16_t* o, size_t len)
154     : mString(allocFromUTF16(o, len))
155 {
156 }
157 
String8(const char32_t * o)158 String8::String8(const char32_t* o)
159     : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
160 
String8(const char32_t * o,size_t len)161 String8::String8(const char32_t* o, size_t len)
162     : mString(allocFromUTF32(o, len))
163 {
164 }
165 
~String8()166 String8::~String8()
167 {
168     SharedBuffer::bufferFromData(mString)->release();
169 }
170 
length() const171 size_t String8::length() const
172 {
173     return SharedBuffer::sizeFromData(mString)-1;
174 }
175 
format(const char * fmt,...)176 String8 String8::format(const char* fmt, ...)
177 {
178     va_list args;
179     va_start(args, fmt);
180 
181     String8 result(formatV(fmt, args));
182 
183     va_end(args);
184     return result;
185 }
186 
formatV(const char * fmt,va_list args)187 String8 String8::formatV(const char* fmt, va_list args)
188 {
189     String8 result;
190     result.appendFormatV(fmt, args);
191     return result;
192 }
193 
clear()194 void String8::clear() {
195     SharedBuffer::bufferFromData(mString)->release();
196     mString = getEmptyString();
197 }
198 
setTo(const String8 & other)199 void String8::setTo(const String8& other)
200 {
201     SharedBuffer::bufferFromData(other.mString)->acquire();
202     SharedBuffer::bufferFromData(mString)->release();
203     mString = other.mString;
204 }
205 
setTo(const char * other)206 status_t String8::setTo(const char* other)
207 {
208     const char *newString = allocFromUTF8(other, strlen(other));
209     SharedBuffer::bufferFromData(mString)->release();
210     mString = newString;
211     if (mString) return OK;
212 
213     mString = getEmptyString();
214     return NO_MEMORY;
215 }
216 
setTo(const char * other,size_t len)217 status_t String8::setTo(const char* other, size_t len)
218 {
219     const char *newString = allocFromUTF8(other, len);
220     SharedBuffer::bufferFromData(mString)->release();
221     mString = newString;
222     if (mString) return OK;
223 
224     mString = getEmptyString();
225     return NO_MEMORY;
226 }
227 
setTo(const char16_t * other,size_t len)228 status_t String8::setTo(const char16_t* other, size_t len)
229 {
230     const char *newString = allocFromUTF16(other, len);
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 char32_t * other,size_t len)239 status_t String8::setTo(const char32_t* other, size_t len)
240 {
241     const char *newString = allocFromUTF32(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 
append(const String8 & other)250 status_t String8::append(const String8& other)
251 {
252     const size_t otherLen = other.bytes();
253     if (bytes() == 0) {
254         setTo(other);
255         return OK;
256     } else if (otherLen == 0) {
257         return OK;
258     }
259 
260     return real_append(other.c_str(), otherLen);
261 }
262 
append(const char * other)263 status_t String8::append(const char* other)
264 {
265     return append(other, strlen(other));
266 }
267 
append(const char * other,size_t otherLen)268 status_t String8::append(const char* other, size_t otherLen)
269 {
270     if (bytes() == 0) {
271         return setTo(other, otherLen);
272     } else if (otherLen == 0) {
273         return OK;
274     }
275 
276     return real_append(other, otherLen);
277 }
278 
appendFormat(const char * fmt,...)279 status_t String8::appendFormat(const char* fmt, ...)
280 {
281     va_list args;
282     va_start(args, fmt);
283 
284     status_t result = appendFormatV(fmt, args);
285 
286     va_end(args);
287     return result;
288 }
289 
appendFormatV(const char * fmt,va_list args)290 status_t String8::appendFormatV(const char* fmt, va_list args)
291 {
292     int n, result = OK;
293     va_list tmp_args;
294 
295     /* args is undefined after vsnprintf.
296      * So we need a copy here to avoid the
297      * second vsnprintf access undefined args.
298      */
299     va_copy(tmp_args, args);
300     n = vsnprintf(nullptr, 0, fmt, tmp_args);
301     va_end(tmp_args);
302 
303     if (n < 0) return UNKNOWN_ERROR;
304 
305     if (n > 0) {
306         size_t oldLength = length();
307         if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
308             oldLength > std::numeric_limits<size_t>::max() - n - 1) {
309             return NO_MEMORY;
310         }
311         char* buf = lockBuffer(oldLength + n);
312         if (buf) {
313             vsnprintf(buf + oldLength, n + 1, fmt, args);
314         } else {
315             result = NO_MEMORY;
316         }
317     }
318     return result;
319 }
320 
real_append(const char * other,size_t otherLen)321 status_t String8::real_append(const char* other, size_t otherLen) {
322     const size_t myLen = bytes();
323 
324     SharedBuffer* buf;
325     size_t newLen;
326     if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
327         __builtin_add_overflow(newLen, 1, &newLen) ||
328         (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
329         return NO_MEMORY;
330     }
331 
332     char* str = (char*)buf->data();
333     mString = str;
334     str += myLen;
335     memcpy(str, other, otherLen);
336     str[otherLen] = '\0';
337     return OK;
338 }
339 
lockBuffer(size_t size)340 char* String8::lockBuffer(size_t size)
341 {
342     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
343         ->editResize(size+1);
344     if (buf) {
345         char* str = (char*)buf->data();
346         mString = str;
347         return str;
348     }
349     return nullptr;
350 }
351 
unlockBuffer()352 void String8::unlockBuffer()
353 {
354     unlockBuffer(strlen(mString));
355 }
356 
unlockBuffer(size_t size)357 status_t String8::unlockBuffer(size_t size)
358 {
359     if (size != this->size()) {
360         SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
361             ->editResize(size+1);
362         if (! buf) {
363             return NO_MEMORY;
364         }
365 
366         char* str = (char*)buf->data();
367         str[size] = 0;
368         mString = str;
369     }
370 
371     return OK;
372 }
373 
find(const char * other,size_t start) const374 ssize_t String8::find(const char* other, size_t start) const
375 {
376     size_t len = size();
377     if (start >= len) {
378         return -1;
379     }
380     const char* s = mString+start;
381     const char* p = strstr(s, other);
382     return p ? p-mString : -1;
383 }
384 
removeAll(const char * other)385 bool String8::removeAll(const char* other) {
386     ALOG_ASSERT(other, "String8::removeAll() requires a non-NULL string");
387 
388     if (*other == '\0')
389         return true;
390 
391     ssize_t index = find(other);
392     if (index < 0) return false;
393 
394     char* buf = lockBuffer(size());
395     if (!buf) return false; // out of memory
396 
397     size_t skip = strlen(other);
398     size_t len = size();
399     size_t tail = index;
400     while (size_t(index) < len) {
401         ssize_t next = find(other, index + skip);
402         if (next < 0) {
403             next = len;
404         }
405 
406         memmove(buf + tail, buf + index + skip, next - index - skip);
407         tail += next - index - skip;
408         index = next;
409     }
410     unlockBuffer(tail);
411     return true;
412 }
413 
toLower()414 void String8::toLower()
415 {
416     const size_t length = size();
417     if (length == 0) return;
418 
419     char* buf = lockBuffer(length);
420     for (size_t i = length; i > 0; --i) {
421         *buf = static_cast<char>(tolower(*buf));
422         buf++;
423     }
424     unlockBuffer(length);
425 }
426 
427 // ---------------------------------------------------------------------------
428 // Path functions
429 
430 // TODO: we should remove all the path functions from String8
431 #if defined(_WIN32)
432 #define OS_PATH_SEPARATOR '\\'
433 #else
434 #define OS_PATH_SEPARATOR '/'
435 #endif
436 
getPathDir(void) const437 String8 String8::getPathDir(void) const
438 {
439     const char* cp;
440     const char*const str = mString;
441 
442     cp = strrchr(str, OS_PATH_SEPARATOR);
443     if (cp == nullptr)
444         return String8("");
445     else
446         return String8(str, cp - str);
447 }
448 
449 /*
450  * Helper function for finding the start of an extension in a pathname.
451  *
452  * Returns a pointer inside mString, or NULL if no extension was found.
453  */
find_extension(const char * str)454 static const char* find_extension(const char* str) {
455     const char* lastSlash;
456     const char* lastDot;
457 
458     // only look at the filename
459     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
460     if (lastSlash == nullptr)
461         lastSlash = str;
462     else
463         lastSlash++;
464 
465     // find the last dot
466     lastDot = strrchr(lastSlash, '.');
467     if (lastDot == nullptr)
468         return nullptr;
469 
470     // looks good, ship it
471     return lastDot;
472 }
473 
getPathExtension(void) const474 String8 String8::getPathExtension(void) const
475 {
476     auto ext = find_extension(mString);
477     if (ext != nullptr)
478         return String8(ext);
479     else
480         return String8("");
481 }
482 
483 }; // namespace android
484