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