• 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 (static_cast<size_t>(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(String8 & s,const char * name)434 static void setPathName(String8& s, const char* name) {
435     size_t len = strlen(name);
436     char* buf = s.lockBuffer(len);
437 
438     memcpy(buf, name, len);
439 
440     // remove trailing path separator, if present
441     if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
442     buf[len] = '\0';
443 
444     s.unlockBuffer(len);
445 }
446 
getPathLeaf(void) const447 String8 String8::getPathLeaf(void) const
448 {
449     const char* cp;
450     const char*const buf = mString;
451 
452     cp = strrchr(buf, OS_PATH_SEPARATOR);
453     if (cp == nullptr)
454         return String8(*this);
455     else
456         return String8(cp+1);
457 }
458 
getPathDir(void) const459 String8 String8::getPathDir(void) const
460 {
461     const char* cp;
462     const char*const str = mString;
463 
464     cp = strrchr(str, OS_PATH_SEPARATOR);
465     if (cp == nullptr)
466         return String8("");
467     else
468         return String8(str, cp - str);
469 }
470 
walkPath(String8 * outRemains) const471 String8 String8::walkPath(String8* outRemains) const
472 {
473     const char* cp;
474     const char*const str = mString;
475     const char* buf = str;
476 
477     cp = strchr(buf, OS_PATH_SEPARATOR);
478     if (cp == buf) {
479         // don't include a leading '/'.
480         buf = buf+1;
481         cp = strchr(buf, OS_PATH_SEPARATOR);
482     }
483 
484     if (cp == nullptr) {
485         String8 res = buf != str ? String8(buf) : *this;
486         if (outRemains) *outRemains = String8("");
487         return res;
488     }
489 
490     String8 res(buf, cp-buf);
491     if (outRemains) *outRemains = String8(cp+1);
492     return res;
493 }
494 
495 /*
496  * Helper function for finding the start of an extension in a pathname.
497  *
498  * Returns a pointer inside mString, or NULL if no extension was found.
499  */
find_extension(void) const500 char* String8::find_extension(void) const
501 {
502     const char* lastSlash;
503     const char* lastDot;
504     const char* const str = mString;
505 
506     // only look at the filename
507     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
508     if (lastSlash == nullptr)
509         lastSlash = str;
510     else
511         lastSlash++;
512 
513     // find the last dot
514     lastDot = strrchr(lastSlash, '.');
515     if (lastDot == nullptr)
516         return nullptr;
517 
518     // looks good, ship it
519     return const_cast<char*>(lastDot);
520 }
521 
getPathExtension(void) const522 String8 String8::getPathExtension(void) const
523 {
524     char* ext;
525 
526     ext = find_extension();
527     if (ext != nullptr)
528         return String8(ext);
529     else
530         return String8("");
531 }
532 
getBasePath(void) const533 String8 String8::getBasePath(void) const
534 {
535     char* ext;
536     const char* const str = mString;
537 
538     ext = find_extension();
539     if (ext == nullptr)
540         return String8(*this);
541     else
542         return String8(str, ext - str);
543 }
544 
appendPath(const char * name)545 String8& String8::appendPath(const char* name)
546 {
547     // TODO: The test below will fail for Win32 paths. Fix later or ignore.
548     if (name[0] != OS_PATH_SEPARATOR) {
549         if (*name == '\0') {
550             // nothing to do
551             return *this;
552         }
553 
554         size_t len = length();
555         if (len == 0) {
556             // no existing filename, just use the new one
557             setPathName(*this, name);
558             return *this;
559         }
560 
561         // make room for oldPath + '/' + newPath
562         int newlen = strlen(name);
563 
564         char* buf = lockBuffer(len+1+newlen);
565 
566         // insert a '/' if needed
567         if (buf[len-1] != OS_PATH_SEPARATOR)
568             buf[len++] = OS_PATH_SEPARATOR;
569 
570         memcpy(buf+len, name, newlen+1);
571         len += newlen;
572 
573         unlockBuffer(len);
574 
575         return *this;
576     } else {
577         setPathName(*this, name);
578         return *this;
579     }
580 }
581 
convertToResPath()582 String8& String8::convertToResPath()
583 {
584 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
585     size_t len = length();
586     if (len > 0) {
587         char * buf = lockBuffer(len);
588         for (char * end = buf + len; buf < end; ++buf) {
589             if (*buf == OS_PATH_SEPARATOR)
590                 *buf = RES_PATH_SEPARATOR;
591         }
592         unlockBuffer(len);
593     }
594 #endif
595     return *this;
596 }
597 
598 }; // namespace android
599