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