• 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 "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