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 "SkParse.h"
11 
is_between(int c,int min,int max)12 static inline bool is_between(int c, int min, int max)
13 {
14     return (unsigned)(c - min) <= (unsigned)(max - min);
15 }
16 
is_ws(int c)17 static inline bool is_ws(int c)
18 {
19     return is_between(c, 1, 32);
20 }
21 
is_digit(int c)22 static inline bool is_digit(int c)
23 {
24     return is_between(c, '0', '9');
25 }
26 
is_sep(int c)27 static inline bool is_sep(int c)
28 {
29     return is_ws(c) || c == ',' || c == ';';
30 }
31 
to_hex(int c)32 static int to_hex(int c)
33 {
34     if (is_digit(c))
35         return c - '0';
36 
37     c |= 0x20;  // make us lower-case
38     if (is_between(c, 'a', 'f'))
39         return c + 10 - 'a';
40     else
41         return -1;
42 }
43 
is_hex(int c)44 static inline bool is_hex(int c)
45 {
46     return to_hex(c) >= 0;
47 }
48 
skip_ws(const char str[])49 static const char* skip_ws(const char str[])
50 {
51     SkASSERT(str);
52     while (is_ws(*str))
53         str++;
54     return str;
55 }
56 
skip_sep(const char str[])57 static const char* skip_sep(const char str[])
58 {
59     SkASSERT(str);
60     while (is_sep(*str))
61         str++;
62     return str;
63 }
64 
Count(const char str[])65 int SkParse::Count(const char str[])
66 {
67     char c;
68     int count = 0;
69     goto skipLeading;
70     do {
71         count++;
72         do {
73             if ((c = *str++) == '\0')
74                 goto goHome;
75         } while (is_sep(c) == false);
76 skipLeading:
77         do {
78             if ((c = *str++) == '\0')
79                 goto goHome;
80         } while (is_sep(c));
81     } while (true);
82 goHome:
83     return count;
84 }
85 
Count(const char str[],char separator)86 int SkParse::Count(const char str[], char separator)
87 {
88     char c;
89     int count = 0;
90     goto skipLeading;
91     do {
92         count++;
93         do {
94             if ((c = *str++) == '\0')
95                 goto goHome;
96         } while (c != separator);
97 skipLeading:
98         do {
99             if ((c = *str++) == '\0')
100                 goto goHome;
101         } while (c == separator);
102     } while (true);
103 goHome:
104     return count;
105 }
106 
FindHex(const char str[],uint32_t * value)107 const char* SkParse::FindHex(const char str[], uint32_t* value)
108 {
109     SkASSERT(str);
110     str = skip_ws(str);
111 
112     if (!is_hex(*str))
113         return NULL;
114 
115     uint32_t n = 0;
116     int max_digits = 8;
117     int digit;
118 
119     while ((digit = to_hex(*str)) >= 0)
120     {
121         if (--max_digits < 0)
122             return NULL;
123         n = (n << 4) | digit;
124         str += 1;
125     }
126 
127     if (*str == 0 || is_ws(*str))
128     {
129         if (value)
130             *value = n;
131         return str;
132     }
133     return NULL;
134 }
135 
FindS32(const char str[],int32_t * value)136 const char* SkParse::FindS32(const char str[], int32_t* value)
137 {
138     SkASSERT(str);
139     str = skip_ws(str);
140 
141     int sign = 0;
142     if (*str == '-')
143     {
144         sign = -1;
145         str += 1;
146     }
147 
148     if (!is_digit(*str))
149         return NULL;
150 
151     int n = 0;
152     while (is_digit(*str))
153     {
154         n = 10*n + *str - '0';
155         str += 1;
156     }
157     if (value)
158         *value = (n ^ sign) - sign;
159     return str;
160 }
161 
FindMSec(const char str[],SkMSec * value)162 const char* SkParse::FindMSec(const char str[], SkMSec* value)
163 {
164     SkASSERT(str);
165     str = skip_ws(str);
166 
167     int sign = 0;
168     if (*str == '-')
169     {
170         sign = -1;
171         str += 1;
172     }
173 
174     if (!is_digit(*str))
175         return NULL;
176 
177     int n = 0;
178     while (is_digit(*str))
179     {
180         n = 10*n + *str - '0';
181         str += 1;
182     }
183     int remaining10s = 3;
184     if (*str == '.') {
185         str++;
186         while (is_digit(*str))
187         {
188             n = 10*n + *str - '0';
189             str += 1;
190             if (--remaining10s == 0)
191                 break;
192         }
193     }
194     while (--remaining10s >= 0)
195         n *= 10;
196     if (value)
197         *value = (n ^ sign) - sign;
198     return str;
199 }
200 
FindScalar(const char str[],SkScalar * value)201 const char* SkParse::FindScalar(const char str[], SkScalar* value) {
202     SkASSERT(str);
203     str = skip_ws(str);
204 
205     char* stop;
206     float v = (float)strtod(str, &stop);
207     if (str == stop) {
208         return NULL;
209     }
210     if (value) {
211         *value = v;
212     }
213     return stop;
214 }
215 
FindScalars(const char str[],SkScalar value[],int count)216 const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
217 {
218     SkASSERT(count >= 0);
219 
220     if (count > 0)
221     {
222         for (;;)
223         {
224             str = SkParse::FindScalar(str, value);
225             if (--count == 0 || str == NULL)
226                 break;
227 
228             // keep going
229             str = skip_sep(str);
230             if (value)
231                 value += 1;
232         }
233     }
234     return str;
235 }
236 
lookup_str(const char str[],const char ** table,int count)237 static bool lookup_str(const char str[], const char** table, int count)
238 {
239     while (--count >= 0)
240         if (!strcmp(str, table[count]))
241             return true;
242     return false;
243 }
244 
FindBool(const char str[],bool * value)245 bool SkParse::FindBool(const char str[], bool* value)
246 {
247     static const char* gYes[] = { "yes", "1", "true" };
248     static const char* gNo[] = { "no", "0", "false" };
249 
250     if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
251     {
252         if (value) *value = true;
253         return true;
254     }
255     else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
256     {
257         if (value) *value = false;
258         return true;
259     }
260     return false;
261 }
262 
FindList(const char target[],const char list[])263 int SkParse::FindList(const char target[], const char list[])
264 {
265     size_t  len = strlen(target);
266     int     index = 0;
267 
268     for (;;)
269     {
270         const char* end = strchr(list, ',');
271         size_t      entryLen;
272 
273         if (end == NULL) // last entry
274             entryLen = strlen(list);
275         else
276             entryLen = end - list;
277 
278         if (entryLen == len && memcmp(target, list, len) == 0)
279             return index;
280         if (end == NULL)
281             break;
282 
283         list = end + 1; // skip the ','
284         index += 1;
285     }
286     return -1;
287 }
288 
289 #ifdef SK_SUPPORT_UNITTEST
UnitTest()290 void SkParse::UnitTest()
291 {
292     // !!! additional parse tests go here
293     SkParse::TestColor();
294 }
295 #endif
296