1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkString_DEFINED
11#define SkString_DEFINED
12
13#include "SkScalar.h"
14
15#include <stdarg.h>
16
17/*  Some helper functions for C strings
18*/
19
20static bool SkStrStartsWith(const char string[], const char prefixStr[]) {
21    SkASSERT(string);
22    SkASSERT(prefixStr);
23    return !strncmp(string, prefixStr, strlen(prefixStr));
24}
25static bool SkStrStartsWith(const char string[], const char prefixChar) {
26    SkASSERT(string);
27    return (prefixChar == *string);
28}
29
30bool SkStrEndsWith(const char string[], const char suffixStr[]);
31bool SkStrEndsWith(const char string[], const char suffixChar);
32
33int SkStrStartsWithOneOf(const char string[], const char prefixes[]);
34
35static int SkStrFind(const char string[], const char substring[]) {
36    const char *first = strstr(string, substring);
37    if (NULL == first) return -1;
38    return SkToS32(first - &string[0]);
39}
40
41static bool SkStrContains(const char string[], const char substring[]) {
42    SkASSERT(string);
43    SkASSERT(substring);
44    return (-1 != SkStrFind(string, substring));
45}
46static bool SkStrContains(const char string[], const char subchar) {
47    SkASSERT(string);
48    char tmp[2];
49    tmp[0] = subchar;
50    tmp[1] = '\0';
51    return (-1 != SkStrFind(string, tmp));
52}
53
54static inline char *SkStrDup(const char string[]) {
55    char *ret = (char *) sk_malloc_throw(strlen(string)+1);
56    memcpy(ret,string,strlen(string)+1);
57    return ret;
58}
59
60
61
62#define SkStrAppendU32_MaxSize  10
63char*   SkStrAppendU32(char buffer[], uint32_t);
64#define SkStrAppendU64_MaxSize  20
65char*   SkStrAppendU64(char buffer[], uint64_t, int minDigits);
66
67#define SkStrAppendS32_MaxSize  (SkStrAppendU32_MaxSize + 1)
68char*   SkStrAppendS32(char buffer[], int32_t);
69#define SkStrAppendS64_MaxSize  (SkStrAppendU64_MaxSize + 1)
70char*   SkStrAppendS64(char buffer[], int64_t, int minDigits);
71
72/**
73 *  Floats have at most 8 significant digits, so we limit our %g to that.
74 *  However, the total string could be 15 characters: -1.2345678e-005
75 *
76 *  In theory we should only expect up to 2 digits for the exponent, but on
77 *  some platforms we have seen 3 (as in the example above).
78 */
79#define SkStrAppendScalar_MaxSize  15
80
81/**
82 *  Write the scaler in decimal format into buffer, and return a pointer to
83 *  the next char after the last one written. Note: a terminating 0 is not
84 *  written into buffer, which must be at least SkStrAppendScalar_MaxSize.
85 *  Thus if the caller wants to add a 0 at the end, buffer must be at least
86 *  SkStrAppendScalar_MaxSize + 1 bytes large.
87 */
88#ifdef SK_SCALAR_IS_FLOAT
89    #define SkStrAppendScalar SkStrAppendFloat
90#else
91    #define SkStrAppendScalar SkStrAppendFixed
92#endif
93
94char* SkStrAppendFloat(char buffer[], float);
95char* SkStrAppendFixed(char buffer[], SkFixed);
96
97/** \class SkString
98
99    Light weight class for managing strings. Uses reference
100    counting to make string assignments and copies very fast
101    with no extra RAM cost. Assumes UTF8 encoding.
102*/
103class SK_API SkString {
104public:
105                SkString();
106    explicit    SkString(size_t len);
107    explicit    SkString(const char text[]);
108                SkString(const char text[], size_t len);
109                SkString(const SkString&);
110                ~SkString();
111
112    bool        isEmpty() const { return 0 == fRec->fLength; }
113    size_t      size() const { return (size_t) fRec->fLength; }
114    const char* c_str() const { return fRec->data(); }
115    char operator[](size_t n) const { return this->c_str()[n]; }
116
117    bool equals(const SkString&) const;
118    bool equals(const char text[]) const;
119    bool equals(const char text[], size_t len) const;
120
121    bool startsWith(const char prefixStr[]) const {
122        return SkStrStartsWith(fRec->data(), prefixStr);
123    }
124    bool startsWith(const char prefixChar) const {
125        return SkStrStartsWith(fRec->data(), prefixChar);
126    }
127    bool endsWith(const char suffixStr[]) const {
128        return SkStrEndsWith(fRec->data(), suffixStr);
129    }
130    bool endsWith(const char suffixChar) const {
131        return SkStrEndsWith(fRec->data(), suffixChar);
132    }
133    bool contains(const char substring[]) const {
134        return SkStrContains(fRec->data(), substring);
135    }
136    bool contains(const char subchar) const {
137        return SkStrContains(fRec->data(), subchar);
138    }
139    int find(const char substring[]) const {
140        return SkStrFind(fRec->data(), substring);
141    }
142
143    friend bool operator==(const SkString& a, const SkString& b) {
144        return a.equals(b);
145    }
146    friend bool operator!=(const SkString& a, const SkString& b) {
147        return !a.equals(b);
148    }
149
150    // these methods edit the string
151
152    SkString& operator=(const SkString&);
153    SkString& operator=(const char text[]);
154
155    char* writable_str();
156    char& operator[](size_t n) { return this->writable_str()[n]; }
157
158    void reset();
159    void resize(size_t len) { this->set(NULL, len); }
160    void set(const SkString& src) { *this = src; }
161    void set(const char text[]);
162    void set(const char text[], size_t len);
163    void setUTF16(const uint16_t[]);
164    void setUTF16(const uint16_t[], size_t len);
165
166    void insert(size_t offset, const SkString& src) { this->insert(offset, src.c_str(), src.size()); }
167    void insert(size_t offset, const char text[]);
168    void insert(size_t offset, const char text[], size_t len);
169    void insertUnichar(size_t offset, SkUnichar);
170    void insertS32(size_t offset, int32_t value);
171    void insertS64(size_t offset, int64_t value, int minDigits = 0);
172    void insertU32(size_t offset, uint32_t value);
173    void insertU64(size_t offset, uint64_t value, int minDigits = 0);
174    void insertHex(size_t offset, uint32_t value, int minDigits = 0);
175    void insertScalar(size_t offset, SkScalar);
176
177    void append(const SkString& str) { this->insert((size_t)-1, str); }
178    void append(const char text[]) { this->insert((size_t)-1, text); }
179    void append(const char text[], size_t len) { this->insert((size_t)-1, text, len); }
180    void appendUnichar(SkUnichar uni) { this->insertUnichar((size_t)-1, uni); }
181    void appendS32(int32_t value) { this->insertS32((size_t)-1, value); }
182    void appendS64(int64_t value, int minDigits = 0) { this->insertS64((size_t)-1, value, minDigits); }
183    void appendU32(uint32_t value) { this->insertU32((size_t)-1, value); }
184    void appendU64(uint64_t value, int minDigits = 0) { this->insertU64((size_t)-1, value, minDigits); }
185    void appendHex(uint32_t value, int minDigits = 0) { this->insertHex((size_t)-1, value, minDigits); }
186    void appendScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
187
188    void prepend(const SkString& str) { this->insert(0, str); }
189    void prepend(const char text[]) { this->insert(0, text); }
190    void prepend(const char text[], size_t len) { this->insert(0, text, len); }
191    void prependUnichar(SkUnichar uni) { this->insertUnichar(0, uni); }
192    void prependS32(int32_t value) { this->insertS32(0, value); }
193    void prependS64(int32_t value, int minDigits = 0) { this->insertS64(0, value, minDigits); }
194    void prependHex(uint32_t value, int minDigits = 0) { this->insertHex(0, value, minDigits); }
195    void prependScalar(SkScalar value) { this->insertScalar((size_t)-1, value); }
196
197    void printf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
198    void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
199    void appendf(const char format[], va_list);
200    void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
201
202    void remove(size_t offset, size_t length);
203
204    SkString& operator+=(const SkString& s) { this->append(s); return *this; }
205    SkString& operator+=(const char text[]) { this->append(text); return *this; }
206    SkString& operator+=(const char c) { this->append(&c, 1); return *this; }
207
208    /**
209     *  Swap contents between this and other. This function is guaranteed
210     *  to never fail or throw.
211     */
212    void swap(SkString& other);
213
214private:
215    struct Rec {
216    public:
217        uint32_t    fLength; // logically size_t, but we want it to stay 32bits
218        int32_t     fRefCnt;
219        char        fBeginningOfData;
220
221        char* data() { return &fBeginningOfData; }
222        const char* data() const { return &fBeginningOfData; }
223    };
224    Rec* fRec;
225
226#ifdef SK_DEBUG
227    const char* fStr;
228    void validate() const;
229#else
230    void validate() const {}
231#endif
232
233    static const Rec gEmptyRec;
234    static Rec* AllocRec(const char text[], size_t len);
235    static Rec* RefRec(Rec*);
236};
237
238class SkAutoUCS2 {
239public:
240    SkAutoUCS2(const char utf8[]);
241    ~SkAutoUCS2();
242
243    /** This returns the number of ucs2 characters
244    */
245    int count() const { return fCount; }
246
247    /** This returns a null terminated ucs2 string
248    */
249    const uint16_t* getUCS2() const { return fUCS2; }
250
251private:
252    int         fCount;
253    uint16_t*   fUCS2;
254};
255
256/// Creates a new string and writes into it using a printf()-style format.
257SkString SkStringPrintf(const char* format, ...);
258
259// Specialized to take advantage of SkString's fast swap path. The unspecialized function is
260// declared in SkTypes.h and called by SkTSort.
261template <> inline void SkTSwap(SkString& a, SkString& b) {
262    a.swap(b);
263}
264
265#endif
266