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