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/Unicode.h> 25 #include <utils/String16.h> 26 #include <utils/threads.h> 27 28 #include <ctype.h> 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 SharedBuffer* gEmptyStringBuf = NULL; 46 static char* gEmptyString = NULL; 47 48 extern int gDarwinCantLoadAllObjects; 49 int gDarwinIsReallyAnnoying; 50 51 void initialize_string8(); 52 53 static inline char* getEmptyString() 54 { 55 gEmptyStringBuf->acquire(); 56 return gEmptyString; 57 } 58 59 void initialize_string8() 60 { 61 // HACK: This dummy dependency forces linking libutils Static.cpp, 62 // which is needed to initialize String8/String16 classes. 63 // These variables are named for Darwin, but are needed elsewhere too, 64 // including static linking on any platform. 65 gDarwinIsReallyAnnoying = gDarwinCantLoadAllObjects; 66 67 SharedBuffer* buf = SharedBuffer::alloc(1); 68 char* str = (char*)buf->data(); 69 *str = 0; 70 gEmptyStringBuf = buf; 71 gEmptyString = str; 72 } 73 74 void terminate_string8() 75 { 76 SharedBuffer::bufferFromData(gEmptyString)->release(); 77 gEmptyStringBuf = NULL; 78 gEmptyString = NULL; 79 } 80 81 // --------------------------------------------------------------------------- 82 83 static char* allocFromUTF8(const char* in, size_t len) 84 { 85 if (len > 0) { 86 if (len == SIZE_MAX) { 87 return NULL; 88 } 89 SharedBuffer* buf = SharedBuffer::alloc(len+1); 90 ALOG_ASSERT(buf, "Unable to allocate shared buffer"); 91 if (buf) { 92 char* str = (char*)buf->data(); 93 memcpy(str, in, len); 94 str[len] = 0; 95 return str; 96 } 97 return NULL; 98 } 99 100 return getEmptyString(); 101 } 102 103 static char* allocFromUTF16(const char16_t* in, size_t len) 104 { 105 if (len == 0) return getEmptyString(); 106 107 // Allow for closing '\0' 108 const ssize_t resultStrLen = utf16_to_utf8_length(in, len) + 1; 109 if (resultStrLen < 1) { 110 return getEmptyString(); 111 } 112 113 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen); 114 ALOG_ASSERT(buf, "Unable to allocate shared buffer"); 115 if (!buf) { 116 return getEmptyString(); 117 } 118 119 char* resultStr = (char*)buf->data(); 120 utf16_to_utf8(in, len, resultStr, resultStrLen); 121 return resultStr; 122 } 123 124 static char* allocFromUTF32(const char32_t* in, size_t len) 125 { 126 if (len == 0) { 127 return getEmptyString(); 128 } 129 130 const ssize_t resultStrLen = utf32_to_utf8_length(in, len) + 1; 131 if (resultStrLen < 1) { 132 return getEmptyString(); 133 } 134 135 SharedBuffer* buf = SharedBuffer::alloc(resultStrLen); 136 ALOG_ASSERT(buf, "Unable to allocate shared buffer"); 137 if (!buf) { 138 return getEmptyString(); 139 } 140 141 char* resultStr = (char*) buf->data(); 142 utf32_to_utf8(in, len, resultStr, resultStrLen); 143 144 return resultStr; 145 } 146 147 // --------------------------------------------------------------------------- 148 149 String8::String8() 150 : mString(getEmptyString()) 151 { 152 } 153 154 String8::String8(StaticLinkage) 155 : mString(0) 156 { 157 // this constructor is used when we can't rely on the static-initializers 158 // having run. In this case we always allocate an empty string. It's less 159 // efficient than using getEmptyString(), but we assume it's uncommon. 160 161 char* data = static_cast<char*>( 162 SharedBuffer::alloc(sizeof(char))->data()); 163 data[0] = 0; 164 mString = data; 165 } 166 167 String8::String8(const String8& o) 168 : mString(o.mString) 169 { 170 SharedBuffer::bufferFromData(mString)->acquire(); 171 } 172 173 String8::String8(const char* o) 174 : mString(allocFromUTF8(o, strlen(o))) 175 { 176 if (mString == NULL) { 177 mString = getEmptyString(); 178 } 179 } 180 181 String8::String8(const char* o, size_t len) 182 : mString(allocFromUTF8(o, len)) 183 { 184 if (mString == NULL) { 185 mString = getEmptyString(); 186 } 187 } 188 189 String8::String8(const String16& o) 190 : mString(allocFromUTF16(o.string(), o.size())) 191 { 192 } 193 194 String8::String8(const char16_t* o) 195 : mString(allocFromUTF16(o, strlen16(o))) 196 { 197 } 198 199 String8::String8(const char16_t* o, size_t len) 200 : mString(allocFromUTF16(o, len)) 201 { 202 } 203 204 String8::String8(const char32_t* o) 205 : mString(allocFromUTF32(o, strlen32(o))) 206 { 207 } 208 209 String8::String8(const char32_t* o, size_t len) 210 : mString(allocFromUTF32(o, len)) 211 { 212 } 213 214 String8::~String8() 215 { 216 SharedBuffer::bufferFromData(mString)->release(); 217 } 218 219 size_t String8::length() const 220 { 221 return SharedBuffer::sizeFromData(mString)-1; 222 } 223 224 String8 String8::format(const char* fmt, ...) 225 { 226 va_list args; 227 va_start(args, fmt); 228 229 String8 result(formatV(fmt, args)); 230 231 va_end(args); 232 return result; 233 } 234 235 String8 String8::formatV(const char* fmt, va_list args) 236 { 237 String8 result; 238 result.appendFormatV(fmt, args); 239 return result; 240 } 241 242 void String8::clear() { 243 SharedBuffer::bufferFromData(mString)->release(); 244 mString = getEmptyString(); 245 } 246 247 void String8::setTo(const String8& other) 248 { 249 SharedBuffer::bufferFromData(other.mString)->acquire(); 250 SharedBuffer::bufferFromData(mString)->release(); 251 mString = other.mString; 252 } 253 254 status_t String8::setTo(const char* other) 255 { 256 const char *newString = allocFromUTF8(other, strlen(other)); 257 SharedBuffer::bufferFromData(mString)->release(); 258 mString = newString; 259 if (mString) return NO_ERROR; 260 261 mString = getEmptyString(); 262 return NO_MEMORY; 263 } 264 265 status_t String8::setTo(const char* other, size_t len) 266 { 267 const char *newString = allocFromUTF8(other, len); 268 SharedBuffer::bufferFromData(mString)->release(); 269 mString = newString; 270 if (mString) return NO_ERROR; 271 272 mString = getEmptyString(); 273 return NO_MEMORY; 274 } 275 276 status_t String8::setTo(const char16_t* other, size_t len) 277 { 278 const char *newString = allocFromUTF16(other, len); 279 SharedBuffer::bufferFromData(mString)->release(); 280 mString = newString; 281 if (mString) return NO_ERROR; 282 283 mString = getEmptyString(); 284 return NO_MEMORY; 285 } 286 287 status_t String8::setTo(const char32_t* other, size_t len) 288 { 289 const char *newString = allocFromUTF32(other, len); 290 SharedBuffer::bufferFromData(mString)->release(); 291 mString = newString; 292 if (mString) return NO_ERROR; 293 294 mString = getEmptyString(); 295 return NO_MEMORY; 296 } 297 298 status_t String8::append(const String8& other) 299 { 300 const size_t otherLen = other.bytes(); 301 if (bytes() == 0) { 302 setTo(other); 303 return NO_ERROR; 304 } else if (otherLen == 0) { 305 return NO_ERROR; 306 } 307 308 return real_append(other.string(), otherLen); 309 } 310 311 status_t String8::append(const char* other) 312 { 313 return append(other, strlen(other)); 314 } 315 316 status_t String8::append(const char* other, size_t otherLen) 317 { 318 if (bytes() == 0) { 319 return setTo(other, otherLen); 320 } else if (otherLen == 0) { 321 return NO_ERROR; 322 } 323 324 return real_append(other, otherLen); 325 } 326 327 status_t String8::appendFormat(const char* fmt, ...) 328 { 329 va_list args; 330 va_start(args, fmt); 331 332 status_t result = appendFormatV(fmt, args); 333 334 va_end(args); 335 return result; 336 } 337 338 status_t String8::appendFormatV(const char* fmt, va_list args) 339 { 340 int n, result = NO_ERROR; 341 va_list tmp_args; 342 343 /* args is undefined after vsnprintf. 344 * So we need a copy here to avoid the 345 * second vsnprintf access undefined args. 346 */ 347 va_copy(tmp_args, args); 348 n = vsnprintf(NULL, 0, fmt, tmp_args); 349 va_end(tmp_args); 350 351 if (n != 0) { 352 size_t oldLength = length(); 353 char* buf = lockBuffer(oldLength + n); 354 if (buf) { 355 vsnprintf(buf + oldLength, n + 1, fmt, args); 356 } else { 357 result = NO_MEMORY; 358 } 359 } 360 return result; 361 } 362 363 status_t String8::real_append(const char* other, size_t otherLen) 364 { 365 const size_t myLen = bytes(); 366 367 SharedBuffer* buf = SharedBuffer::bufferFromData(mString) 368 ->editResize(myLen+otherLen+1); 369 if (buf) { 370 char* str = (char*)buf->data(); 371 mString = str; 372 str += myLen; 373 memcpy(str, other, otherLen); 374 str[otherLen] = '\0'; 375 return NO_ERROR; 376 } 377 return NO_MEMORY; 378 } 379 380 char* String8::lockBuffer(size_t size) 381 { 382 SharedBuffer* buf = SharedBuffer::bufferFromData(mString) 383 ->editResize(size+1); 384 if (buf) { 385 char* str = (char*)buf->data(); 386 mString = str; 387 return str; 388 } 389 return NULL; 390 } 391 392 void String8::unlockBuffer() 393 { 394 unlockBuffer(strlen(mString)); 395 } 396 397 status_t String8::unlockBuffer(size_t size) 398 { 399 if (size != this->size()) { 400 SharedBuffer* buf = SharedBuffer::bufferFromData(mString) 401 ->editResize(size+1); 402 if (! buf) { 403 return NO_MEMORY; 404 } 405 406 char* str = (char*)buf->data(); 407 str[size] = 0; 408 mString = str; 409 } 410 411 return NO_ERROR; 412 } 413 414 ssize_t String8::find(const char* other, size_t start) const 415 { 416 size_t len = size(); 417 if (start >= len) { 418 return -1; 419 } 420 const char* s = mString+start; 421 const char* p = strstr(s, other); 422 return p ? p-mString : -1; 423 } 424 425 bool String8::removeAll(const char* other) { 426 ssize_t index = find(other); 427 if (index < 0) return false; 428 429 char* buf = lockBuffer(size()); 430 if (!buf) return false; // out of memory 431 432 size_t skip = strlen(other); 433 size_t len = size(); 434 size_t tail = index; 435 while (size_t(index) < len) { 436 ssize_t next = find(other, index + skip); 437 if (next < 0) { 438 next = len; 439 } 440 441 memmove(buf + tail, buf + index + skip, next - index - skip); 442 tail += next - index - skip; 443 index = next; 444 } 445 unlockBuffer(tail); 446 return true; 447 } 448 449 void String8::toLower() 450 { 451 toLower(0, size()); 452 } 453 454 void String8::toLower(size_t start, size_t length) 455 { 456 const size_t len = size(); 457 if (start >= len) { 458 return; 459 } 460 if (start+length > len) { 461 length = len-start; 462 } 463 char* buf = lockBuffer(len); 464 buf += start; 465 while (length > 0) { 466 *buf = tolower(*buf); 467 buf++; 468 length--; 469 } 470 unlockBuffer(len); 471 } 472 473 void String8::toUpper() 474 { 475 toUpper(0, size()); 476 } 477 478 void String8::toUpper(size_t start, size_t length) 479 { 480 const size_t len = size(); 481 if (start >= len) { 482 return; 483 } 484 if (start+length > len) { 485 length = len-start; 486 } 487 char* buf = lockBuffer(len); 488 buf += start; 489 while (length > 0) { 490 *buf = toupper(*buf); 491 buf++; 492 length--; 493 } 494 unlockBuffer(len); 495 } 496 497 size_t String8::getUtf32Length() const 498 { 499 return utf8_to_utf32_length(mString, length()); 500 } 501 502 int32_t String8::getUtf32At(size_t index, size_t *next_index) const 503 { 504 return utf32_from_utf8_at(mString, length(), index, next_index); 505 } 506 507 void String8::getUtf32(char32_t* dst) const 508 { 509 utf8_to_utf32(mString, length(), dst); 510 } 511 512 // --------------------------------------------------------------------------- 513 // Path functions 514 515 void String8::setPathName(const char* name) 516 { 517 setPathName(name, strlen(name)); 518 } 519 520 void String8::setPathName(const char* name, size_t len) 521 { 522 char* buf = lockBuffer(len); 523 524 memcpy(buf, name, len); 525 526 // remove trailing path separator, if present 527 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR) 528 len--; 529 530 buf[len] = '\0'; 531 532 unlockBuffer(len); 533 } 534 535 String8 String8::getPathLeaf(void) const 536 { 537 const char* cp; 538 const char*const buf = mString; 539 540 cp = strrchr(buf, OS_PATH_SEPARATOR); 541 if (cp == NULL) 542 return String8(*this); 543 else 544 return String8(cp+1); 545 } 546 547 String8 String8::getPathDir(void) const 548 { 549 const char* cp; 550 const char*const str = mString; 551 552 cp = strrchr(str, OS_PATH_SEPARATOR); 553 if (cp == NULL) 554 return String8(""); 555 else 556 return String8(str, cp - str); 557 } 558 559 String8 String8::walkPath(String8* outRemains) const 560 { 561 const char* cp; 562 const char*const str = mString; 563 const char* buf = str; 564 565 cp = strchr(buf, OS_PATH_SEPARATOR); 566 if (cp == buf) { 567 // don't include a leading '/'. 568 buf = buf+1; 569 cp = strchr(buf, OS_PATH_SEPARATOR); 570 } 571 572 if (cp == NULL) { 573 String8 res = buf != str ? String8(buf) : *this; 574 if (outRemains) *outRemains = String8(""); 575 return res; 576 } 577 578 String8 res(buf, cp-buf); 579 if (outRemains) *outRemains = String8(cp+1); 580 return res; 581 } 582 583 /* 584 * Helper function for finding the start of an extension in a pathname. 585 * 586 * Returns a pointer inside mString, or NULL if no extension was found. 587 */ 588 char* String8::find_extension(void) const 589 { 590 const char* lastSlash; 591 const char* lastDot; 592 const char* const str = mString; 593 594 // only look at the filename 595 lastSlash = strrchr(str, OS_PATH_SEPARATOR); 596 if (lastSlash == NULL) 597 lastSlash = str; 598 else 599 lastSlash++; 600 601 // find the last dot 602 lastDot = strrchr(lastSlash, '.'); 603 if (lastDot == NULL) 604 return NULL; 605 606 // looks good, ship it 607 return const_cast<char*>(lastDot); 608 } 609 610 String8 String8::getPathExtension(void) const 611 { 612 char* ext; 613 614 ext = find_extension(); 615 if (ext != NULL) 616 return String8(ext); 617 else 618 return String8(""); 619 } 620 621 String8 String8::getBasePath(void) const 622 { 623 char* ext; 624 const char* const str = mString; 625 626 ext = find_extension(); 627 if (ext == NULL) 628 return String8(*this); 629 else 630 return String8(str, ext - str); 631 } 632 633 String8& String8::appendPath(const char* name) 634 { 635 // TODO: The test below will fail for Win32 paths. Fix later or ignore. 636 if (name[0] != OS_PATH_SEPARATOR) { 637 if (*name == '\0') { 638 // nothing to do 639 return *this; 640 } 641 642 size_t len = length(); 643 if (len == 0) { 644 // no existing filename, just use the new one 645 setPathName(name); 646 return *this; 647 } 648 649 // make room for oldPath + '/' + newPath 650 int newlen = strlen(name); 651 652 char* buf = lockBuffer(len+1+newlen); 653 654 // insert a '/' if needed 655 if (buf[len-1] != OS_PATH_SEPARATOR) 656 buf[len++] = OS_PATH_SEPARATOR; 657 658 memcpy(buf+len, name, newlen+1); 659 len += newlen; 660 661 unlockBuffer(len); 662 663 return *this; 664 } else { 665 setPathName(name); 666 return *this; 667 } 668 } 669 670 String8& String8::convertToResPath() 671 { 672 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR 673 size_t len = length(); 674 if (len > 0) { 675 char * buf = lockBuffer(len); 676 for (char * end = buf + len; buf < end; ++buf) { 677 if (*buf == OS_PATH_SEPARATOR) 678 *buf = RES_PATH_SEPARATOR; 679 } 680 unlockBuffer(len); 681 } 682 #endif 683 return *this; 684 } 685 686 }; // namespace android 687