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