1 /* libs/graphics/xml/SkParse.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #include "SkParse.h"
19
is_between(int c,int min,int max)20 static inline bool is_between(int c, int min, int max)
21 {
22 return (unsigned)(c - min) <= (unsigned)(max - min);
23 }
24
is_ws(int c)25 static inline bool is_ws(int c)
26 {
27 return is_between(c, 1, 32);
28 }
29
is_digit(int c)30 static inline bool is_digit(int c)
31 {
32 return is_between(c, '0', '9');
33 }
34
is_sep(int c)35 static inline bool is_sep(int c)
36 {
37 return is_ws(c) || c == ',' || c == ';';
38 }
39
to_hex(int c)40 static int to_hex(int c)
41 {
42 if (is_digit(c))
43 return c - '0';
44
45 c |= 0x20; // make us lower-case
46 if (is_between(c, 'a', 'f'))
47 return c + 10 - 'a';
48 else
49 return -1;
50 }
51
is_hex(int c)52 static inline bool is_hex(int c)
53 {
54 return to_hex(c) >= 0;
55 }
56
skip_ws(const char str[])57 static const char* skip_ws(const char str[])
58 {
59 SkASSERT(str);
60 while (is_ws(*str))
61 str++;
62 return str;
63 }
64
skip_sep(const char str[])65 static const char* skip_sep(const char str[])
66 {
67 SkASSERT(str);
68 while (is_sep(*str))
69 str++;
70 return str;
71 }
72
Count(const char str[])73 int SkParse::Count(const char str[])
74 {
75 char c;
76 int count = 0;
77 goto skipLeading;
78 do {
79 count++;
80 do {
81 if ((c = *str++) == '\0')
82 goto goHome;
83 } while (is_sep(c) == false);
84 skipLeading:
85 do {
86 if ((c = *str++) == '\0')
87 goto goHome;
88 } while (is_sep(c));
89 } while (true);
90 goHome:
91 return count;
92 }
93
Count(const char str[],char separator)94 int SkParse::Count(const char str[], char separator)
95 {
96 char c;
97 int count = 0;
98 goto skipLeading;
99 do {
100 count++;
101 do {
102 if ((c = *str++) == '\0')
103 goto goHome;
104 } while (c != separator);
105 skipLeading:
106 do {
107 if ((c = *str++) == '\0')
108 goto goHome;
109 } while (c == separator);
110 } while (true);
111 goHome:
112 return count;
113 }
114
FindHex(const char str[],uint32_t * value)115 const char* SkParse::FindHex(const char str[], uint32_t* value)
116 {
117 SkASSERT(str);
118 str = skip_ws(str);
119
120 if (!is_hex(*str))
121 return NULL;
122
123 uint32_t n = 0;
124 int max_digits = 8;
125 int digit;
126
127 while ((digit = to_hex(*str)) >= 0)
128 {
129 if (--max_digits < 0)
130 return NULL;
131 n = (n << 4) | digit;
132 str += 1;
133 }
134
135 if (*str == 0 || is_ws(*str))
136 {
137 if (value)
138 *value = n;
139 return str;
140 }
141 return false;
142 }
143
FindS32(const char str[],int32_t * value)144 const char* SkParse::FindS32(const char str[], int32_t* value)
145 {
146 SkASSERT(str);
147 str = skip_ws(str);
148
149 int sign = 0;
150 if (*str == '-')
151 {
152 sign = -1;
153 str += 1;
154 }
155
156 if (!is_digit(*str))
157 return NULL;
158
159 int n = 0;
160 while (is_digit(*str))
161 {
162 n = 10*n + *str - '0';
163 str += 1;
164 }
165 if (value)
166 *value = (n ^ sign) - sign;
167 return str;
168 }
169
FindMSec(const char str[],SkMSec * value)170 const char* SkParse::FindMSec(const char str[], SkMSec* value)
171 {
172 SkASSERT(str);
173 str = skip_ws(str);
174
175 int sign = 0;
176 if (*str == '-')
177 {
178 sign = -1;
179 str += 1;
180 }
181
182 if (!is_digit(*str))
183 return NULL;
184
185 int n = 0;
186 while (is_digit(*str))
187 {
188 n = 10*n + *str - '0';
189 str += 1;
190 }
191 int remaining10s = 3;
192 if (*str == '.') {
193 str++;
194 while (is_digit(*str))
195 {
196 n = 10*n + *str - '0';
197 str += 1;
198 if (--remaining10s == 0)
199 break;
200 }
201 }
202 while (--remaining10s >= 0)
203 n *= 10;
204 if (value)
205 *value = (n ^ sign) - sign;
206 return str;
207 }
208
FindScalar(const char str[],SkScalar * value)209 const char* SkParse::FindScalar(const char str[], SkScalar* value) {
210 SkASSERT(str);
211 str = skip_ws(str);
212 #ifdef SK_SCALAR_IS_FLOAT
213 char* stop;
214 float v = (float)strtod(str, &stop);
215 if (str == stop) {
216 return NULL;
217 }
218 if (value) {
219 *value = v;
220 }
221 return stop;
222 #else
223 int sign = 0;
224 if (*str == '-')
225 {
226 sign = -1;
227 str += 1;
228 }
229
230 if (!is_digit(*str) && *str != '.')
231 return NULL;
232
233 int n = 0;
234 while (is_digit(*str))
235 {
236 n = 10*n + *str - '0';
237 if (n > 0x7FFF)
238 return NULL;
239 str += 1;
240 }
241 n <<= 16;
242
243 if (*str == '.')
244 {
245 static const int gFractions[] = { (1 << 24) / 10, (1 << 24) / 100, (1 << 24) / 1000,
246 (1 << 24) / 10000, (1 << 24) / 100000 };
247 str += 1;
248 int d = 0;
249 const int* fraction = gFractions;
250 const int* end = &fraction[SK_ARRAY_COUNT(gFractions)];
251 while (is_digit(*str) && fraction < end)
252 d += (*str++ - '0') * *fraction++;
253 d += 0x80; // round
254 n += d >> 8;
255 }
256 while (is_digit(*str))
257 str += 1;
258 if (value)
259 {
260 n = (n ^ sign) - sign; // apply the sign
261 *value = SkFixedToScalar(n);
262 }
263 #endif
264 return str;
265 }
266
FindScalars(const char str[],SkScalar value[],int count)267 const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
268 {
269 SkASSERT(count >= 0);
270
271 if (count > 0)
272 {
273 for (;;)
274 {
275 str = SkParse::FindScalar(str, value);
276 if (--count == 0 || str == NULL)
277 break;
278
279 // keep going
280 str = skip_sep(str);
281 if (value)
282 value += 1;
283 }
284 }
285 return str;
286 }
287
lookup_str(const char str[],const char ** table,int count)288 static bool lookup_str(const char str[], const char** table, int count)
289 {
290 while (--count >= 0)
291 if (!strcmp(str, table[count]))
292 return true;
293 return false;
294 }
295
FindBool(const char str[],bool * value)296 bool SkParse::FindBool(const char str[], bool* value)
297 {
298 static const char* gYes[] = { "yes", "1", "true" };
299 static const char* gNo[] = { "no", "0", "false" };
300
301 if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
302 {
303 if (value) *value = true;
304 return true;
305 }
306 else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
307 {
308 if (value) *value = false;
309 return true;
310 }
311 return false;
312 }
313
FindList(const char target[],const char list[])314 int SkParse::FindList(const char target[], const char list[])
315 {
316 size_t len = strlen(target);
317 int index = 0;
318
319 for (;;)
320 {
321 const char* end = strchr(list, ',');
322 size_t entryLen;
323
324 if (end == NULL) // last entry
325 entryLen = strlen(list);
326 else
327 entryLen = end - list;
328
329 if (entryLen == len && memcmp(target, list, len) == 0)
330 return index;
331 if (end == NULL)
332 break;
333
334 list = end + 1; // skip the ','
335 index += 1;
336 }
337 return -1;
338 }
339
340 #ifdef SK_SUPPORT_UNITTEST
UnitTest()341 void SkParse::UnitTest()
342 {
343 // !!! additional parse tests go here
344 SkParse::TestColor();
345 }
346 #endif
347