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 (static_cast<size_t>(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(String8 & s,const char * name)434 static void setPathName(String8& s, const char* name) {
435 size_t len = strlen(name);
436 char* buf = s.lockBuffer(len);
437
438 memcpy(buf, name, len);
439
440 // remove trailing path separator, if present
441 if (len > 0 && buf[len - 1] == OS_PATH_SEPARATOR) len--;
442 buf[len] = '\0';
443
444 s.unlockBuffer(len);
445 }
446
getPathLeaf(void) const447 String8 String8::getPathLeaf(void) const
448 {
449 const char* cp;
450 const char*const buf = mString;
451
452 cp = strrchr(buf, OS_PATH_SEPARATOR);
453 if (cp == nullptr)
454 return String8(*this);
455 else
456 return String8(cp+1);
457 }
458
getPathDir(void) const459 String8 String8::getPathDir(void) const
460 {
461 const char* cp;
462 const char*const str = mString;
463
464 cp = strrchr(str, OS_PATH_SEPARATOR);
465 if (cp == nullptr)
466 return String8("");
467 else
468 return String8(str, cp - str);
469 }
470
walkPath(String8 * outRemains) const471 String8 String8::walkPath(String8* outRemains) const
472 {
473 const char* cp;
474 const char*const str = mString;
475 const char* buf = str;
476
477 cp = strchr(buf, OS_PATH_SEPARATOR);
478 if (cp == buf) {
479 // don't include a leading '/'.
480 buf = buf+1;
481 cp = strchr(buf, OS_PATH_SEPARATOR);
482 }
483
484 if (cp == nullptr) {
485 String8 res = buf != str ? String8(buf) : *this;
486 if (outRemains) *outRemains = String8("");
487 return res;
488 }
489
490 String8 res(buf, cp-buf);
491 if (outRemains) *outRemains = String8(cp+1);
492 return res;
493 }
494
495 /*
496 * Helper function for finding the start of an extension in a pathname.
497 *
498 * Returns a pointer inside mString, or NULL if no extension was found.
499 */
find_extension(void) const500 char* String8::find_extension(void) const
501 {
502 const char* lastSlash;
503 const char* lastDot;
504 const char* const str = mString;
505
506 // only look at the filename
507 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
508 if (lastSlash == nullptr)
509 lastSlash = str;
510 else
511 lastSlash++;
512
513 // find the last dot
514 lastDot = strrchr(lastSlash, '.');
515 if (lastDot == nullptr)
516 return nullptr;
517
518 // looks good, ship it
519 return const_cast<char*>(lastDot);
520 }
521
getPathExtension(void) const522 String8 String8::getPathExtension(void) const
523 {
524 char* ext;
525
526 ext = find_extension();
527 if (ext != nullptr)
528 return String8(ext);
529 else
530 return String8("");
531 }
532
getBasePath(void) const533 String8 String8::getBasePath(void) const
534 {
535 char* ext;
536 const char* const str = mString;
537
538 ext = find_extension();
539 if (ext == nullptr)
540 return String8(*this);
541 else
542 return String8(str, ext - str);
543 }
544
appendPath(const char * name)545 String8& String8::appendPath(const char* name)
546 {
547 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
548 if (name[0] != OS_PATH_SEPARATOR) {
549 if (*name == '\0') {
550 // nothing to do
551 return *this;
552 }
553
554 size_t len = length();
555 if (len == 0) {
556 // no existing filename, just use the new one
557 setPathName(*this, name);
558 return *this;
559 }
560
561 // make room for oldPath + '/' + newPath
562 int newlen = strlen(name);
563
564 char* buf = lockBuffer(len+1+newlen);
565
566 // insert a '/' if needed
567 if (buf[len-1] != OS_PATH_SEPARATOR)
568 buf[len++] = OS_PATH_SEPARATOR;
569
570 memcpy(buf+len, name, newlen+1);
571 len += newlen;
572
573 unlockBuffer(len);
574
575 return *this;
576 } else {
577 setPathName(*this, name);
578 return *this;
579 }
580 }
581
convertToResPath()582 String8& String8::convertToResPath()
583 {
584 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
585 size_t len = length();
586 if (len > 0) {
587 char * buf = lockBuffer(len);
588 for (char * end = buf + len; buf < end; ++buf) {
589 if (*buf == OS_PATH_SEPARATOR)
590 *buf = RES_PATH_SEPARATOR;
591 }
592 unlockBuffer(len);
593 }
594 #endif
595 return *this;
596 }
597
598 }; // namespace android
599