• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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