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