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