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