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