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