1/* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "include/core/SkString.h" 9#include "include/core/SkStringView.h" 10#include "include/private/SkTPin.h" 11#include "include/private/SkTo.h" 12#include "src/core/SkSafeMath.h" 13#include "src/core/SkUtils.h" 14#include "src/utils/SkUTF.h" 15 16#include <cstdio> 17#include <new> 18#include <utility> 19#include <vector> 20 21// number of bytes (on the stack) to receive the printf result 22static const size_t kBufferSize = 1024; 23 24struct StringBuffer { 25 char* fText; 26 int fLength; 27}; 28 29template <int SIZE> 30static StringBuffer apply_format_string(const char* format, va_list args, char (&stackBuffer)[SIZE], 31 SkString* heapBuffer) { 32 // First, attempt to print directly to the stack buffer. 33 va_list argsCopy; 34 va_copy(argsCopy, args); 35 int outLength = std::vsnprintf(stackBuffer, SIZE, format, args); 36 if (outLength < 0) { 37 SkDebugf("SkString: vsnprintf reported error."); 38 va_end(argsCopy); 39 return {stackBuffer, 0}; 40 } 41 if (outLength < SIZE) { 42 va_end(argsCopy); 43 return {stackBuffer, outLength}; 44 } 45 46 // Our text was too long to fit on the stack! However, we now know how much space we need to 47 // format it. Format the string into our heap buffer. `set` automatically reserves an extra 48 // byte at the end of the buffer for a null terminator, so we don't need to add one here. 49 heapBuffer->set(nullptr, outLength); 50 char* heapBufferDest = heapBuffer->writable_str(); 51 SkDEBUGCODE(int checkLength =) std::vsnprintf(heapBufferDest, outLength + 1, format, argsCopy); 52 SkASSERT(checkLength == outLength); 53 va_end(argsCopy); 54 return {heapBufferDest, outLength}; 55} 56 57/////////////////////////////////////////////////////////////////////////////// 58 59bool SkStrEndsWith(const char string[], const char suffixStr[]) { 60 SkASSERT(string); 61 SkASSERT(suffixStr); 62 size_t strLen = strlen(string); 63 size_t suffixLen = strlen(suffixStr); 64 return strLen >= suffixLen && 65 !strncmp(string + strLen - suffixLen, suffixStr, suffixLen); 66} 67 68bool SkStrEndsWith(const char string[], const char suffixChar) { 69 SkASSERT(string); 70 size_t strLen = strlen(string); 71 if (0 == strLen) { 72 return false; 73 } else { 74 return (suffixChar == string[strLen-1]); 75 } 76} 77 78int SkStrStartsWithOneOf(const char string[], const char prefixes[]) { 79 int index = 0; 80 do { 81 const char* limit = strchr(prefixes, '\0'); 82 if (!strncmp(string, prefixes, limit - prefixes)) { 83 return index; 84 } 85 prefixes = limit + 1; 86 index++; 87 } while (prefixes[0]); 88 return -1; 89} 90 91char* SkStrAppendU32(char string[], uint32_t dec) { 92 SkDEBUGCODE(char* start = string;) 93 94 char buffer[kSkStrAppendU32_MaxSize]; 95 char* p = buffer + sizeof(buffer); 96 97 do { 98 *--p = SkToU8('0' + dec % 10); 99 dec /= 10; 100 } while (dec != 0); 101 102 SkASSERT(p >= buffer); 103 char* stop = buffer + sizeof(buffer); 104 while (p < stop) { 105 *string++ = *p++; 106 } 107 SkASSERT(string - start <= kSkStrAppendU32_MaxSize); 108 return string; 109} 110 111char* SkStrAppendS32(char string[], int32_t dec) { 112 uint32_t udec = dec; 113 if (dec < 0) { 114 *string++ = '-'; 115 udec = ~udec + 1; // udec = -udec, but silences some warnings that are trying to be helpful 116 } 117 return SkStrAppendU32(string, udec); 118} 119 120char* SkStrAppendU64(char string[], uint64_t dec, int minDigits) { 121 SkDEBUGCODE(char* start = string;) 122 123 char buffer[kSkStrAppendU64_MaxSize]; 124 char* p = buffer + sizeof(buffer); 125 126 do { 127 *--p = SkToU8('0' + (int32_t) (dec % 10)); 128 dec /= 10; 129 minDigits--; 130 } while (dec != 0); 131 132 while (minDigits > 0) { 133 *--p = '0'; 134 minDigits--; 135 } 136 137 SkASSERT(p >= buffer); 138 size_t cp_len = buffer + sizeof(buffer) - p; 139 memcpy(string, p, cp_len); 140 string += cp_len; 141 142 SkASSERT(string - start <= kSkStrAppendU64_MaxSize); 143 return string; 144} 145 146char* SkStrAppendS64(char string[], int64_t dec, int minDigits) { 147 uint64_t udec = dec; 148 if (dec < 0) { 149 *string++ = '-'; 150 udec = ~udec + 1; // udec = -udec, but silences some warnings that are trying to be helpful 151 } 152 return SkStrAppendU64(string, udec, minDigits); 153} 154 155char* SkStrAppendScalar(char string[], SkScalar value) { 156 // Handle infinity and NaN ourselves to ensure consistent cross-platform results. 157 // (e.g.: `inf` versus `1.#INF00`, `nan` versus `-nan` for high-bit-set NaNs) 158 if (SkScalarIsNaN(value)) { 159 strcpy(string, "nan"); 160 return string + 3; 161 } 162 if (!SkScalarIsFinite(value)) { 163 if (value > 0) { 164 strcpy(string, "inf"); 165 return string + 3; 166 } else { 167 strcpy(string, "-inf"); 168 return string + 4; 169 } 170 } 171 172 // since floats have at most 8 significant digits, we limit our %g to that. 173 static const char gFormat[] = "%.8g"; 174 // make it 1 larger for the terminating 0 175 char buffer[kSkStrAppendScalar_MaxSize + 1]; 176 int len = snprintf(buffer, sizeof(buffer), gFormat, value); 177 memcpy(string, buffer, len); 178 SkASSERT(len <= kSkStrAppendScalar_MaxSize); 179 return string + len; 180} 181 182/////////////////////////////////////////////////////////////////////////////// 183 184const SkString::Rec SkString::gEmptyRec(0, 0); 185 186#define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec) 187 188static uint32_t trim_size_t_to_u32(size_t value) { 189 if (sizeof(size_t) > sizeof(uint32_t)) { 190 if (value > UINT32_MAX) { 191 value = UINT32_MAX; 192 } 193 } 194 return (uint32_t)value; 195} 196 197static size_t check_add32(size_t base, size_t extra) { 198 SkASSERT(base <= UINT32_MAX); 199 if (sizeof(size_t) > sizeof(uint32_t)) { 200 if (base + extra > UINT32_MAX) { 201 extra = UINT32_MAX - base; 202 } 203 } 204 return extra; 205} 206 207sk_sp<SkString::Rec> SkString::Rec::Make(const char text[], size_t len) { 208 if (0 == len) { 209 return sk_sp<SkString::Rec>(const_cast<Rec*>(&gEmptyRec)); 210 } 211 212 SkSafeMath safe; 213 // We store a 32bit version of the length 214 uint32_t stringLen = safe.castTo<uint32_t>(len); 215 // Add SizeOfRec() for our overhead and 1 for null-termination 216 size_t allocationSize = safe.add(len, SizeOfRec() + sizeof(char)); 217 // Align up to a multiple of 4 218 allocationSize = safe.alignUp(allocationSize, 4); 219 220 SkASSERT_RELEASE(safe.ok()); 221 222 void* storage = ::operator new (allocationSize); 223 sk_sp<Rec> rec(new (storage) Rec(stringLen, 1)); 224 if (text) { 225 memcpy(rec->data(), text, len); 226 } 227 rec->data()[len] = 0; 228 return rec; 229} 230 231void SkString::Rec::ref() const { 232 if (this == &SkString::gEmptyRec) { 233 return; 234 } 235 SkAssertResult(this->fRefCnt.fetch_add(+1, std::memory_order_relaxed)); 236} 237 238void SkString::Rec::unref() const { 239 if (this == &SkString::gEmptyRec) { 240 return; 241 } 242 int32_t oldRefCnt = this->fRefCnt.fetch_add(-1, std::memory_order_acq_rel); 243 SkASSERT(oldRefCnt); 244 if (1 == oldRefCnt) { 245 delete this; 246 } 247} 248 249bool SkString::Rec::unique() const { 250 return fRefCnt.load(std::memory_order_acquire) == 1; 251} 252 253#ifdef SK_DEBUG 254int32_t SkString::Rec::getRefCnt() const { 255 return fRefCnt.load(std::memory_order_relaxed); 256} 257 258const SkString& SkString::validate() const { 259 // make sure no one has written over our global 260 SkASSERT(0 == gEmptyRec.fLength); 261 SkASSERT(0 == gEmptyRec.getRefCnt()); 262 SkASSERT(0 == gEmptyRec.data()[0]); 263 264 if (fRec.get() != &gEmptyRec) { 265 SkASSERT(fRec->fLength > 0); 266 SkASSERT(fRec->getRefCnt() > 0); 267 SkASSERT(0 == fRec->data()[fRec->fLength]); 268 } 269 return *this; 270} 271#endif 272 273/////////////////////////////////////////////////////////////////////////////// 274 275SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) { 276} 277 278SkString::SkString(size_t len) { 279 fRec = Rec::Make(nullptr, len); 280} 281 282SkString::SkString(const char text[]) { 283 size_t len = text ? strlen(text) : 0; 284 285 fRec = Rec::Make(text, len); 286} 287 288SkString::SkString(const char text[], size_t len) { 289 fRec = Rec::Make(text, len); 290} 291 292SkString::SkString(const SkString& src) : fRec(src.validate().fRec) {} 293 294SkString::SkString(SkString&& src) : fRec(std::move(src.validate().fRec)) { 295 src.fRec.reset(const_cast<Rec*>(&gEmptyRec)); 296} 297 298SkString::SkString(const std::string& src) { 299 fRec = Rec::Make(src.c_str(), src.size()); 300} 301 302SkString::SkString(skstd::string_view src) { 303 fRec = Rec::Make(src.data(), src.length()); 304} 305 306SkString::~SkString() { 307 this->validate(); 308} 309 310bool SkString::equals(const SkString& src) const { 311 return fRec == src.fRec || this->equals(src.c_str(), src.size()); 312} 313 314bool SkString::equals(const char text[]) const { 315 return this->equals(text, text ? strlen(text) : 0); 316} 317 318bool SkString::equals(const char text[], size_t len) const { 319 SkASSERT(len == 0 || text != nullptr); 320 321 return fRec->fLength == len && !sk_careful_memcmp(fRec->data(), text, len); 322} 323 324SkString& SkString::operator=(const SkString& src) { 325 this->validate(); 326 fRec = src.fRec; // sk_sp<Rec>::operator=(const sk_sp<Ref>&) checks for self-assignment. 327 return *this; 328} 329 330SkString& SkString::operator=(SkString&& src) { 331 this->validate(); 332 333 if (fRec != src.fRec) { 334 this->swap(src); 335 } 336 return *this; 337} 338 339SkString& SkString::operator=(const char text[]) { 340 this->validate(); 341 return *this = SkString(text); 342} 343 344void SkString::reset() { 345 this->validate(); 346 fRec.reset(const_cast<Rec*>(&gEmptyRec)); 347} 348 349char* SkString::writable_str() { 350 this->validate(); 351 352 if (fRec->fLength) { 353 if (!fRec->unique()) { 354 fRec = Rec::Make(fRec->data(), fRec->fLength); 355 } 356 } 357 return fRec->data(); 358} 359 360void SkString::resize(size_t len) { 361 len = trim_size_t_to_u32(len); 362 if (0 == len) { 363 this->reset(); 364 } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) { 365 // Use less of the buffer we have without allocating a smaller one. 366 char* p = this->writable_str(); 367 p[len] = '\0'; 368 fRec->fLength = SkToU32(len); 369 } else { 370 SkString newString(len); 371 char* dest = newString.writable_str(); 372 int copyLen = std::min<uint32_t>(len, this->size()); 373 memcpy(dest, this->c_str(), copyLen); 374 dest[copyLen] = '\0'; 375 this->swap(newString); 376 } 377} 378 379void SkString::set(const char text[]) { 380 this->set(text, text ? strlen(text) : 0); 381} 382 383void SkString::set(const char text[], size_t len) { 384 len = trim_size_t_to_u32(len); 385 if (0 == len) { 386 this->reset(); 387 } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) { 388 // Use less of the buffer we have without allocating a smaller one. 389 char* p = this->writable_str(); 390 if (text) { 391 memcpy(p, text, len); 392 } 393 p[len] = '\0'; 394 fRec->fLength = SkToU32(len); 395 } else { 396 SkString tmp(text, len); 397 this->swap(tmp); 398 } 399} 400 401void SkString::insert(size_t offset, const char text[]) { 402 this->insert(offset, text, text ? strlen(text) : 0); 403} 404 405void SkString::insert(size_t offset, const char text[], size_t len) { 406 if (len) { 407 size_t length = fRec->fLength; 408 if (offset > length) { 409 offset = length; 410 } 411 412 // Check if length + len exceeds 32bits, we trim len 413 len = check_add32(length, len); 414 if (0 == len) { 415 return; 416 } 417 418 /* If we're the only owner, and we have room in our allocation for the insert, 419 do it in place, rather than allocating a new buffer. 420 421 To know we have room, compare the allocated sizes 422 beforeAlloc = SkAlign4(length + 1) 423 afterAlloc = SkAligh4(length + 1 + len) 424 but SkAlign4(x) is (x + 3) >> 2 << 2 425 which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2 426 and we can then eliminate the +1+3 since that doesn't affec the answer 427 */ 428 if (fRec->unique() && (length >> 2) == ((length + len) >> 2)) { 429 char* dst = this->writable_str(); 430 431 if (offset < length) { 432 memmove(dst + offset + len, dst + offset, length - offset); 433 } 434 memcpy(dst + offset, text, len); 435 436 dst[length + len] = 0; 437 fRec->fLength = SkToU32(length + len); 438 } else { 439 /* Seems we should use realloc here, since that is safe if it fails 440 (we have the original data), and might be faster than alloc/copy/free. 441 */ 442 SkString tmp(fRec->fLength + len); 443 char* dst = tmp.writable_str(); 444 445 if (offset > 0) { 446 memcpy(dst, fRec->data(), offset); 447 } 448 memcpy(dst + offset, text, len); 449 if (offset < fRec->fLength) { 450 memcpy(dst + offset + len, fRec->data() + offset, 451 fRec->fLength - offset); 452 } 453 454 this->swap(tmp); 455 } 456 } 457} 458 459void SkString::insertUnichar(size_t offset, SkUnichar uni) { 460 char buffer[SkUTF::kMaxBytesInUTF8Sequence]; 461 size_t len = SkUTF::ToUTF8(uni, buffer); 462 463 if (len) { 464 this->insert(offset, buffer, len); 465 } 466} 467 468void SkString::insertS32(size_t offset, int32_t dec) { 469 char buffer[kSkStrAppendS32_MaxSize]; 470 char* stop = SkStrAppendS32(buffer, dec); 471 this->insert(offset, buffer, stop - buffer); 472} 473 474void SkString::insertS64(size_t offset, int64_t dec, int minDigits) { 475 char buffer[kSkStrAppendS64_MaxSize]; 476 char* stop = SkStrAppendS64(buffer, dec, minDigits); 477 this->insert(offset, buffer, stop - buffer); 478} 479 480void SkString::insertU32(size_t offset, uint32_t dec) { 481 char buffer[kSkStrAppendU32_MaxSize]; 482 char* stop = SkStrAppendU32(buffer, dec); 483 this->insert(offset, buffer, stop - buffer); 484} 485 486void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) { 487 char buffer[kSkStrAppendU64_MaxSize]; 488 char* stop = SkStrAppendU64(buffer, dec, minDigits); 489 this->insert(offset, buffer, stop - buffer); 490} 491 492void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) { 493 minDigits = SkTPin(minDigits, 0, 8); 494 495 char buffer[8]; 496 char* p = buffer + sizeof(buffer); 497 498 do { 499 *--p = SkHexadecimalDigits::gUpper[hex & 0xF]; 500 hex >>= 4; 501 minDigits -= 1; 502 } while (hex != 0); 503 504 while (--minDigits >= 0) { 505 *--p = '0'; 506 } 507 508 SkASSERT(p >= buffer); 509 this->insert(offset, p, buffer + sizeof(buffer) - p); 510} 511 512void SkString::insertScalar(size_t offset, SkScalar value) { 513 char buffer[kSkStrAppendScalar_MaxSize]; 514 char* stop = SkStrAppendScalar(buffer, value); 515 this->insert(offset, buffer, stop - buffer); 516} 517 518/////////////////////////////////////////////////////////////////////////////// 519 520void SkString::printf(const char format[], ...) { 521 va_list args; 522 va_start(args, format); 523 this->printVAList(format, args); 524 va_end(args); 525} 526 527void SkString::printVAList(const char format[], va_list args) { 528 char stackBuffer[kBufferSize]; 529 StringBuffer result = apply_format_string(format, args, stackBuffer, this); 530 531 if (result.fText == stackBuffer) { 532 this->set(result.fText, result.fLength); 533 } 534} 535 536void SkString::appendf(const char format[], ...) { 537 va_list args; 538 va_start(args, format); 539 this->appendVAList(format, args); 540 va_end(args); 541} 542 543void SkString::appendVAList(const char format[], va_list args) { 544 if (this->isEmpty()) { 545 this->printVAList(format, args); 546 return; 547 } 548 549 SkString overflow; 550 char stackBuffer[kBufferSize]; 551 StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow); 552 553 this->append(result.fText, result.fLength); 554} 555 556void SkString::prependf(const char format[], ...) { 557 va_list args; 558 va_start(args, format); 559 this->prependVAList(format, args); 560 va_end(args); 561} 562 563void SkString::prependVAList(const char format[], va_list args) { 564 if (this->isEmpty()) { 565 this->printVAList(format, args); 566 return; 567 } 568 569 SkString overflow; 570 char stackBuffer[kBufferSize]; 571 StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow); 572 573 this->prepend(result.fText, result.fLength); 574} 575 576/////////////////////////////////////////////////////////////////////////////// 577 578void SkString::remove(size_t offset, size_t length) { 579 size_t size = this->size(); 580 581 if (offset < size) { 582 if (length > size - offset) { 583 length = size - offset; 584 } 585 SkASSERT(length <= size); 586 SkASSERT(offset <= size - length); 587 if (length > 0) { 588 SkString tmp(size - length); 589 char* dst = tmp.writable_str(); 590 const char* src = this->c_str(); 591 592 if (offset) { 593 memcpy(dst, src, offset); 594 } 595 size_t tail = size - (offset + length); 596 if (tail) { 597 memcpy(dst + offset, src + (offset + length), tail); 598 } 599 SkASSERT(dst[tmp.size()] == 0); 600 this->swap(tmp); 601 } 602 } 603} 604 605void SkString::swap(SkString& other) { 606 this->validate(); 607 other.validate(); 608 609 using std::swap; 610 swap(fRec, other.fRec); 611} 612 613/////////////////////////////////////////////////////////////////////////////// 614 615SkString SkStringPrintf(const char* format, ...) { 616 SkString formattedOutput; 617 va_list args; 618 va_start(args, format); 619 formattedOutput.printVAList(format, args); 620 va_end(args); 621 return formattedOutput; 622} 623 624void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode, 625 SkTArray<SkString>* out) { 626 if (splitMode == kCoalesce_SkStrSplitMode) { 627 // Skip any delimiters. 628 str += strspn(str, delimiters); 629 } 630 if (!*str) { 631 return; 632 } 633 634 while (true) { 635 // Find a token. 636 const size_t len = strcspn(str, delimiters); 637 if (splitMode == kStrict_SkStrSplitMode || len > 0) { 638 out->push_back().set(str, len); 639 str += len; 640 } 641 642 if (!*str) { 643 return; 644 } 645 if (splitMode == kCoalesce_SkStrSplitMode) { 646 // Skip any delimiters. 647 str += strspn(str, delimiters); 648 } else { 649 // Skip one delimiter. 650 str += 1; 651 } 652 } 653} 654