xref: /aosp_15_r20/external/skia/src/utils/SkParse.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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