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
16static 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
53bool 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
62bool 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
72int 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
85char* 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
105char* 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
114char* 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
140char* 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
149char* 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
162const SkString::Rec SkString::gEmptyRec(0, 0);
163
164#define SizeOfRec()     (gEmptyRec.data() - (const char*)&gEmptyRec)
165
166static 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
175static 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
185sk_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
209void 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
216void 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
227bool SkString::Rec::unique() const {
228    return fRefCnt.load(std::memory_order_acquire) == 1;
229}
230
231#ifdef SK_DEBUG
232void 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
248SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
249}
250
251SkString::SkString(size_t len) {
252    fRec = Rec::Make(nullptr, len);
253}
254
255SkString::SkString(const char text[]) {
256    size_t  len = text ? strlen(text) : 0;
257
258    fRec = Rec::Make(text, len);
259}
260
261SkString::SkString(const char text[], size_t len) {
262    fRec = Rec::Make(text, len);
263}
264
265SkString::SkString(const SkString& src) {
266    src.validate();
267
268    fRec = src.fRec;
269}
270
271SkString::SkString(SkString&& src) {
272    src.validate();
273
274    fRec = std::move(src.fRec);
275    src.fRec.reset(const_cast<Rec*>(&gEmptyRec));
276}
277
278SkString::~SkString() {
279    this->validate();
280}
281
282bool SkString::equals(const SkString& src) const {
283    return fRec == src.fRec || this->equals(src.c_str(), src.size());
284}
285
286bool SkString::equals(const char text[]) const {
287    return this->equals(text, text ? strlen(text) : 0);
288}
289
290bool 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
296SkString& 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
306SkString& SkString::operator=(SkString&& src) {
307    this->validate();
308
309    if (fRec != src.fRec) {
310        this->swap(src);
311    }
312    return *this;
313}
314
315SkString& SkString::operator=(const char text[]) {
316    this->validate();
317
318    SkString tmp(text);
319    this->swap(tmp);
320
321    return *this;
322}
323
324void SkString::reset() {
325    this->validate();
326    fRec.reset(const_cast<Rec*>(&gEmptyRec));
327}
328
329char* 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
340void SkString::set(const char text[]) {
341    this->set(text, text ? strlen(text) : 0);
342}
343
344void 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
372void SkString::insert(size_t offset, const char text[]) {
373    this->insert(offset, text, text ? strlen(text) : 0);
374}
375
376void 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
430void 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
439void 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
445void 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
451void 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
457void 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
463void 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
483void 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
489void SkString::printf(const char format[], ...) {
490    V_SKSTRING_PRINTF((*this), format);
491}
492
493void 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
501void 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
509void 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
517void 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
528void 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
555void SkString::swap(SkString& other) {
556    this->validate();
557    other.validate();
558
559    SkTSwap(fRec, other.fRec);
560}
561
562///////////////////////////////////////////////////////////////////////////////
563
564SkString SkStringPrintf(const char* format, ...) {
565    SkString formattedOutput;
566    V_SKSTRING_PRINTF(formattedOutput, format);
567    return formattedOutput;
568}
569
570void 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