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