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
20 static const size_t kBufferSize = 1024;
21 
apply_format_string(const char * format,va_list args,char * stackBuffer,size_t stackBufferSize,int * length,SkString * heapBuffer)22 static 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 
SkStrEndsWith(const char string[],const char suffixStr[])69 bool 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 
SkStrEndsWith(const char string[],const char suffixChar)78 bool 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 
SkStrStartsWithOneOf(const char string[],const char prefixes[])88 int 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 
SkStrAppendU32(char string[],uint32_t dec)101 char* 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 
SkStrAppendS32(char string[],int32_t dec)121 char* 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 
SkStrAppendU64(char string[],uint64_t dec,int minDigits)130 char* 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 
SkStrAppendS64(char string[],int64_t dec,int minDigits)156 char* 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 
SkStrAppendFloat(char string[],float value)165 char* 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 
178 const SkString::Rec SkString::gEmptyRec(0, 0);
179 
180 #define SizeOfRec()     (gEmptyRec.data() - (const char*)&gEmptyRec)
181 
trim_size_t_to_u32(size_t value)182 static 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 
check_add32(size_t base,size_t extra)191 static 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 
Make(const char text[],size_t len)201 sk_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 
ref() const225 void 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 
unref() const232 void 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 
unique() const243 bool SkString::Rec::unique() const {
244     return fRefCnt.load(std::memory_order_acquire) == 1;
245 }
246 
247 #ifdef SK_DEBUG
validate() const248 const 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 
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) : fRec(src.validate().fRec) {}
283 
SkString(SkString && src)284 SkString::SkString(SkString&& src) : fRec(std::move(src.validate().fRec)) {
285     src.fRec.reset(const_cast<Rec*>(&gEmptyRec));
286 }
287 
~SkString()288 SkString::~SkString() {
289     this->validate();
290 }
291 
equals(const SkString & src) const292 bool SkString::equals(const SkString& src) const {
293     return fRec == src.fRec || this->equals(src.c_str(), src.size());
294 }
295 
equals(const char text[]) const296 bool SkString::equals(const char text[]) const {
297     return this->equals(text, text ? strlen(text) : 0);
298 }
299 
equals(const char text[],size_t len) const300 bool 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 
operator =(const SkString & src)306 SkString& 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 
operator =(SkString && src)312 SkString& SkString::operator=(SkString&& src) {
313     this->validate();
314 
315     if (fRec != src.fRec) {
316         this->swap(src);
317     }
318     return *this;
319 }
320 
operator =(const char text[])321 SkString& SkString::operator=(const char text[]) {
322     this->validate();
323     return *this = SkString(text);
324 }
325 
reset()326 void SkString::reset() {
327     this->validate();
328     fRec.reset(const_cast<Rec*>(&gEmptyRec));
329 }
330 
writable_str()331 char* 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 
set(const char text[])342 void SkString::set(const char text[]) {
343     this->set(text, text ? strlen(text) : 0);
344 }
345 
set(const char text[],size_t len)346 void 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 
insert(size_t offset,const char text[])374 void SkString::insert(size_t offset, const char text[]) {
375     this->insert(offset, text, text ? strlen(text) : 0);
376 }
377 
insert(size_t offset,const char text[],size_t len)378 void 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 
insertUnichar(size_t offset,SkUnichar uni)432 void 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 
insertS32(size_t offset,int32_t dec)441 void 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 
insertS64(size_t offset,int64_t dec,int minDigits)447 void 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 
insertU32(size_t offset,uint32_t dec)453 void 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 
insertU64(size_t offset,uint64_t dec,int minDigits)459 void 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 
insertHex(size_t offset,uint32_t hex,int minDigits)465 void 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 
insertScalar(size_t offset,SkScalar value)485 void 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 
printf(const char format[],...)491 void SkString::printf(const char format[], ...) {
492     V_SKSTRING_PRINTF((*this), format);
493 }
494 
appendf(const char format[],...)495 void 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 
appendVAList(const char format[],va_list args)504 void 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 
prependf(const char format[],...)512 void 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 
prependVAList(const char format[],va_list args)521 void 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 
remove(size_t offset,size_t length)532 void 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 
swap(SkString & other)559 void SkString::swap(SkString& other) {
560     this->validate();
561     other.validate();
562 
563     using std::swap;
564     swap(fRec, other.fRec);
565 }
566 
567 ///////////////////////////////////////////////////////////////////////////////
568 
SkStringPrintf(const char * format,...)569 SkString SkStringPrintf(const char* format, ...) {
570     SkString formattedOutput;
571     V_SKSTRING_PRINTF(formattedOutput, format);
572     return formattedOutput;
573 }
574 
SkStrSplit(const char * str,const char * delimiters,SkStrSplitMode splitMode,SkTArray<SkString> * out)575 void 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