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