michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkParse.h" michael@0: michael@0: static inline bool is_between(int c, int min, int max) michael@0: { michael@0: return (unsigned)(c - min) <= (unsigned)(max - min); michael@0: } michael@0: michael@0: static inline bool is_ws(int c) michael@0: { michael@0: return is_between(c, 1, 32); michael@0: } michael@0: michael@0: static inline bool is_digit(int c) michael@0: { michael@0: return is_between(c, '0', '9'); michael@0: } michael@0: michael@0: static inline bool is_sep(int c) michael@0: { michael@0: return is_ws(c) || c == ',' || c == ';'; michael@0: } michael@0: michael@0: static int to_hex(int c) michael@0: { michael@0: if (is_digit(c)) michael@0: return c - '0'; michael@0: michael@0: c |= 0x20; // make us lower-case michael@0: if (is_between(c, 'a', 'f')) michael@0: return c + 10 - 'a'; michael@0: else michael@0: return -1; michael@0: } michael@0: michael@0: static inline bool is_hex(int c) michael@0: { michael@0: return to_hex(c) >= 0; michael@0: } michael@0: michael@0: static const char* skip_ws(const char str[]) michael@0: { michael@0: SkASSERT(str); michael@0: while (is_ws(*str)) michael@0: str++; michael@0: return str; michael@0: } michael@0: michael@0: static const char* skip_sep(const char str[]) michael@0: { michael@0: SkASSERT(str); michael@0: while (is_sep(*str)) michael@0: str++; michael@0: return str; michael@0: } michael@0: michael@0: int SkParse::Count(const char str[]) michael@0: { michael@0: char c; michael@0: int count = 0; michael@0: goto skipLeading; michael@0: do { michael@0: count++; michael@0: do { michael@0: if ((c = *str++) == '\0') michael@0: goto goHome; michael@0: } while (is_sep(c) == false); michael@0: skipLeading: michael@0: do { michael@0: if ((c = *str++) == '\0') michael@0: goto goHome; michael@0: } while (is_sep(c)); michael@0: } while (true); michael@0: goHome: michael@0: return count; michael@0: } michael@0: michael@0: int SkParse::Count(const char str[], char separator) michael@0: { michael@0: char c; michael@0: int count = 0; michael@0: goto skipLeading; michael@0: do { michael@0: count++; michael@0: do { michael@0: if ((c = *str++) == '\0') michael@0: goto goHome; michael@0: } while (c != separator); michael@0: skipLeading: michael@0: do { michael@0: if ((c = *str++) == '\0') michael@0: goto goHome; michael@0: } while (c == separator); michael@0: } while (true); michael@0: goHome: michael@0: return count; michael@0: } michael@0: michael@0: const char* SkParse::FindHex(const char str[], uint32_t* value) michael@0: { michael@0: SkASSERT(str); michael@0: str = skip_ws(str); michael@0: michael@0: if (!is_hex(*str)) michael@0: return NULL; michael@0: michael@0: uint32_t n = 0; michael@0: int max_digits = 8; michael@0: int digit; michael@0: michael@0: while ((digit = to_hex(*str)) >= 0) michael@0: { michael@0: if (--max_digits < 0) michael@0: return NULL; michael@0: n = (n << 4) | digit; michael@0: str += 1; michael@0: } michael@0: michael@0: if (*str == 0 || is_ws(*str)) michael@0: { michael@0: if (value) michael@0: *value = n; michael@0: return str; michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: const char* SkParse::FindS32(const char str[], int32_t* value) michael@0: { michael@0: SkASSERT(str); michael@0: str = skip_ws(str); michael@0: michael@0: int sign = 0; michael@0: if (*str == '-') michael@0: { michael@0: sign = -1; michael@0: str += 1; michael@0: } michael@0: michael@0: if (!is_digit(*str)) michael@0: return NULL; michael@0: michael@0: int n = 0; michael@0: while (is_digit(*str)) michael@0: { michael@0: n = 10*n + *str - '0'; michael@0: str += 1; michael@0: } michael@0: if (value) michael@0: *value = (n ^ sign) - sign; michael@0: return str; michael@0: } michael@0: michael@0: const char* SkParse::FindMSec(const char str[], SkMSec* value) michael@0: { michael@0: SkASSERT(str); michael@0: str = skip_ws(str); michael@0: michael@0: int sign = 0; michael@0: if (*str == '-') michael@0: { michael@0: sign = -1; michael@0: str += 1; michael@0: } michael@0: michael@0: if (!is_digit(*str)) michael@0: return NULL; michael@0: michael@0: int n = 0; michael@0: while (is_digit(*str)) michael@0: { michael@0: n = 10*n + *str - '0'; michael@0: str += 1; michael@0: } michael@0: int remaining10s = 3; michael@0: if (*str == '.') { michael@0: str++; michael@0: while (is_digit(*str)) michael@0: { michael@0: n = 10*n + *str - '0'; michael@0: str += 1; michael@0: if (--remaining10s == 0) michael@0: break; michael@0: } michael@0: } michael@0: while (--remaining10s >= 0) michael@0: n *= 10; michael@0: if (value) michael@0: *value = (n ^ sign) - sign; michael@0: return str; michael@0: } michael@0: michael@0: const char* SkParse::FindScalar(const char str[], SkScalar* value) { michael@0: SkASSERT(str); michael@0: str = skip_ws(str); michael@0: michael@0: char* stop; michael@0: float v = (float)strtod(str, &stop); michael@0: if (str == stop) { michael@0: return NULL; michael@0: } michael@0: if (value) { michael@0: *value = v; michael@0: } michael@0: return stop; michael@0: } michael@0: michael@0: const char* SkParse::FindScalars(const char str[], SkScalar value[], int count) michael@0: { michael@0: SkASSERT(count >= 0); michael@0: michael@0: if (count > 0) michael@0: { michael@0: for (;;) michael@0: { michael@0: str = SkParse::FindScalar(str, value); michael@0: if (--count == 0 || str == NULL) michael@0: break; michael@0: michael@0: // keep going michael@0: str = skip_sep(str); michael@0: if (value) michael@0: value += 1; michael@0: } michael@0: } michael@0: return str; michael@0: } michael@0: michael@0: static bool lookup_str(const char str[], const char** table, int count) michael@0: { michael@0: while (--count >= 0) michael@0: if (!strcmp(str, table[count])) michael@0: return true; michael@0: return false; michael@0: } michael@0: michael@0: bool SkParse::FindBool(const char str[], bool* value) michael@0: { michael@0: static const char* gYes[] = { "yes", "1", "true" }; michael@0: static const char* gNo[] = { "no", "0", "false" }; michael@0: michael@0: if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes))) michael@0: { michael@0: if (value) *value = true; michael@0: return true; michael@0: } michael@0: else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo))) michael@0: { michael@0: if (value) *value = false; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: int SkParse::FindList(const char target[], const char list[]) michael@0: { michael@0: size_t len = strlen(target); michael@0: int index = 0; michael@0: michael@0: for (;;) michael@0: { michael@0: const char* end = strchr(list, ','); michael@0: size_t entryLen; michael@0: michael@0: if (end == NULL) // last entry michael@0: entryLen = strlen(list); michael@0: else michael@0: entryLen = end - list; michael@0: michael@0: if (entryLen == len && memcmp(target, list, len) == 0) michael@0: return index; michael@0: if (end == NULL) michael@0: break; michael@0: michael@0: list = end + 1; // skip the ',' michael@0: index += 1; michael@0: } michael@0: return -1; michael@0: } michael@0: michael@0: #ifdef SK_SUPPORT_UNITTEST michael@0: void SkParse::UnitTest() michael@0: { michael@0: // !!! additional parse tests go here michael@0: SkParse::TestColor(); michael@0: } michael@0: #endif