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