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