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