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