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