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