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 16 static 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 53 bool 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 62 bool 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 72 int 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 85 char* 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 105 char* 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 114 char* 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 140 char* 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 149 char* 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 162 const SkString::Rec SkString::gEmptyRec(0, 0); 163 164 #define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec) 165 166 static 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 175 static 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 185 sk_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 209 void 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 216 void 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 227 bool SkString::Rec::unique() const { 228 return fRefCnt.load(std::memory_order_acquire) == 1; 229 } 230 231 #ifdef SK_DEBUG 232 void 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 248 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) { 249 } 250 251 SkString::SkString(size_t len) { 252 fRec = Rec::Make(nullptr, len); 253 } 254 255 SkString::SkString(const char text[]) { 256 size_t len = text ? strlen(text) : 0; 257 258 fRec = Rec::Make(text, len); 259 } 260 261 SkString::SkString(const char text[], size_t len) { 262 fRec = Rec::Make(text, len); 263 } 264 265 SkString::SkString(const SkString& src) { 266 src.validate(); 267 268 fRec = src.fRec; 269 } 270 271 SkString::SkString(SkString&& src) { 272 src.validate(); 273 274 fRec = std::move(src.fRec); 275 src.fRec.reset(const_cast<Rec*>(&gEmptyRec)); 276 } 277 278 SkString::~SkString() { 279 this->validate(); 280 } 281 282 bool SkString::equals(const SkString& src) const { 283 return fRec == src.fRec || this->equals(src.c_str(), src.size()); 284 } 285 286 bool SkString::equals(const char text[]) const { 287 return this->equals(text, text ? strlen(text) : 0); 288 } 289 290 bool 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 296 SkString& 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 306 SkString& SkString::operator=(SkString&& src) { 307 this->validate(); 308 309 if (fRec != src.fRec) { 310 this->swap(src); 311 } 312 return *this; 313 } 314 315 SkString& SkString::operator=(const char text[]) { 316 this->validate(); 317 318 SkString tmp(text); 319 this->swap(tmp); 320 321 return *this; 322 } 323 324 void SkString::reset() { 325 this->validate(); 326 fRec.reset(const_cast<Rec*>(&gEmptyRec)); 327 } 328 329 char* 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 340 void SkString::set(const char text[]) { 341 this->set(text, text ? strlen(text) : 0); 342 } 343 344 void 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 372 void SkString::insert(size_t offset, const char text[]) { 373 this->insert(offset, text, text ? strlen(text) : 0); 374 } 375 376 void 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 430 void 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 439 void 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 445 void 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 451 void 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 457 void 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 463 void 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 483 void 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 489 void SkString::printf(const char format[], ...) { 490 V_SKSTRING_PRINTF((*this), format); 491 } 492 493 void 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 501 void 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 509 void 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 517 void 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 528 void 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 555 void SkString::swap(SkString& other) { 556 this->validate(); 557 other.validate(); 558 559 SkTSwap(fRec, other.fRec); 560 } 561 562 /////////////////////////////////////////////////////////////////////////////// 563 564 SkString SkStringPrintf(const char* format, ...) { 565 SkString formattedOutput; 566 V_SKSTRING_PRINTF(formattedOutput, format); 567 return formattedOutput; 568 } 569 570 void 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