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