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(StaticLinkage)128 String8::String8(StaticLinkage)
129 : mString(nullptr)
130 {
131 // this constructor is used when we can't rely on the static-initializers
132 // having run. In this case we always allocate an empty string. It's less
133 // efficient than using getEmptyString(), but we assume it's uncommon.
134
135 char* data = static_cast<char*>(
136 SharedBuffer::alloc(sizeof(char))->data());
137 data[0] = 0;
138 mString = data;
139 }
140
String8(const String8 & o)141 String8::String8(const String8& o)
142 : mString(o.mString)
143 {
144 SharedBuffer::bufferFromData(mString)->acquire();
145 }
146
String8(const char * o)147 String8::String8(const char* o)
148 : mString(allocFromUTF8(o, strlen(o)))
149 {
150 if (mString == nullptr) {
151 mString = getEmptyString();
152 }
153 }
154
String8(const char * o,size_t len)155 String8::String8(const char* o, size_t len)
156 : mString(allocFromUTF8(o, len))
157 {
158 if (mString == nullptr) {
159 mString = getEmptyString();
160 }
161 }
162
String8(const String16 & o)163 String8::String8(const String16& o)
164 : mString(allocFromUTF16(o.string(), o.size()))
165 {
166 }
167
String8(const char16_t * o)168 String8::String8(const char16_t* o)
169 : mString(allocFromUTF16(o, strlen16(o)))
170 {
171 }
172
String8(const char16_t * o,size_t len)173 String8::String8(const char16_t* o, size_t len)
174 : mString(allocFromUTF16(o, len))
175 {
176 }
177
String8(const char32_t * o)178 String8::String8(const char32_t* o)
179 : mString(allocFromUTF32(o, strlen32(o)))
180 {
181 }
182
String8(const char32_t * o,size_t len)183 String8::String8(const char32_t* o, size_t len)
184 : mString(allocFromUTF32(o, len))
185 {
186 }
187
~String8()188 String8::~String8()
189 {
190 SharedBuffer::bufferFromData(mString)->release();
191 }
192
length() const193 size_t String8::length() const
194 {
195 return SharedBuffer::sizeFromData(mString)-1;
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 OK;
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 OK;
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 OK;
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 OK;
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 OK;
278 } else if (otherLen == 0) {
279 return OK;
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 OK;
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 n, result = OK;
315 va_list tmp_args;
316
317 /* args is undefined after vsnprintf.
318 * So we need a copy here to avoid the
319 * second vsnprintf access undefined args.
320 */
321 va_copy(tmp_args, args);
322 n = vsnprintf(nullptr, 0, fmt, tmp_args);
323 va_end(tmp_args);
324
325 if (n < 0) return UNKNOWN_ERROR;
326
327 if (n > 0) {
328 size_t oldLength = length();
329 if ((size_t)n > SIZE_MAX - 1 ||
330 oldLength > SIZE_MAX - (size_t)n - 1) {
331 return NO_MEMORY;
332 }
333 char* buf = lockBuffer(oldLength + n);
334 if (buf) {
335 vsnprintf(buf + oldLength, n + 1, fmt, args);
336 } else {
337 result = NO_MEMORY;
338 }
339 }
340 return result;
341 }
342
real_append(const char * other,size_t otherLen)343 status_t String8::real_append(const char* other, size_t otherLen)
344 {
345 const size_t myLen = bytes();
346
347 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
348 ->editResize(myLen+otherLen+1);
349 if (buf) {
350 char* str = (char*)buf->data();
351 mString = str;
352 str += myLen;
353 memcpy(str, other, otherLen);
354 str[otherLen] = '\0';
355 return OK;
356 }
357 return NO_MEMORY;
358 }
359
lockBuffer(size_t size)360 char* String8::lockBuffer(size_t size)
361 {
362 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
363 ->editResize(size+1);
364 if (buf) {
365 char* str = (char*)buf->data();
366 mString = str;
367 return str;
368 }
369 return nullptr;
370 }
371
unlockBuffer()372 void String8::unlockBuffer()
373 {
374 unlockBuffer(strlen(mString));
375 }
376
unlockBuffer(size_t size)377 status_t String8::unlockBuffer(size_t size)
378 {
379 if (size != this->size()) {
380 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
381 ->editResize(size+1);
382 if (! buf) {
383 return NO_MEMORY;
384 }
385
386 char* str = (char*)buf->data();
387 str[size] = 0;
388 mString = str;
389 }
390
391 return OK;
392 }
393
find(const char * other,size_t start) const394 ssize_t String8::find(const char* other, size_t start) const
395 {
396 size_t len = size();
397 if (start >= len) {
398 return -1;
399 }
400 const char* s = mString+start;
401 const char* p = strstr(s, other);
402 return p ? p-mString : -1;
403 }
404
removeAll(const char * other)405 bool String8::removeAll(const char* other) {
406 ssize_t index = find(other);
407 if (index < 0) return false;
408
409 char* buf = lockBuffer(size());
410 if (!buf) return false; // out of memory
411
412 size_t skip = strlen(other);
413 size_t len = size();
414 size_t tail = index;
415 while (size_t(index) < len) {
416 ssize_t next = find(other, index + skip);
417 if (next < 0) {
418 next = len;
419 }
420
421 memmove(buf + tail, buf + index + skip, next - index - skip);
422 tail += next - index - skip;
423 index = next;
424 }
425 unlockBuffer(tail);
426 return true;
427 }
428
toLower()429 void String8::toLower()
430 {
431 toLower(0, size());
432 }
433
toLower(size_t start,size_t length)434 void String8::toLower(size_t start, size_t length)
435 {
436 const size_t len = size();
437 if (start >= len) {
438 return;
439 }
440 if (start+length > len) {
441 length = len-start;
442 }
443 char* buf = lockBuffer(len);
444 buf += start;
445 while (length > 0) {
446 *buf = tolower(*buf);
447 buf++;
448 length--;
449 }
450 unlockBuffer(len);
451 }
452
toUpper()453 void String8::toUpper()
454 {
455 toUpper(0, size());
456 }
457
toUpper(size_t start,size_t length)458 void String8::toUpper(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 = toupper(*buf);
471 buf++;
472 length--;
473 }
474 unlockBuffer(len);
475 }
476
getUtf32Length() const477 size_t String8::getUtf32Length() const
478 {
479 return utf8_to_utf32_length(mString, length());
480 }
481
getUtf32At(size_t index,size_t * next_index) const482 int32_t String8::getUtf32At(size_t index, size_t *next_index) const
483 {
484 return utf32_from_utf8_at(mString, length(), index, next_index);
485 }
486
getUtf32(char32_t * dst) const487 void String8::getUtf32(char32_t* dst) const
488 {
489 utf8_to_utf32(mString, length(), dst);
490 }
491
492 // ---------------------------------------------------------------------------
493 // Path functions
494
setPathName(const char * name)495 void String8::setPathName(const char* name)
496 {
497 setPathName(name, strlen(name));
498 }
499
setPathName(const char * name,size_t len)500 void String8::setPathName(const char* name, size_t len)
501 {
502 char* buf = lockBuffer(len);
503
504 memcpy(buf, name, len);
505
506 // remove trailing path separator, if present
507 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
508 len--;
509
510 buf[len] = '\0';
511
512 unlockBuffer(len);
513 }
514
getPathLeaf(void) const515 String8 String8::getPathLeaf(void) const
516 {
517 const char* cp;
518 const char*const buf = mString;
519
520 cp = strrchr(buf, OS_PATH_SEPARATOR);
521 if (cp == nullptr)
522 return String8(*this);
523 else
524 return String8(cp+1);
525 }
526
getPathDir(void) const527 String8 String8::getPathDir(void) const
528 {
529 const char* cp;
530 const char*const str = mString;
531
532 cp = strrchr(str, OS_PATH_SEPARATOR);
533 if (cp == nullptr)
534 return String8("");
535 else
536 return String8(str, cp - str);
537 }
538
walkPath(String8 * outRemains) const539 String8 String8::walkPath(String8* outRemains) const
540 {
541 const char* cp;
542 const char*const str = mString;
543 const char* buf = str;
544
545 cp = strchr(buf, OS_PATH_SEPARATOR);
546 if (cp == buf) {
547 // don't include a leading '/'.
548 buf = buf+1;
549 cp = strchr(buf, OS_PATH_SEPARATOR);
550 }
551
552 if (cp == nullptr) {
553 String8 res = buf != str ? String8(buf) : *this;
554 if (outRemains) *outRemains = String8("");
555 return res;
556 }
557
558 String8 res(buf, cp-buf);
559 if (outRemains) *outRemains = String8(cp+1);
560 return res;
561 }
562
563 /*
564 * Helper function for finding the start of an extension in a pathname.
565 *
566 * Returns a pointer inside mString, or NULL if no extension was found.
567 */
find_extension(void) const568 char* String8::find_extension(void) const
569 {
570 const char* lastSlash;
571 const char* lastDot;
572 const char* const str = mString;
573
574 // only look at the filename
575 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
576 if (lastSlash == nullptr)
577 lastSlash = str;
578 else
579 lastSlash++;
580
581 // find the last dot
582 lastDot = strrchr(lastSlash, '.');
583 if (lastDot == nullptr)
584 return nullptr;
585
586 // looks good, ship it
587 return const_cast<char*>(lastDot);
588 }
589
getPathExtension(void) const590 String8 String8::getPathExtension(void) const
591 {
592 char* ext;
593
594 ext = find_extension();
595 if (ext != nullptr)
596 return String8(ext);
597 else
598 return String8("");
599 }
600
getBasePath(void) const601 String8 String8::getBasePath(void) const
602 {
603 char* ext;
604 const char* const str = mString;
605
606 ext = find_extension();
607 if (ext == nullptr)
608 return String8(*this);
609 else
610 return String8(str, ext - str);
611 }
612
appendPath(const char * name)613 String8& String8::appendPath(const char* name)
614 {
615 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
616 if (name[0] != OS_PATH_SEPARATOR) {
617 if (*name == '\0') {
618 // nothing to do
619 return *this;
620 }
621
622 size_t len = length();
623 if (len == 0) {
624 // no existing filename, just use the new one
625 setPathName(name);
626 return *this;
627 }
628
629 // make room for oldPath + '/' + newPath
630 int newlen = strlen(name);
631
632 char* buf = lockBuffer(len+1+newlen);
633
634 // insert a '/' if needed
635 if (buf[len-1] != OS_PATH_SEPARATOR)
636 buf[len++] = OS_PATH_SEPARATOR;
637
638 memcpy(buf+len, name, newlen+1);
639 len += newlen;
640
641 unlockBuffer(len);
642
643 return *this;
644 } else {
645 setPathName(name);
646 return *this;
647 }
648 }
649
convertToResPath()650 String8& String8::convertToResPath()
651 {
652 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
653 size_t len = length();
654 if (len > 0) {
655 char * buf = lockBuffer(len);
656 for (char * end = buf + len; buf < end; ++buf) {
657 if (*buf == OS_PATH_SEPARATOR)
658 *buf = RES_PATH_SEPARATOR;
659 }
660 unlockBuffer(len);
661 }
662 #endif
663 return *this;
664 }
665
666 }; // namespace android
667