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