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