• 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/Unicode.h>
25 #include <utils/String16.h>
26 #include <utils/threads.h>
27 
28 #include <ctype.h>
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 
45 static SharedBuffer* gEmptyStringBuf = NULL;
46 static char* gEmptyString = NULL;
47 
48 extern int gDarwinCantLoadAllObjects;
49 int gDarwinIsReallyAnnoying;
50 
51 void initialize_string8();
52 
getEmptyString()53 static inline char* getEmptyString()
54 {
55     gEmptyStringBuf->acquire();
56     return gEmptyString;
57 }
58 
initialize_string8()59 void initialize_string8()
60 {
61     // HACK: This dummy dependency forces linking libutils Static.cpp,
62     // which is needed to initialize String8/String16 classes.
63     // These variables are named for Darwin, but are needed elsewhere too,
64     // including static linking on any platform.
65     gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects;
66 
67     SharedBuffer* buf = SharedBuffer::alloc(1);
68     char* str = (char*)buf->data();
69     *str = 0;
70     gEmptyStringBuf = buf;
71     gEmptyString = str;
72 }
73 
terminate_string8()74 void terminate_string8()
75 {
76     SharedBuffer::bufferFromData(gEmptyString)->release();
77     gEmptyStringBuf = NULL;
78     gEmptyString = NULL;
79 }
80 
81 // ---------------------------------------------------------------------------
82 
allocFromUTF8(const char * in,size_t len)83 static char* allocFromUTF8(const char* in, size_t len)
84 {
85     if (len > 0) {
86         if (len == SIZE_MAX) {
87             return NULL;
88         }
89         SharedBuffer* buf = SharedBuffer::alloc(len+1);
90         ALOG_ASSERT(buf, "Unable to allocate shared buffer");
91         if (buf) {
92             char* str = (char*)buf->data();
93             memcpy(str, in, len);
94             str[len] = 0;
95             return str;
96         }
97         return NULL;
98     }
99 
100     return getEmptyString();
101 }
102 
allocFromUTF16(const char16_t * in,size_t len)103 static char* allocFromUTF16(const char16_t* in, size_t len)
104 {
105     if (len == 0) return getEmptyString();
106 
107      // Allow for closing '\0'
108     const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
109     if (resultStrLen < 1) {
110         return getEmptyString();
111     }
112 
113     SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
114     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
115     if (!buf) {
116         return getEmptyString();
117     }
118 
119     char* resultStr = (char*)buf->data();
120     utf16_to_utf8(in, len, resultStr, resultStrLen);
121     return resultStr;
122 }
123 
allocFromUTF32(const char32_t * in,size_t len)124 static char* allocFromUTF32(const char32_t* in, size_t len)
125 {
126     if (len == 0) {
127         return getEmptyString();
128     }
129 
130     const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
131     if (resultStrLen < 1) {
132         return getEmptyString();
133     }
134 
135     SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
136     ALOG_ASSERT(buf, "Unable to allocate shared buffer");
137     if (!buf) {
138         return getEmptyString();
139     }
140 
141     char* resultStr = (char*) buf->data();
142     utf32_to_utf8(in, len, resultStr, resultStrLen);
143 
144     return resultStr;
145 }
146 
147 // ---------------------------------------------------------------------------
148 
String8()149 String8::String8()
150     : mString(getEmptyString())
151 {
152 }
153 
String8(StaticLinkage)154 String8::String8(StaticLinkage)
155     : mString(0)
156 {
157     // this constructor is used when we can't rely on the static-initializers
158     // having run. In this case we always allocate an empty string. It's less
159     // efficient than using getEmptyString(), but we assume it's uncommon.
160 
161     char* data = static_cast<char*>(
162             SharedBuffer::alloc(sizeof(char))->data());
163     data[0] = 0;
164     mString = data;
165 }
166 
String8(const String8 & o)167 String8::String8(const String8& o)
168     : mString(o.mString)
169 {
170     SharedBuffer::bufferFromData(mString)->acquire();
171 }
172 
String8(const char * o)173 String8::String8(const char* o)
174     : mString(allocFromUTF8(o, strlen(o)))
175 {
176     if (mString == NULL) {
177         mString = getEmptyString();
178     }
179 }
180 
String8(const char * o,size_t len)181 String8::String8(const char* o, size_t len)
182     : mString(allocFromUTF8(o, len))
183 {
184     if (mString == NULL) {
185         mString = getEmptyString();
186     }
187 }
188 
String8(const String16 & o)189 String8::String8(const String16& o)
190     : mString(allocFromUTF16(o.string(), o.size()))
191 {
192 }
193 
String8(const char16_t * o)194 String8::String8(const char16_t* o)
195     : mString(allocFromUTF16(o, strlen16(o)))
196 {
197 }
198 
String8(const char16_t * o,size_t len)199 String8::String8(const char16_t* o, size_t len)
200     : mString(allocFromUTF16(o, len))
201 {
202 }
203 
String8(const char32_t * o)204 String8::String8(const char32_t* o)
205     : mString(allocFromUTF32(o, strlen32(o)))
206 {
207 }
208 
String8(const char32_t * o,size_t len)209 String8::String8(const char32_t* o, size_t len)
210     : mString(allocFromUTF32(o, len))
211 {
212 }
213 
~String8()214 String8::~String8()
215 {
216     SharedBuffer::bufferFromData(mString)->release();
217 }
218 
length() const219 size_t String8::length() const
220 {
221     return SharedBuffer::sizeFromData(mString)-1;
222 }
223 
format(const char * fmt,...)224 String8 String8::format(const char* fmt, ...)
225 {
226     va_list args;
227     va_start(args, fmt);
228 
229     String8 result(formatV(fmt, args));
230 
231     va_end(args);
232     return result;
233 }
234 
formatV(const char * fmt,va_list args)235 String8 String8::formatV(const char* fmt, va_list args)
236 {
237     String8 result;
238     result.appendFormatV(fmt, args);
239     return result;
240 }
241 
clear()242 void String8::clear() {
243     SharedBuffer::bufferFromData(mString)->release();
244     mString = getEmptyString();
245 }
246 
setTo(const String8 & other)247 void String8::setTo(const String8& other)
248 {
249     SharedBuffer::bufferFromData(other.mString)->acquire();
250     SharedBuffer::bufferFromData(mString)->release();
251     mString = other.mString;
252 }
253 
setTo(const char * other)254 status_t String8::setTo(const char* other)
255 {
256     const char *newString = allocFromUTF8(other, strlen(other));
257     SharedBuffer::bufferFromData(mString)->release();
258     mString = newString;
259     if (mString) return NO_ERROR;
260 
261     mString = getEmptyString();
262     return NO_MEMORY;
263 }
264 
setTo(const char * other,size_t len)265 status_t String8::setTo(const char* other, size_t len)
266 {
267     const char *newString = allocFromUTF8(other, len);
268     SharedBuffer::bufferFromData(mString)->release();
269     mString = newString;
270     if (mString) return NO_ERROR;
271 
272     mString = getEmptyString();
273     return NO_MEMORY;
274 }
275 
setTo(const char16_t * other,size_t len)276 status_t String8::setTo(const char16_t* other, size_t len)
277 {
278     const char *newString = allocFromUTF16(other, len);
279     SharedBuffer::bufferFromData(mString)->release();
280     mString = newString;
281     if (mString) return NO_ERROR;
282 
283     mString = getEmptyString();
284     return NO_MEMORY;
285 }
286 
setTo(const char32_t * other,size_t len)287 status_t String8::setTo(const char32_t* other, size_t len)
288 {
289     const char *newString = allocFromUTF32(other, len);
290     SharedBuffer::bufferFromData(mString)->release();
291     mString = newString;
292     if (mString) return NO_ERROR;
293 
294     mString = getEmptyString();
295     return NO_MEMORY;
296 }
297 
append(const String8 & other)298 status_t String8::append(const String8& other)
299 {
300     const size_t otherLen = other.bytes();
301     if (bytes() == 0) {
302         setTo(other);
303         return NO_ERROR;
304     } else if (otherLen == 0) {
305         return NO_ERROR;
306     }
307 
308     return real_append(other.string(), otherLen);
309 }
310 
append(const char * other)311 status_t String8::append(const char* other)
312 {
313     return append(other, strlen(other));
314 }
315 
append(const char * other,size_t otherLen)316 status_t String8::append(const char* other, size_t otherLen)
317 {
318     if (bytes() == 0) {
319         return setTo(other, otherLen);
320     } else if (otherLen == 0) {
321         return NO_ERROR;
322     }
323 
324     return real_append(other, otherLen);
325 }
326 
appendFormat(const char * fmt,...)327 status_t String8::appendFormat(const char* fmt, ...)
328 {
329     va_list args;
330     va_start(args, fmt);
331 
332     status_t result = appendFormatV(fmt, args);
333 
334     va_end(args);
335     return result;
336 }
337 
appendFormatV(const char * fmt,va_list args)338 status_t String8::appendFormatV(const char* fmt, va_list args)
339 {
340     int n, result = NO_ERROR;
341     va_list tmp_args;
342 
343     /* args is undefined after vsnprintf.
344      * So we need a copy here to avoid the
345      * second vsnprintf access undefined args.
346      */
347     va_copy(tmp_args, args);
348     n = vsnprintf(NULL, 0, fmt, tmp_args);
349     va_end(tmp_args);
350 
351     if (n != 0) {
352         size_t oldLength = length();
353         char* buf = lockBuffer(oldLength + n);
354         if (buf) {
355             vsnprintf(buf + oldLength, n + 1, fmt, args);
356         } else {
357             result = NO_MEMORY;
358         }
359     }
360     return result;
361 }
362 
real_append(const char * other,size_t otherLen)363 status_t String8::real_append(const char* other, size_t otherLen)
364 {
365     const size_t myLen = bytes();
366 
367     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
368         ->editResize(myLen+otherLen+1);
369     if (buf) {
370         char* str = (char*)buf->data();
371         mString = str;
372         str += myLen;
373         memcpy(str, other, otherLen);
374         str[otherLen] = '\0';
375         return NO_ERROR;
376     }
377     return NO_MEMORY;
378 }
379 
lockBuffer(size_t size)380 char* String8::lockBuffer(size_t size)
381 {
382     SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
383         ->editResize(size+1);
384     if (buf) {
385         char* str = (char*)buf->data();
386         mString = str;
387         return str;
388     }
389     return NULL;
390 }
391 
unlockBuffer()392 void String8::unlockBuffer()
393 {
394     unlockBuffer(strlen(mString));
395 }
396 
unlockBuffer(size_t size)397 status_t String8::unlockBuffer(size_t size)
398 {
399     if (size != this->size()) {
400         SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
401             ->editResize(size+1);
402         if (! buf) {
403             return NO_MEMORY;
404         }
405 
406         char* str = (char*)buf->data();
407         str[size] = 0;
408         mString = str;
409     }
410 
411     return NO_ERROR;
412 }
413 
find(const char * other,size_t start) const414 ssize_t String8::find(const char* other, size_t start) const
415 {
416     size_t len = size();
417     if (start >= len) {
418         return -1;
419     }
420     const char* s = mString+start;
421     const char* p = strstr(s, other);
422     return p ? p-mString : -1;
423 }
424 
removeAll(const char * other)425 bool String8::removeAll(const char* other) {
426     ssize_t index = find(other);
427     if (index < 0) return false;
428 
429     char* buf = lockBuffer(size());
430     if (!buf) return false; // out of memory
431 
432     size_t skip = strlen(other);
433     size_t len = size();
434     size_t tail = index;
435     while (size_t(index) < len) {
436         ssize_t next = find(other, index + skip);
437         if (next < 0) {
438             next = len;
439         }
440 
441         memmove(buf + tail, buf + index + skip, next - index - skip);
442         tail += next - index - skip;
443         index = next;
444     }
445     unlockBuffer(tail);
446     return true;
447 }
448 
toLower()449 void String8::toLower()
450 {
451     toLower(0, size());
452 }
453 
toLower(size_t start,size_t length)454 void String8::toLower(size_t start, size_t length)
455 {
456     const size_t len = size();
457     if (start >= len) {
458         return;
459     }
460     if (start+length > len) {
461         length = len-start;
462     }
463     char* buf = lockBuffer(len);
464     buf += start;
465     while (length > 0) {
466         *buf = tolower(*buf);
467         buf++;
468         length--;
469     }
470     unlockBuffer(len);
471 }
472 
toUpper()473 void String8::toUpper()
474 {
475     toUpper(0, size());
476 }
477 
toUpper(size_t start,size_t length)478 void String8::toUpper(size_t start, size_t length)
479 {
480     const size_t len = size();
481     if (start >= len) {
482         return;
483     }
484     if (start+length > len) {
485         length = len-start;
486     }
487     char* buf = lockBuffer(len);
488     buf += start;
489     while (length > 0) {
490         *buf = toupper(*buf);
491         buf++;
492         length--;
493     }
494     unlockBuffer(len);
495 }
496 
getUtf32Length() const497 size_t String8::getUtf32Length() const
498 {
499     return utf8_to_utf32_length(mString, length());
500 }
501 
getUtf32At(size_t index,size_t * next_index) const502 int32_t String8::getUtf32At(size_t index, size_t *next_index) const
503 {
504     return utf32_from_utf8_at(mString, length(), index, next_index);
505 }
506 
getUtf32(char32_t * dst) const507 void String8::getUtf32(char32_t* dst) const
508 {
509     utf8_to_utf32(mString, length(), dst);
510 }
511 
512 // ---------------------------------------------------------------------------
513 // Path functions
514 
setPathName(const char * name)515 void String8::setPathName(const char* name)
516 {
517     setPathName(name, strlen(name));
518 }
519 
setPathName(const char * name,size_t len)520 void String8::setPathName(const char* name, size_t len)
521 {
522     char* buf = lockBuffer(len);
523 
524     memcpy(buf, name, len);
525 
526     // remove trailing path separator, if present
527     if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
528         len--;
529 
530     buf[len] = '\0';
531 
532     unlockBuffer(len);
533 }
534 
getPathLeaf(void) const535 String8 String8::getPathLeaf(void) const
536 {
537     const char* cp;
538     const char*const buf = mString;
539 
540     cp = strrchr(buf, OS_PATH_SEPARATOR);
541     if (cp == NULL)
542         return String8(*this);
543     else
544         return String8(cp+1);
545 }
546 
getPathDir(void) const547 String8 String8::getPathDir(void) const
548 {
549     const char* cp;
550     const char*const str = mString;
551 
552     cp = strrchr(str, OS_PATH_SEPARATOR);
553     if (cp == NULL)
554         return String8("");
555     else
556         return String8(str, cp - str);
557 }
558 
walkPath(String8 * outRemains) const559 String8 String8::walkPath(String8* outRemains) const
560 {
561     const char* cp;
562     const char*const str = mString;
563     const char* buf = str;
564 
565     cp = strchr(buf, OS_PATH_SEPARATOR);
566     if (cp == buf) {
567         // don't include a leading '/'.
568         buf = buf+1;
569         cp = strchr(buf, OS_PATH_SEPARATOR);
570     }
571 
572     if (cp == NULL) {
573         String8 res = buf != str ? String8(buf) : *this;
574         if (outRemains) *outRemains = String8("");
575         return res;
576     }
577 
578     String8 res(buf, cp-buf);
579     if (outRemains) *outRemains = String8(cp+1);
580     return res;
581 }
582 
583 /*
584  * Helper function for finding the start of an extension in a pathname.
585  *
586  * Returns a pointer inside mString, or NULL if no extension was found.
587  */
find_extension(void) const588 char* String8::find_extension(void) const
589 {
590     const char* lastSlash;
591     const char* lastDot;
592     const char* const str = mString;
593 
594     // only look at the filename
595     lastSlash = strrchr(str, OS_PATH_SEPARATOR);
596     if (lastSlash == NULL)
597         lastSlash = str;
598     else
599         lastSlash++;
600 
601     // find the last dot
602     lastDot = strrchr(lastSlash, '.');
603     if (lastDot == NULL)
604         return NULL;
605 
606     // looks good, ship it
607     return const_cast<char*>(lastDot);
608 }
609 
getPathExtension(void) const610 String8 String8::getPathExtension(void) const
611 {
612     char* ext;
613 
614     ext = find_extension();
615     if (ext != NULL)
616         return String8(ext);
617     else
618         return String8("");
619 }
620 
getBasePath(void) const621 String8 String8::getBasePath(void) const
622 {
623     char* ext;
624     const char* const str = mString;
625 
626     ext = find_extension();
627     if (ext == NULL)
628         return String8(*this);
629     else
630         return String8(str, ext - str);
631 }
632 
appendPath(const char * name)633 String8& String8::appendPath(const char* name)
634 {
635     // TODO: The test below will fail for Win32 paths. Fix later or ignore.
636     if (name[0] != OS_PATH_SEPARATOR) {
637         if (*name == '\0') {
638             // nothing to do
639             return *this;
640         }
641 
642         size_t len = length();
643         if (len == 0) {
644             // no existing filename, just use the new one
645             setPathName(name);
646             return *this;
647         }
648 
649         // make room for oldPath + '/' + newPath
650         int newlen = strlen(name);
651 
652         char* buf = lockBuffer(len+1+newlen);
653 
654         // insert a '/' if needed
655         if (buf[len-1] != OS_PATH_SEPARATOR)
656             buf[len++] = OS_PATH_SEPARATOR;
657 
658         memcpy(buf+len, name, newlen+1);
659         len += newlen;
660 
661         unlockBuffer(len);
662 
663         return *this;
664     } else {
665         setPathName(name);
666         return *this;
667     }
668 }
669 
convertToResPath()670 String8& String8::convertToResPath()
671 {
672 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
673     size_t len = length();
674     if (len > 0) {
675         char * buf = lockBuffer(len);
676         for (char * end = buf + len; buf < end; ++buf) {
677             if (*buf == OS_PATH_SEPARATOR)
678                 *buf = RES_PATH_SEPARATOR;
679         }
680         unlockBuffer(len);
681     }
682 #endif
683     return *this;
684 }
685 
686 }; // namespace android
687