Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 
      9 #include "SkAtomics.h"
     10 #include "SkString.h"
     11 #include "SkUtils.h"
     12 #include <stdarg.h>
     13 #include <stdio.h>
     14 
     15 // number of bytes (on the stack) to receive the printf result
     16 static const size_t kBufferSize = 1024;
     17 
     18 #ifdef SK_BUILD_FOR_WIN
     19     #define VSNPRINTF(buffer, size, format, args) \
     20         _vsnprintf_s(buffer, size, _TRUNCATE, format, args)
     21     #define SNPRINTF    _snprintf
     22 #else
     23     #define VSNPRINTF   vsnprintf
     24     #define SNPRINTF    snprintf
     25 #endif
     26 
     27 #define ARGS_TO_BUFFER(format, buffer, size, written)      \
     28     do {                                                   \
     29         va_list args;                                      \
     30         va_start(args, format);                            \
     31         written = VSNPRINTF(buffer, size, format, args);   \
     32         SkASSERT(written >= 0 && written < SkToInt(size)); \
     33         va_end(args);                                      \
     34     } while (0)
     35 
     36 #ifdef SK_BUILD_FOR_WIN
     37 #define V_SKSTRING_PRINTF(output, format)                               \
     38     do {                                                                \
     39         va_list args;                                                   \
     40         va_start(args, format);                                         \
     41         char buffer[kBufferSize];                                       \
     42         int length = _vsnprintf_s(buffer, sizeof(buffer),               \
     43                                   _TRUNCATE, format, args);             \
     44         va_end(args);                                                   \
     45         if (length >= 0 && length < (int)sizeof(buffer)) {              \
     46             output.set(buffer, length);                                 \
     47             break;                                                      \
     48         }                                                               \
     49         va_start(args, format);                                         \
     50         length = _vscprintf(format, args);                              \
     51         va_end(args);                                                   \
     52         SkAutoTMalloc<char> autoTMalloc((size_t)length + 1);            \
     53         va_start(args, format);                                         \
     54         SkDEBUGCODE(int check = ) _vsnprintf_s(autoTMalloc.get(),       \
     55                                                length + 1, _TRUNCATE,   \
     56                                                format, args);           \
     57         va_end(args);                                                   \
     58         SkASSERT(check == length);                                      \
     59         output.set(autoTMalloc.get(), length);                          \
     60         SkASSERT(output[length] == '\0');                               \
     61     } while (false)
     62 #else
     63 #define V_SKSTRING_PRINTF(output, format)                               \
     64     do {                                                                \
     65         va_list args;                                                   \
     66         va_start(args, format);                                         \
     67         char buffer[kBufferSize];                                       \
     68         int length = vsnprintf(buffer, sizeof(buffer), format, args);   \
     69         va_end(args);                                                   \
     70         if (length < 0) {                                               \
     71             break;                                                      \
     72         }                                                               \
     73         if (length < (int)sizeof(buffer)) {                             \
     74             output.set(buffer, length);                                 \
     75             break;                                                      \
     76         }                                                               \
     77         SkAutoTMalloc<char> autoTMalloc((size_t)length + 1);            \
     78         va_start(args, format);                                         \
     79         SkDEBUGCODE(int check = ) vsnprintf(autoTMalloc.get(),          \
     80                                             length + 1, format, args);  \
     81         va_end(args);                                                   \
     82         SkASSERT(check == length);                                      \
     83         output.set(autoTMalloc.get(), length);                          \
     84         SkASSERT(output[length] == '\0');                               \
     85     } while (false)
     86 #endif
     87 
     88 ///////////////////////////////////////////////////////////////////////////////
     89 
     90 bool SkStrEndsWith(const char string[], const char suffixStr[]) {
     91     SkASSERT(string);
     92     SkASSERT(suffixStr);
     93     size_t  strLen = strlen(string);
     94     size_t  suffixLen = strlen(suffixStr);
     95     return  strLen >= suffixLen &&
     96             !strncmp(string + strLen - suffixLen, suffixStr, suffixLen);
     97 }
     98 
     99 bool SkStrEndsWith(const char string[], const char suffixChar) {
    100     SkASSERT(string);
    101     size_t  strLen = strlen(string);
    102     if (0 == strLen) {
    103         return false;
    104     } else {
    105         return (suffixChar == string[strLen-1]);
    106     }
    107 }
    108 
    109 int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
    110     int index = 0;
    111     do {
    112         const char* limit = strchr(prefixes, '\0');
    113         if (!strncmp(string, prefixes, limit - prefixes)) {
    114             return index;
    115         }
    116         prefixes = limit + 1;
    117         index++;
    118     } while (prefixes[0]);
    119     return -1;
    120 }
    121 
    122 char* SkStrAppendU32(char string[], uint32_t dec) {
    123     SkDEBUGCODE(char* start = string;)
    124 
    125     char    buffer[SkStrAppendU32_MaxSize];
    126     char*   p = buffer + sizeof(buffer);
    127 
    128     do {
    129         *--p = SkToU8('0' + dec % 10);
    130         dec /= 10;
    131     } while (dec != 0);
    132 
    133     SkASSERT(p >= buffer);
    134     char* stop = buffer + sizeof(buffer);
    135     while (p < stop) {
    136         *string++ = *p++;
    137     }
    138     SkASSERT(string - start <= SkStrAppendU32_MaxSize);
    139     return string;
    140 }
    141 
    142 char* SkStrAppendS32(char string[], int32_t dec) {
    143     uint32_t udec = dec;
    144     if (dec < 0) {
    145         *string++ = '-';
    146         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
    147     }
    148     return SkStrAppendU32(string, udec);
    149 }
    150 
    151 char* SkStrAppendU64(char string[], uint64_t dec, int minDigits) {
    152     SkDEBUGCODE(char* start = string;)
    153 
    154     char    buffer[SkStrAppendU64_MaxSize];
    155     char*   p = buffer + sizeof(buffer);
    156 
    157     do {
    158         *--p = SkToU8('0' + (int32_t) (dec % 10));
    159         dec /= 10;
    160         minDigits--;
    161     } while (dec != 0);
    162 
    163     while (minDigits > 0) {
    164         *--p = '0';
    165         minDigits--;
    166     }
    167 
    168     SkASSERT(p >= buffer);
    169     size_t cp_len = buffer + sizeof(buffer) - p;
    170     memcpy(string, p, cp_len);
    171     string += cp_len;
    172 
    173     SkASSERT(string - start <= SkStrAppendU64_MaxSize);
    174     return string;
    175 }
    176 
    177 char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
    178     uint64_t udec = dec;
    179     if (dec < 0) {
    180         *string++ = '-';
    181         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
    182     }
    183     return SkStrAppendU64(string, udec, minDigits);
    184 }
    185 
    186 char* SkStrAppendFloat(char string[], float value) {
    187     // since floats have at most 8 significant digits, we limit our %g to that.
    188     static const char gFormat[] = "%.8g";
    189     // make it 1 larger for the terminating 0
    190     char buffer[SkStrAppendScalar_MaxSize + 1];
    191     int len = SNPRINTF(buffer, sizeof(buffer), gFormat, value);
    192     memcpy(string, buffer, len);
    193     SkASSERT(len <= SkStrAppendScalar_MaxSize);
    194     return string + len;
    195 }
    196 
    197 ///////////////////////////////////////////////////////////////////////////////
    198 
    199 // the 3 values are [length] [refcnt] [terminating zero data]
    200 const SkString::Rec SkString::gEmptyRec = { 0, 0, 0 };
    201 
    202 #define SizeOfRec()     (gEmptyRec.data() - (const char*)&gEmptyRec)
    203 
    204 static uint32_t trim_size_t_to_u32(size_t value) {
    205     if (sizeof(size_t) > sizeof(uint32_t)) {
    206         if (value > SK_MaxU32) {
    207             value = SK_MaxU32;
    208         }
    209     }
    210     return (uint32_t)value;
    211 }
    212 
    213 static size_t check_add32(size_t base, size_t extra) {
    214     SkASSERT(base <= SK_MaxU32);
    215     if (sizeof(size_t) > sizeof(uint32_t)) {
    216         if (base + extra > SK_MaxU32) {
    217             extra = SK_MaxU32 - base;
    218         }
    219     }
    220     return extra;
    221 }
    222 
    223 SkString::Rec* SkString::AllocRec(const char text[], size_t len) {
    224     Rec* rec;
    225 
    226     if (0 == len) {
    227         rec = const_cast<Rec*>(&gEmptyRec);
    228     } else {
    229         len = trim_size_t_to_u32(len);
    230 
    231         // add 1 for terminating 0, then align4 so we can have some slop when growing the string
    232         rec = (Rec*)sk_malloc_throw(SizeOfRec() + SkAlign4(len + 1));
    233         rec->fLength = SkToU32(len);
    234         rec->fRefCnt = 1;
    235         if (text) {
    236             memcpy(rec->data(), text, len);
    237         }
    238         rec->data()[len] = 0;
    239     }
    240     return rec;
    241 }
    242 
    243 SkString::Rec* SkString::RefRec(Rec* src) {
    244     if (src != &gEmptyRec) {
    245         sk_atomic_inc(&src->fRefCnt);
    246     }
    247     return src;
    248 }
    249 
    250 #ifdef SK_DEBUG
    251 void SkString::validate() const {
    252     // make sure know one has written over our global
    253     SkASSERT(0 == gEmptyRec.fLength);
    254     SkASSERT(0 == gEmptyRec.fRefCnt);
    255     SkASSERT(0 == gEmptyRec.data()[0]);
    256 
    257     if (fRec != &gEmptyRec) {
    258         SkASSERT(fRec->fLength > 0);
    259         SkASSERT(fRec->fRefCnt > 0);
    260         SkASSERT(0 == fRec->data()[fRec->fLength]);
    261     }
    262 }
    263 #endif
    264 
    265 ///////////////////////////////////////////////////////////////////////////////
    266 
    267 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
    268 }
    269 
    270 SkString::SkString(size_t len) {
    271     fRec = AllocRec(nullptr, len);
    272 }
    273 
    274 SkString::SkString(const char text[]) {
    275     size_t  len = text ? strlen(text) : 0;
    276 
    277     fRec = AllocRec(text, len);
    278 }
    279 
    280 SkString::SkString(const char text[], size_t len) {
    281     fRec = AllocRec(text, len);
    282 }
    283 
    284 SkString::SkString(const SkString& src) {
    285     src.validate();
    286 
    287     fRec = RefRec(src.fRec);
    288 }
    289 
    290 SkString::SkString(SkString&& src) {
    291     src.validate();
    292 
    293     fRec = src.fRec;
    294     src.fRec = const_cast<Rec*>(&gEmptyRec);
    295 }
    296 
    297 SkString::~SkString() {
    298     this->validate();
    299 
    300     if (fRec->fLength) {
    301         SkASSERT(fRec->fRefCnt > 0);
    302         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    303             sk_free(fRec);
    304         }
    305     }
    306 }
    307 
    308 bool SkString::equals(const SkString& src) const {
    309     return fRec == src.fRec || this->equals(src.c_str(), src.size());
    310 }
    311 
    312 bool SkString::equals(const char text[]) const {
    313     return this->equals(text, text ? strlen(text) : 0);
    314 }
    315 
    316 bool SkString::equals(const char text[], size_t len) const {
    317     SkASSERT(len == 0 || text != nullptr);
    318 
    319     return fRec->fLength == len && !memcmp(fRec->data(), text, len);
    320 }
    321 
    322 SkString& SkString::operator=(const SkString& src) {
    323     this->validate();
    324 
    325     if (fRec != src.fRec) {
    326         SkString    tmp(src);
    327         this->swap(tmp);
    328     }
    329     return *this;
    330 }
    331 
    332 SkString& SkString::operator=(SkString&& src) {
    333     this->validate();
    334 
    335     if (fRec != src.fRec) {
    336         this->swap(src);
    337     }
    338     return *this;
    339 }
    340 
    341 SkString& SkString::operator=(const char text[]) {
    342     this->validate();
    343 
    344     SkString tmp(text);
    345     this->swap(tmp);
    346 
    347     return *this;
    348 }
    349 
    350 void SkString::reset() {
    351     this->validate();
    352 
    353     if (fRec->fLength) {
    354         SkASSERT(fRec->fRefCnt > 0);
    355         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    356             sk_free(fRec);
    357         }
    358     }
    359 
    360     fRec = const_cast<Rec*>(&gEmptyRec);
    361 }
    362 
    363 char* SkString::writable_str() {
    364     this->validate();
    365 
    366     if (fRec->fLength) {
    367         if (fRec->fRefCnt > 1) {
    368             Rec* rec = AllocRec(fRec->data(), fRec->fLength);
    369             if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
    370                 // In this case after our check of fRecCnt > 1, we suddenly
    371                 // did become the only owner, so now we have two copies of the
    372                 // data (fRec and rec), so we need to delete one of them.
    373                 sk_free(fRec);
    374             }
    375             fRec = rec;
    376         }
    377     }
    378     return fRec->data();
    379 }
    380 
    381 void SkString::set(const char text[]) {
    382     this->set(text, text ? strlen(text) : 0);
    383 }
    384 
    385 void SkString::set(const char text[], size_t len) {
    386     len = trim_size_t_to_u32(len);
    387 
    388     if (0 == len) {
    389         this->reset();
    390     } else if (1 == fRec->fRefCnt && len <= fRec->fLength) {
    391         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))?
    392         // just use less of the buffer without allocating a smaller one
    393         char* p = this->writable_str();
    394         if (text) {
    395             memcpy(p, text, len);
    396         }
    397         p[len] = 0;
    398         fRec->fLength = SkToU32(len);
    399     } else if (1 == fRec->fRefCnt && (fRec->fLength >> 2) == (len >> 2)) {
    400         // we have spare room in the current allocation, so don't alloc a larger one
    401         char* p = this->writable_str();
    402         if (text) {
    403             memcpy(p, text, len);
    404         }
    405         p[len] = 0;
    406         fRec->fLength = SkToU32(len);
    407     } else {
    408         SkString tmp(text, len);
    409         this->swap(tmp);
    410     }
    411 }
    412 
    413 void SkString::setUTF16(const uint16_t src[]) {
    414     int count = 0;
    415 
    416     while (src[count]) {
    417         count += 1;
    418     }
    419     this->setUTF16(src, count);
    420 }
    421 
    422 void SkString::setUTF16(const uint16_t src[], size_t count) {
    423     count = trim_size_t_to_u32(count);
    424 
    425     if (0 == count) {
    426         this->reset();
    427     } else if (count <= fRec->fLength) {
    428         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
    429         if (count < fRec->fLength) {
    430             this->resize(count);
    431         }
    432         char* p = this->writable_str();
    433         for (size_t i = 0; i < count; i++) {
    434             p[i] = SkToU8(src[i]);
    435         }
    436         p[count] = 0;
    437     } else {
    438         SkString tmp(count); // puts a null terminator at the end of the string
    439         char*    p = tmp.writable_str();
    440 
    441         for (size_t i = 0; i < count; i++) {
    442             p[i] = SkToU8(src[i]);
    443         }
    444         this->swap(tmp);
    445     }
    446 }
    447 
    448 void SkString::insert(size_t offset, const char text[]) {
    449     this->insert(offset, text, text ? strlen(text) : 0);
    450 }
    451 
    452 void SkString::insert(size_t offset, const char text[], size_t len) {
    453     if (len) {
    454         size_t length = fRec->fLength;
    455         if (offset > length) {
    456             offset = length;
    457         }
    458 
    459         // Check if length + len exceeds 32bits, we trim len
    460         len = check_add32(length, len);
    461         if (0 == len) {
    462             return;
    463         }
    464 
    465         /*  If we're the only owner, and we have room in our allocation for the insert,
    466             do it in place, rather than allocating a new buffer.
    467 
    468             To know we have room, compare the allocated sizes
    469             beforeAlloc = SkAlign4(length + 1)
    470             afterAlloc  = SkAligh4(length + 1 + len)
    471             but SkAlign4(x) is (x + 3) >> 2 << 2
    472             which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
    473             and we can then eliminate the +1+3 since that doesn't affec the answer
    474         */
    475         if (1 == fRec->fRefCnt && (length >> 2) == ((length + len) >> 2)) {
    476             char* dst = this->writable_str();
    477 
    478             if (offset < length) {
    479                 memmove(dst + offset + len, dst + offset, length - offset);
    480             }
    481             memcpy(dst + offset, text, len);
    482 
    483             dst[length + len] = 0;
    484             fRec->fLength = SkToU32(length + len);
    485         } else {
    486             /*  Seems we should use realloc here, since that is safe if it fails
    487                 (we have the original data), and might be faster than alloc/copy/free.
    488             */
    489             SkString    tmp(fRec->fLength + len);
    490             char*       dst = tmp.writable_str();
    491 
    492             if (offset > 0) {
    493                 memcpy(dst, fRec->data(), offset);
    494             }
    495             memcpy(dst + offset, text, len);
    496             if (offset < fRec->fLength) {
    497                 memcpy(dst + offset + len, fRec->data() + offset,
    498                        fRec->fLength - offset);
    499             }
    500 
    501             this->swap(tmp);
    502         }
    503     }
    504 }
    505 
    506 void SkString::insertUnichar(size_t offset, SkUnichar uni) {
    507     char    buffer[kMaxBytesInUTF8Sequence];
    508     size_t  len = SkUTF8_FromUnichar(uni, buffer);
    509 
    510     if (len) {
    511         this->insert(offset, buffer, len);
    512     }
    513 }
    514 
    515 void SkString::insertS32(size_t offset, int32_t dec) {
    516     char    buffer[SkStrAppendS32_MaxSize];
    517     char*   stop = SkStrAppendS32(buffer, dec);
    518     this->insert(offset, buffer, stop - buffer);
    519 }
    520 
    521 void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
    522     char    buffer[SkStrAppendS64_MaxSize];
    523     char*   stop = SkStrAppendS64(buffer, dec, minDigits);
    524     this->insert(offset, buffer, stop - buffer);
    525 }
    526 
    527 void SkString::insertU32(size_t offset, uint32_t dec) {
    528     char    buffer[SkStrAppendU32_MaxSize];
    529     char*   stop = SkStrAppendU32(buffer, dec);
    530     this->insert(offset, buffer, stop - buffer);
    531 }
    532 
    533 void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) {
    534     char    buffer[SkStrAppendU64_MaxSize];
    535     char*   stop = SkStrAppendU64(buffer, dec, minDigits);
    536     this->insert(offset, buffer, stop - buffer);
    537 }
    538 
    539 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
    540     minDigits = SkTPin(minDigits, 0, 8);
    541 
    542     static const char gHex[] = "0123456789ABCDEF";
    543 
    544     char    buffer[8];
    545     char*   p = buffer + sizeof(buffer);
    546 
    547     do {
    548         *--p = gHex[hex & 0xF];
    549         hex >>= 4;
    550         minDigits -= 1;
    551     } while (hex != 0);
    552 
    553     while (--minDigits >= 0) {
    554         *--p = '0';
    555     }
    556 
    557     SkASSERT(p >= buffer);
    558     this->insert(offset, p, buffer + sizeof(buffer) - p);
    559 }
    560 
    561 void SkString::insertScalar(size_t offset, SkScalar value) {
    562     char    buffer[SkStrAppendScalar_MaxSize];
    563     char*   stop = SkStrAppendScalar(buffer, value);
    564     this->insert(offset, buffer, stop - buffer);
    565 }
    566 
    567 void SkString::printf(const char format[], ...) {
    568     V_SKSTRING_PRINTF((*this), format);
    569 }
    570 
    571 void SkString::appendf(const char format[], ...) {
    572     char    buffer[kBufferSize];
    573     int length;
    574     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    575 
    576     this->append(buffer, length);
    577 }
    578 
    579 void SkString::appendVAList(const char format[], va_list args) {
    580     char    buffer[kBufferSize];
    581     int length = VSNPRINTF(buffer, kBufferSize, format, args);
    582     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
    583 
    584     this->append(buffer, length);
    585 }
    586 
    587 void SkString::prependf(const char format[], ...) {
    588     char    buffer[kBufferSize];
    589     int length;
    590     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
    591 
    592     this->prepend(buffer, length);
    593 }
    594 
    595 void SkString::prependVAList(const char format[], va_list args) {
    596     char    buffer[kBufferSize];
    597     int length = VSNPRINTF(buffer, kBufferSize, format, args);
    598     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
    599 
    600     this->prepend(buffer, length);
    601 }
    602 
    603 
    604 ///////////////////////////////////////////////////////////////////////////////
    605 
    606 void SkString::remove(size_t offset, size_t length) {
    607     size_t size = this->size();
    608 
    609     if (offset < size) {
    610         if (length > size - offset) {
    611             length = size - offset;
    612         }
    613         SkASSERT(length <= size);
    614         SkASSERT(offset <= size - length);
    615         if (length > 0) {
    616             SkString    tmp(size - length);
    617             char*       dst = tmp.writable_str();
    618             const char* src = this->c_str();
    619 
    620             if (offset) {
    621                 memcpy(dst, src, offset);
    622             }
    623             size_t tail = size - (offset + length);
    624             if (tail) {
    625                 memcpy(dst + offset, src + (offset + length), tail);
    626             }
    627             SkASSERT(dst[tmp.size()] == 0);
    628             this->swap(tmp);
    629         }
    630     }
    631 }
    632 
    633 void SkString::swap(SkString& other) {
    634     this->validate();
    635     other.validate();
    636 
    637     SkTSwap<Rec*>(fRec, other.fRec);
    638 }
    639 
    640 ///////////////////////////////////////////////////////////////////////////////
    641 
    642 SkString SkStringPrintf(const char* format, ...) {
    643     SkString formattedOutput;
    644     V_SKSTRING_PRINTF(formattedOutput, format);
    645     return formattedOutput;
    646 }
    647 
    648 void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
    649                 SkTArray<SkString>* out) {
    650     if (splitMode == kCoalesce_SkStrSplitMode) {
    651         // Skip any delimiters.
    652         str += strspn(str, delimiters);
    653     }
    654     if (!*str) {
    655         return;
    656     }
    657 
    658     while (true) {
    659         // Find a token.
    660         const size_t len = strcspn(str, delimiters);
    661         if (splitMode == kStrict_SkStrSplitMode || len > 0) {
    662             out->push_back().set(str, len);
    663             str += len;
    664         }
    665 
    666         if (!*str) {
    667             return;
    668         }
    669         if (splitMode == kCoalesce_SkStrSplitMode) {
    670             // Skip any delimiters.
    671             str += strspn(str, delimiters);
    672         } else {
    673             // Skip one delimiter.
    674             str += 1;
    675         }
    676     }
    677 }
    678 
    679 #undef VSNPRINTF
    680 #undef SNPRINTF
    681