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 "SkAtomics.h"
     11 #include "SkFixed.h"
     12 #include "SkString.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(nullptr, 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(SkString&& src) {
    279     src.validate();
    280 
    281     fRec = src.fRec;
    282     src.fRec = const_cast<Rec*>(&gEmptyRec);
    283 }
    284 
    285 SkString::~SkString() {
    286     this->validate();
    287 
    288     if (fRec->fLength) {
    289         SkASSERT(fRec->fRefCnt > 0);
    290         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    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 != nullptr);
    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=(SkString&& src) {
    321     this->validate();
    322 
    323     if (fRec != src.fRec) {
    324         this->swap(src);
    325     }
    326     return *this;
    327 }
    328 
    329 SkString& SkString::operator=(const char text[]) {
    330     this->validate();
    331 
    332     SkString tmp(text);
    333     this->swap(tmp);
    334 
    335     return *this;
    336 }
    337 
    338 void SkString::reset() {
    339     this->validate();
    340 
    341     if (fRec->fLength) {
    342         SkASSERT(fRec->fRefCnt > 0);
    343         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    344             sk_free(fRec);
    345         }
    346     }
    347 
    348     fRec = const_cast<Rec*>(&gEmptyRec);
    349 }
    350 
    351 char* SkString::writable_str() {
    352     this->validate();
    353 
    354     if (fRec->fLength) {
    355         if (fRec->fRefCnt > 1) {
    356             Rec* rec = AllocRec(fRec->data(), fRec->fLength);
    357             if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    358                 // In this case after our check of fRecCnt > 1, we suddenly
    359                 // did become the only owner, so now we have two copies of the
    360                 // data (fRec and rec), so we need to delete one of them.
    361                 sk_free(fRec);
    362             }
    363             fRec = rec;
    364         }
    365     }
    366     return fRec->data();
    367 }
    368 
    369 void SkString::set(const char text[]) {
    370     this->set(text, text ? strlen(text) : 0);
    371 }
    372 
    373 void SkString::set(const char text[], size_t len) {
    374     len = trim_size_t_to_u32(len);
    375 
    376     if (0 == len) {
    377         this->reset();
    378     } else if (1 == fRec->fRefCnt && len <= fRec->fLength) {
    379         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))?
    380         // just use less of the buffer without allocating a smaller one
    381         char* p = this->writable_str();
    382         if (text) {
    383             memcpy(p, text, len);
    384         }
    385         p[len] = 0;
    386         fRec->fLength = SkToU32(len);
    387     } else if (1 == fRec->fRefCnt && (fRec->fLength >> 2) == (len >> 2)) {
    388         // we have spare room in the current allocation, so don't alloc a larger one
    389         char* p = this->writable_str();
    390         if (text) {
    391             memcpy(p, text, len);
    392         }
    393         p[len] = 0;
    394         fRec->fLength = SkToU32(len);
    395     } else {
    396         SkString tmp(text, len);
    397         this->swap(tmp);
    398     }
    399 }
    400 
    401 void SkString::setUTF16(const uint16_t src[]) {
    402     int count = 0;
    403 
    404     while (src[count]) {
    405         count += 1;
    406     }
    407     this->setUTF16(src, count);
    408 }
    409 
    410 void SkString::setUTF16(const uint16_t src[], size_t count) {
    411     count = trim_size_t_to_u32(count);
    412 
    413     if (0 == count) {
    414         this->reset();
    415     } else if (count <= fRec->fLength) {
    416         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
    417         if (count < fRec->fLength) {
    418             this->resize(count);
    419         }
    420         char* p = this->writable_str();
    421         for (size_t i = 0; i < count; i++) {
    422             p[i] = SkToU8(src[i]);
    423         }
    424         p[count] = 0;
    425     } else {
    426         SkString tmp(count); // puts a null terminator at the end of the string
    427         char*    p = tmp.writable_str();
    428 
    429         for (size_t i = 0; i < count; i++) {
    430             p[i] = SkToU8(src[i]);
    431         }
    432         this->swap(tmp);
    433     }
    434 }
    435 
    436 void SkString::insert(size_t offset, const char text[]) {
    437     this->insert(offset, text, text ? strlen(text) : 0);
    438 }
    439 
    440 void SkString::insert(size_t offset, const char text[], size_t len) {
    441     if (len) {
    442         size_t length = fRec->fLength;
    443         if (offset > length) {
    444             offset = length;
    445         }
    446 
    447         // Check if length + len exceeds 32bits, we trim len
    448         len = check_add32(length, len);
    449         if (0 == len) {
    450             return;
    451         }
    452 
    453         /*  If we're the only owner, and we have room in our allocation for the insert,
    454             do it in place, rather than allocating a new buffer.
    455 
    456             To know we have room, compare the allocated sizes
    457             beforeAlloc = SkAlign4(length + 1)
    458             afterAlloc  = SkAligh4(length + 1 + len)
    459             but SkAlign4(x) is (x + 3) >> 2 << 2
    460             which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
    461             and we can then eliminate the +1+3 since that doesn't affec the answer
    462         */
    463         if (1 == fRec->fRefCnt && (length >> 2) == ((length + len) >> 2)) {
    464             char* dst = this->writable_str();
    465 
    466             if (offset < length) {
    467                 memmove(dst + offset + len, dst + offset, length - offset);
    468             }
    469             memcpy(dst + offset, text, len);
    470 
    471             dst[length + len] = 0;
    472             fRec->fLength = SkToU32(length + len);
    473         } else {
    474             /*  Seems we should use realloc here, since that is safe if it fails
    475                 (we have the original data), and might be faster than alloc/copy/free.
    476             */
    477             SkString    tmp(fRec->fLength + len);
    478             char*       dst = tmp.writable_str();
    479 
    480             if (offset > 0) {
    481                 memcpy(dst, fRec->data(), offset);
    482             }
    483             memcpy(dst + offset, text, len);
    484             if (offset < fRec->fLength) {
    485                 memcpy(dst + offset + len, fRec->data() + offset,
    486                        fRec->fLength - offset);
    487             }
    488 
    489             this->swap(tmp);
    490         }
    491     }
    492 }
    493 
    494 void SkString::insertUnichar(size_t offset, SkUnichar uni) {
    495     char    buffer[kMaxBytesInUTF8Sequence];
    496     size_t  len = SkUTF8_FromUnichar(uni, buffer);
    497 
    498     if (len) {
    499         this->insert(offset, buffer, len);
    500     }
    501 }
    502 
    503 void SkString::insertS32(size_t offset, int32_t dec) {
    504     char    buffer[SkStrAppendS32_MaxSize];
    505     char*   stop = SkStrAppendS32(buffer, dec);
    506     this->insert(offset, buffer, stop - buffer);
    507 }
    508 
    509 void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
    510     char    buffer[SkStrAppendS64_MaxSize];
    511     char*   stop = SkStrAppendS64(buffer, dec, minDigits);
    512     this->insert(offset, buffer, stop - buffer);
    513 }
    514 
    515 void SkString::insertU32(size_t offset, uint32_t dec) {
    516     char    buffer[SkStrAppendU32_MaxSize];
    517     char*   stop = SkStrAppendU32(buffer, dec);
    518     this->insert(offset, buffer, stop - buffer);
    519 }
    520 
    521 void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) {
    522     char    buffer[SkStrAppendU64_MaxSize];
    523     char*   stop = SkStrAppendU64(buffer, dec, minDigits);
    524     this->insert(offset, buffer, stop - buffer);
    525 }
    526 
    527 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
    528     minDigits = SkTPin(minDigits, 0, 8);
    529 
    530     static const char gHex[] = "0123456789ABCDEF";
    531 
    532     char    buffer[8];
    533     char*   p = buffer + sizeof(buffer);
    534 
    535     do {
    536         *--p = gHex[hex & 0xF];
    537         hex >>= 4;
    538         minDigits -= 1;
    539     } while (hex != 0);
    540 
    541     while (--minDigits >= 0) {
    542         *--p = '0';
    543     }
    544 
    545     SkASSERT(p >= buffer);
    546     this->insert(offset, p, buffer + sizeof(buffer) - p);
    547 }
    548 
    549 void SkString::insertScalar(size_t offset, SkScalar value) {
    550     char    buffer[SkStrAppendScalar_MaxSize];
    551     char*   stop = SkStrAppendScalar(buffer, value);
    552     this->insert(offset, buffer, stop - buffer);
    553 }
    554 
    555 void SkString::printf(const char format[], ...) {
    556     char    buffer[kBufferSize];
    557     int length;
    558     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    559 
    560     this->set(buffer, length);
    561 }
    562 
    563 void SkString::appendf(const char format[], ...) {
    564     char    buffer[kBufferSize];
    565     int length;
    566     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    567 
    568     this->append(buffer, length);
    569 }
    570 
    571 void SkString::appendVAList(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->append(buffer, length);
    577 }
    578 
    579 void SkString::prependf(const char format[], ...) {
    580     char    buffer[kBufferSize];
    581     int length;
    582     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    583 
    584     this->prepend(buffer, length);
    585 }
    586 
    587 void SkString::prependVAList(const char format[], va_list args) {
    588     char    buffer[kBufferSize];
    589     int length = VSNPRINTF(buffer, kBufferSize, format, args);
    590     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
    591 
    592     this->prepend(buffer, length);
    593 }
    594 
    595 
    596 ///////////////////////////////////////////////////////////////////////////////
    597 
    598 void SkString::remove(size_t offset, size_t length) {
    599     size_t size = this->size();
    600 
    601     if (offset < size) {
    602         if (length > size - offset) {
    603             length = size - offset;
    604         }
    605         SkASSERT(length <= size);
    606         SkASSERT(offset <= size - length);
    607         if (length > 0) {
    608             SkString    tmp(size - length);
    609             char*       dst = tmp.writable_str();
    610             const char* src = this->c_str();
    611 
    612             if (offset) {
    613                 memcpy(dst, src, offset);
    614             }
    615             size_t tail = size - (offset + length);
    616             if (tail) {
    617                 memcpy(dst + offset, src + (offset + length), tail);
    618             }
    619             SkASSERT(dst[tmp.size()] == 0);
    620             this->swap(tmp);
    621         }
    622     }
    623 }
    624 
    625 void SkString::swap(SkString& other) {
    626     this->validate();
    627     other.validate();
    628 
    629     SkTSwap<Rec*>(fRec, other.fRec);
    630 }
    631 
    632 ///////////////////////////////////////////////////////////////////////////////
    633 
    634 SkString SkStringPrintf(const char* format, ...) {
    635     SkString formattedOutput;
    636     char buffer[kBufferSize];
    637     SK_UNUSED int length;
    638     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    639     formattedOutput.set(buffer);
    640     return formattedOutput;
    641 }
    642 
    643 void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
    644                 SkTArray<SkString>* out) {
    645     if (splitMode == kCoalesce_SkStrSplitMode) {
    646         // Skip any delimiters.
    647         str += strspn(str, delimiters);
    648     }
    649     if (!*str) {
    650         return;
    651     }
    652 
    653     while (true) {
    654         // Find a token.
    655         const size_t len = strcspn(str, delimiters);
    656         if (splitMode == kStrict_SkStrSplitMode || len > 0) {
    657             out->push_back().set(str, len);
    658             str += len;
    659         }
    660 
    661         if (!*str) {
    662             return;
    663         }
    664         if (splitMode == kCoalesce_SkStrSplitMode) {
    665             // Skip any delimiters.
    666             str += strspn(str, delimiters);
    667         } else {
    668             // Skip one delimiter.
    669             str += 1;
    670         }
    671     }
    672 }
    673 
    674 #undef VSNPRINTF
    675 #undef SNPRINTF
    676