• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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