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