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