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