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