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 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 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 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 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 125 String8::String8() 126 : mString(getEmptyString()) 127 { 128 } 129 130 String8::String8(const String8& o) 131 : mString(o.mString) 132 { 133 SharedBuffer::bufferFromData(mString)->acquire(); 134 } 135 136 String8::String8(const char* o) 137 : mString(allocFromUTF8(o, strlen(o))) 138 { 139 if (mString == nullptr) { 140 mString = getEmptyString(); 141 } 142 } 143 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 152 String8::String8(const String16& o) 153 : mString(allocFromUTF16(o.string(), o.size())) 154 { 155 } 156 157 String8::String8(const char16_t* o) 158 : mString(allocFromUTF16(o, strlen16(o))) 159 { 160 } 161 162 String8::String8(const char16_t* o, size_t len) 163 : mString(allocFromUTF16(o, len)) 164 { 165 } 166 167 String8::String8(const char32_t* o) 168 : mString(allocFromUTF32(o, std::char_traits<char32_t>::length(o))) {} 169 170 String8::String8(const char32_t* o, size_t len) 171 : mString(allocFromUTF32(o, len)) 172 { 173 } 174 175 String8::~String8() 176 { 177 SharedBuffer::bufferFromData(mString)->release(); 178 } 179 180 size_t String8::length() const 181 { 182 return SharedBuffer::sizeFromData(mString)-1; 183 } 184 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 196 String8 String8::formatV(const char* fmt, va_list args) 197 { 198 String8 result; 199 result.appendFormatV(fmt, args); 200 return result; 201 } 202 203 void String8::clear() { 204 SharedBuffer::bufferFromData(mString)->release(); 205 mString = getEmptyString(); 206 } 207 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 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 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 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 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 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 272 status_t String8::append(const char* other) 273 { 274 return append(other, strlen(other)); 275 } 276 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 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 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 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 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 361 void String8::unlockBuffer() 362 { 363 unlockBuffer(strlen(mString)); 364 } 365 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 383 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 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 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 434 void String8::setPathName(const char* name) 435 { 436 setPathName(name, strlen(name)); 437 } 438 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 454 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 466 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 478 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 */ 507 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 529 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 540 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 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 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