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 result = NO_ERROR; 327 int n = vsnprintf(NULL, 0, fmt, args); 328 if (n != 0) { 329 size_t oldLength = length(); 330 char* buf = lockBuffer(oldLength + n); 331 if (buf) { 332 vsnprintf(buf + oldLength, n + 1, fmt, args); 333 } else { 334 result = NO_MEMORY; 335 } 336 } 337 return result; 338 } 339 340 status_t String8::real_append(const char* other, size_t otherLen) 341 { 342 const size_t myLen = bytes(); 343 344 SharedBuffer* buf = SharedBuffer::bufferFromData(mString) 345 ->editResize(myLen+otherLen+1); 346 if (buf) { 347 char* str = (char*)buf->data(); 348 mString = str; 349 str += myLen; 350 memcpy(str, other, otherLen); 351 str[otherLen] = '\0'; 352 return NO_ERROR; 353 } 354 return NO_MEMORY; 355 } 356 357 char* String8::lockBuffer(size_t size) 358 { 359 SharedBuffer* buf = SharedBuffer::bufferFromData(mString) 360 ->editResize(size+1); 361 if (buf) { 362 char* str = (char*)buf->data(); 363 mString = str; 364 return str; 365 } 366 return NULL; 367 } 368 369 void String8::unlockBuffer() 370 { 371 unlockBuffer(strlen(mString)); 372 } 373 374 status_t String8::unlockBuffer(size_t size) 375 { 376 if (size != this->size()) { 377 SharedBuffer* buf = SharedBuffer::bufferFromData(mString) 378 ->editResize(size+1); 379 if (! buf) { 380 return NO_MEMORY; 381 } 382 383 char* str = (char*)buf->data(); 384 str[size] = 0; 385 mString = str; 386 } 387 388 return NO_ERROR; 389 } 390 391 ssize_t String8::find(const char* other, size_t start) const 392 { 393 size_t len = size(); 394 if (start >= len) { 395 return -1; 396 } 397 const char* s = mString+start; 398 const char* p = strstr(s, other); 399 return p ? p-mString : -1; 400 } 401 402 void String8::toLower() 403 { 404 toLower(0, size()); 405 } 406 407 void String8::toLower(size_t start, size_t length) 408 { 409 const size_t len = size(); 410 if (start >= len) { 411 return; 412 } 413 if (start+length > len) { 414 length = len-start; 415 } 416 char* buf = lockBuffer(len); 417 buf += start; 418 while (length > 0) { 419 *buf = tolower(*buf); 420 buf++; 421 length--; 422 } 423 unlockBuffer(len); 424 } 425 426 void String8::toUpper() 427 { 428 toUpper(0, size()); 429 } 430 431 void String8::toUpper(size_t start, size_t length) 432 { 433 const size_t len = size(); 434 if (start >= len) { 435 return; 436 } 437 if (start+length > len) { 438 length = len-start; 439 } 440 char* buf = lockBuffer(len); 441 buf += start; 442 while (length > 0) { 443 *buf = toupper(*buf); 444 buf++; 445 length--; 446 } 447 unlockBuffer(len); 448 } 449 450 size_t String8::getUtf32Length() const 451 { 452 return utf8_to_utf32_length(mString, length()); 453 } 454 455 int32_t String8::getUtf32At(size_t index, size_t *next_index) const 456 { 457 return utf32_from_utf8_at(mString, length(), index, next_index); 458 } 459 460 void String8::getUtf32(char32_t* dst) const 461 { 462 utf8_to_utf32(mString, length(), dst); 463 } 464 465 // --------------------------------------------------------------------------- 466 // Path functions 467 468 void String8::setPathName(const char* name) 469 { 470 setPathName(name, strlen(name)); 471 } 472 473 void String8::setPathName(const char* name, size_t len) 474 { 475 char* buf = lockBuffer(len); 476 477 memcpy(buf, name, len); 478 479 // remove trailing path separator, if present 480 if (len > 0 && buf[len-1] == OS_PATH_SEPARATOR) 481 len--; 482 483 buf[len] = '\0'; 484 485 unlockBuffer(len); 486 } 487 488 String8 String8::getPathLeaf(void) const 489 { 490 const char* cp; 491 const char*const buf = mString; 492 493 cp = strrchr(buf, OS_PATH_SEPARATOR); 494 if (cp == NULL) 495 return String8(*this); 496 else 497 return String8(cp+1); 498 } 499 500 String8 String8::getPathDir(void) const 501 { 502 const char* cp; 503 const char*const str = mString; 504 505 cp = strrchr(str, OS_PATH_SEPARATOR); 506 if (cp == NULL) 507 return String8(""); 508 else 509 return String8(str, cp - str); 510 } 511 512 String8 String8::walkPath(String8* outRemains) const 513 { 514 const char* cp; 515 const char*const str = mString; 516 const char* buf = str; 517 518 cp = strchr(buf, OS_PATH_SEPARATOR); 519 if (cp == buf) { 520 // don't include a leading '/'. 521 buf = buf+1; 522 cp = strchr(buf, OS_PATH_SEPARATOR); 523 } 524 525 if (cp == NULL) { 526 String8 res = buf != str ? String8(buf) : *this; 527 if (outRemains) *outRemains = String8(""); 528 return res; 529 } 530 531 String8 res(buf, cp-buf); 532 if (outRemains) *outRemains = String8(cp+1); 533 return res; 534 } 535 536 /* 537 * Helper function for finding the start of an extension in a pathname. 538 * 539 * Returns a pointer inside mString, or NULL if no extension was found. 540 */ 541 char* String8::find_extension(void) const 542 { 543 const char* lastSlash; 544 const char* lastDot; 545 int extLen; 546 const char* const str = mString; 547 548 // only look at the filename 549 lastSlash = strrchr(str, OS_PATH_SEPARATOR); 550 if (lastSlash == NULL) 551 lastSlash = str; 552 else 553 lastSlash++; 554 555 // find the last dot 556 lastDot = strrchr(lastSlash, '.'); 557 if (lastDot == NULL) 558 return NULL; 559 560 // looks good, ship it 561 return const_cast<char*>(lastDot); 562 } 563 564 String8 String8::getPathExtension(void) const 565 { 566 char* ext; 567 568 ext = find_extension(); 569 if (ext != NULL) 570 return String8(ext); 571 else 572 return String8(""); 573 } 574 575 String8 String8::getBasePath(void) const 576 { 577 char* ext; 578 const char* const str = mString; 579 580 ext = find_extension(); 581 if (ext == NULL) 582 return String8(*this); 583 else 584 return String8(str, ext - str); 585 } 586 587 String8& String8::appendPath(const char* name) 588 { 589 // TODO: The test below will fail for Win32 paths. Fix later or ignore. 590 if (name[0] != OS_PATH_SEPARATOR) { 591 if (*name == '\0') { 592 // nothing to do 593 return *this; 594 } 595 596 size_t len = length(); 597 if (len == 0) { 598 // no existing filename, just use the new one 599 setPathName(name); 600 return *this; 601 } 602 603 // make room for oldPath + '/' + newPath 604 int newlen = strlen(name); 605 606 char* buf = lockBuffer(len+1+newlen); 607 608 // insert a '/' if needed 609 if (buf[len-1] != OS_PATH_SEPARATOR) 610 buf[len++] = OS_PATH_SEPARATOR; 611 612 memcpy(buf+len, name, newlen+1); 613 len += newlen; 614 615 unlockBuffer(len); 616 617 return *this; 618 } else { 619 setPathName(name); 620 return *this; 621 } 622 } 623 624 String8& String8::convertToResPath() 625 { 626 #if OS_PATH_SEPARATOR != RES_PATH_SEPARATOR 627 size_t len = length(); 628 if (len > 0) { 629 char * buf = lockBuffer(len); 630 for (char * end = buf + len; buf < end; ++buf) { 631 if (*buf == OS_PATH_SEPARATOR) 632 *buf = RES_PATH_SEPARATOR; 633 } 634 unlockBuffer(len); 635 } 636 #endif 637 return *this; 638 } 639 640 }; // namespace android 641