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