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