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