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 #ifdef SK_SCALAR_IS_FLOAT
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 #else
215 int sign = 0;
216 if (*str == '-')
217 {
218 sign = -1;
219 str += 1;
220 }
221
222 if (!is_digit(*str) && *str != '.')
223 return NULL;
224
225 int n = 0;
226 while (is_digit(*str))
227 {
228 n = 10*n + *str - '0';
229 if (n > 0x7FFF)
230 return NULL;
231 str += 1;
232 }
233 n <<= 16;
234
235 if (*str == '.')
236 {
237 static const int gFractions[] = { (1 << 24) / 10, (1 << 24) / 100, (1 << 24) / 1000,
238 (1 << 24) / 10000, (1 << 24) / 100000 };
239 str += 1;
240 int d = 0;
241 const int* fraction = gFractions;
242 const int* end = &fraction[SK_ARRAY_COUNT(gFractions)];
243 while (is_digit(*str) && fraction < end)
244 d += (*str++ - '0') * *fraction++;
245 d += 0x80; // round
246 n += d >> 8;
247 }
248 while (is_digit(*str))
249 str += 1;
250 if (value)
251 {
252 n = (n ^ sign) - sign; // apply the sign
253 *value = SkFixedToScalar(n);
254 }
255 #endif
256 return str;
257 }
258
FindScalars(const char str[],SkScalar value[],int count)259 const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
260 {
261 SkASSERT(count >= 0);
262
263 if (count > 0)
264 {
265 for (;;)
266 {
267 str = SkParse::FindScalar(str, value);
268 if (--count == 0 || str == NULL)
269 break;
270
271 // keep going
272 str = skip_sep(str);
273 if (value)
274 value += 1;
275 }
276 }
277 return str;
278 }
279
lookup_str(const char str[],const char ** table,int count)280 static bool lookup_str(const char str[], const char** table, int count)
281 {
282 while (--count >= 0)
283 if (!strcmp(str, table[count]))
284 return true;
285 return false;
286 }
287
FindBool(const char str[],bool * value)288 bool SkParse::FindBool(const char str[], bool* value)
289 {
290 static const char* gYes[] = { "yes", "1", "true" };
291 static const char* gNo[] = { "no", "0", "false" };
292
293 if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
294 {
295 if (value) *value = true;
296 return true;
297 }
298 else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
299 {
300 if (value) *value = false;
301 return true;
302 }
303 return false;
304 }
305
FindList(const char target[],const char list[])306 int SkParse::FindList(const char target[], const char list[])
307 {
308 size_t len = strlen(target);
309 int index = 0;
310
311 for (;;)
312 {
313 const char* end = strchr(list, ',');
314 size_t entryLen;
315
316 if (end == NULL) // last entry
317 entryLen = strlen(list);
318 else
319 entryLen = end - list;
320
321 if (entryLen == len && memcmp(target, list, len) == 0)
322 return index;
323 if (end == NULL)
324 break;
325
326 list = end + 1; // skip the ','
327 index += 1;
328 }
329 return -1;
330 }
331
332 #ifdef SK_SUPPORT_UNITTEST
UnitTest()333 void SkParse::UnitTest()
334 {
335 // !!! additional parse tests go here
336 SkParse::TestColor();
337 }
338 #endif
339