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