1 /* libs/graphics/sgl/SkString.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkString.h"
19 #include "SkFixed.h"
20 #include "SkUtils.h"
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 // number of bytes (on the stack) to receive the printf result
25 static const size_t kBufferSize = 256;
26
27 #ifdef SK_BUILD_FOR_WIN
28 #define VSNPRINTF _vsnprintf
29 #define SNPRINTF _snprintf
30 #else
31 #define VSNPRINTF vsnprintf
32 #define SNPRINTF snprintf
33 #endif
34
35 #define ARGS_TO_BUFFER(format, buffer, size) \
36 do { \
37 va_list args; \
38 va_start(args, format); \
39 VSNPRINTF(buffer, size, format, args); \
40 va_end(args); \
41 } while (0)
42
43 ///////////////////////////////////////////////////////////////////////////////
44
SkStrStartsWith(const char string[],const char prefix[])45 bool SkStrStartsWith(const char string[], const char prefix[]) {
46 SkASSERT(string);
47 SkASSERT(prefix);
48 return !strncmp(string, prefix, strlen(prefix));
49 }
50
SkStrEndsWith(const char string[],const char suffix[])51 bool SkStrEndsWith(const char string[], const char suffix[]) {
52 SkASSERT(string);
53 SkASSERT(suffix);
54 size_t strLen = strlen(string);
55 size_t suffixLen = strlen(suffix);
56 return strLen >= suffixLen &&
57 !strncmp(string + strLen - suffixLen, suffix, suffixLen);
58 }
59
SkStrStartsWithOneOf(const char string[],const char prefixes[])60 int SkStrStartsWithOneOf(const char string[], const char prefixes[]) {
61 int index = 0;
62 do {
63 const char* limit = strchr(prefixes, '\0');
64 if (!strncmp(string, prefixes, limit - prefixes)) {
65 return index;
66 }
67 prefixes = limit + 1;
68 index++;
69 } while (prefixes[0]);
70 return -1;
71 }
72
SkStrAppendS32(char string[],int32_t dec)73 char* SkStrAppendS32(char string[], int32_t dec) {
74 SkDEBUGCODE(char* start = string;)
75
76 char buffer[SkStrAppendS32_MaxSize];
77 char* p = buffer + sizeof(buffer);
78 bool neg = false;
79
80 if (dec < 0) {
81 neg = true;
82 dec = -dec;
83 }
84
85 do {
86 *--p = SkToU8('0' + dec % 10);
87 dec /= 10;
88 } while (dec != 0);
89
90 if (neg) {
91 *--p = '-';
92 }
93
94 SkASSERT(p >= buffer);
95 char* stop = buffer + sizeof(buffer);
96 while (p < stop) {
97 *string++ = *p++;
98 }
99 SkASSERT(string - start <= SkStrAppendS32_MaxSize);
100 return string;
101 }
102
SkStrAppendS64(char string[],int64_t dec,int minDigits)103 char* SkStrAppendS64(char string[], int64_t dec, int minDigits) {
104 SkDEBUGCODE(char* start = string;)
105
106 char buffer[SkStrAppendS64_MaxSize];
107 char* p = buffer + sizeof(buffer);
108 bool neg = false;
109
110 if (dec < 0) {
111 neg = true;
112 dec = -dec;
113 }
114
115 do {
116 *--p = SkToU8('0' + dec % 10);
117 dec /= 10;
118 minDigits--;
119 } while (dec != 0);
120
121 while (minDigits > 0) {
122 *--p = '0';
123 minDigits--;
124 }
125
126 if (neg) {
127 *--p = '-';
128 }
129 SkASSERT(p >= buffer);
130 size_t cp_len = buffer + sizeof(buffer) - p;
131 memcpy(string, p, cp_len);
132 string += cp_len;
133
134 SkASSERT(string - start <= SkStrAppendS64_MaxSize);
135 return string;
136 }
137
138 #ifdef SK_CAN_USE_FLOAT
SkStrAppendFloat(char string[],float value)139 char* SkStrAppendFloat(char string[], float value) {
140 // since floats have at most 8 significant digits, we limit our %g to that.
141 static const char gFormat[] = "%.8g";
142 // make it 1 larger for the terminating 0
143 char buffer[SkStrAppendScalar_MaxSize + 1];
144 int len = SNPRINTF(buffer, sizeof(buffer), gFormat, value);
145 memcpy(string, buffer, len);
146 SkASSERT(len <= SkStrAppendScalar_MaxSize);
147 return string + len;
148 }
149 #endif
150
SkStrAppendFixed(char string[],SkFixed x)151 char* SkStrAppendFixed(char string[], SkFixed x) {
152 SkDEBUGCODE(char* start = string;)
153 if (x < 0) {
154 *string++ = '-';
155 x = -x;
156 }
157
158 unsigned frac = x & 0xFFFF;
159 x >>= 16;
160 if (frac == 0xFFFF) {
161 // need to do this to "round up", since 65535/65536 is closer to 1 than to .9999
162 x += 1;
163 frac = 0;
164 }
165 string = SkStrAppendS32(string, x);
166
167 // now handle the fractional part (if any)
168 if (frac) {
169 static const uint16_t gTens[] = { 1000, 100, 10, 1 };
170 const uint16_t* tens = gTens;
171
172 x = SkFixedRound(frac * 10000);
173 SkASSERT(x <= 10000);
174 if (x == 10000) {
175 x -= 1;
176 }
177 *string++ = '.';
178 do {
179 unsigned powerOfTen = *tens++;
180 *string++ = SkToU8('0' + x / powerOfTen);
181 x %= powerOfTen;
182 } while (x != 0);
183 }
184
185 SkASSERT(string - start <= SkStrAppendScalar_MaxSize);
186 return string;
187 }
188
189 ///////////////////////////////////////////////////////////////////////////////
190
191 #define kMaxRefCnt_SkString SK_MaxU16
192
193 // the 3 values are [length] [refcnt] [terminating zero data]
194 const SkString::Rec SkString::gEmptyRec = { 0, 0, 0 };
195
196 #define SizeOfRec() (gEmptyRec.data() - (const char*)&gEmptyRec)
197
AllocRec(const char text[],U16CPU len)198 SkString::Rec* SkString::AllocRec(const char text[], U16CPU len) {
199 Rec* rec;
200
201 if (len == 0) {
202 rec = const_cast<Rec*>(&gEmptyRec);
203 } else {
204 // add 1 for terminating 0, then align4 so we can have some slop when growing the string
205 rec = (Rec*)sk_malloc_throw(SizeOfRec() + SkAlign4(len + 1));
206 rec->fLength = SkToU16(len);
207 rec->fRefCnt = 1;
208 if (text) {
209 memcpy(rec->data(), text, len);
210 }
211 rec->data()[len] = 0;
212 }
213 return rec;
214 }
215
RefRec(Rec * src)216 SkString::Rec* SkString::RefRec(Rec* src) {
217 if (src != &gEmptyRec) {
218 if (src->fRefCnt == kMaxRefCnt_SkString) {
219 src = AllocRec(src->data(), src->fLength);
220 } else {
221 src->fRefCnt += 1;
222 }
223 }
224 return src;
225 }
226
227 #ifdef SK_DEBUG
validate() const228 void SkString::validate() const {
229 // make sure know one has written over our global
230 SkASSERT(gEmptyRec.fLength == 0);
231 SkASSERT(gEmptyRec.fRefCnt == 0);
232 SkASSERT(gEmptyRec.data()[0] == 0);
233
234 if (fRec != &gEmptyRec) {
235 SkASSERT(fRec->fLength > 0);
236 SkASSERT(fRec->fRefCnt > 0);
237 SkASSERT(fRec->data()[fRec->fLength] == 0);
238 }
239 SkASSERT(fStr == c_str());
240 }
241 #endif
242
243 ///////////////////////////////////////////////////////////////////////////////
244
SkString()245 SkString::SkString() : fRec(const_cast<Rec*>(&gEmptyRec)) {
246 #ifdef SK_DEBUG
247 fStr = fRec->data();
248 #endif
249 }
250
SkString(size_t len)251 SkString::SkString(size_t len) {
252 SkASSERT(SkToU16(len) == len); // can't handle larger than 64K
253
254 fRec = AllocRec(NULL, (U16CPU)len);
255 #ifdef SK_DEBUG
256 fStr = fRec->data();
257 #endif
258 }
259
SkString(const char text[])260 SkString::SkString(const char text[]) {
261 size_t len = text ? strlen(text) : 0;
262
263 fRec = AllocRec(text, (U16CPU)len);
264 #ifdef SK_DEBUG
265 fStr = fRec->data();
266 #endif
267 }
268
SkString(const char text[],size_t len)269 SkString::SkString(const char text[], size_t len) {
270 fRec = AllocRec(text, (U16CPU)len);
271 #ifdef SK_DEBUG
272 fStr = fRec->data();
273 #endif
274 }
275
SkString(const SkString & src)276 SkString::SkString(const SkString& src) {
277 src.validate();
278
279 fRec = RefRec(src.fRec);
280 #ifdef SK_DEBUG
281 fStr = fRec->data();
282 #endif
283 }
284
~SkString()285 SkString::~SkString() {
286 this->validate();
287
288 if (fRec->fLength) {
289 SkASSERT(fRec->fRefCnt > 0);
290 if (--fRec->fRefCnt == 0) {
291 sk_free(fRec);
292 }
293 }
294 }
295
equals(const SkString & src) const296 bool SkString::equals(const SkString& src) const {
297 return fRec == src.fRec || this->equals(src.c_str(), src.size());
298 }
299
equals(const char text[]) const300 bool SkString::equals(const char text[]) const {
301 return this->equals(text, text ? strlen(text) : 0);
302 }
303
equals(const char text[],size_t len) const304 bool SkString::equals(const char text[], size_t len) const {
305 SkASSERT(len == 0 || text != NULL);
306
307 return fRec->fLength == len && !memcmp(fRec->data(), text, len);
308 }
309
operator =(const SkString & src)310 SkString& SkString::operator=(const SkString& src) {
311 this->validate();
312
313 if (fRec != src.fRec) {
314 SkString tmp(src);
315 this->swap(tmp);
316 }
317 return *this;
318 }
319
operator =(const char text[])320 SkString& SkString::operator=(const char text[]) {
321 this->validate();
322
323 SkString tmp(text);
324 this->swap(tmp);
325
326 return *this;
327 }
328
reset()329 void SkString::reset() {
330 this->validate();
331
332 if (fRec->fLength) {
333 SkASSERT(fRec->fRefCnt > 0);
334 if (--fRec->fRefCnt == 0) {
335 sk_free(fRec);
336 }
337 }
338
339 fRec = const_cast<Rec*>(&gEmptyRec);
340 #ifdef SK_DEBUG
341 fStr = fRec->data();
342 #endif
343 }
344
writable_str()345 char* SkString::writable_str() {
346 this->validate();
347
348 if (fRec->fLength) {
349 if (fRec->fRefCnt > 1) {
350 fRec->fRefCnt -= 1;
351 fRec = AllocRec(fRec->data(), fRec->fLength);
352 #ifdef SK_DEBUG
353 fStr = fRec->data();
354 #endif
355 }
356 }
357 return fRec->data();
358 }
359
set(const char text[])360 void SkString::set(const char text[]) {
361 this->set(text, text ? strlen(text) : 0);
362 }
363
set(const char text[],size_t len)364 void SkString::set(const char text[], size_t len) {
365 if (len == 0) {
366 this->reset();
367 } else if (fRec->fRefCnt == 1 && len <= fRec->fLength) {
368 // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))?
369 // just use less of the buffer without allocating a smaller one
370 char* p = this->writable_str();
371 if (text) {
372 memcpy(p, text, len);
373 }
374 p[len] = 0;
375 fRec->fLength = SkToU16(len);
376 } else if (fRec->fRefCnt == 1 && ((unsigned)fRec->fLength >> 2) == (len >> 2)) {
377 // we have spare room in the current allocation, so don't alloc a larger one
378 char* p = this->writable_str();
379 if (text) {
380 memcpy(p, text, len);
381 }
382 p[len] = 0;
383 fRec->fLength = SkToU16(len);
384 } else {
385 SkString tmp(text, len);
386 this->swap(tmp);
387 }
388 }
389
setUTF16(const uint16_t src[])390 void SkString::setUTF16(const uint16_t src[]) {
391 int count = 0;
392
393 while (src[count]) {
394 count += 1;
395 }
396 setUTF16(src, count);
397 }
398
setUTF16(const uint16_t src[],size_t count)399 void SkString::setUTF16(const uint16_t src[], size_t count) {
400 if (count == 0) {
401 this->reset();
402 } else if (count <= fRec->fLength) {
403 // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))
404 if (count < fRec->fLength) {
405 this->resize(count);
406 }
407 char* p = this->writable_str();
408 for (size_t i = 0; i < count; i++) {
409 p[i] = SkToU8(src[i]);
410 }
411 p[count] = 0;
412 } else {
413 SkString tmp(count); // puts a null terminator at the end of the string
414 char* p = tmp.writable_str();
415
416 for (size_t i = 0; i < count; i++) {
417 p[i] = SkToU8(src[i]);
418 }
419 this->swap(tmp);
420 }
421 }
422
insert(size_t offset,const char text[])423 void SkString::insert(size_t offset, const char text[]) {
424 this->insert(offset, text, text ? strlen(text) : 0);
425 }
426
insert(size_t offset,const char text[],size_t len)427 void SkString::insert(size_t offset, const char text[], size_t len) {
428 if (len) {
429 size_t length = fRec->fLength;
430 if (offset > length) {
431 offset = length;
432 }
433
434 /* If we're the only owner, and we have room in our allocation for the insert,
435 do it in place, rather than allocating a new buffer.
436
437 To know we have room, compare the allocated sizes
438 beforeAlloc = SkAlign4(length + 1)
439 afterAlloc = SkAligh4(length + 1 + len)
440 but SkAlign4(x) is (x + 3) >> 2 << 2
441 which is equivalent for testing to (length + 1 + 3) >> 2 == (length + 1 + 3 + len) >> 2
442 and we can then eliminate the +1+3 since that doesn't affec the answer
443 */
444 if (fRec->fRefCnt == 1 && (length >> 2) == ((length + len) >> 2)) {
445 char* dst = this->writable_str();
446
447 if (offset < length) {
448 memmove(dst + offset + len, dst + offset, length - offset);
449 }
450 memcpy(dst + offset, text, len);
451
452 dst[length + len] = 0;
453 fRec->fLength = SkToU16(length + len);
454 } else {
455 /* Seems we should use realloc here, since that is safe if it fails
456 (we have the original data), and might be faster than alloc/copy/free.
457 */
458 SkString tmp(fRec->fLength + len);
459 char* dst = tmp.writable_str();
460
461 if (offset > 0) {
462 memcpy(dst, fRec->data(), offset);
463 }
464 memcpy(dst + offset, text, len);
465 if (offset < fRec->fLength) {
466 memcpy(dst + offset + len, fRec->data() + offset,
467 fRec->fLength - offset);
468 }
469
470 this->swap(tmp);
471 }
472 }
473 }
474
insertUnichar(size_t offset,SkUnichar uni)475 void SkString::insertUnichar(size_t offset, SkUnichar uni) {
476 char buffer[kMaxBytesInUTF8Sequence];
477 size_t len = SkUTF8_FromUnichar(uni, buffer);
478
479 if (len) {
480 this->insert(offset, buffer, len);
481 }
482 }
483
insertS32(size_t offset,int32_t dec)484 void SkString::insertS32(size_t offset, int32_t dec) {
485 char buffer[SkStrAppendS32_MaxSize];
486 char* stop = SkStrAppendS32(buffer, dec);
487 this->insert(offset, buffer, stop - buffer);
488 }
489
insertS64(size_t offset,int64_t dec,int minDigits)490 void SkString::insertS64(size_t offset, int64_t dec, int minDigits) {
491 char buffer[SkStrAppendS64_MaxSize];
492 char* stop = SkStrAppendS64(buffer, dec, minDigits);
493 this->insert(offset, buffer, stop - buffer);
494 }
495
insertHex(size_t offset,uint32_t hex,int minDigits)496 void SkString::insertHex(size_t offset, uint32_t hex, int minDigits) {
497 minDigits = SkPin32(minDigits, 0, 8);
498
499 static const char gHex[] = "0123456789ABCDEF";
500
501 char buffer[8];
502 char* p = buffer + sizeof(buffer);
503
504 do {
505 *--p = gHex[hex & 0xF];
506 hex >>= 4;
507 minDigits -= 1;
508 } while (hex != 0);
509
510 while (--minDigits >= 0) {
511 *--p = '0';
512 }
513
514 SkASSERT(p >= buffer);
515 this->insert(offset, p, buffer + sizeof(buffer) - p);
516 }
517
insertScalar(size_t offset,SkScalar value)518 void SkString::insertScalar(size_t offset, SkScalar value) {
519 char buffer[SkStrAppendScalar_MaxSize];
520 char* stop = SkStrAppendScalar(buffer, value);
521 this->insert(offset, buffer, stop - buffer);
522 }
523
printf(const char format[],...)524 void SkString::printf(const char format[], ...) {
525 char buffer[kBufferSize];
526 ARGS_TO_BUFFER(format, buffer, kBufferSize);
527
528 this->set(buffer, strlen(buffer));
529 }
530
appendf(const char format[],...)531 void SkString::appendf(const char format[], ...) {
532 char buffer[kBufferSize];
533 ARGS_TO_BUFFER(format, buffer, kBufferSize);
534
535 this->append(buffer, strlen(buffer));
536 }
537
prependf(const char format[],...)538 void SkString::prependf(const char format[], ...) {
539 char buffer[kBufferSize];
540 ARGS_TO_BUFFER(format, buffer, kBufferSize);
541
542 this->prepend(buffer, strlen(buffer));
543 }
544
545 #undef VSNPRINTF
546
547 ///////////////////////////////////////////////////////////////////////////////
548
remove(size_t offset,size_t length)549 void SkString::remove(size_t offset, size_t length) {
550 size_t size = this->size();
551
552 if (offset < size) {
553 if (offset + length > size) {
554 length = size - offset;
555 }
556 if (length > 0) {
557 SkASSERT(size > length);
558 SkString tmp(size - length);
559 char* dst = tmp.writable_str();
560 const char* src = this->c_str();
561
562 if (offset) {
563 SkASSERT(offset <= tmp.size());
564 memcpy(dst, src, offset);
565 }
566 size_t tail = size - offset - length;
567 SkASSERT((int32_t)tail >= 0);
568 if (tail) {
569 // SkASSERT(offset + length <= tmp.size());
570 memcpy(dst + offset, src + offset + length, tail);
571 }
572 SkASSERT(dst[tmp.size()] == 0);
573 this->swap(tmp);
574 }
575 }
576 }
577
swap(SkString & other)578 void SkString::swap(SkString& other) {
579 this->validate();
580 other.validate();
581
582 SkTSwap<Rec*>(fRec, other.fRec);
583 #ifdef SK_DEBUG
584 SkTSwap<const char*>(fStr, other.fStr);
585 #endif
586 }
587
588 ///////////////////////////////////////////////////////////////////////////////
589
SkAutoUCS2(const char utf8[])590 SkAutoUCS2::SkAutoUCS2(const char utf8[]) {
591 size_t len = strlen(utf8);
592 fUCS2 = (uint16_t*)sk_malloc_throw((len + 1) * sizeof(uint16_t));
593
594 uint16_t* dst = fUCS2;
595 for (;;) {
596 SkUnichar uni = SkUTF8_NextUnichar(&utf8);
597 *dst++ = SkToU16(uni);
598 if (uni == 0) {
599 break;
600 }
601 }
602 fCount = (int)(dst - fUCS2);
603 }
604
~SkAutoUCS2()605 SkAutoUCS2::~SkAutoUCS2() {
606 sk_free(fUCS2);
607 }
608