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