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 13static inline bool is_between(int c, int min, int max) 14{ 15 return (unsigned)(c - min) <= (unsigned)(max - min); 16} 17 18static inline bool is_ws(int c) 19{ 20 return is_between(c, 1, 32); 21} 22 23static inline bool is_digit(int c) 24{ 25 return is_between(c, '0', '9'); 26} 27 28static inline bool is_sep(int c) 29{ 30 return is_ws(c) || c == ',' || c == ';'; 31} 32 33static 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 45static inline bool is_hex(int c) 46{ 47 return to_hex(c) >= 0; 48} 49 50static const char* skip_ws(const char str[]) 51{ 52 SkASSERT(str); 53 while (is_ws(*str)) 54 str++; 55 return str; 56} 57 58static const char* skip_sep(const char str[]) 59{ 60 SkASSERT(str); 61 while (is_sep(*str)) 62 str++; 63 return str; 64} 65 66int 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); 77skipLeading: 78 do { 79 if ((c = *str++) == '\0') 80 goto goHome; 81 } while (is_sep(c)); 82 } while (true); 83goHome: 84 return count; 85} 86 87int 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); 98skipLeading: 99 do { 100 if ((c = *str++) == '\0') 101 goto goHome; 102 } while (c == separator); 103 } while (true); 104goHome: 105 return count; 106} 107 108const 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 137const 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 163const 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 202const 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 217const 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 238static 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 246bool 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 264int 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 291void SkParse::UnitTest() 292{ 293 // !!! additional parse tests go here 294 SkParse::TestColor(); 295} 296#endif 297