LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkString.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 345 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 50 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #if defined(_MSC_VER) && _MSC_VER < 1900
      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             : #if defined(_MSC_VER) && _MSC_VER < 1900
      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           0 : bool SkStrEndsWith(const char string[], const char suffixStr[]) {
      91           0 :     SkASSERT(string);
      92           0 :     SkASSERT(suffixStr);
      93           0 :     size_t  strLen = strlen(string);
      94           0 :     size_t  suffixLen = strlen(suffixStr);
      95           0 :     return  strLen >= suffixLen &&
      96           0 :             !strncmp(string + strLen - suffixLen, suffixStr, suffixLen);
      97             : }
      98             : 
      99           0 : bool SkStrEndsWith(const char string[], const char suffixChar) {
     100           0 :     SkASSERT(string);
     101           0 :     size_t  strLen = strlen(string);
     102           0 :     if (0 == strLen) {
     103           0 :         return false;
     104             :     } else {
     105           0 :         return (suffixChar == string[strLen-1]);
     106             :     }
     107             : }
     108             : 
     109           0 : int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
     110           0 :     int index = 0;
     111           0 :     do {
     112           0 :         const char* limit = strchr(prefixes, '\0');
     113           0 :         if (!strncmp(string, prefixes, limit - prefixes)) {
     114           0 :             return index;
     115             :         }
     116           0 :         prefixes = limit + 1;
     117           0 :         index++;
     118           0 :     } while (prefixes[0]);
     119           0 :     return -1;
     120             : }
     121             : 
     122           0 : char* SkStrAppendU32(char string[], uint32_t dec) {
     123           0 :     SkDEBUGCODE(char* start = string;)
     124             : 
     125             :     char    buffer[SkStrAppendU32_MaxSize];
     126           0 :     char*   p = buffer + sizeof(buffer);
     127             : 
     128           0 :     do {
     129           0 :         *--p = SkToU8('0' + dec % 10);
     130           0 :         dec /= 10;
     131           0 :     } while (dec != 0);
     132             : 
     133           0 :     SkASSERT(p >= buffer);
     134           0 :     char* stop = buffer + sizeof(buffer);
     135           0 :     while (p < stop) {
     136           0 :         *string++ = *p++;
     137             :     }
     138           0 :     SkASSERT(string - start <= SkStrAppendU32_MaxSize);
     139           0 :     return string;
     140             : }
     141             : 
     142           0 : char* SkStrAppendS32(char string[], int32_t dec) {
     143           0 :     uint32_t udec = dec;
     144           0 :     if (dec < 0) {
     145           0 :         *string++ = '-';
     146           0 :         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
     147             :     }
     148           0 :     return SkStrAppendU32(string, udec);
     149             : }
     150             : 
     151           0 : char* SkStrAppendU64(char string[], uint64_t dec, int minDigits) {
     152           0 :     SkDEBUGCODE(char* start = string;)
     153             : 
     154             :     char    buffer[SkStrAppendU64_MaxSize];
     155           0 :     char*   p = buffer + sizeof(buffer);
     156             : 
     157           0 :     do {
     158           0 :         *--p = SkToU8('0' + (int32_t) (dec % 10));
     159           0 :         dec /= 10;
     160           0 :         minDigits--;
     161           0 :     } while (dec != 0);
     162             : 
     163           0 :     while (minDigits > 0) {
     164           0 :         *--p = '0';
     165           0 :         minDigits--;
     166             :     }
     167             : 
     168           0 :     SkASSERT(p >= buffer);
     169           0 :     size_t cp_len = buffer + sizeof(buffer) - p;
     170           0 :     memcpy(string, p, cp_len);
     171           0 :     string += cp_len;
     172             : 
     173           0 :     SkASSERT(string - start <= SkStrAppendU64_MaxSize);
     174           0 :     return string;
     175             : }
     176             : 
     177           0 : char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
     178           0 :     uint64_t udec = dec;
     179           0 :     if (dec < 0) {
     180           0 :         *string++ = '-';
     181           0 :         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
     182             :     }
     183           0 :     return SkStrAppendU64(string, udec, minDigits);
     184             : }
     185             : 
     186           0 : 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           0 :     int len = SNPRINTF(buffer, sizeof(buffer), gFormat, value);
     192           0 :     memcpy(string, buffer, len);
     193           0 :     SkASSERT(len <= SkStrAppendScalar_MaxSize);
     194           0 :     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           0 : static uint32_t trim_size_t_to_u32(size_t value) {
     205             :     if (sizeof(size_t) > sizeof(uint32_t)) {
     206           0 :         if (value > SK_MaxU32) {
     207           0 :             value = SK_MaxU32;
     208             :         }
     209             :     }
     210           0 :     return (uint32_t)value;
     211             : }
     212             : 
     213           0 : static size_t check_add32(size_t base, size_t extra) {
     214           0 :     SkASSERT(base <= SK_MaxU32);
     215             :     if (sizeof(size_t) > sizeof(uint32_t)) {
     216           0 :         if (base + extra > SK_MaxU32) {
     217           0 :             extra = SK_MaxU32 - base;
     218             :         }
     219             :     }
     220           0 :     return extra;
     221             : }
     222             : 
     223           0 : SkString::Rec* SkString::AllocRec(const char text[], size_t len) {
     224             :     Rec* rec;
     225             : 
     226           0 :     if (0 == len) {
     227           0 :         rec = const_cast<Rec*>(&gEmptyRec);
     228             :     } else {
     229           0 :         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           0 :         rec = (Rec*)sk_malloc_throw(SizeOfRec() + SkAlign4(len + 1));
     233           0 :         rec->fLength = SkToU32(len);
     234           0 :         rec->fRefCnt = 1;
     235           0 :         if (text) {
     236           0 :             memcpy(rec->data(), text, len);
     237             :         }
     238           0 :         rec->data()[len] = 0;
     239             :     }
     240           0 :     return rec;
     241             : }
     242             : 
     243           0 : SkString::Rec* SkString::RefRec(Rec* src) {
     244           0 :     if (src != &gEmptyRec) {
     245           0 :         sk_atomic_inc(&src->fRefCnt);
     246             :     }
     247           0 :     return src;
     248             : }
     249             : 
     250             : #ifdef SK_DEBUG
     251           0 : void SkString::validate() const {
     252             :     // make sure know one has written over our global
     253           0 :     SkASSERT(0 == gEmptyRec.fLength);
     254           0 :     SkASSERT(0 == gEmptyRec.fRefCnt);
     255           0 :     SkASSERT(0 == gEmptyRec.data()[0]);
     256             : 
     257           0 :     if (fRec != &gEmptyRec) {
     258           0 :         SkASSERT(fRec->fLength > 0);
     259           0 :         SkASSERT(fRec->fRefCnt > 0);
     260           0 :         SkASSERT(0 == fRec->data()[fRec->fLength]);
     261             :     }
     262           0 : }
     263             : #endif
     264             : 
     265             : ///////////////////////////////////////////////////////////////////////////////
     266             : 
     267           0 : SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
     268           0 : }
     269             : 
     270           0 : SkString::SkString(size_t len) {
     271           0 :     fRec = AllocRec(nullptr, len);
     272           0 : }
     273             : 
     274           0 : SkString::SkString(const char text[]) {
     275           0 :     size_t  len = text ? strlen(text) : 0;
     276             : 
     277           0 :     fRec = AllocRec(text, len);
     278           0 : }
     279             : 
     280           0 : SkString::SkString(const char text[], size_t len) {
     281           0 :     fRec = AllocRec(text, len);
     282           0 : }
     283             : 
     284           0 : SkString::SkString(const SkString& src) {
     285           0 :     src.validate();
     286             : 
     287           0 :     fRec = RefRec(src.fRec);
     288           0 : }
     289             : 
     290           0 : SkString::SkString(SkString&& src) {
     291           0 :     src.validate();
     292             : 
     293           0 :     fRec = src.fRec;
     294           0 :     src.fRec = const_cast<Rec*>(&gEmptyRec);
     295           0 : }
     296             : 
     297           0 : SkString::~SkString() {
     298           0 :     this->validate();
     299             : 
     300           0 :     if (fRec->fLength) {
     301           0 :         SkASSERT(fRec->fRefCnt > 0);
     302           0 :         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
     303           0 :             sk_free(fRec);
     304             :         }
     305             :     }
     306           0 : }
     307             : 
     308           0 : bool SkString::equals(const SkString& src) const {
     309           0 :     return fRec == src.fRec || this->equals(src.c_str(), src.size());
     310             : }
     311             : 
     312           0 : bool SkString::equals(const char text[]) const {
     313           0 :     return this->equals(text, text ? strlen(text) : 0);
     314             : }
     315             : 
     316           0 : bool SkString::equals(const char text[], size_t len) const {
     317           0 :     SkASSERT(len == 0 || text != nullptr);
     318             : 
     319           0 :     return fRec->fLength == len && !memcmp(fRec->data(), text, len);
     320             : }
     321             : 
     322           0 : SkString& SkString::operator=(const SkString& src) {
     323           0 :     this->validate();
     324             : 
     325           0 :     if (fRec != src.fRec) {
     326           0 :         SkString    tmp(src);
     327           0 :         this->swap(tmp);
     328             :     }
     329           0 :     return *this;
     330             : }
     331             : 
     332           0 : SkString& SkString::operator=(SkString&& src) {
     333           0 :     this->validate();
     334             : 
     335           0 :     if (fRec != src.fRec) {
     336           0 :         this->swap(src);
     337             :     }
     338           0 :     return *this;
     339             : }
     340             : 
     341           0 : SkString& SkString::operator=(const char text[]) {
     342           0 :     this->validate();
     343             : 
     344           0 :     SkString tmp(text);
     345           0 :     this->swap(tmp);
     346             : 
     347           0 :     return *this;
     348             : }
     349             : 
     350           0 : void SkString::reset() {
     351           0 :     this->validate();
     352             : 
     353           0 :     if (fRec->fLength) {
     354           0 :         SkASSERT(fRec->fRefCnt > 0);
     355           0 :         if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
     356           0 :             sk_free(fRec);
     357             :         }
     358             :     }
     359             : 
     360           0 :     fRec = const_cast<Rec*>(&gEmptyRec);
     361           0 : }
     362             : 
     363           0 : char* SkString::writable_str() {
     364           0 :     this->validate();
     365             : 
     366           0 :     if (fRec->fLength) {
     367           0 :         if (fRec->fRefCnt > 1) {
     368           0 :             Rec* rec = AllocRec(fRec->data(), fRec->fLength);
     369           0 :             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           0 :                 sk_free(fRec);
     374             :             }
     375           0 :             fRec = rec;
     376             :         }
     377             :     }
     378           0 :     return fRec->data();
     379             : }
     380             : 
     381           0 : void SkString::set(const char text[]) {
     382           0 :     this->set(text, text ? strlen(text) : 0);
     383           0 : }
     384             : 
     385           0 : void SkString::set(const char text[], size_t len) {
     386           0 :     len = trim_size_t_to_u32(len);
     387             : 
     388           0 :     if (0 == len) {
     389           0 :         this->reset();
     390           0 :     } 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           0 :         char* p = this->writable_str();
     394           0 :         if (text) {
     395           0 :             memcpy(p, text, len);
     396             :         }
     397           0 :         p[len] = 0;
     398           0 :         fRec->fLength = SkToU32(len);
     399           0 :     } 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           0 :         char* p = this->writable_str();
     402           0 :         if (text) {
     403           0 :             memcpy(p, text, len);
     404             :         }
     405           0 :         p[len] = 0;
     406           0 :         fRec->fLength = SkToU32(len);
     407             :     } else {
     408           0 :         SkString tmp(text, len);
     409           0 :         this->swap(tmp);
     410             :     }
     411           0 : }
     412             : 
     413           0 : void SkString::setUTF16(const uint16_t src[]) {
     414           0 :     int count = 0;
     415             : 
     416           0 :     while (src[count]) {
     417           0 :         count += 1;
     418             :     }
     419           0 :     this->setUTF16(src, count);
     420           0 : }
     421             : 
     422           0 : void SkString::setUTF16(const uint16_t src[], size_t count) {
     423           0 :     count = trim_size_t_to_u32(count);
     424             : 
     425           0 :     if (0 == count) {
     426           0 :         this->reset();
     427           0 :     } else if (count <= fRec->fLength) {
     428             :         // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
     429           0 :         if (count < fRec->fLength) {
     430           0 :             this->resize(count);
     431             :         }
     432           0 :         char* p = this->writable_str();
     433           0 :         for (size_t i = 0; i < count; i++) {
     434           0 :             p[i] = SkToU8(src[i]);
     435             :         }
     436           0 :         p[count] = 0;
     437             :     } else {
     438           0 :         SkString tmp(count); // puts a null terminator at the end of the string
     439           0 :         char*    p = tmp.writable_str();
     440             : 
     441           0 :         for (size_t i = 0; i < count; i++) {
     442           0 :             p[i] = SkToU8(src[i]);
     443             :         }
     444           0 :         this->swap(tmp);
     445             :     }
     446           0 : }
     447             : 
     448           0 : void SkString::insert(size_t offset, const char text[]) {
     449           0 :     this->insert(offset, text, text ? strlen(text) : 0);
     450           0 : }
     451             : 
     452           0 : void SkString::insert(size_t offset, const char text[], size_t len) {
     453           0 :     if (len) {
     454           0 :         size_t length = fRec->fLength;
     455           0 :         if (offset > length) {
     456           0 :             offset = length;
     457             :         }
     458             : 
     459             :         // Check if length + len exceeds 32bits, we trim len
     460           0 :         len = check_add32(length, len);
     461           0 :         if (0 == len) {
     462           0 :             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           0 :         if (1 == fRec->fRefCnt && (length >> 2) == ((length + len) >> 2)) {
     476           0 :             char* dst = this->writable_str();
     477             : 
     478           0 :             if (offset < length) {
     479           0 :                 memmove(dst + offset + len, dst + offset, length - offset);
     480             :             }
     481           0 :             memcpy(dst + offset, text, len);
     482             : 
     483           0 :             dst[length + len] = 0;
     484           0 :             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           0 :             SkString    tmp(fRec->fLength + len);
     490           0 :             char*       dst = tmp.writable_str();
     491             : 
     492           0 :             if (offset > 0) {
     493           0 :                 memcpy(dst, fRec->data(), offset);
     494             :             }
     495           0 :             memcpy(dst + offset, text, len);
     496           0 :             if (offset < fRec->fLength) {
     497           0 :                 memcpy(dst + offset + len, fRec->data() + offset,
     498           0 :                        fRec->fLength - offset);
     499             :             }
     500             : 
     501           0 :             this->swap(tmp);
     502             :         }
     503             :     }
     504             : }
     505             : 
     506           0 : void SkString::insertUnichar(size_t offset, SkUnichar uni) {
     507             :     char    buffer[kMaxBytesInUTF8Sequence];
     508           0 :     size_t  len = SkUTF8_FromUnichar(uni, buffer);
     509             : 
     510           0 :     if (len) {
     511           0 :         this->insert(offset, buffer, len);
     512             :     }
     513           0 : }
     514             : 
     515           0 : void SkString::insertS32(size_t offset, int32_t dec) {
     516             :     char    buffer[SkStrAppendS32_MaxSize];
     517           0 :     char*   stop = SkStrAppendS32(buffer, dec);
     518           0 :     this->insert(offset, buffer, stop - buffer);
     519           0 : }
     520             : 
     521           0 : void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
     522             :     char    buffer[SkStrAppendS64_MaxSize];
     523           0 :     char*   stop = SkStrAppendS64(buffer, dec, minDigits);
     524           0 :     this->insert(offset, buffer, stop - buffer);
     525           0 : }
     526             : 
     527           0 : void SkString::insertU32(size_t offset, uint32_t dec) {
     528             :     char    buffer[SkStrAppendU32_MaxSize];
     529           0 :     char*   stop = SkStrAppendU32(buffer, dec);
     530           0 :     this->insert(offset, buffer, stop - buffer);
     531           0 : }
     532             : 
     533           0 : void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) {
     534             :     char    buffer[SkStrAppendU64_MaxSize];
     535           0 :     char*   stop = SkStrAppendU64(buffer, dec, minDigits);
     536           0 :     this->insert(offset, buffer, stop - buffer);
     537           0 : }
     538             : 
     539           0 : void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
     540           0 :     minDigits = SkTPin(minDigits, 0, 8);
     541             : 
     542             :     static const char gHex[] = "0123456789ABCDEF";
     543             : 
     544             :     char    buffer[8];
     545           0 :     char*   p = buffer + sizeof(buffer);
     546             : 
     547           0 :     do {
     548           0 :         *--p = gHex[hex & 0xF];
     549           0 :         hex >>= 4;
     550           0 :         minDigits -= 1;
     551           0 :     } while (hex != 0);
     552             : 
     553           0 :     while (--minDigits >= 0) {
     554           0 :         *--p = '0';
     555             :     }
     556             : 
     557           0 :     SkASSERT(p >= buffer);
     558           0 :     this->insert(offset, p, buffer + sizeof(buffer) - p);
     559           0 : }
     560             : 
     561           0 : void SkString::insertScalar(size_t offset, SkScalar value) {
     562             :     char    buffer[SkStrAppendScalar_MaxSize];
     563           0 :     char*   stop = SkStrAppendScalar(buffer, value);
     564           0 :     this->insert(offset, buffer, stop - buffer);
     565           0 : }
     566             : 
     567           0 : void SkString::printf(const char format[], ...) {
     568           0 :     V_SKSTRING_PRINTF((*this), format);
     569           0 : }
     570             : 
     571           0 : void SkString::appendf(const char format[], ...) {
     572             :     char    buffer[kBufferSize];
     573             :     int length;
     574           0 :     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
     575             : 
     576           0 :     this->append(buffer, length);
     577           0 : }
     578             : 
     579           0 : void SkString::appendVAList(const char format[], va_list args) {
     580             :     char    buffer[kBufferSize];
     581           0 :     int length = VSNPRINTF(buffer, kBufferSize, format, args);
     582           0 :     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
     583             : 
     584           0 :     this->append(buffer, length);
     585           0 : }
     586             : 
     587           0 : void SkString::prependf(const char format[], ...) {
     588             :     char    buffer[kBufferSize];
     589             :     int length;
     590           0 :     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
     591             : 
     592           0 :     this->prepend(buffer, length);
     593           0 : }
     594             : 
     595           0 : void SkString::prependVAList(const char format[], va_list args) {
     596             :     char    buffer[kBufferSize];
     597           0 :     int length = VSNPRINTF(buffer, kBufferSize, format, args);
     598           0 :     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
     599             : 
     600           0 :     this->prepend(buffer, length);
     601           0 : }
     602             : 
     603             : 
     604             : ///////////////////////////////////////////////////////////////////////////////
     605             : 
     606           0 : void SkString::remove(size_t offset, size_t length) {
     607           0 :     size_t size = this->size();
     608             : 
     609           0 :     if (offset < size) {
     610           0 :         if (length > size - offset) {
     611           0 :             length = size - offset;
     612             :         }
     613           0 :         SkASSERT(length <= size);
     614           0 :         SkASSERT(offset <= size - length);
     615           0 :         if (length > 0) {
     616           0 :             SkString    tmp(size - length);
     617           0 :             char*       dst = tmp.writable_str();
     618           0 :             const char* src = this->c_str();
     619             : 
     620           0 :             if (offset) {
     621           0 :                 memcpy(dst, src, offset);
     622             :             }
     623           0 :             size_t tail = size - (offset + length);
     624           0 :             if (tail) {
     625           0 :                 memcpy(dst + offset, src + (offset + length), tail);
     626             :             }
     627           0 :             SkASSERT(dst[tmp.size()] == 0);
     628           0 :             this->swap(tmp);
     629             :         }
     630             :     }
     631           0 : }
     632             : 
     633           0 : void SkString::swap(SkString& other) {
     634           0 :     this->validate();
     635           0 :     other.validate();
     636             : 
     637           0 :     SkTSwap<Rec*>(fRec, other.fRec);
     638           0 : }
     639             : 
     640             : ///////////////////////////////////////////////////////////////////////////////
     641             : 
     642           0 : SkString SkStringPrintf(const char* format, ...) {
     643           0 :     SkString formattedOutput;
     644           0 :     V_SKSTRING_PRINTF(formattedOutput, format);
     645           0 :     return formattedOutput;
     646             : }
     647             : 
     648           0 : void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
     649             :                 SkTArray<SkString>* out) {
     650           0 :     if (splitMode == kCoalesce_SkStrSplitMode) {
     651             :         // Skip any delimiters.
     652           0 :         str += strspn(str, delimiters);
     653             :     }
     654           0 :     if (!*str) {
     655           0 :         return;
     656             :     }
     657             : 
     658             :     while (true) {
     659             :         // Find a token.
     660           0 :         const size_t len = strcspn(str, delimiters);
     661           0 :         if (splitMode == kStrict_SkStrSplitMode || len > 0) {
     662           0 :             out->push_back().set(str, len);
     663           0 :             str += len;
     664             :         }
     665             : 
     666           0 :         if (!*str) {
     667           0 :             return;
     668             :         }
     669           0 :         if (splitMode == kCoalesce_SkStrSplitMode) {
     670             :             // Skip any delimiters.
     671           0 :             str += strspn(str, delimiters);
     672             :         } else {
     673             :             // Skip one delimiter.
     674           0 :             str += 1;
     675             :         }
     676           0 :     }
     677             : }
     678             : 
     679             : #undef VSNPRINTF
     680             : #undef SNPRINTF

Generated by: LCOV version 1.13