Home | History | Annotate | Download | only in core
      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 = 1024;
     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, written)      \
     30     do {                                                   \
     31         va_list args;                                      \
     32         va_start(args, format);                            \
     33         written = VSNPRINTF(buffer, size, format, args);   \
     34         SkASSERT(written >= 0 && written < SkToInt(size)); \
     35         va_end(args);                                      \
     36     } while (0)
     37 
     38 ///////////////////////////////////////////////////////////////////////////////
     39 
     40 bool SkStrEndsWith(const char string[], const char suffixStr[]) {
     41     SkASSERT(string);
     42     SkASSERT(suffixStr);
     43     size_t  strLen = strlen(string);
     44     size_t  suffixLen = strlen(suffixStr);
     45     return  strLen >= suffixLen &&
     46             !strncmp(string + strLen - suffixLen, suffixStr, suffixLen);
     47 }
     48 
     49 bool SkStrEndsWith(const char string[], const char suffixChar) {
     50     SkASSERT(string);
     51     size_t  strLen = strlen(string);
     52     if (0 == strLen) {
     53         return false;
     54     } else {
     55         return (suffixChar == string[strLen-1]);
     56     }
     57 }
     58 
     59 int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
     60     int index = 0;
     61     do {
     62         const char* limit = strchr(prefixes, '\0');
     63         if (!strncmp(string, prefixes, limit - prefixes)) {
     64             return index;
     65         }
     66         prefixes = limit + 1;
     67         index++;
     68     } while (prefixes[0]);
     69     return -1;
     70 }
     71 
     72 char* SkStrAppendU32(char string[], uint32_t dec) {
     73     SkDEBUGCODE(char* start = string;)
     74 
     75     char    buffer[SkStrAppendU32_MaxSize];
     76     char*   p = buffer + sizeof(buffer);
     77 
     78     do {
     79         *--p = SkToU8('0' + dec % 10);
     80         dec /= 10;
     81     } while (dec != 0);
     82 
     83     SkASSERT(p >= buffer);
     84     char* stop = buffer + sizeof(buffer);
     85     while (p < stop) {
     86         *string++ = *p++;
     87     }
     88     SkASSERT(string - start <= SkStrAppendU32_MaxSize);
     89     return string;
     90 }
     91 
     92 char* SkStrAppendS32(char string[], int32_t dec) {
     93     uint32_t udec = dec;
     94     if (dec < 0) {
     95         *string++ = '-';
     96         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
     97     }
     98     return SkStrAppendU32(string, udec);
     99 }
    100 
    101 char* SkStrAppendU64(char string[], uint64_t dec, int minDigits) {
    102     SkDEBUGCODE(char* start = string;)
    103 
    104     char    buffer[SkStrAppendU64_MaxSize];
    105     char*   p = buffer + sizeof(buffer);
    106 
    107     do {
    108         *--p = SkToU8('0' + (int32_t) (dec % 10));
    109         dec /= 10;
    110         minDigits--;
    111     } while (dec != 0);
    112 
    113     while (minDigits > 0) {
    114         *--p = '0';
    115         minDigits--;
    116     }
    117 
    118     SkASSERT(p >= buffer);
    119     size_t cp_len = buffer + sizeof(buffer) - p;
    120     memcpy(string, p, cp_len);
    121     string += cp_len;
    122 
    123     SkASSERT(string - start <= SkStrAppendU64_MaxSize);
    124     return string;
    125 }
    126 
    127 char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
    128     uint64_t udec = dec;
    129     if (dec < 0) {
    130         *string++ = '-';
    131         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
    132     }
    133     return SkStrAppendU64(string, udec, minDigits);
    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 = SkFixedRoundToInt(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 static uint32_t trim_size_t_to_u32(size_t value) {
    193     if (sizeof(size_t) > sizeof(uint32_t)) {
    194         if (value > SK_MaxU32) {
    195             value = SK_MaxU32;
    196         }
    197     }
    198     return (uint32_t)value;
    199 }
    200 
    201 static size_t check_add32(size_t base, size_t extra) {
    202     SkASSERT(base <= SK_MaxU32);
    203     if (sizeof(size_t) > sizeof(uint32_t)) {
    204         if (base + extra > SK_MaxU32) {
    205             extra = SK_MaxU32 - base;
    206         }
    207     }
    208     return extra;
    209 }
    210 
    211 SkString::Rec* SkString::AllocRec(const char text[], size_t len) {
    212     Rec* rec;
    213 
    214     if (0 == len) {
    215         rec = const_cast<Rec*>(&gEmptyRec);
    216     } else {
    217         len = trim_size_t_to_u32(len);
    218 
    219         // add 1 for terminating 0, then align4 so we can have some slop when growing the string
    220         rec = (Rec*)sk_malloc_throw(SizeOfRec() + SkAlign4(len + 1));
    221         rec->fLength = SkToU32(len);
    222         rec->fRefCnt = 1;
    223         if (text) {
    224             memcpy(rec->data(), text, len);
    225         }
    226         rec->data()[len] = 0;
    227     }
    228     return rec;
    229 }
    230 
    231 SkString::Rec* SkString::RefRec(Rec* src) {
    232     if (src != &gEmptyRec) {
    233         sk_atomic_inc(&src->fRefCnt);
    234     }
    235     return src;
    236 }
    237 
    238 #ifdef SK_DEBUG
    239 void SkString::validate() const {
    240     // make sure know one has written over our global
    241     SkASSERT(0 == gEmptyRec.fLength);
    242     SkASSERT(0 == gEmptyRec.fRefCnt);
    243     SkASSERT(0 == gEmptyRec.data()[0]);
    244 
    245     if (fRec != &gEmptyRec) {
    246         SkASSERT(fRec->fLength > 0);
    247         SkASSERT(fRec->fRefCnt > 0);
    248         SkASSERT(0 == fRec->data()[fRec->fLength]);
    249     }
    250 }
    251 #endif
    252 
    253 ///////////////////////////////////////////////////////////////////////////////
    254 
    255 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
    256 }
    257 
    258 SkString::SkString(size_t len) {
    259     fRec = AllocRec(NULL, len);
    260 }
    261 
    262 SkString::SkString(const char text[]) {
    263     size_t  len = text ? strlen(text) : 0;
    264 
    265     fRec = AllocRec(text, len);
    266 }
    267 
    268 SkString::SkString(const char text[], size_t len) {
    269     fRec = AllocRec(text, len);
    270 }
    271 
    272 SkString::SkString(const SkString& src) {
    273     src.validate();
    274 
    275     fRec = RefRec(src.fRec);
    276 }
    277 
    278 SkString::~SkString() {
    279     this->validate();
    280 
    281     if (fRec->fLength) {
    282         SkASSERT(fRec->fRefCnt > 0);
    283         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    284             sk_free(fRec);
    285         }
    286     }
    287 }
    288 
    289 bool SkString::equals(const SkString& src) const {
    290     return fRec == src.fRec || this->equals(src.c_str(), src.size());
    291 }
    292 
    293 bool SkString::equals(const char text[]) const {
    294     return this->equals(text, text ? strlen(text) : 0);
    295 }
    296 
    297 bool SkString::equals(const char text[], size_t len) const {
    298     SkASSERT(len == 0 || text != NULL);
    299 
    300     return fRec->fLength == len && !memcmp(fRec->data(), text, len);
    301 }
    302 
    303 SkString& SkString::operator=(const SkString& src) {
    304     this->validate();
    305 
    306     if (fRec != src.fRec) {
    307         SkString    tmp(src);
    308         this->swap(tmp);
    309     }
    310     return *this;
    311 }
    312 
    313 SkString& SkString::operator=(const char text[]) {
    314     this->validate();
    315 
    316     SkString tmp(text);
    317     this->swap(tmp);
    318 
    319     return *this;
    320 }
    321 
    322 void SkString::reset() {
    323     this->validate();
    324 
    325     if (fRec->fLength) {
    326         SkASSERT(fRec->fRefCnt > 0);
    327         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    328             sk_free(fRec);
    329         }
    330     }
    331 
    332     fRec = const_cast<Rec*>(&gEmptyRec);
    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         }
    349     }
    350     return fRec->data();
    351 }
    352 
    353 void SkString::set(const char text[]) {
    354     this->set(text, text ? strlen(text) : 0);
    355 }
    356 
    357 void SkString::set(const char text[], size_t len) {
    358     len = trim_size_t_to_u32(len);
    359 
    360     if (0 == len) {
    361         this->reset();
    362     } else if (1 == fRec->fRefCnt && len <= fRec->fLength) {
    363         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))?
    364         // just use less of the buffer without allocating a smaller one
    365         char* p = this->writable_str();
    366         if (text) {
    367             memcpy(p, text, len);
    368         }
    369         p[len] = 0;
    370         fRec->fLength = SkToU32(len);
    371     } else if (1 == fRec->fRefCnt && (fRec->fLength >> 2) == (len >> 2)) {
    372         // we have spare room in the current allocation, so don't alloc a larger one
    373         char* p = this->writable_str();
    374         if (text) {
    375             memcpy(p, text, len);
    376         }
    377         p[len] = 0;
    378         fRec->fLength = SkToU32(len);
    379     } else {
    380         SkString tmp(text, len);
    381         this->swap(tmp);
    382     }
    383 }
    384 
    385 void SkString::setUTF16(const uint16_t src[]) {
    386     int count = 0;
    387 
    388     while (src[count]) {
    389         count += 1;
    390     }
    391     this->setUTF16(src, count);
    392 }
    393 
    394 void SkString::setUTF16(const uint16_t src[], size_t count) {
    395     count = trim_size_t_to_u32(count);
    396 
    397     if (0 == count) {
    398         this->reset();
    399     } else if (count <= fRec->fLength) {
    400         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
    401         if (count < fRec->fLength) {
    402             this->resize(count);
    403         }
    404         char* p = this->writable_str();
    405         for (size_t i = 0; i < count; i++) {
    406             p[i] = SkToU8(src[i]);
    407         }
    408         p[count] = 0;
    409     } else {
    410         SkString tmp(count); // puts a null terminator at the end of the string
    411         char*    p = tmp.writable_str();
    412 
    413         for (size_t i = 0; i < count; i++) {
    414             p[i] = SkToU8(src[i]);
    415         }
    416         this->swap(tmp);
    417     }
    418 }
    419 
    420 void SkString::insert(size_t offset, const char text[]) {
    421     this->insert(offset, text, text ? strlen(text) : 0);
    422 }
    423 
    424 void SkString::insert(size_t offset, const char text[], size_t len) {
    425     if (len) {
    426         size_t length = fRec->fLength;
    427         if (offset > length) {
    428             offset = length;
    429         }
    430 
    431         // Check if length + len exceeds 32bits, we trim len
    432         len = check_add32(length, len);
    433         if (0 == len) {
    434             return;
    435         }
    436 
    437         /*  If we're the only owner, and we have room in our allocation for the insert,
    438             do it in place, rather than allocating a new buffer.
    439 
    440             To know we have room, compare the allocated sizes
    441             beforeAlloc = SkAlign4(length + 1)
    442             afterAlloc  = SkAligh4(length + 1 + len)
    443             but SkAlign4(x) is (x + 3) >> 2 << 2
    444             which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
    445             and we can then eliminate the +1+3 since that doesn't affec the answer
    446         */
    447         if (1 == fRec->fRefCnt && (length >> 2) == ((length + len) >> 2)) {
    448             char* dst = this->writable_str();
    449 
    450             if (offset < length) {
    451                 memmove(dst + offset + len, dst + offset, length - offset);
    452             }
    453             memcpy(dst + offset, text, len);
    454 
    455             dst[length + len] = 0;
    456             fRec->fLength = SkToU32(length + len);
    457         } else {
    458             /*  Seems we should use realloc here, since that is safe if it fails
    459                 (we have the original data), and might be faster than alloc/copy/free.
    460             */
    461             SkString    tmp(fRec->fLength + len);
    462             char*       dst = tmp.writable_str();
    463 
    464             if (offset > 0) {
    465                 memcpy(dst, fRec->data(), offset);
    466             }
    467             memcpy(dst + offset, text, len);
    468             if (offset < fRec->fLength) {
    469                 memcpy(dst + offset + len, fRec->data() + offset,
    470                        fRec->fLength - offset);
    471             }
    472 
    473             this->swap(tmp);
    474         }
    475     }
    476 }
    477 
    478 void SkString::insertUnichar(size_t offset, SkUnichar uni) {
    479     char    buffer[kMaxBytesInUTF8Sequence];
    480     size_t  len = SkUTF8_FromUnichar(uni, buffer);
    481 
    482     if (len) {
    483         this->insert(offset, buffer, len);
    484     }
    485 }
    486 
    487 void SkString::insertS32(size_t offset, int32_t dec) {
    488     char    buffer[SkStrAppendS32_MaxSize];
    489     char*   stop = SkStrAppendS32(buffer, dec);
    490     this->insert(offset, buffer, stop - buffer);
    491 }
    492 
    493 void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
    494     char    buffer[SkStrAppendS64_MaxSize];
    495     char*   stop = SkStrAppendS64(buffer, dec, minDigits);
    496     this->insert(offset, buffer, stop - buffer);
    497 }
    498 
    499 void SkString::insertU32(size_t offset, uint32_t dec) {
    500     char    buffer[SkStrAppendU32_MaxSize];
    501     char*   stop = SkStrAppendU32(buffer, dec);
    502     this->insert(offset, buffer, stop - buffer);
    503 }
    504 
    505 void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) {
    506     char    buffer[SkStrAppendU64_MaxSize];
    507     char*   stop = SkStrAppendU64(buffer, dec, minDigits);
    508     this->insert(offset, buffer, stop - buffer);
    509 }
    510 
    511 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
    512     minDigits = SkPin32(minDigits, 0, 8);
    513 
    514     static const char gHex[] = "0123456789ABCDEF";
    515 
    516     char    buffer[8];
    517     char*   p = buffer + sizeof(buffer);
    518 
    519     do {
    520         *--p = gHex[hex & 0xF];
    521         hex >>= 4;
    522         minDigits -= 1;
    523     } while (hex != 0);
    524 
    525     while (--minDigits >= 0) {
    526         *--p = '0';
    527     }
    528 
    529     SkASSERT(p >= buffer);
    530     this->insert(offset, p, buffer + sizeof(buffer) - p);
    531 }
    532 
    533 void SkString::insertScalar(size_t offset, SkScalar value) {
    534     char    buffer[SkStrAppendScalar_MaxSize];
    535     char*   stop = SkStrAppendScalar(buffer, value);
    536     this->insert(offset, buffer, stop - buffer);
    537 }
    538 
    539 void SkString::printf(const char format[], ...) {
    540     char    buffer[kBufferSize];
    541     int length;
    542     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    543 
    544     this->set(buffer, length);
    545 }
    546 
    547 void SkString::appendf(const char format[], ...) {
    548     char    buffer[kBufferSize];
    549     int length;
    550     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    551 
    552     this->append(buffer, length);
    553 }
    554 
    555 void SkString::appendVAList(const char format[], va_list args) {
    556     char    buffer[kBufferSize];
    557     int length = VSNPRINTF(buffer, kBufferSize, format, args);
    558     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
    559 
    560     this->append(buffer, length);
    561 }
    562 
    563 void SkString::prependf(const char format[], ...) {
    564     char    buffer[kBufferSize];
    565     int length;
    566     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    567 
    568     this->prepend(buffer, length);
    569 }
    570 
    571 void SkString::prependVAList(const char format[], va_list args) {
    572     char    buffer[kBufferSize];
    573     int length = VSNPRINTF(buffer, kBufferSize, format, args);
    574     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
    575 
    576     this->prepend(buffer, length);
    577 }
    578 
    579 
    580 ///////////////////////////////////////////////////////////////////////////////
    581 
    582 void SkString::remove(size_t offset, size_t length) {
    583     size_t size = this->size();
    584 
    585     if (offset < size) {
    586         if (length > size - offset) {
    587             length = size - offset;
    588         }
    589         SkASSERT(length <= size);
    590         SkASSERT(offset <= size - length);
    591         if (length > 0) {
    592             SkString    tmp(size - length);
    593             char*       dst = tmp.writable_str();
    594             const char* src = this->c_str();
    595 
    596             if (offset) {
    597                 memcpy(dst, src, offset);
    598             }
    599             size_t tail = size - (offset + length);
    600             if (tail) {
    601                 memcpy(dst + offset, src + (offset + length), tail);
    602             }
    603             SkASSERT(dst[tmp.size()] == 0);
    604             this->swap(tmp);
    605         }
    606     }
    607 }
    608 
    609 void SkString::swap(SkString& other) {
    610     this->validate();
    611     other.validate();
    612 
    613     SkTSwap<Rec*>(fRec, other.fRec);
    614 }
    615 
    616 ///////////////////////////////////////////////////////////////////////////////
    617 
    618 SkString SkStringPrintf(const char* format, ...) {
    619     SkString formattedOutput;
    620     char buffer[kBufferSize];
    621     SK_UNUSED int length;
    622     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    623     formattedOutput.set(buffer);
    624     return formattedOutput;
    625 }
    626 
    627 void SkStrSplit(const char* str, const char* delimiters, SkTArray<SkString>* out) {
    628     const char* end = str + strlen(str);
    629     while (str != end) {
    630         // Find a token.
    631         const size_t len = strcspn(str, delimiters);
    632         out->push_back().set(str, len);
    633         str += len;
    634         // Skip any delimiters.
    635         str += strspn(str, delimiters);
    636     }
    637 }
    638 
    639 #undef VSNPRINTF
    640 #undef SNPRINTF
    641