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 25 static 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 45 bool SkStrStartsWith(const char string[], const char prefix[]) { 46 SkASSERT(string); 47 SkASSERT(prefix); 48 return !strncmp(string, prefix, strlen(prefix)); 49 } 50 51 bool 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 60 int 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 73 char* 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 103 char* 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 139 char* 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 151 char* 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] 194 const SkString::Rec SkString::gEmptyRec = { 0, 0, 0 }; 195 196 #define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec) 197 198 SkString::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 216 SkString::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 228 void 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 245 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) { 246 #ifdef SK_DEBUG 247 fStr = fRec->data(); 248 #endif 249 } 250 251 SkString::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 260 SkString::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 269 SkString::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 276 SkString::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 285 SkString::~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 296 bool SkString::equals(const SkString& src) const { 297 return fRec == src.fRec || this->equals(src.c_str(), src.size()); 298 } 299 300 bool SkString::equals(const char text[]) const { 301 return this->equals(text, text ? strlen(text) : 0); 302 } 303 304 bool 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 310 SkString& 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 320 SkString& SkString::operator=(const char text[]) { 321 this->validate(); 322 323 SkString tmp(text); 324 this->swap(tmp); 325 326 return *this; 327 } 328 329 void 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 345 char* 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 360 void SkString::set(const char text[]) { 361 this->set(text, text ? strlen(text) : 0); 362 } 363 364 void 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 390 void 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 399 void 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 423 void SkString::insert(size_t offset, const char text[]) { 424 this->insert(offset, text, text ? strlen(text) : 0); 425 } 426 427 void 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 475 void 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 484 void 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 490 void 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 496 void 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 518 void 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 524 void 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 531 void 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 538 void 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 #undef VSNPRINTF 546 547 /////////////////////////////////////////////////////////////////////////////// 548 549 void SkString::remove(size_t offset, size_t length) { 550 size_t size = this->size(); 551 552 if (offset < size) { 553 if (offset + length > size) { 554 length = size - offset; 555 } 556 if (length > 0) { 557 SkASSERT(size > length); 558 SkString tmp(size - length); 559 char* dst = tmp.writable_str(); 560 const char* src = this->c_str(); 561 562 if (offset) { 563 SkASSERT(offset <= tmp.size()); 564 memcpy(dst, src, offset); 565 } 566 size_t tail = size - offset - length; 567 SkASSERT((int32_t)tail >= 0); 568 if (tail) { 569 // SkASSERT(offset + length <= tmp.size()); 570 memcpy(dst + offset, src + offset + length, tail); 571 } 572 SkASSERT(dst[tmp.size()] == 0); 573 this->swap(tmp); 574 } 575 } 576 } 577 578 void SkString::swap(SkString& other) { 579 this->validate(); 580 other.validate(); 581 582 SkTSwap<Rec*>(fRec, other.fRec); 583 #ifdef SK_DEBUG 584 SkTSwap<const char*>(fStr, other.fStr); 585 #endif 586 } 587 588 /////////////////////////////////////////////////////////////////////////////// 589 590 SkAutoUCS2::SkAutoUCS2(const char utf8[]) { 591 size_t len = strlen(utf8); 592 fUCS2 = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t)); 593 594 uint16_t* dst = fUCS2; 595 for (;;) { 596 SkUnichar uni = SkUTF8_NextUnichar(&utf8); 597 *dst++ = SkToU16(uni); 598 if (uni == 0) { 599 break; 600 } 601 } 602 fCount = (int)(dst - fUCS2); 603 } 604 605 SkAutoUCS2::~SkAutoUCS2() { 606 sk_free(fUCS2); 607 } 608