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