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(const String8 & o)128 String8::String8(const String8& o)
129 : mString(o.mString)
130 {
131 SharedBuffer::bufferFromData(mString)->acquire();
132 }
133
String8(const char * o)134 String8::String8(const char* o)
135 : mString(allocFromUTF8(o, strlen(o)))
136 {
137 if (mString == nullptr) {
138 mString = getEmptyString();
139 }
140 }
141
String8(const char * o,size_t len)142 String8::String8(const char* o, size_t len)
143 : mString(allocFromUTF8(o, len))
144 {
145 if (mString == nullptr) {
146 mString = getEmptyString();
147 }
148 }
149
String8(const String16 & o)150 String8::String8(const String16& o)
151 : mString(allocFromUTF16(o.string(), o.size()))
152 {
153 }
154
String8(const char16_t * o)155 String8::String8(const char16_t* o)
156 : mString(allocFromUTF16(o, strlen16(o)))
157 {
158 }
159
String8(const char16_t * o,size_t len)160 String8::String8(const char16_t* o, size_t len)
161 : mString(allocFromUTF16(o, len))
162 {
163 }
164
String8(const char32_t * o)165 String8::String8(const char32_t* o)
166 : mString(allocFromUTF32(o, strlen32(o)))
167 {
168 }
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) {
313 size_t oldLength = length();
314 char* buf = lockBuffer(oldLength + n);
315 if (buf) {
316 vsnprintf(buf + oldLength, n + 1, fmt, args);
317 } else {
318 result = NO_MEMORY;
319 }
320 }
321 return result;
322 }
323
real_append(const char * other,size_t otherLen)324 status_t String8::real_append(const char* other, size_t otherLen)
325 {
326 const size_t myLen = bytes();
327
328 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
329 ->editResize(myLen+otherLen+1);
330 if (buf) {
331 char* str = (char*)buf->data();
332 mString = str;
333 str += myLen;
334 memcpy(str, other, otherLen);
335 str[otherLen] = '\0';
336 return OK;
337 }
338 return NO_MEMORY;
339 }
340
lockBuffer(size_t size)341 char* String8::lockBuffer(size_t size)
342 {
343 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
344 ->editResize(size+1);
345 if (buf) {
346 char* str = (char*)buf->data();
347 mString = str;
348 return str;
349 }
350 return nullptr;
351 }
352
unlockBuffer()353 void String8::unlockBuffer()
354 {
355 unlockBuffer(strlen(mString));
356 }
357
unlockBuffer(size_t size)358 status_t String8::unlockBuffer(size_t size)
359 {
360 if (size != this->size()) {
361 SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
362 ->editResize(size+1);
363 if (! buf) {
364 return NO_MEMORY;
365 }
366
367 char* str = (char*)buf->data();
368 str[size] = 0;
369 mString = str;
370 }
371
372 return OK;
373 }
374
find(const char * other,size_t start) const375 ssize_t String8::find(const char* other, size_t start) const
376 {
377 size_t len = size();
378 if (start >= len) {
379 return -1;
380 }
381 const char* s = mString+start;
382 const char* p = strstr(s, other);
383 return p ? p-mString : -1;
384 }
385
removeAll(const char * other)386 bool String8::removeAll(const char* other) {
387 ssize_t index = find(other);
388 if (index < 0) return false;
389
390 char* buf = lockBuffer(size());
391 if (!buf) return false; // out of memory
392
393 size_t skip = strlen(other);
394 size_t len = size();
395 size_t tail = index;
396 while (size_t(index) < len) {
397 ssize_t next = find(other, index + skip);
398 if (next < 0) {
399 next = len;
400 }
401
402 memmove(buf + tail, buf + index + skip, next - index - skip);
403 tail += next - index - skip;
404 index = next;
405 }
406 unlockBuffer(tail);
407 return true;
408 }
409
toLower()410 void String8::toLower()
411 {
412 toLower(0, size());
413 }
414
toLower(size_t start,size_t length)415 void String8::toLower(size_t start, size_t length)
416 {
417 const size_t len = size();
418 if (start >= len) {
419 return;
420 }
421 if (start+length > len) {
422 length = len-start;
423 }
424 char* buf = lockBuffer(len);
425 buf += start;
426 while (length > 0) {
427 *buf = static_cast<char>(tolower(*buf));
428 buf++;
429 length--;
430 }
431 unlockBuffer(len);
432 }
433
toUpper()434 void String8::toUpper()
435 {
436 toUpper(0, size());
437 }
438
toUpper(size_t start,size_t length)439 void String8::toUpper(size_t start, size_t length)
440 {
441 const size_t len = size();
442 if (start >= len) {
443 return;
444 }
445 if (start+length > len) {
446 length = len-start;
447 }
448 char* buf = lockBuffer(len);
449 buf += start;
450 while (length > 0) {
451 *buf = static_cast<char>(toupper(*buf));
452 buf++;
453 length--;
454 }
455 unlockBuffer(len);
456 }
457
458 // ---------------------------------------------------------------------------
459 // Path functions
460
setPathName(const char * name)461 void String8::setPathName(const char* name)
462 {
463 setPathName(name, strlen(name));
464 }
465
setPathName(const char * name,size_t len)466 void String8::setPathName(const char* name, size_t len)
467 {
468 char* buf = lockBuffer(len);
469
470 memcpy(buf, name, len);
471
472 // remove trailing path separator, if present
473 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR)
474 len--;
475
476 buf[len] = '\0';
477
478 unlockBuffer(len);
479 }
480
getPathLeaf(void) const481 String8 String8::getPathLeaf(void) const
482 {
483 const char* cp;
484 const char*const buf = mString;
485
486 cp = strrchr(buf, OS_PATH_SEPARATOR);
487 if (cp == nullptr)
488 return String8(*this);
489 else
490 return String8(cp+1);
491 }
492
getPathDir(void) const493 String8 String8::getPathDir(void) const
494 {
495 const char* cp;
496 const char*const str = mString;
497
498 cp = strrchr(str, OS_PATH_SEPARATOR);
499 if (cp == nullptr)
500 return String8("");
501 else
502 return String8(str, cp - str);
503 }
504
walkPath(String8 * outRemains) const505 String8 String8::walkPath(String8* outRemains) const
506 {
507 const char* cp;
508 const char*const str = mString;
509 const char* buf = str;
510
511 cp = strchr(buf, OS_PATH_SEPARATOR);
512 if (cp == buf) {
513 // don't include a leading '/'.
514 buf = buf+1;
515 cp = strchr(buf, OS_PATH_SEPARATOR);
516 }
517
518 if (cp == nullptr) {
519 String8 res = buf != str ? String8(buf) : *this;
520 if (outRemains) *outRemains = String8("");
521 return res;
522 }
523
524 String8 res(buf, cp-buf);
525 if (outRemains) *outRemains = String8(cp+1);
526 return res;
527 }
528
529 /*
530 * Helper function for finding the start of an extension in a pathname.
531 *
532 * Returns a pointer inside mString, or NULL if no extension was found.
533 */
find_extension(void) const534 char* String8::find_extension(void) const
535 {
536 const char* lastSlash;
537 const char* lastDot;
538 const char* const str = mString;
539
540 // only look at the filename
541 lastSlash = strrchr(str, OS_PATH_SEPARATOR);
542 if (lastSlash == nullptr)
543 lastSlash = str;
544 else
545 lastSlash++;
546
547 // find the last dot
548 lastDot = strrchr(lastSlash, '.');
549 if (lastDot == nullptr)
550 return nullptr;
551
552 // looks good, ship it
553 return const_cast<char*>(lastDot);
554 }
555
getPathExtension(void) const556 String8 String8::getPathExtension(void) const
557 {
558 char* ext;
559
560 ext = find_extension();
561 if (ext != nullptr)
562 return String8(ext);
563 else
564 return String8("");
565 }
566
getBasePath(void) const567 String8 String8::getBasePath(void) const
568 {
569 char* ext;
570 const char* const str = mString;
571
572 ext = find_extension();
573 if (ext == nullptr)
574 return String8(*this);
575 else
576 return String8(str, ext - str);
577 }
578
appendPath(const char * name)579 String8& String8::appendPath(const char* name)
580 {
581 // TODO: The test below will fail for Win32 paths. Fix later or ignore.
582 if (name[0] != OS_PATH_SEPARATOR) {
583 if (*name == '\0') {
584 // nothing to do
585 return *this;
586 }
587
588 size_t len = length();
589 if (len == 0) {
590 // no existing filename, just use the new one
591 setPathName(name);
592 return *this;
593 }
594
595 // make room for oldPath + '/' + newPath
596 int newlen = strlen(name);
597
598 char* buf = lockBuffer(len+1+newlen);
599
600 // insert a '/' if needed
601 if (buf[len-1] != OS_PATH_SEPARATOR)
602 buf[len++] = OS_PATH_SEPARATOR;
603
604 memcpy(buf+len, name, newlen+1);
605 len += newlen;
606
607 unlockBuffer(len);
608
609 return *this;
610 } else {
611 setPathName(name);
612 return *this;
613 }
614 }
615
convertToResPath()616 String8& String8::convertToResPath()
617 {
618 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR
619 size_t len = length();
620 if (len > 0) {
621 char * buf = lockBuffer(len);
622 for (char * end = buf + len; buf < end; ++buf) {
623 if (*buf == OS_PATH_SEPARATOR)
624 *buf = RES_PATH_SEPARATOR;
625 }
626 unlockBuffer(len);
627 }
628 #endif
629 return *this;
630 }
631
632 }; // namespace android
633