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 <limits>
29 #include <string>
30
31 #include "SharedBuffer.h"
32
33 /*
34 * Functions outside android is below the namespace android, since they use
35 * functions and constants in android namespace.
36 */
37
38 // ---------------------------------------------------------------------------
39
40 namespace android {
41
42 // Separator used by resource paths. This is not platform dependent contrary
43 // to OS_PATH_SEPARATOR.
44 #define RES_PATH_SEPARATOR '/'
45
getEmptyString()46 static inline char* getEmptyString() {
47 static SharedBuffer* gEmptyStringBuf = [] {
48 SharedBuffer* buf = SharedBuffer::alloc(1);
49 char* str = static_cast<char*>(buf->data());
50 *str = 0;
51 return buf;
52 }();
53
54 gEmptyStringBuf->acquire();
55 return static_cast<char*>(gEmptyStringBuf->data());
56 }
57
58 // ---------------------------------------------------------------------------
59
allocFromUTF8(const char * in,size_t len)60 static char* allocFromUTF8(const char* in, size_t len)
61 {
62 if (len > 0) {
63 if (len == SIZE_MAX) {
64 return nullptr;
65 }
66 SharedBuffer* buf = SharedBuffer::alloc(len+1);
67 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
68 if (buf) {
69 char* str = (char*)buf->data();
70 memcpy(str, in, len);
71 str[len] = 0;
72 return str;
73 }
74 return nullptr;
75 }
76
77 return getEmptyString();
78 }
79
allocFromUTF16(const char16_t * in,size_t len)80 static char* allocFromUTF16(const char16_t* in, size_t len)
81 {
82 if (len == 0) return getEmptyString();
83
84 // Allow for closing '\0'
85 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1;
86 if (resultStrLen < 1) {
87 return getEmptyString();
88 }
89
90 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
91 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
92 if (!buf) {
93 return getEmptyString();
94 }
95
96 char* resultStr = (char*)buf->data();
97 utf16_to_utf8(in, len, resultStr, resultStrLen);
98 return resultStr;
99 }
100
allocFromUTF32(const char32_t * in,size_t len)101 static char* allocFromUTF32(const char32_t* in, size_t len)
102 {
103 if (len == 0) {
104 return getEmptyString();
105 }
106
107 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1;
108 if (resultStrLen < 1) {
109 return getEmptyString();
110 }
111
112 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen);
113 ALOG_ASSERT(buf, "Unable to allocate shared buffer");
114 if (!buf) {
115 return getEmptyString();
116 }
117
118 char* resultStr = (char*) buf->data();
119 utf32_to_utf8(in, len, resultStr, resultStrLen);
120
121 return resultStr;
122 }
123
124 // ---------------------------------------------------------------------------
125
String8()126 String8::String8()
127 : mString(getEmptyString())
128 {
129 }
130
String8(const String8 & o)131 String8::String8(const String8& o)
132 : mString(o.mString)
133 {
134 SharedBuffer::bufferFromData(mString)->acquire();
135 }
136
String8(const char * o)137 String8::String8(const char* o)
138 : mString(allocFromUTF8(o, strlen(o)))
139 {
140 if (mString == nullptr) {
141 mString = getEmptyString();
142 }
143 }
144
String8(const char * o,size_t len)145 String8::String8(const char* o, size_t len)
146 : mString(allocFromUTF8(o, len))
147 {
148 if (mString == nullptr) {
149 mString = getEmptyString();
150 }
151 }
152
String8(const String16 & o)153 String8::String8(const String16& o)
154 : mString(allocFromUTF16(o.string(), o.size()))
155 {
156 }
157
String8(const char16_t * o)158 String8::String8(const char16_t* o)
159 : mString(allocFromUTF16(o, strlen16(o)))
160 {
161 }
162
String8(const char16_t * o,size_t len)163 String8::String8(const char16_t* o, size_t len)
164 : mString(allocFromUTF16(o, len))
165 {
166 }
167
String8(const char32_t * o)168 String8::String8(const char32_t* o)
169 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {}
170
String8(const char32_t * o,size_t len)171 String8::String8(const char32_t* o, size_t len)
172 : mString(allocFromUTF32(o, len))
173 {
174 }
175
~String8()176 String8::~String8()
177 {
178 SharedBuffer::bufferFromData(mString)->release();
179 }
180
length() const181 size_t String8::length() const
182 {
183 return SharedBuffer::sizeFromData(mString)-1;
184 }
185
format(const char * fmt,...)186 String8 String8::format(const char* fmt, ...)
187 {
188 va_list args;
189 va_start(args, fmt);
190
191 String8 result(formatV(fmt, args));
192
193 va_end(args);
194 return result;
195 }
196
formatV(const char * fmt,va_list args)197 String8 String8::formatV(const char* fmt, va_list args)
198 {
199 String8 result;
200 result.appendFormatV(fmt, args);
201 return result;
202 }
203
clear()204 void String8::clear() {
205 SharedBuffer::bufferFromData(mString)->release();
206 mString = getEmptyString();
207 }
208
setTo(const String8 & other)209 void String8::setTo(const String8& other)
210 {
211 SharedBuffer::bufferFromData(other.mString)->acquire();
212 SharedBuffer::bufferFromData(mString)->release();
213 mString = other.mString;
214 }
215
setTo(const char * other)216 status_t String8::setTo(const char* other)
217 {
218 const char *newString = allocFromUTF8(other, strlen(other));
219 SharedBuffer::bufferFromData(mString)->release();
220 mString = newString;
221 if (mString) return OK;
222
223 mString = getEmptyString();
224 return NO_MEMORY;
225 }
226
setTo(const char * other,size_t len)227 status_t String8::setTo(const char* other, size_t len)
228 {
229 const char *newString = allocFromUTF8(other, len);
230 SharedBuffer::bufferFromData(mString)->release();
231 mString = newString;
232 if (mString) return OK;
233
234 mString = getEmptyString();
235 return NO_MEMORY;
236 }
237
setTo(const char16_t * other,size_t len)238 status_t String8::setTo(const char16_t* other, size_t len)
239 {
240 const char *newString = allocFromUTF16(other, len);
241 SharedBuffer::bufferFromData(mString)->release();
242 mString = newString;
243 if (mString) return OK;
244
245 mString = getEmptyString();
246 return NO_MEMORY;
247 }
248
setTo(const char32_t * other,size_t len)249 status_t String8::setTo(const char32_t* other, size_t len)
250 {
251 const char *newString = allocFromUTF32(other, len);
252 SharedBuffer::bufferFromData(mString)->release();
253 mString = newString;
254 if (mString) return OK;
255
256 mString = getEmptyString();
257 return NO_MEMORY;
258 }
259
append(const String8 & other)260 status_t String8::append(const String8& other)
261 {
262 const size_t otherLen = other.bytes();
263 if (bytes() == 0) {
264 setTo(other);
265 return OK;
266 } else if (otherLen == 0) {
267 return OK;
268 }
269
270 return real_append(other.string(), otherLen);
271 }
272
append(const char * other)273 status_t String8::append(const char* other)
274 {
275 return append(other, strlen(other));
276 }
277
append(const char * other,size_t otherLen)278 status_t String8::append(const char* other, size_t otherLen)
279 {
280 if (bytes() == 0) {
281 return setTo(other, otherLen);
282 } else if (otherLen == 0) {
283 return OK;
284 }
285
286 return real_append(other, otherLen);
287 }
288
appendFormat(const char * fmt,...)289 status_t String8::appendFormat(const char* fmt, ...)
290 {
291 va_list args;
292 va_start(args, fmt);
293
294 status_t result = appendFormatV(fmt, args);
295
296 va_end(args);
297 return result;
298 }
299
appendFormatV(const char * fmt,va_list args)300 status_t String8::appendFormatV(const char* fmt, va_list args)
301 {
302 int n, result = OK;
303 va_list tmp_args;
304
305 /* args is undefined after vsnprintf.
306 * So we need a copy here to avoid the
307 * second vsnprintf access undefined args.
308 */
309 va_copy(tmp_args, args);
310 n = vsnprintf(nullptr, 0, fmt, tmp_args);
311 va_end(tmp_args);
312
313 if (n < 0) return UNKNOWN_ERROR;
314
315 if (n > 0) {
316 size_t oldLength = length();
317 if (static_cast<size_t>(n) > std::numeric_limits<size_t>::max() - 1 ||
318 oldLength > std::numeric_limits<size_t>::max() - n - 1) {
319 return NO_MEMORY;
320 }
321 char* buf = lockBuffer(oldLength + n);
322 if (buf) {
323 vsnprintf(buf + oldLength, n + 1, fmt, args);
324 } else {
325 result = NO_MEMORY;
326 }
327 }
328 return result;
329 }
330
real_append(const char * other,size_t otherLen)331 status_t String8::real_append(const char* other, size_t otherLen) {
332 const size_t myLen = bytes();
333
334 SharedBuffer* buf;
335 size_t newLen;
336 if (__builtin_add_overflow(myLen, otherLen, &newLen) ||
337 __builtin_add_overflow(newLen, 1, &newLen) ||
338 (buf = SharedBuffer::bufferFromData(mString)->editResize(newLen)) == nullptr) {
339 return NO_MEMORY;
340 }
341
342 char* str = (char*)buf->data();
343 mString = str;
344 str += myLen;
345 memcpy(str, other, otherLen);
346 str[otherLen] = '\0';
347 return OK;
348 }
349
lockBuffer(size_t size)350 char* String8::lockBuffer(size_t size)
351 {
352 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
353 ->editResize(size+1);
354 if (buf) {
355 char* str = (char*)buf->data();
356 mString = str;
357 return str;
358 }
359 return nullptr;
360 }
361
unlockBuffer()362 void String8::unlockBuffer()
363 {
364 unlockBuffer(strlen(mString));
365 }
366
unlockBuffer(size_t size)367 status_t String8::unlockBuffer(size_t size)
368 {
369 if (size != this->size()) {
370 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
371 ->editResize(size+1);
372 if (! buf) {
373 return NO_MEMORY;
374 }
375
376 char* str = (char*)buf->data();
377 str[size] = 0;
378 mString = str;
379 }
380
381 return OK;
382 }
383
find(const char * other,size_t start) const384 ssize_t String8::find(const char* other, size_t start) const
385 {
386 size_t len = size();
387 if (start >= len) {
388 return -1;
389 }
390 const char* s = mString+start;
391 const char* p = strstr(s, other);
392 return p ? p-mString : -1;
393 }
394
removeAll(const char * other)395 bool String8::removeAll(const char* other) {
396 ssize_t index = find(other);
397 if (index < 0) return false;
398
399 char* buf = lockBuffer(size());
400 if (!buf) return false; // out of memory
401
402 size_t skip = strlen(other);
403 size_t len = size();
404 size_t tail = index;
405 while (size_t(index) < len) {
406 ssize_t next = find(other, index + skip);
407 if (next < 0) {
408 next = len;
409 }
410
411 memmove(buf + tail, buf + index + skip, next - index - skip);
412 tail += next - index - skip;
413 index = next;
414 }
415 unlockBuffer(tail);
416 return true;
417 }
418
toLower()419 void String8::toLower()
420 {
421 const size_t length = size();
422 if (length == 0) return;
423
424 char* buf = lockBuffer(length);
425 for (size_t i = length; i > 0; --i) {
426 *buf = static_cast<char>(tolower(*buf));
427 buf++;
428 }
429 unlockBuffer(length);
430 }
431
432 // ---------------------------------------------------------------------------
433 // Path functions
434
setPathName(String8 & s,const char * name)435 static void setPathName(String8& s, const char* name) {
436 size_t len = strlen(name);
437 char* buf = s.lockBuffer(len);
438
439 memcpy(buf, name, len);
440
441 // remove trailing path separator, if present
442 if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
443 buf[len] = '\0';
444
445 s.unlockBuffer(len);
446 }
447
getPathLeaf(void) const448 String8 String8::getPathLeaf(void) const
449 {
450 const char* cp;
451 const char*const buf = mString;
452
453 cp = strrchr(buf, OS_PATH_SEPARATOR);
454 if (cp == nullptr)
455 return String8(*this);
456 else
457 return String8(cp+1);
458 }
459
getPathDir(void) const460 String8 String8::getPathDir(void) const
461 {
462 const char* cp;
463 const char*const str = mString;
464
465 cp = strrchr(str, OS_PATH_SEPARATOR);
466 if (cp == nullptr)
467 return String8("");
468 else
469 return String8(str, cp - str);
470 }
471
walkPath(String8 * outRemains) const472 String8 String8::walkPath(String8* outRemains) const
473 {
474 const char* cp;
475 const char*const str = mString;
476 const char* buf = str;
477
478 cp = strchr(buf, OS_PATH_SEPARATOR);
479 if (cp == buf) {
480 // don't include a leading '/'.
481 buf = buf+1;
482 cp = strchr(buf, OS_PATH_SEPARATOR);
483 }
484
485 if (cp == nullptr) {
486 String8 res = buf != str ? String8(buf) : *this;
487 if (outRemains) *outRemains = String8("");
488 return res;
489 }
490
491 String8 res(buf, cp-buf);
492 if (outRemains) *outRemains = String8(cp+1);
493 return res;
494 }
495
496 /*
497 * Helper function for finding the start of an extension in a pathname.
498 *
499 * Returns a pointer inside mString, or NULL if no extension was found.
500 */
find_extension(void) const501 char* String8::find_extension(void) const
502 {
503 const char* lastSlash;
504 const char* lastDot;
505 const char* const str = mString;
506
507 // only look at the filename
508 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
509 if (lastSlash == nullptr)
510 lastSlash = str;
511 else
512 lastSlash++;
513
514 // find the last dot
515 lastDot = strrchr(lastSlash, '.');
516 if (lastDot == nullptr)
517 return nullptr;
518
519 // looks good, ship it
520 return const_cast<char*>(lastDot);
521 }
522
getPathExtension(void) const523 String8 String8::getPathExtension(void) const
524 {
525 char* ext;
526
527 ext = find_extension();
528 if (ext != nullptr)
529 return String8(ext);
530 else
531 return String8("");
532 }
533
getBasePath(void) const534 String8 String8::getBasePath(void) const
535 {
536 char* ext;
537 const char* const str = mString;
538
539 ext = find_extension();
540 if (ext == nullptr)
541 return String8(*this);
542 else
543 return String8(str, ext - str);
544 }
545
appendPath(const char * name)546 String8& String8::appendPath(const char* name)
547 {
548 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
549 if (name[0] != OS_PATH_SEPARATOR) {
550 if (*name == '\0') {
551 // nothing to do
552 return *this;
553 }
554
555 size_t len = length();
556 if (len == 0) {
557 // no existing filename, just use the new one
558 setPathName(*this, name);
559 return *this;
560 }
561
562 // make room for oldPath + '/' + newPath
563 int newlen = strlen(name);
564
565 char* buf = lockBuffer(len+1+newlen);
566
567 // insert a '/' if needed
568 if (buf[len-1] != OS_PATH_SEPARATOR)
569 buf[len++] = OS_PATH_SEPARATOR;
570
571 memcpy(buf+len, name, newlen+1);
572 len += newlen;
573
574 unlockBuffer(len);
575
576 return *this;
577 } else {
578 setPathName(*this, name);
579 return *this;
580 }
581 }
582
convertToResPath()583 String8& String8::convertToResPath()
584 {
585 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
586 size_t len = length();
587 if (len > 0) {
588 char * buf = lockBuffer(len);
589 for (char * end = buf + len; buf < end; ++buf) {
590 if (*buf == OS_PATH_SEPARATOR)
591 *buf = RES_PATH_SEPARATOR;
592 }
593 unlockBuffer(len);
594 }
595 #endif
596 return *this;
597 }
598
599 }; // namespace android
600