• 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 #include "include/core/SkString.h"
9 
10 #include "include/private/base/SkTPin.h"
11 #include "include/private/base/SkMalloc.h"
12 #include "include/private/base/SkDebug.h"
13 #include "include/private/base/SkTo.h"
14 #include "src/base/SkSafeMath.h"
15 #include "src/base/SkUTF.h"
16 #include "src/base/SkUtils.h"
17 
18 #include <algorithm>
19 #include <cstdio>
20 #include <cstring>
21 #include <new>
22 #include <string_view>
23 #include <utility>
24 
25 // number of bytes (on the stack) to receive the printf result
26 static const size_t kBufferSize = 1024;
27 
28 struct StringBuffer {
29     char*  fText;
30     int    fLength;
31 };
32 
33 template <int SIZE>
34 static StringBuffer apply_format_string(const char* format, va_list args, char (&stackBuffer)[SIZE],
35                                         SkString* heapBuffer) SK_PRINTF_LIKE(1, 0);
36 
37 template <int SIZE>
apply_format_string(const char * format,va_list args,char (& stackBuffer)[SIZE],SkString * heapBuffer)38 static StringBuffer apply_format_string(const char* format, va_list args, char (&stackBuffer)[SIZE],
39                                         SkString* heapBuffer) {
40     // First, attempt to print directly to the stack buffer.
41     va_list argsCopy;
42     va_copy(argsCopy, args);
43     int outLength = std::vsnprintf(stackBuffer, SIZE, format, args);
44     if (outLength < 0) {
45         SkDebugf("SkString: vsnprintf reported error.");
46         va_end(argsCopy);
47         return {stackBuffer, 0};
48     }
49     if (outLength < SIZE) {
50         va_end(argsCopy);
51         return {stackBuffer, outLength};
52     }
53 
54     // Our text was too long to fit on the stack! However, we now know how much space we need to
55     // format it. Format the string into our heap buffer. `set` automatically reserves an extra
56     // byte at the end of the buffer for a null terminator, so we don't need to add one here.
57     heapBuffer->set(nullptr, outLength);
58     char* heapBufferDest = heapBuffer->data();
59     SkDEBUGCODE(int checkLength =) std::vsnprintf(heapBufferDest, outLength + 1, format, argsCopy);
60     SkASSERT(checkLength == outLength);
61     va_end(argsCopy);
62     return {heapBufferDest, outLength};
63 }
64 
65 ///////////////////////////////////////////////////////////////////////////////
66 
SkStrEndsWith(const char string[],const char suffixStr[])67 bool SkStrEndsWith(const char string[], const char suffixStr[]) {
68     SkASSERT(string);
69     SkASSERT(suffixStr);
70     size_t  strLen = strlen(string);
71     size_t  suffixLen = strlen(suffixStr);
72     return  strLen >= suffixLen &&
73             !strncmp(string + strLen - suffixLen, suffixStr, suffixLen);
74 }
75 
SkStrEndsWith(const char string[],const char suffixChar)76 bool SkStrEndsWith(const char string[], const char suffixChar) {
77     SkASSERT(string);
78     size_t  strLen = strlen(string);
79     if (0 == strLen) {
80         return false;
81     } else {
82         return (suffixChar == string[strLen-1]);
83     }
84 }
85 
SkStrStartsWithOneOf(const char string[],const char prefixes[])86 int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
87     int index = 0;
88     do {
89         const char* limit = strchr(prefixes, '\0');
90         if (!strncmp(string, prefixes, limit - prefixes)) {
91             return index;
92         }
93         prefixes = limit + 1;
94         index++;
95     } while (prefixes[0]);
96     return -1;
97 }
98 
SkStrAppendU32(char string[],uint32_t dec)99 char* SkStrAppendU32(char string[], uint32_t dec) {
100     SkDEBUGCODE(char* start = string;)
101 
102     char    buffer[kSkStrAppendU32_MaxSize];
103     char*   p = buffer + sizeof(buffer);
104 
105     do {
106         *--p = SkToU8('0' + dec % 10);
107         dec /= 10;
108     } while (dec != 0);
109 
110     SkASSERT(p >= buffer);
111     size_t cp_len = buffer + sizeof(buffer) - p;
112     memcpy(string, p, cp_len);
113     string += cp_len;
114 
115     SkASSERT(string - start <= kSkStrAppendU32_MaxSize);
116     return string;
117 }
118 
SkStrAppendS32(char string[],int32_t dec)119 char* SkStrAppendS32(char string[], int32_t dec) {
120     uint32_t udec = dec;
121     if (dec < 0) {
122         *string++ = '-';
123         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
124     }
125     return SkStrAppendU32(string, udec);
126 }
127 
SkStrAppendU64(char string[],uint64_t dec,int minDigits)128 char* SkStrAppendU64(char string[], uint64_t dec, int minDigits) {
129     SkDEBUGCODE(char* start = string;)
130 
131     char    buffer[kSkStrAppendU64_MaxSize];
132     char*   p = buffer + sizeof(buffer);
133 
134     do {
135         *--p = SkToU8('0' + (int32_t) (dec % 10));
136         dec /= 10;
137         minDigits--;
138     } while (dec != 0);
139 
140     while (minDigits > 0) {
141         *--p = '0';
142         minDigits--;
143     }
144 
145     SkASSERT(p >= buffer);
146     size_t cp_len = buffer + sizeof(buffer) - p;
147     memcpy(string, p, cp_len);
148     string += cp_len;
149 
150     SkASSERT(string - start <= kSkStrAppendU64_MaxSize);
151     return string;
152 }
153 
SkStrAppendS64(char string[],int64_t dec,int minDigits)154 char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
155     uint64_t udec = dec;
156     if (dec < 0) {
157         *string++ = '-';
158         udec = ~udec + 1;  // udec = -udec, but silences some warnings that are trying to be helpful
159     }
160     return SkStrAppendU64(string, udec, minDigits);
161 }
162 
SkStrAppendScalar(char string[],SkScalar value)163 char* SkStrAppendScalar(char string[], SkScalar value) {
164     // Handle infinity and NaN ourselves to ensure consistent cross-platform results.
165     // (e.g.: `inf` versus `1.#INF00`, `nan` versus `-nan` for high-bit-set NaNs)
166     if (SkScalarIsNaN(value)) {
167         strcpy(string, "nan");
168         return string + 3;
169     }
170     if (!SkScalarIsFinite(value)) {
171         if (value > 0) {
172             strcpy(string, "inf");
173             return string + 3;
174         } else {
175             strcpy(string, "-inf");
176             return string + 4;
177         }
178     }
179 
180     // since floats have at most 8 significant digits, we limit our %g to that.
181     static const char gFormat[] = "%.8g";
182     // make it 1 larger for the terminating 0
183     char buffer[kSkStrAppendScalar_MaxSize + 1];
184     int len = snprintf(buffer, sizeof(buffer), gFormat, value);
185     memcpy(string, buffer, len);
186     SkASSERT(len <= kSkStrAppendScalar_MaxSize);
187     return string + len;
188 }
189 
190 ///////////////////////////////////////////////////////////////////////////////
191 
192 const SkString::Rec SkString::gEmptyRec(0, 0);
193 
194 #define SizeOfRec()     (gEmptyRec.data() - (const char*)&gEmptyRec)
195 
trim_size_t_to_u32(size_t value)196 static uint32_t trim_size_t_to_u32(size_t value) {
197     if (sizeof(size_t) > sizeof(uint32_t)) {
198         if (value > UINT32_MAX) {
199             value = UINT32_MAX;
200         }
201     }
202     return (uint32_t)value;
203 }
204 
check_add32(size_t base,size_t extra)205 static size_t check_add32(size_t base, size_t extra) {
206     SkASSERT(base <= UINT32_MAX);
207     if (sizeof(size_t) > sizeof(uint32_t)) {
208         if (base + extra > UINT32_MAX) {
209             extra = UINT32_MAX - base;
210         }
211     }
212     return extra;
213 }
214 
Make(const char text[],size_t len)215 sk_sp<SkString::Rec> SkString::Rec::Make(const char text[], size_t len) {
216     if (0 == len) {
217         return sk_sp<SkString::Rec>(const_cast<Rec*>(&gEmptyRec));
218     }
219 
220     SkSafeMath safe;
221     // We store a 32bit version of the length
222     uint32_t stringLen = safe.castTo<uint32_t>(len);
223     // Add SizeOfRec() for our overhead and 1 for null-termination
224     size_t allocationSize = safe.add(len, SizeOfRec() + sizeof(char));
225     // Align up to a multiple of 4
226     allocationSize = safe.alignUp(allocationSize, 4);
227 
228     SkASSERT_RELEASE(safe.ok());
229 
230     void* storage = ::operator new (allocationSize);
231     sk_sp<Rec> rec(new (storage) Rec(stringLen, 1));
232     if (text) {
233         memcpy(rec->data(), text, len);
234     }
235     rec->data()[len] = 0;
236     return rec;
237 }
238 
ref() const239 void SkString::Rec::ref() const {
240     if (this == &SkString::gEmptyRec) {
241         return;
242     }
243     SkAssertResult(this->fRefCnt.fetch_add(+1, std::memory_order_relaxed));
244 }
245 
unref() const246 void SkString::Rec::unref() const {
247     if (this == &SkString::gEmptyRec) {
248         return;
249     }
250     int32_t oldRefCnt = this->fRefCnt.fetch_add(-1, std::memory_order_acq_rel);
251     SkASSERT(oldRefCnt);
252     if (1 == oldRefCnt) {
253         delete this;
254     }
255 }
256 
unique() const257 bool SkString::Rec::unique() const {
258     return fRefCnt.load(std::memory_order_acquire) == 1;
259 }
260 
261 #ifdef SK_DEBUG
getRefCnt() const262 int32_t SkString::Rec::getRefCnt() const {
263     return fRefCnt.load(std::memory_order_relaxed);
264 }
265 
validate() const266 const SkString& SkString::validate() const {
267     // make sure no one has written over our global
268     SkASSERT(0 == gEmptyRec.fLength);
269     SkASSERT(0 == gEmptyRec.getRefCnt());
270     SkASSERT(0 == gEmptyRec.data()[0]);
271 
272     if (fRec.get() != &gEmptyRec) {
273         SkASSERT(fRec->fLength > 0);
274         SkASSERT(fRec->getRefCnt() > 0);
275         SkASSERT(0 == fRec->data()[fRec->fLength]);
276     }
277     return *this;
278 }
279 #endif
280 
281 ///////////////////////////////////////////////////////////////////////////////
282 
SkString()283 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
284 }
285 
SkString(size_t len)286 SkString::SkString(size_t len) {
287     fRec = Rec::Make(nullptr, len);
288 }
289 
SkString(const char text[])290 SkString::SkString(const char text[]) {
291     size_t  len = text ? strlen(text) : 0;
292 
293     fRec = Rec::Make(text, len);
294 }
295 
SkString(const char text[],size_t len)296 SkString::SkString(const char text[], size_t len) {
297     fRec = Rec::Make(text, len);
298 }
299 
SkString(const SkString & src)300 SkString::SkString(const SkString& src) : fRec(src.validate().fRec) {}
301 
SkString(SkString && src)302 SkString::SkString(SkString&& src) : fRec(std::move(src.validate().fRec)) {
303     src.fRec.reset(const_cast<Rec*>(&gEmptyRec));
304 }
305 
SkString(const std::string & src)306 SkString::SkString(const std::string& src) {
307     fRec = Rec::Make(src.c_str(), src.size());
308 }
309 
SkString(std::string_view src)310 SkString::SkString(std::string_view src) {
311     fRec = Rec::Make(src.data(), src.length());
312 }
313 
~SkString()314 SkString::~SkString() {
315     this->validate();
316 }
317 
equals(const SkString & src) const318 bool SkString::equals(const SkString& src) const {
319     return fRec == src.fRec || this->equals(src.c_str(), src.size());
320 }
321 
equals(const char text[]) const322 bool SkString::equals(const char text[]) const {
323     return this->equals(text, text ? strlen(text) : 0);
324 }
325 
equals(const char text[],size_t len) const326 bool SkString::equals(const char text[], size_t len) const {
327     SkASSERT(len == 0 || text != nullptr);
328 
329     return fRec->fLength == len && !sk_careful_memcmp(fRec->data(), text, len);
330 }
331 
operator =(const SkString & src)332 SkString& SkString::operator=(const SkString& src) {
333     this->validate();
334     fRec = src.fRec;  // sk_sp<Rec>::operator=(const sk_sp<Ref>&) checks for self-assignment.
335     return *this;
336 }
337 
operator =(SkString && src)338 SkString& SkString::operator=(SkString&& src) {
339     this->validate();
340 
341     if (fRec != src.fRec) {
342         this->swap(src);
343     }
344     return *this;
345 }
346 
operator =(const char text[])347 SkString& SkString::operator=(const char text[]) {
348     this->validate();
349     return *this = SkString(text);
350 }
351 
reset()352 void SkString::reset() {
353     this->validate();
354     fRec.reset(const_cast<Rec*>(&gEmptyRec));
355 }
356 
data()357 char* SkString::data() {
358     this->validate();
359 
360     if (fRec->fLength) {
361         if (!fRec->unique()) {
362             fRec = Rec::Make(fRec->data(), fRec->fLength);
363         }
364     }
365     return fRec->data();
366 }
367 
resize(size_t len)368 void SkString::resize(size_t len) {
369     len = trim_size_t_to_u32(len);
370     if (0 == len) {
371         this->reset();
372     } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) {
373         // Use less of the buffer we have without allocating a smaller one.
374         char* p = this->data();
375         p[len] = '\0';
376         fRec->fLength = SkToU32(len);
377     } else {
378         SkString newString(len);
379         char* dest = newString.data();
380         int copyLen = std::min<uint32_t>(len, this->size());
381         memcpy(dest, this->c_str(), copyLen);
382         dest[copyLen] = '\0';
383         this->swap(newString);
384     }
385 }
386 
set(const char text[])387 void SkString::set(const char text[]) {
388     this->set(text, text ? strlen(text) : 0);
389 }
390 
set(const char text[],size_t len)391 void SkString::set(const char text[], size_t len) {
392     len = trim_size_t_to_u32(len);
393     if (0 == len) {
394         this->reset();
395     } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) {
396         // Use less of the buffer we have without allocating a smaller one.
397         char* p = this->data();
398         if (text) {
399             memcpy(p, text, len);
400         }
401         p[len] = '\0';
402         fRec->fLength = SkToU32(len);
403     } else {
404         SkString tmp(text, len);
405         this->swap(tmp);
406     }
407 }
408 
insert(size_t offset,const char text[])409 void SkString::insert(size_t offset, const char text[]) {
410     this->insert(offset, text, text ? strlen(text) : 0);
411 }
412 
insert(size_t offset,const char text[],size_t len)413 void SkString::insert(size_t offset, const char text[], size_t len) {
414     if (len) {
415         size_t length = fRec->fLength;
416         if (offset > length) {
417             offset = length;
418         }
419 
420         // Check if length + len exceeds 32bits, we trim len
421         len = check_add32(length, len);
422         if (0 == len) {
423             return;
424         }
425 
426         /*  If we're the only owner, and we have room in our allocation for the insert,
427             do it in place, rather than allocating a new buffer.
428 
429             To know we have room, compare the allocated sizes
430             beforeAlloc = SkAlign4(length + 1)
431             afterAlloc  = SkAligh4(length + 1 + len)
432             but SkAlign4(x) is (x + 3) >> 2 << 2
433             which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
434             and we can then eliminate the +1+3 since that doesn't affec the answer
435         */
436         if (fRec->unique() && (length >> 2) == ((length + len) >> 2)) {
437             char* dst = this->data();
438 
439             if (offset < length) {
440                 memmove(dst + offset + len, dst + offset, length - offset);
441             }
442             memcpy(dst + offset, text, len);
443 
444             dst[length + len] = 0;
445             fRec->fLength = SkToU32(length + len);
446         } else {
447             /*  Seems we should use realloc here, since that is safe if it fails
448                 (we have the original data), and might be faster than alloc/copy/free.
449             */
450             SkString    tmp(fRec->fLength + len);
451             char*       dst = tmp.data();
452 
453             if (offset > 0) {
454                 memcpy(dst, fRec->data(), offset);
455             }
456             memcpy(dst + offset, text, len);
457             if (offset < fRec->fLength) {
458                 memcpy(dst + offset + len, fRec->data() + offset,
459                        fRec->fLength - offset);
460             }
461 
462             this->swap(tmp);
463         }
464     }
465 }
466 
insertUnichar(size_t offset,SkUnichar uni)467 void SkString::insertUnichar(size_t offset, SkUnichar uni) {
468     char    buffer[SkUTF::kMaxBytesInUTF8Sequence];
469     size_t  len = SkUTF::ToUTF8(uni, buffer);
470 
471     if (len) {
472         this->insert(offset, buffer, len);
473     }
474 }
475 
insertS32(size_t offset,int32_t dec)476 void SkString::insertS32(size_t offset, int32_t dec) {
477     char    buffer[kSkStrAppendS32_MaxSize];
478     char*   stop = SkStrAppendS32(buffer, dec);
479     this->insert(offset, buffer, stop - buffer);
480 }
481 
insertS64(size_t offset,int64_t dec,int minDigits)482 void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
483     char    buffer[kSkStrAppendS64_MaxSize];
484     char*   stop = SkStrAppendS64(buffer, dec, minDigits);
485     this->insert(offset, buffer, stop - buffer);
486 }
487 
insertU32(size_t offset,uint32_t dec)488 void SkString::insertU32(size_t offset, uint32_t dec) {
489     char    buffer[kSkStrAppendU32_MaxSize];
490     char*   stop = SkStrAppendU32(buffer, dec);
491     this->insert(offset, buffer, stop - buffer);
492 }
493 
insertU64(size_t offset,uint64_t dec,int minDigits)494 void SkString::insertU64(size_t offset, uint64_t dec, int minDigits) {
495     char    buffer[kSkStrAppendU64_MaxSize];
496     char*   stop = SkStrAppendU64(buffer, dec, minDigits);
497     this->insert(offset, buffer, stop - buffer);
498 }
499 
insertHex(size_t offset,uint32_t hex,int minDigits)500 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
501     minDigits = SkTPin(minDigits, 0, 8);
502 
503     char    buffer[8];
504     char*   p = buffer + sizeof(buffer);
505 
506     do {
507         *--p = SkHexadecimalDigits::gUpper[hex & 0xF];
508         hex >>= 4;
509         minDigits -= 1;
510     } while (hex != 0);
511 
512     while (--minDigits >= 0) {
513         *--p = '0';
514     }
515 
516     SkASSERT(p >= buffer);
517     this->insert(offset, p, buffer + sizeof(buffer) - p);
518 }
519 
insertScalar(size_t offset,SkScalar value)520 void SkString::insertScalar(size_t offset, SkScalar value) {
521     char    buffer[kSkStrAppendScalar_MaxSize];
522     char*   stop = SkStrAppendScalar(buffer, value);
523     this->insert(offset, buffer, stop - buffer);
524 }
525 
526 ///////////////////////////////////////////////////////////////////////////////
527 
printf(const char format[],...)528 void SkString::printf(const char format[], ...) {
529     va_list args;
530     va_start(args, format);
531     this->printVAList(format, args);
532     va_end(args);
533 }
534 
printVAList(const char format[],va_list args)535 void SkString::printVAList(const char format[], va_list args) {
536     char stackBuffer[kBufferSize];
537     StringBuffer result = apply_format_string(format, args, stackBuffer, this);
538 
539     if (result.fText == stackBuffer) {
540         this->set(result.fText, result.fLength);
541     }
542 }
543 
appendf(const char format[],...)544 void SkString::appendf(const char format[], ...) {
545     va_list args;
546     va_start(args, format);
547     this->appendVAList(format, args);
548     va_end(args);
549 }
550 
appendVAList(const char format[],va_list args)551 void SkString::appendVAList(const char format[], va_list args) {
552     if (this->isEmpty()) {
553         this->printVAList(format, args);
554         return;
555     }
556 
557     SkString overflow;
558     char stackBuffer[kBufferSize];
559     StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow);
560 
561     this->append(result.fText, result.fLength);
562 }
563 
prependf(const char format[],...)564 void SkString::prependf(const char format[], ...) {
565     va_list args;
566     va_start(args, format);
567     this->prependVAList(format, args);
568     va_end(args);
569 }
570 
prependVAList(const char format[],va_list args)571 void SkString::prependVAList(const char format[], va_list args) {
572     if (this->isEmpty()) {
573         this->printVAList(format, args);
574         return;
575     }
576 
577     SkString overflow;
578     char stackBuffer[kBufferSize];
579     StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow);
580 
581     this->prepend(result.fText, result.fLength);
582 }
583 
584 ///////////////////////////////////////////////////////////////////////////////
585 
remove(size_t offset,size_t length)586 void SkString::remove(size_t offset, size_t length) {
587     size_t size = this->size();
588 
589     if (offset < size) {
590         if (length > size - offset) {
591             length = size - offset;
592         }
593         SkASSERT(length <= size);
594         SkASSERT(offset <= size - length);
595         if (length > 0) {
596             SkString    tmp(size - length);
597             char*       dst = tmp.data();
598             const char* src = this->c_str();
599 
600             if (offset) {
601                 memcpy(dst, src, offset);
602             }
603             size_t tail = size - (offset + length);
604             if (tail) {
605                 memcpy(dst + offset, src + (offset + length), tail);
606             }
607             SkASSERT(dst[tmp.size()] == 0);
608             this->swap(tmp);
609         }
610     }
611 }
612 
swap(SkString & other)613 void SkString::swap(SkString& other) {
614     this->validate();
615     other.validate();
616 
617     using std::swap;
618     swap(fRec, other.fRec);
619 }
620 
621 ///////////////////////////////////////////////////////////////////////////////
622 
SkStringPrintf(const char * format,...)623 SkString SkStringPrintf(const char* format, ...) {
624     SkString formattedOutput;
625     va_list args;
626     va_start(args, format);
627     formattedOutput.printVAList(format, args);
628     va_end(args);
629     return formattedOutput;
630 }
631 
SkStrSplit(const char * str,const char * delimiters,SkStrSplitMode splitMode,SkTArray<SkString> * out)632 void SkStrSplit(const char* str, const char* delimiters, SkStrSplitMode splitMode,
633                 SkTArray<SkString>* out) {
634     if (splitMode == kCoalesce_SkStrSplitMode) {
635         // Skip any delimiters.
636         str += strspn(str, delimiters);
637     }
638     if (!*str) {
639         return;
640     }
641 
642     while (true) {
643         // Find a token.
644         const size_t len = strcspn(str, delimiters);
645         if (splitMode == kStrict_SkStrSplitMode || len > 0) {
646             out->push_back().set(str, len);
647             str += len;
648         }
649 
650         if (!*str) {
651             return;
652         }
653         if (splitMode == kCoalesce_SkStrSplitMode) {
654             // Skip any delimiters.
655             str += strspn(str, delimiters);
656         } else {
657             // Skip one delimiter.
658             str += 1;
659         }
660     }
661 }
662