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