• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkStrEndsWith(const char string[],const char suffixStr[])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 
SkStrEndsWith(const char string[],const char suffixChar)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 
SkStrStartsWithOneOf(const char string[],const char prefixes[])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 
SkStrAppendU32(char string[],uint32_t dec)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 
SkStrAppendS32(char string[],int32_t dec)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 
SkStrAppendU64(char string[],uint64_t dec,int minDigits)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 
SkStrAppendS64(char string[],int64_t dec,int minDigits)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 
SkStrAppendFloat(char string[],float value)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 
trim_size_t_to_u32(size_t value)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 
check_add32(size_t base,size_t extra)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 
AllocRec(const char text[],size_t len)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 
RefRec(Rec * src)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
validate() const251 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 
SkString()267 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
268 }
269 
SkString(size_t len)270 SkString::SkString(size_t len) {
271     fRec = AllocRec(nullptr, len);
272 }
273 
SkString(const char text[])274 SkString::SkString(const char text[]) {
275     size_t  len = text ? strlen(text) : 0;
276 
277     fRec = AllocRec(text, len);
278 }
279 
SkString(const char text[],size_t len)280 SkString::SkString(const char text[], size_t len) {
281     fRec = AllocRec(text, len);
282 }
283 
SkString(const SkString & src)284 SkString::SkString(const SkString& src) {
285     src.validate();
286 
287     fRec = RefRec(src.fRec);
288 }
289 
SkString(SkString && src)290 SkString::SkString(SkString&& src) {
291     src.validate();
292 
293     fRec = src.fRec;
294     src.fRec = const_cast<Rec*>(&gEmptyRec);
295 }
296 
~SkString()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 
equals(const SkString & src) const308 bool SkString::equals(const SkString& src) const {
309     return fRec == src.fRec || this->equals(src.c_str(), src.size());
310 }
311 
equals(const char text[]) const312 bool SkString::equals(const char text[]) const {
313     return this->equals(text, text ? strlen(text) : 0);
314 }
315 
equals(const char text[],size_t len) const316 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 
operator =(const SkString & src)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 
operator =(SkString && src)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 
operator =(const char text[])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 
reset()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 
writable_str()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 
set(const char text[])381 void SkString::set(const char text[]) {
382     this->set(text, text ? strlen(text) : 0);
383 }
384 
set(const char text[],size_t len)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 
setUTF16(const uint16_t src[])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 
setUTF16(const uint16_t src[],size_t count)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 
insert(size_t offset,const char text[])448 void SkString::insert(size_t offset, const char text[]) {
449     this->insert(offset, text, text ? strlen(text) : 0);
450 }
451 
insert(size_t offset,const char text[],size_t len)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 
insertUnichar(size_t offset,SkUnichar uni)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 
insertS32(size_t offset,int32_t dec)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 
insertS64(size_t offset,int64_t dec,int minDigits)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 
insertU32(size_t offset,uint32_t dec)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 
insertU64(size_t offset,uint64_t dec,int minDigits)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 
insertHex(size_t offset,uint32_t hex,int minDigits)539 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
540     minDigits = SkTPin(minDigits, 0, 8);
541 
542     char    buffer[8];
543     char*   p = buffer + sizeof(buffer);
544 
545     do {
546         *--p = SkHexadecimalDigits::gUpper[hex & 0xF];
547         hex >>= 4;
548         minDigits -= 1;
549     } while (hex != 0);
550 
551     while (--minDigits >= 0) {
552         *--p = '0';
553     }
554 
555     SkASSERT(p >= buffer);
556     this->insert(offset, p, buffer + sizeof(buffer) - p);
557 }
558 
insertScalar(size_t offset,SkScalar value)559 void SkString::insertScalar(size_t offset, SkScalar value) {
560     char    buffer[SkStrAppendScalar_MaxSize];
561     char*   stop = SkStrAppendScalar(buffer, value);
562     this->insert(offset, buffer, stop - buffer);
563 }
564 
printf(const char format[],...)565 void SkString::printf(const char format[], ...) {
566     V_SKSTRING_PRINTF((*this), format);
567 }
568 
appendf(const char format[],...)569 void SkString::appendf(const char format[], ...) {
570     char    buffer[kBufferSize];
571     int length;
572     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
573 
574     this->append(buffer, length);
575 }
576 
appendVAList(const char format[],va_list args)577 void SkString::appendVAList(const char format[], va_list args) {
578     char    buffer[kBufferSize];
579     int length = VSNPRINTF(buffer, kBufferSize, format, args);
580     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
581 
582     this->append(buffer, length);
583 }
584 
prependf(const char format[],...)585 void SkString::prependf(const char format[], ...) {
586     char    buffer[kBufferSize];
587     int length;
588     ARGS_TO_BUFFER(format, buffer, kBufferSize, length);
589 
590     this->prepend(buffer, length);
591 }
592 
prependVAList(const char format[],va_list args)593 void SkString::prependVAList(const char format[], va_list args) {
594     char    buffer[kBufferSize];
595     int length = VSNPRINTF(buffer, kBufferSize, format, args);
596     SkASSERT(length >= 0 && length < SkToInt(kBufferSize));
597 
598     this->prepend(buffer, length);
599 }
600 
601 
602 ///////////////////////////////////////////////////////////////////////////////
603 
remove(size_t offset,size_t length)604 void SkString::remove(size_t offset, size_t length) {
605     size_t size = this->size();
606 
607     if (offset < size) {
608         if (length > size - offset) {
609             length = size - offset;
610         }
611         SkASSERT(length <= size);
612         SkASSERT(offset <= size - length);
613         if (length > 0) {
614             SkString    tmp(size - length);
615             char*       dst = tmp.writable_str();
616             const char* src = this->c_str();
617 
618             if (offset) {
619                 memcpy(dst, src, offset);
620             }
621             size_t tail = size - (offset + length);
622             if (tail) {
623                 memcpy(dst + offset, src + (offset + length), tail);
624             }
625             SkASSERT(dst[tmp.size()] == 0);
626             this->swap(tmp);
627         }
628     }
629 }
630 
swap(SkString & other)631 void SkString::swap(SkString& other) {
632     this->validate();
633     other.validate();
634 
635     SkTSwap<Rec*>(fRec, other.fRec);
636 }
637 
638 ///////////////////////////////////////////////////////////////////////////////
639 
SkStringPrintf(const char * format,...)640 SkString SkStringPrintf(const char* format, ...) {
641     SkString formattedOutput;
642     V_SKSTRING_PRINTF(formattedOutput, format);
643     return formattedOutput;
644 }
645 
SkStrSplit(const char * str,const char * delimiters,SkStrSplitMode splitMode,SkTArray<SkString> * out)646 void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
647                 SkTArray<SkString>* out) {
648     if (splitMode == kCoalesce_SkStrSplitMode) {
649         // Skip any delimiters.
650         str += strspn(str, delimiters);
651     }
652     if (!*str) {
653         return;
654     }
655 
656     while (true) {
657         // Find a token.
658         const size_t len = strcspn(str, delimiters);
659         if (splitMode == kStrict_SkStrSplitMode || len > 0) {
660             out->push_back().set(str, len);
661             str += len;
662         }
663 
664         if (!*str) {
665             return;
666         }
667         if (splitMode == kCoalesce_SkStrSplitMode) {
668             // Skip any delimiters.
669             str += strspn(str, delimiters);
670         } else {
671             // Skip one delimiter.
672             str += 1;
673         }
674     }
675 }
676 
677 #undef VSNPRINTF
678 #undef SNPRINTF
679