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