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 "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 
39 // Separator used by resource paths. This is not platform dependent contrary
40 // to OS_PATH_SEPARATOR.
41 #define RES_PATH_SEPARATOR '/'
42 
getEmptyString()43 static inline char* getEmptyString() {
44     static SharedBuffer* gEmptyStringBuf = [] {
45         SharedBuffer* buf = SharedBuffer::alloc(1);
46         char* str = static_cast<char*>(buf->data());
47         *str = 0;
48         return buf;
49     }();
50 
51     gEmptyStringBuf->acquire();
52     return static_cast<char*>(gEmptyStringBuf->data());
53 }
54 
55 // ---------------------------------------------------------------------------
56 
allocFromUTF8(const char * in,size_t len)57 static char* allocFromUTF8(const char* in, size_t len)
58 {
59     if (len > 0) {
60         if (len == SIZE_MAX) {
61             return nullptr;
62         }
63         SharedBuffer* buf = SharedBuffer::alloc(len+1);
64         ALOG_ASSERT(buf, "Unable to allocate shared buffer");
65         if (buf) {
66             char* str = (char*)buf->data();
67             memcpy(str, in, len);
68             str[len] = 0;
69             return str;
70         }
71         return nullptr;
72     }
73 
74     return getEmptyString();
75 }
76 
allocFromUTF16(const char16_t * in,size_t len)77 static char* allocFromUTF16(const char16_t* in, size_t len)
78 {
79     if (len == 0) return getEmptyString();
80 
81      // Allow for closing '\0'
82     const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
83     if (resultStrLen < 1) {
84         return getEmptyString();
85     }
86 
87     SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
88     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
89     if (!buf) {
90         return getEmptyString();
91     }
92 
93     char* resultStr = (char*)buf->data();
94     utf16_to_utf8(in, len, resultStr, resultStrLen);
95     return resultStr;
96 }
97 
allocFromUTF32(const char32_t * in,size_t len)98 static char* allocFromUTF32(const char32_t* in, size_t len)
99 {
100     if (len == 0) {
101         return getEmptyString();
102     }
103 
104     const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
105     if (resultStrLen < 1) {
106         return getEmptyString();
107     }
108 
109     SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
110     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
111     if (!buf) {
112         return getEmptyString();
113     }
114 
115     char* resultStr = (char*) buf->data();
116     utf32_to_utf8(in, len, resultStr, resultStrLen);
117 
118     return resultStr;
119 }
120 
121 // ---------------------------------------------------------------------------
122 
String8()123 String8::String8()
124     : mString(getEmptyString())
125 {
126 }
127 
String8(const String8 & o)128 String8::String8(const String8& o)
129     : mString(o.mString)
130 {
131     SharedBuffer::bufferFromData(mString)->acquire();
132 }
133 
String8(const char * o)134 String8::String8(const char* o)
135     : mString(allocFromUTF8(o, strlen(o)))
136 {
137     if (mString == nullptr) {
138         mString = getEmptyString();
139     }
140 }
141 
String8(const char * o,size_t len)142 String8::String8(const char* o, size_t len)
143     : mString(allocFromUTF8(o, len))
144 {
145     if (mString == nullptr) {
146         mString = getEmptyString();
147     }
148 }
149 
String8(const String16 & o)150 String8::String8(const String16& o)
151     : mString(allocFromUTF16(o.string(), o.size()))
152 {
153 }
154 
String8(const char16_t * o)155 String8::String8(const char16_t* o)
156     : mString(allocFromUTF16(o, strlen16(o)))
157 {
158 }
159 
String8(const char16_t * o,size_t len)160 String8::String8(const char16_t* o, size_t len)
161     : mString(allocFromUTF16(o, len))
162 {
163 }
164 
String8(const char32_t * o)165 String8::String8(const char32_t* o)
166     : mString(allocFromUTF32(o, strlen32(o)))
167 {
168 }
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) {
313         size_t oldLength = length();
314         char* buf = lockBuffer(oldLength + n);
315         if (buf) {
316             vsnprintf(buf + oldLength, n + 1, fmt, args);
317         } else {
318             result = NO_MEMORY;
319         }
320     }
321     return result;
322 }
323 
real_append(const char * other,size_t otherLen)324 status_t String8::real_append(const char* other, size_t otherLen)
325 {
326     const size_t myLen = bytes();
327 
328     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
329         ->editResize(myLen+otherLen+1);
330     if (buf) {
331         char* str = (char*)buf->data();
332         mString = str;
333         str += myLen;
334         memcpy(str, other, otherLen);
335         str[otherLen] = '\0';
336         return OK;
337     }
338     return NO_MEMORY;
339 }
340 
lockBuffer(size_t size)341 char* String8::lockBuffer(size_t size)
342 {
343     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
344         ->editResize(size+1);
345     if (buf) {
346         char* str = (char*)buf->data();
347         mString = str;
348         return str;
349     }
350     return nullptr;
351 }
352 
unlockBuffer()353 void String8::unlockBuffer()
354 {
355     unlockBuffer(strlen(mString));
356 }
357 
unlockBuffer(size_t size)358 status_t String8::unlockBuffer(size_t size)
359 {
360     if (size != this->size()) {
361         SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
362             ->editResize(size+1);
363         if (! buf) {
364             return NO_MEMORY;
365         }
366 
367         char* str = (char*)buf->data();
368         str[size] = 0;
369         mString = str;
370     }
371 
372     return OK;
373 }
374 
find(const char * other,size_t start) const375 ssize_t String8::find(const char* other, size_t start) const
376 {
377     size_t len = size();
378     if (start >= len) {
379         return -1;
380     }
381     const char* s = mString+start;
382     const char* p = strstr(s, other);
383     return p ? p-mString : -1;
384 }
385 
removeAll(const char * other)386 bool String8::removeAll(const char* other) {
387     ssize_t index = find(other);
388     if (index < 0) return false;
389 
390     char* buf = lockBuffer(size());
391     if (!buf) return false; // out of memory
392 
393     size_t skip = strlen(other);
394     size_t len = size();
395     size_t tail = index;
396     while (size_t(index) < len) {
397         ssize_t next = find(other, index + skip);
398         if (next < 0) {
399             next = len;
400         }
401 
402         memmove(buf + tail, buf + index + skip, next - index - skip);
403         tail += next - index - skip;
404         index = next;
405     }
406     unlockBuffer(tail);
407     return true;
408 }
409 
toLower()410 void String8::toLower()
411 {
412     toLower(0, size());
413 }
414 
toLower(size_t start,size_t length)415 void String8::toLower(size_t start, size_t length)
416 {
417     const size_t len = size();
418     if (start >= len) {
419         return;
420     }
421     if (start+length > len) {
422         length = len-start;
423     }
424     char* buf = lockBuffer(len);
425     buf += start;
426     while (length > 0) {
427         *buf = static_cast<char>(tolower(*buf));
428         buf++;
429         length--;
430     }
431     unlockBuffer(len);
432 }
433 
toUpper()434 void String8::toUpper()
435 {
436     toUpper(0, size());
437 }
438 
toUpper(size_t start,size_t length)439 void String8::toUpper(size_t start, size_t length)
440 {
441     const size_t len = size();
442     if (start >= len) {
443         return;
444     }
445     if (start+length > len) {
446         length = len-start;
447     }
448     char* buf = lockBuffer(len);
449     buf += start;
450     while (length > 0) {
451         *buf = static_cast<char>(toupper(*buf));
452         buf++;
453         length--;
454     }
455     unlockBuffer(len);
456 }
457 
458 // ---------------------------------------------------------------------------
459 // Path functions
460 
setPathName(const char * name)461 void String8::setPathName(const char* name)
462 {
463     setPathName(name, strlen(name));
464 }
465 
setPathName(const char * name,size_t len)466 void String8::setPathName(const char* name, size_t len)
467 {
468     char* buf = lockBuffer(len);
469 
470     memcpy(buf, name, len);
471 
472     // remove trailing path separator, if present
473     if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
474         len--;
475 
476     buf[len] = '\0';
477 
478     unlockBuffer(len);
479 }
480 
getPathLeaf(void) const481 String8 String8::getPathLeaf(void) const
482 {
483     const char* cp;
484     const char*const buf = mString;
485 
486     cp = strrchr(buf, OS_PATH_SEPARATOR);
487     if (cp == nullptr)
488         return String8(*this);
489     else
490         return String8(cp+1);
491 }
492 
getPathDir(void) const493 String8 String8::getPathDir(void) const
494 {
495     const char* cp;
496     const char*const str = mString;
497 
498     cp = strrchr(str, OS_PATH_SEPARATOR);
499     if (cp == nullptr)
500         return String8("");
501     else
502         return String8(str, cp - str);
503 }
504 
walkPath(String8 * outRemains) const505 String8 String8::walkPath(String8* outRemains) const
506 {
507     const char* cp;
508     const char*const str = mString;
509     const char* buf = str;
510 
511     cp = strchr(buf, OS_PATH_SEPARATOR);
512     if (cp == buf) {
513         // don't include a leading '/'.
514         buf = buf+1;
515         cp = strchr(buf, OS_PATH_SEPARATOR);
516     }
517 
518     if (cp == nullptr) {
519         String8 res = buf != str ? String8(buf) : *this;
520         if (outRemains) *outRemains = String8("");
521         return res;
522     }
523 
524     String8 res(buf, cp-buf);
525     if (outRemains) *outRemains = String8(cp+1);
526     return res;
527 }
528 
529 /*
530  * Helper function for finding the start of an extension in a pathname.
531  *
532  * Returns a pointer inside mString, or NULL if no extension was found.
533  */
find_extension(void) const534 char* String8::find_extension(void) const
535 {
536     const char* lastSlash;
537     const char* lastDot;
538     const char* const str = mString;
539 
540     // only look at the filename
541     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
542     if (lastSlash == nullptr)
543         lastSlash = str;
544     else
545         lastSlash++;
546 
547     // find the last dot
548     lastDot = strrchr(lastSlash, '.');
549     if (lastDot == nullptr)
550         return nullptr;
551 
552     // looks good, ship it
553     return const_cast<char*>(lastDot);
554 }
555 
getPathExtension(void) const556 String8 String8::getPathExtension(void) const
557 {
558     char* ext;
559 
560     ext = find_extension();
561     if (ext != nullptr)
562         return String8(ext);
563     else
564         return String8("");
565 }
566 
getBasePath(void) const567 String8 String8::getBasePath(void) const
568 {
569     char* ext;
570     const char* const str = mString;
571 
572     ext = find_extension();
573     if (ext == nullptr)
574         return String8(*this);
575     else
576         return String8(str, ext - str);
577 }
578 
appendPath(const char * name)579 String8& String8::appendPath(const char* name)
580 {
581     // TODO: The test below will fail for Win32 paths. Fix later or ignore.
582     if (name[0] != OS_PATH_SEPARATOR) {
583         if (*name == '\0') {
584             // nothing to do
585             return *this;
586         }
587 
588         size_t len = length();
589         if (len == 0) {
590             // no existing filename, just use the new one
591             setPathName(name);
592             return *this;
593         }
594 
595         // make room for oldPath + '/' + newPath
596         int newlen = strlen(name);
597 
598         char* buf = lockBuffer(len+1+newlen);
599 
600         // insert a '/' if needed
601         if (buf[len-1] != OS_PATH_SEPARATOR)
602             buf[len++] = OS_PATH_SEPARATOR;
603 
604         memcpy(buf+len, name, newlen+1);
605         len += newlen;
606 
607         unlockBuffer(len);
608 
609         return *this;
610     } else {
611         setPathName(name);
612         return *this;
613     }
614 }
615 
convertToResPath()616 String8& String8::convertToResPath()
617 {
618 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
619     size_t len = length();
620     if (len > 0) {
621         char * buf = lockBuffer(len);
622         for (char * end = buf + len; buf < end; ++buf) {
623             if (*buf == OS_PATH_SEPARATOR)
624                 *buf = RES_PATH_SEPARATOR;
625         }
626         unlockBuffer(len);
627     }
628 #endif
629     return *this;
630 }
631 
632 }; // namespace android
633