• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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