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 #include "include/core/SkScalar.h"
9 #include "include/core/SkTypes.h"
10 #include "include/private/base/SkTo.h"
11 #include "include/utils/SkParse.h"
12
13 #include <cstdint>
14 #include <cstdlib>
15 #include <cstring>
16 #include <limits>
17 #include <string>
18
is_between(int c,int min,int max)19 static inline bool is_between(int c, int min, int max)
20 {
21 return (unsigned)(c - min) <= (unsigned)(max - min);
22 }
23
is_ws(int c)24 static inline bool is_ws(int c)
25 {
26 return is_between(c, 1, 32);
27 }
28
is_digit(int c)29 static inline bool is_digit(int c)
30 {
31 return is_between(c, '0', '9');
32 }
33
is_sep(int c)34 static inline bool is_sep(int c)
35 {
36 return is_ws(c) || c == ',' || c == ';';
37 }
38
to_hex(int c)39 static int to_hex(int c)
40 {
41 if (is_digit(c))
42 return c - '0';
43
44 c |= 0x20; // make us lower-case
45 if (is_between(c, 'a', 'f'))
46 return c + 10 - 'a';
47 else
48 return -1;
49 }
50
is_hex(int c)51 static inline bool is_hex(int c)
52 {
53 return to_hex(c) >= 0;
54 }
55
skip_ws(const char str[])56 static const char* skip_ws(const char str[])
57 {
58 SkASSERT(str);
59 while (is_ws(*str))
60 str++;
61 return str;
62 }
63
skip_sep(const char str[])64 static const char* skip_sep(const char str[])
65 {
66 SkASSERT(str);
67 while (is_sep(*str))
68 str++;
69 return str;
70 }
71
Count(const char str[])72 int SkParse::Count(const char str[])
73 {
74 char c;
75 int count = 0;
76 goto skipLeading;
77 do {
78 count++;
79 do {
80 if ((c = *str++) == '\0')
81 goto goHome;
82 } while (is_sep(c) == false);
83 skipLeading:
84 do {
85 if ((c = *str++) == '\0')
86 goto goHome;
87 } while (is_sep(c));
88 } while (true);
89 goHome:
90 return count;
91 }
92
Count(const char str[],char separator)93 int SkParse::Count(const char str[], char separator)
94 {
95 char c;
96 int count = 0;
97 goto skipLeading;
98 do {
99 count++;
100 do {
101 if ((c = *str++) == '\0')
102 goto goHome;
103 } while (c != separator);
104 skipLeading:
105 do {
106 if ((c = *str++) == '\0')
107 goto goHome;
108 } while (c == separator);
109 } while (true);
110 goHome:
111 return count;
112 }
113
FindHex(const char str[],uint32_t * value)114 const char* SkParse::FindHex(const char str[], uint32_t* value)
115 {
116 SkASSERT(str);
117 str = skip_ws(str);
118
119 if (!is_hex(*str))
120 return nullptr;
121
122 uint32_t n = 0;
123 int max_digits = 8;
124 int digit;
125
126 while ((digit = to_hex(*str)) >= 0)
127 {
128 if (--max_digits < 0)
129 return nullptr;
130 n = (n << 4) | digit;
131 str += 1;
132 }
133
134 if (*str == 0 || is_ws(*str))
135 {
136 if (value)
137 *value = n;
138 return str;
139 }
140 return nullptr;
141 }
142
FindS32(const char str[],int32_t * value)143 const char* SkParse::FindS32(const char str[], int32_t* value)
144 {
145 SkASSERT(str);
146 str = skip_ws(str);
147
148 int sign = 1;
149 int64_t maxAbsValue = std::numeric_limits<int>::max();
150 if (*str == '-')
151 {
152 sign = -1;
153 maxAbsValue = -static_cast<int64_t>(std::numeric_limits<int>::min());
154 str += 1;
155 }
156
157 if (!is_digit(*str)) {
158 return nullptr;
159 }
160
161 int64_t n = 0;
162 while (is_digit(*str))
163 {
164 n = 10*n + *str - '0';
165 if (n > maxAbsValue) {
166 return nullptr;
167 }
168
169 str += 1;
170 }
171 if (value) {
172 *value = SkToS32(sign*n);
173 }
174 return str;
175 }
176
FindScalar(const char str[],SkScalar * value)177 const char* SkParse::FindScalar(const char str[], SkScalar* value) {
178 SkASSERT(str);
179 str = skip_ws(str);
180
181 char* stop;
182 float v = (float)strtod(str, &stop);
183 if (str == stop) {
184 return nullptr;
185 }
186 if (value) {
187 *value = v;
188 }
189 return stop;
190 }
191
FindScalars(const char str[],SkScalar value[],int count)192 const char* SkParse::FindScalars(const char str[], SkScalar value[], int count)
193 {
194 SkASSERT(count >= 0);
195
196 if (count > 0)
197 {
198 for (;;)
199 {
200 str = SkParse::FindScalar(str, value);
201 if (--count == 0 || str == nullptr)
202 break;
203
204 // keep going
205 str = skip_sep(str);
206 if (value)
207 value += 1;
208 }
209 }
210 return str;
211 }
212
lookup_str(const char str[],const char ** table,int count)213 static bool lookup_str(const char str[], const char** table, int count)
214 {
215 while (--count >= 0)
216 if (!strcmp(str, table[count]))
217 return true;
218 return false;
219 }
220
FindBool(const char str[],bool * value)221 bool SkParse::FindBool(const char str[], bool* value)
222 {
223 static const char* gYes[] = { "yes", "1", "true" };
224 static const char* gNo[] = { "no", "0", "false" };
225
226 if (lookup_str(str, gYes, std::size(gYes)))
227 {
228 if (value) *value = true;
229 return true;
230 }
231 else if (lookup_str(str, gNo, std::size(gNo)))
232 {
233 if (value) *value = false;
234 return true;
235 }
236 return false;
237 }
238
FindList(const char target[],const char list[])239 int SkParse::FindList(const char target[], const char list[])
240 {
241 size_t len = strlen(target);
242 int index = 0;
243
244 for (;;)
245 {
246 const char* end = strchr(list, ',');
247 size_t entryLen;
248
249 if (end == nullptr) // last entry
250 entryLen = strlen(list);
251 else
252 entryLen = end - list;
253
254 if (entryLen == len && memcmp(target, list, len) == 0)
255 return index;
256 if (end == nullptr)
257 break;
258
259 list = end + 1; // skip the ','
260 index += 1;
261 }
262 return -1;
263 }
264