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