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