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