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