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