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