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 14 static inline bool is_between(int c, int min, int max) 15 { 16 return (unsigned)(c - min) <= (unsigned)(max - min); 17 } 18 19 static inline bool is_ws(int c) 20 { 21 return is_between(c, 1, 32); 22 } 23 24 static inline bool is_digit(int c) 25 { 26 return is_between(c, '0', '9'); 27 } 28 29 static inline bool is_sep(int c) 30 { 31 return is_ws(c) || c == ',' || c == ';'; 32 } 33 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 46 static inline bool is_hex(int c) 47 { 48 return to_hex(c) >= 0; 49 } 50 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 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 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 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 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 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 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 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 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 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 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 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 292 void SkParse::UnitTest() 293 { 294 // !!! additional parse tests go here 295 SkParse::TestColor(); 296 } 297 #endif 298