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