blob: 69808a34c4fc364135c4a940b9b268af0004c9aa [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* 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
20static inline bool is_between(int c, int min, int max)
21{
22 return (unsigned)(c - min) <= (unsigned)(max - min);
23}
24
25static inline bool is_ws(int c)
26{
27 return is_between(c, 1, 32);
28}
29
30static inline bool is_digit(int c)
31{
32 return is_between(c, '0', '9');
33}
34
35static inline bool is_sep(int c)
36{
37 return is_ws(c) || c == ',' || c == ';';
38}
39
40static 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
52static inline bool is_hex(int c)
53{
54 return to_hex(c) >= 0;
55}
56
57static const char* skip_ws(const char str[])
58{
59 SkASSERT(str);
60 while (is_ws(*str))
61 str++;
62 return str;
63}
64
65static const char* skip_sep(const char str[])
66{
67 SkASSERT(str);
68 while (is_sep(*str))
69 str++;
70 return str;
71}
72
73int 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);
84skipLeading:
85 do {
86 if ((c = *str++) == '\0')
87 goto goHome;
88 } while (is_sep(c));
89 } while (true);
90goHome:
91 return count;
92}
93
94int 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);
105skipLeading:
106 do {
107 if ((c = *str++) == '\0')
108 goto goHome;
109 } while (c == separator);
110 } while (true);
111goHome:
112 return count;
113}
114
115const 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
144const 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
170const 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
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000209const char* SkParse::FindScalar(const char str[], SkScalar* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210 SkASSERT(str);
211 str = skip_ws(str);
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000212#ifdef SK_SCALAR_IS_FLOAT
213 char* stop;
reed@android.come191b162009-12-18 21:33:39 +0000214 float v = (float)strtod(str, &stop);
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000215 if (str == stop) {
216 return NULL;
217 }
218 if (value) {
219 *value = v;
220 }
221 return stop;
222#else
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 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 }
reed@android.coma8cf0aa2009-09-24 20:06:03 +0000263#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 return str;
265}
266
267const 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
288static 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
296bool 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
314int 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
341void SkParse::UnitTest()
342{
343 // !!! additional parse tests go here
344 SkParse::TestColor();
345}
346#endif