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