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