blob: 5d1b8ceea3d6b6590e246235f81cefee9704c13c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkString.h"
11#include "SkFixed.h"
reed@google.com4bce1152011-09-14 16:13:58 +000012#include "SkThread.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkUtils.h"
14#include <stdarg.h>
reed@google.comfa06e522011-02-28 21:29:58 +000015#include <stdio.h>
16
17// number of bytes (on the stack) to receive the printf result
rileya@google.coma9baf112012-09-14 19:03:42 +000018static const size_t kBufferSize = 512;
reed@google.comfa06e522011-02-28 21:29:58 +000019
20#ifdef SK_BUILD_FOR_WIN
tomhudson@google.com47e0a092011-07-08 17:49:22 +000021 #define VSNPRINTF(buffer, size, format, args) \
22 _vsnprintf_s(buffer, size, _TRUNCATE, format, args)
reed@google.comfa06e522011-02-28 21:29:58 +000023 #define SNPRINTF _snprintf
24#else
25 #define VSNPRINTF vsnprintf
26 #define SNPRINTF snprintf
27#endif
28
29#define ARGS_TO_BUFFER(format, buffer, size) \
30 do { \
31 va_list args; \
32 va_start(args, format); \
33 VSNPRINTF(buffer, size, format, args); \
34 va_end(args); \
35 } while (0)
36
37///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +000038
epoger@google.come8ebeb12012-10-29 16:42:11 +000039bool SkStrEndsWith(const char string[], const char suffixStr[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 SkASSERT(string);
epoger@google.come8ebeb12012-10-29 16:42:11 +000041 SkASSERT(suffixStr);
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 size_t strLen = strlen(string);
epoger@google.come8ebeb12012-10-29 16:42:11 +000043 size_t suffixLen = strlen(suffixStr);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044 return strLen >= suffixLen &&
epoger@google.come8ebeb12012-10-29 16:42:11 +000045 !strncmp(string + strLen - suffixLen, suffixStr, suffixLen);
46}
47
48bool SkStrEndsWith(const char string[], const char suffixChar) {
49 SkASSERT(string);
50 size_t strLen = strlen(string);
51 if (0 == strLen) {
52 return false;
53 } else {
54 return (suffixChar == string[strLen-1]);
55 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000056}
57
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000058int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000059 int index = 0;
60 do {
61 const char* limit = strchr(prefixes, '\0');
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000062 if (!strncmp(string, prefixes, limit - prefixes)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 return index;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000064 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 prefixes = limit + 1;
66 index++;
67 } while (prefixes[0]);
68 return -1;
69}
70
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000071char* SkStrAppendS32(char string[], int32_t dec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 SkDEBUGCODE(char* start = string;)
73
74 char buffer[SkStrAppendS32_MaxSize];
75 char* p = buffer + sizeof(buffer);
76 bool neg = false;
77
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000078 if (dec < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 neg = true;
80 dec = -dec;
81 }
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000082
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 do {
84 *--p = SkToU8('0' + dec % 10);
85 dec /= 10;
86 } while (dec != 0);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000087
88 if (neg) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 *--p = '-';
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000090 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000091
92 SkASSERT(p >= buffer);
93 char* stop = buffer + sizeof(buffer);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000094 while (p < stop) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 *string++ = *p++;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +000096 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 SkASSERT(string - start <= SkStrAppendS32_MaxSize);
98 return string;
99}
100
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000101char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000102 SkDEBUGCODE(char* start = string;)
103
104 char buffer[SkStrAppendS64_MaxSize];
105 char* p = buffer + sizeof(buffer);
106 bool neg = false;
107
108 if (dec < 0) {
109 neg = true;
110 dec = -dec;
111 }
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000112
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000113 do {
caryclark@google.com803eceb2012-06-06 12:09:34 +0000114 *--p = SkToU8('0' + (int32_t) (dec % 10));
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000115 dec /= 10;
116 minDigits--;
117 } while (dec != 0);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000118
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000119 while (minDigits > 0) {
120 *--p = '0';
121 minDigits--;
122 }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000123
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000124 if (neg) {
125 *--p = '-';
126 }
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000127 SkASSERT(p >= buffer);
128 size_t cp_len = buffer + sizeof(buffer) - p;
129 memcpy(string, p, cp_len);
130 string += cp_len;
131
132 SkASSERT(string - start <= SkStrAppendS64_MaxSize);
133 return string;
134}
135
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000136char* SkStrAppendFloat(char string[], float value) {
reed@google.com8072e4f2011-03-01 15:44:08 +0000137 // since floats have at most 8 significant digits, we limit our %g to that.
138 static const char gFormat[] = "%.8g";
139 // make it 1 larger for the terminating 0
140 char buffer[SkStrAppendScalar_MaxSize + 1];
141 int len = SNPRINTF(buffer, sizeof(buffer), gFormat, value);
142 memcpy(string, buffer, len);
vandebo@chromium.org677cbed2011-03-03 18:20:12 +0000143 SkASSERT(len <= SkStrAppendScalar_MaxSize);
reed@google.com8072e4f2011-03-01 15:44:08 +0000144 return string + len;
vandebo@chromium.org677cbed2011-03-03 18:20:12 +0000145}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000147char* SkStrAppendFixed(char string[], SkFixed x) {
vandebo@chromium.org677cbed2011-03-03 18:20:12 +0000148 SkDEBUGCODE(char* start = string;)
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000149 if (x < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 *string++ = '-';
151 x = -x;
152 }
153
154 unsigned frac = x & 0xFFFF;
155 x >>= 16;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000156 if (frac == 0xFFFF) {
157 // need to do this to "round up", since 65535/65536 is closer to 1 than to .9999
reed@android.com8a1c16f2008-12-17 15:59:43 +0000158 x += 1;
159 frac = 0;
160 }
161 string = SkStrAppendS32(string, x);
162
163 // now handle the fractional part (if any)
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000164 if (frac) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165 static const uint16_t gTens[] = { 1000, 100, 10, 1 };
166 const uint16_t* tens = gTens;
167
168 x = SkFixedRound(frac * 10000);
169 SkASSERT(x <= 10000);
170 if (x == 10000) {
171 x -= 1;
172 }
173 *string++ = '.';
174 do {
175 unsigned powerOfTen = *tens++;
176 *string++ = SkToU8('0' + x / powerOfTen);
177 x %= powerOfTen;
178 } while (x != 0);
179 }
reed@google.comfa06e522011-02-28 21:29:58 +0000180
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181 SkASSERT(string - start <= SkStrAppendScalar_MaxSize);
182 return string;
183}
184
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000185///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187// the 3 values are [length] [refcnt] [terminating zero data]
188const SkString::Rec SkString::gEmptyRec = { 0, 0, 0 };
189
190#define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec)
191
reed@google.com4bce1152011-09-14 16:13:58 +0000192SkString::Rec* SkString::AllocRec(const char text[], size_t len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 Rec* rec;
194
reed@google.com4bce1152011-09-14 16:13:58 +0000195 if (0 == len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 rec = const_cast<Rec*>(&gEmptyRec);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000197 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 // add 1 for terminating 0, then align4 so we can have some slop when growing the string
199 rec = (Rec*)sk_malloc_throw(SizeOfRec() + SkAlign4(len + 1));
reed@google.com4bce1152011-09-14 16:13:58 +0000200 rec->fLength = len;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 rec->fRefCnt = 1;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000202 if (text) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 memcpy(rec->data(), text, len);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000204 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 rec->data()[len] = 0;
206 }
207 return rec;
208}
209
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000210SkString::Rec* SkString::RefRec(Rec* src) {
211 if (src != &gEmptyRec) {
reed@google.com4bce1152011-09-14 16:13:58 +0000212 sk_atomic_inc(&src->fRefCnt);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 }
214 return src;
215}
216
217#ifdef SK_DEBUG
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000218void SkString::validate() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 // make sure know one has written over our global
reed@google.com4bce1152011-09-14 16:13:58 +0000220 SkASSERT(0 == gEmptyRec.fLength);
221 SkASSERT(0 == gEmptyRec.fRefCnt);
222 SkASSERT(0 == gEmptyRec.data()[0]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000224 if (fRec != &gEmptyRec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 SkASSERT(fRec->fLength > 0);
226 SkASSERT(fRec->fRefCnt > 0);
reed@google.com4bce1152011-09-14 16:13:58 +0000227 SkASSERT(0 == fRec->data()[fRec->fLength]);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 }
229 SkASSERT(fStr == c_str());
230}
231#endif
232
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000233///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
235SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
236#ifdef SK_DEBUG
237 fStr = fRec->data();
238#endif
239}
240
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000241SkString::SkString(size_t len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkASSERT(SkToU16(len) == len); // can't handle larger than 64K
243
244 fRec = AllocRec(NULL, (U16CPU)len);
245#ifdef SK_DEBUG
246 fStr = fRec->data();
247#endif
248}
249
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000250SkString::SkString(const char text[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 size_t len = text ? strlen(text) : 0;
252
253 fRec = AllocRec(text, (U16CPU)len);
254#ifdef SK_DEBUG
255 fStr = fRec->data();
256#endif
257}
258
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000259SkString::SkString(const char text[], size_t len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260 fRec = AllocRec(text, (U16CPU)len);
261#ifdef SK_DEBUG
262 fStr = fRec->data();
263#endif
264}
265
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000266SkString::SkString(const SkString& src) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 src.validate();
268
269 fRec = RefRec(src.fRec);
270#ifdef SK_DEBUG
271 fStr = fRec->data();
272#endif
273}
274
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000275SkString::~SkString() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 this->validate();
277
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000278 if (fRec->fLength) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 SkASSERT(fRec->fRefCnt > 0);
reed@google.com4bce1152011-09-14 16:13:58 +0000280 if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 sk_free(fRec);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000282 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000283 }
284}
285
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000286bool SkString::equals(const SkString& src) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 return fRec == src.fRec || this->equals(src.c_str(), src.size());
288}
289
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000290bool SkString::equals(const char text[]) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 return this->equals(text, text ? strlen(text) : 0);
292}
293
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000294bool SkString::equals(const char text[], size_t len) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000295 SkASSERT(len == 0 || text != NULL);
296
297 return fRec->fLength == len && !memcmp(fRec->data(), text, len);
298}
299
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000300SkString& SkString::operator=(const SkString& src) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 this->validate();
302
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000303 if (fRec != src.fRec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 SkString tmp(src);
305 this->swap(tmp);
306 }
307 return *this;
308}
309
bsalomon@google.comfc296292011-05-06 13:53:47 +0000310SkString& SkString::operator=(const char text[]) {
311 this->validate();
312
313 SkString tmp(text);
314 this->swap(tmp);
315
316 return *this;
317}
318
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000319void SkString::reset() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 this->validate();
321
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000322 if (fRec->fLength) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000323 SkASSERT(fRec->fRefCnt > 0);
reed@google.com4bce1152011-09-14 16:13:58 +0000324 if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325 sk_free(fRec);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 }
328
329 fRec = const_cast<Rec*>(&gEmptyRec);
330#ifdef SK_DEBUG
331 fStr = fRec->data();
332#endif
333}
334
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000335char* SkString::writable_str() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 this->validate();
337
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000338 if (fRec->fLength) {
339 if (fRec->fRefCnt > 1) {
reed@google.com4bce1152011-09-14 16:13:58 +0000340 Rec* rec = AllocRec(fRec->data(), fRec->fLength);
341 if (sk_atomic_dec(&fRec->fRefCnt) == 1) {
342 // In this case after our check of fRecCnt > 1, we suddenly
343 // did become the only owner, so now we have two copies of the
344 // data (fRec and rec), so we need to delete one of them.
345 sk_free(fRec);
346 }
347 fRec = rec;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 #ifdef SK_DEBUG
349 fStr = fRec->data();
350 #endif
351 }
352 }
353 return fRec->data();
354}
355
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000356void SkString::set(const char text[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 this->set(text, text ? strlen(text) : 0);
358}
359
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000360void SkString::set(const char text[], size_t len) {
reed@google.com4bce1152011-09-14 16:13:58 +0000361 if (0 == len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 this->reset();
reed@google.com4bce1152011-09-14 16:13:58 +0000363 } else if (1 == fRec->fRefCnt && len <= fRec->fLength) {
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000364 // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))?
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 // just use less of the buffer without allocating a smaller one
366 char* p = this->writable_str();
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000367 if (text) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000368 memcpy(p, text, len);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000369 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 p[len] = 0;
reed@google.com4bce1152011-09-14 16:13:58 +0000371 fRec->fLength = len;
372 } else if (1 == fRec->fRefCnt && (fRec->fLength >> 2) == (len >> 2)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373 // we have spare room in the current allocation, so don't alloc a larger one
374 char* p = this->writable_str();
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000375 if (text) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376 memcpy(p, text, len);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000377 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000378 p[len] = 0;
reed@google.com4bce1152011-09-14 16:13:58 +0000379 fRec->fLength = len;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000380 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 SkString tmp(text, len);
382 this->swap(tmp);
383 }
384}
385
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000386void SkString::setUTF16(const uint16_t src[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000387 int count = 0;
388
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000389 while (src[count]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390 count += 1;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000391 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392 setUTF16(src, count);
393}
394
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000395void SkString::setUTF16(const uint16_t src[], size_t count) {
reed@google.com4bce1152011-09-14 16:13:58 +0000396 if (0 == count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397 this->reset();
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000398 } else if (count <= fRec->fLength) {
399 // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
400 if (count < fRec->fLength) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 this->resize(count);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000402 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000403 char* p = this->writable_str();
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000404 for (size_t i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000405 p[i] = SkToU8(src[i]);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000406 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 p[count] = 0;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000408 } else {
409 SkString tmp(count); // puts a null terminator at the end of the string
410 char* p = tmp.writable_str();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000412 for (size_t i = 0; i < count; i++) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000413 p[i] = SkToU8(src[i]);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000414 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000415 this->swap(tmp);
416 }
417}
418
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000419void SkString::insert(size_t offset, const char text[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000420 this->insert(offset, text, text ? strlen(text) : 0);
421}
422
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000423void SkString::insert(size_t offset, const char text[], size_t len) {
424 if (len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425 size_t length = fRec->fLength;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000426 if (offset > length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000427 offset = length;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000428 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429
430 /* If we're the only owner, and we have room in our allocation for the insert,
431 do it in place, rather than allocating a new buffer.
432
433 To know we have room, compare the allocated sizes
434 beforeAlloc = SkAlign4(length + 1)
435 afterAlloc = SkAligh4(length + 1 + len)
436 but SkAlign4(x) is (x + 3) >> 2 << 2
437 which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
438 and we can then eliminate the +1+3 since that doesn't affec the answer
439 */
reed@google.com4bce1152011-09-14 16:13:58 +0000440 if (1 == fRec->fRefCnt && (length >> 2) == ((length + len) >> 2)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000441 char* dst = this->writable_str();
442
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000443 if (offset < length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000444 memmove(dst + offset + len, dst + offset, length - offset);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000445 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000446 memcpy(dst + offset, text, len);
447
448 dst[length + len] = 0;
reed@google.com4bce1152011-09-14 16:13:58 +0000449 fRec->fLength = length + len;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000450 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000451 /* Seems we should use realloc here, since that is safe if it fails
452 (we have the original data), and might be faster than alloc/copy/free.
453 */
454 SkString tmp(fRec->fLength + len);
455 char* dst = tmp.writable_str();
456
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000457 if (offset > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000458 memcpy(dst, fRec->data(), offset);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000459 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000460 memcpy(dst + offset, text, len);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000461 if (offset < fRec->fLength) {
462 memcpy(dst + offset + len, fRec->data() + offset,
463 fRec->fLength - offset);
464 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465
466 this->swap(tmp);
467 }
468 }
469}
470
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000471void SkString::insertUnichar(size_t offset, SkUnichar uni) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000472 char buffer[kMaxBytesInUTF8Sequence];
473 size_t len = SkUTF8_FromUnichar(uni, buffer);
474
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000475 if (len) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000476 this->insert(offset, buffer, len);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000477 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000478}
479
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000480void SkString::insertS32(size_t offset, int32_t dec) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481 char buffer[SkStrAppendS32_MaxSize];
482 char* stop = SkStrAppendS32(buffer, dec);
483 this->insert(offset, buffer, stop - buffer);
484}
485
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000486void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
vandebo@chromium.orgd877fdb2010-10-12 23:08:13 +0000487 char buffer[SkStrAppendS64_MaxSize];
488 char* stop = SkStrAppendS64(buffer, dec, minDigits);
489 this->insert(offset, buffer, stop - buffer);
490}
491
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000492void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000493 minDigits = SkPin32(minDigits, 0, 8);
reed@google.comfa06e522011-02-28 21:29:58 +0000494
reed@android.com8a1c16f2008-12-17 15:59:43 +0000495 static const char gHex[] = "0123456789ABCDEF";
496
497 char buffer[8];
498 char* p = buffer + sizeof(buffer);
499
500 do {
501 *--p = gHex[hex & 0xF];
502 hex >>= 4;
503 minDigits -= 1;
504 } while (hex != 0);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000505
506 while (--minDigits >= 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000507 *--p = '0';
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000508 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000509
510 SkASSERT(p >= buffer);
511 this->insert(offset, p, buffer + sizeof(buffer) - p);
512}
513
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000514void SkString::insertScalar(size_t offset, SkScalar value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000515 char buffer[SkStrAppendScalar_MaxSize];
516 char* stop = SkStrAppendScalar(buffer, value);
517 this->insert(offset, buffer, stop - buffer);
518}
519
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520void SkString::printf(const char format[], ...) {
521 char buffer[kBufferSize];
522 ARGS_TO_BUFFER(format, buffer, kBufferSize);
523
524 this->set(buffer, strlen(buffer));
525}
526
527void SkString::appendf(const char format[], ...) {
528 char buffer[kBufferSize];
529 ARGS_TO_BUFFER(format, buffer, kBufferSize);
reed@google.comfa06e522011-02-28 21:29:58 +0000530
reed@android.com8a1c16f2008-12-17 15:59:43 +0000531 this->append(buffer, strlen(buffer));
532}
533
534void SkString::prependf(const char format[], ...) {
535 char buffer[kBufferSize];
536 ARGS_TO_BUFFER(format, buffer, kBufferSize);
reed@google.comfa06e522011-02-28 21:29:58 +0000537
reed@android.com8a1c16f2008-12-17 15:59:43 +0000538 this->prepend(buffer, strlen(buffer));
539}
540
reed@google.comfa06e522011-02-28 21:29:58 +0000541///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000543void SkString::remove(size_t offset, size_t length) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544 size_t size = this->size();
545
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000546 if (offset < size) {
547 if (offset + length > size) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548 length = size - offset;
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000549 }
550 if (length > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000551 SkASSERT(size > length);
552 SkString tmp(size - length);
553 char* dst = tmp.writable_str();
554 const char* src = this->c_str();
555
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000556 if (offset) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557 SkASSERT(offset <= tmp.size());
558 memcpy(dst, src, offset);
559 }
560 size_t tail = size - offset - length;
561 SkASSERT((int32_t)tail >= 0);
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000562 if (tail) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 // SkASSERT(offset + length <= tmp.size());
564 memcpy(dst + offset, src + offset + length, tail);
565 }
566 SkASSERT(dst[tmp.size()] == 0);
567 this->swap(tmp);
568 }
569 }
570}
571
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000572void SkString::swap(SkString& other) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573 this->validate();
574 other.validate();
575
576 SkTSwap<Rec*>(fRec, other.fRec);
577#ifdef SK_DEBUG
578 SkTSwap<const char*>(fStr, other.fStr);
579#endif
580}
581
mike@reedtribe.org4e1d3ac2011-04-10 01:04:37 +0000582///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000583
mike@reedtribe.orgd5e05d42011-04-10 00:44:32 +0000584SkAutoUCS2::SkAutoUCS2(const char utf8[]) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585 size_t len = strlen(utf8);
586 fUCS2 = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t));
587
588 uint16_t* dst = fUCS2;
mike@reedtribe.orgd5e05d42011-04-10 00:44:32 +0000589 for (;;) {
590 SkUnichar uni = SkUTF8_NextUnichar(&utf8);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591 *dst++ = SkToU16(uni);
mike@reedtribe.orgd5e05d42011-04-10 00:44:32 +0000592 if (uni == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000593 break;
mike@reedtribe.orgd5e05d42011-04-10 00:44:32 +0000594 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595 }
596 fCount = (int)(dst - fUCS2);
597}
598
mike@reedtribe.orgd5e05d42011-04-10 00:44:32 +0000599SkAutoUCS2::~SkAutoUCS2() {
600 sk_free(fUCS2);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000601}
tomhudson@google.com3a1f6a02011-06-30 14:39:52 +0000602
603///////////////////////////////////////////////////////////////////////////////
604
605SkString SkStringPrintf(const char* format, ...) {
606 SkString formattedOutput;
607 char buffer[kBufferSize];
608 ARGS_TO_BUFFER(format, buffer, kBufferSize);
609 formattedOutput.set(buffer);
610 return formattedOutput;
611}
612
613#undef VSNPRINTF
tomhudson@google.com47e0a092011-07-08 17:49:22 +0000614#undef SNPRINTF