1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkParse.h"
11 
12 #include <stdlib.h>
13 
is_between(int c,int min,int max)14 static inline bool is_between(int c, int min, int max)
15 {
16     return (unsigned)(c - min) <= (unsigned)(max - min);
17 }
18 
is_ws(int c)19 static inline bool is_ws(int c)
20 {
21     return is_between(c, 1, 32);
22 }
23 
is_digit(int c)24 static inline bool is_digit(int c)
25 {
26     return is_between(c, '0', '9');
27 }
28 
is_sep(int c)29 static inline bool is_sep(int c)
30 {
31     return is_ws(c) || c == ',' || c == ';';
32 }
33 
to_hex(int c)34 static int to_hex(int c)
35 {
36     if (is_digit(c))
37         return c - '0';
38 
39     c |= 0x20;  // make us lower-case
40     if (is_between(c, 'a', 'f'))
41         return c + 10 - 'a';
42     else
43         return -1;
44 }
45 
is_hex(int c)46 static inline bool is_hex(int c)
47 {
48     return to_hex(c) >= 0;
49 }
50 
skip_ws(const char str[])51 static const char* skip_ws(const char str[])
52 {
53     SkASSERT(str);
54     while (is_ws(*str))
55         str++;
56     return str;
57 }
58 
skip_sep(const char str[])59 static const char* skip_sep(const char str[])
60 {
61     SkASSERT(str);
62     while (is_sep(*str))
63         str++;
64     return str;
65 }
66 
Count(const char str[])67 int SkParse::Count(const char str[])
68 {
69     char c;
70     int count = 0;
71     goto skipLeading;
72     do {
73         count++;
74         do {
75             if ((c = *str++) == '\0')
76                 goto goHome;
77         } while (is_sep(c) == false);
78 skipLeading:
79         do {
80             if ((c = *str++) == '\0')
81                 goto goHome;
82         } while (is_sep(c));
83     } while (true);
84 goHome:
85     return count;
86 }
87 
Count(const char str[],char separator)88 int SkParse::Count(const char str[], char separator)
89 {
90     char c;
91     int count = 0;
92     goto skipLeading;
93     do {
94         count++;
95         do {
96             if ((c = *str++) == '\0')
97                 goto goHome;
98         } while (c != separator);
99 skipLeading:
100         do {
101             if ((c = *str++) == '\0')
102                 goto goHome;
103         } while (c == separator);
104     } while (true);
105 goHome:
106     return count;
107 }
108 
FindHex(const char str[],uint32_t * value)109 const char* SkParse::FindHex(const char str[], uint32_t* value)
110 {
111     SkASSERT(str);
112     str = skip_ws(str);
113 
114     if (!is_hex(*str))
115         return nullptr;
116 
117     uint32_t n = 0;
118     int max_digits = 8;
119     int digit;
120 
121     while ((digit = to_hex(*str)) >= 0)
122     {
123         if (--max_digits < 0)
124             return nullptr;
125         n = (n << 4) | digit;
126         str += 1;
127     }
128 
129     if (*str == 0 || is_ws(*str))
130     {
131         if (value)
132             *value = n;
133         return str;
134     }
135     return nullptr;
136 }
137 
FindS32(const char str[],int32_t * value)138 const char* SkParse::FindS32(const char str[], int32_t* value)
139 {
140     SkASSERT(str);
141     str = skip_ws(str);
142 
143     int sign = 0;
144     if (*str == '-')
145     {
146         sign = -1;
147         str += 1;
148     }
149 
150     if (!is_digit(*str))
151         return nullptr;
152 
153     int n = 0;
154     while (is_digit(*str))
155     {
156         n = 10*n + *str - '0';
157         str += 1;
158     }
159     if (value)
160         *value = (n ^ sign) - sign;
161     return str;
162 }
163 
FindMSec(const char str[],SkMSec * value)164 const char* SkParse::FindMSec(const char str[], SkMSec* value)
165 {
166     SkASSERT(str);
167     str = skip_ws(str);
168 
169     int sign = 0;
170     if (*str == '-')
171     {
172         sign = -1;
173         str += 1;
174     }
175 
176     if (!is_digit(*str))
177         return nullptr;
178 
179     int n = 0;
180     while (is_digit(*str))
181     {
182         n = 10*n + *str - '0';
183         str += 1;
184     }
185     int remaining10s = 3;
186     if (*str == '.') {
187         str++;
188         while (is_digit(*str))
189         {
190             n = 10*n + *str - '0';
191             str += 1;
192             if (--remaining10s == 0)
193                 break;
194         }
195     }
196     while (--remaining10s >= 0)
197         n *= 10;
198     if (value)
199         *value = (n ^ sign) - sign;
200     return str;
201 }
202 
FindScalar(const char str[],SkScalar * value)203 const char* SkParse::FindScalar(const char str[], SkScalar* value) {
204     SkASSERT(str);
205     str = skip_ws(str);
206 
207     char* stop;
208     float v = (float)strtod(str, &stop);
209     if (str == stop) {
210         return nullptr;
211     }
212     if (value) {
213         *value = v;
214     }
215     return stop;
216 }
217 
FindScalars(const char str[],SkScalar value[],int count)218 const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
219 {
220     SkASSERT(count >= 0);
221 
222     if (count > 0)
223     {
224         for (;;)
225         {
226             str = SkParse::FindScalar(str, value);
227             if (--count == 0 || str == nullptr)
228                 break;
229 
230             // keep going
231             str = skip_sep(str);
232             if (value)
233                 value += 1;
234         }
235     }
236     return str;
237 }
238 
lookup_str(const char str[],const char ** table,int count)239 static bool lookup_str(const char str[], const char** table, int count)
240 {
241     while (--count >= 0)
242         if (!strcmp(str, table[count]))
243             return true;
244     return false;
245 }
246 
FindBool(const char str[],bool * value)247 bool SkParse::FindBool(const char str[], bool* value)
248 {
249     static const char* gYes[] = { "yes", "1", "true" };
250     static const char* gNo[] = { "no", "0", "false" };
251 
252     if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes)))
253     {
254         if (value) *value = true;
255         return true;
256     }
257     else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo)))
258     {
259         if (value) *value = false;
260         return true;
261     }
262     return false;
263 }
264 
FindList(const char target[],const char list[])265 int SkParse::FindList(const char target[], const char list[])
266 {
267     size_t  len = strlen(target);
268     int     index = 0;
269 
270     for (;;)
271     {
272         const char* end = strchr(list, ',');
273         size_t      entryLen;
274 
275         if (end == nullptr) // last entry
276             entryLen = strlen(list);
277         else
278             entryLen = end - list;
279 
280         if (entryLen == len && memcmp(target, list, len) == 0)
281             return index;
282         if (end == nullptr)
283             break;
284 
285         list = end + 1; // skip the ','
286         index += 1;
287     }
288     return -1;
289 }
290 
291 #ifdef SK_SUPPORT_UNITTEST
UnitTest()292 void SkParse::UnitTest()
293 {
294     // !!! additional parse tests go here
295     SkParse::TestColor();
296 }
297 #endif
298