diff options
Diffstat (limited to 'libs/graphics/xml/SkParse.cpp')
-rw-r--r-- | libs/graphics/xml/SkParse.cpp | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/libs/graphics/xml/SkParse.cpp b/libs/graphics/xml/SkParse.cpp new file mode 100644 index 0000000000..b7d312c1af --- /dev/null +++ b/libs/graphics/xml/SkParse.cpp @@ -0,0 +1,319 @@ +#include "SkParse.h" + +static inline bool is_between(int c, int min, int max) +{ + return (unsigned)(c - min) <= (unsigned)(max - min); +} + +static inline bool is_ws(int c) +{ + return is_between(c, 1, 32); +} + +static inline bool is_digit(int c) +{ + return is_between(c, '0', '9'); +} + +static inline bool is_sep(int c) +{ + return is_ws(c) || c == ',' || c == ';'; +} + +static int to_hex(int c) +{ + if (is_digit(c)) + return c - '0'; + + c |= 0x20; // make us lower-case + if (is_between(c, 'a', 'f')) + return c + 10 - 'a'; + else + return -1; +} + +static inline bool is_hex(int c) +{ + return to_hex(c) >= 0; +} + +static const char* skip_ws(const char str[]) +{ + SkASSERT(str); + while (is_ws(*str)) + str++; + return str; +} + +static const char* skip_sep(const char str[]) +{ + SkASSERT(str); + while (is_sep(*str)) + str++; + return str; +} + +int SkParse::Count(const char str[]) +{ + char c; + int count = 0; + goto skipLeading; + do { + count++; + do { + if ((c = *str++) == '\0') + goto goHome; + } while (is_sep(c) == false); +skipLeading: + do { + if ((c = *str++) == '\0') + goto goHome; + } while (is_sep(c)); + } while (true); +goHome: + return count; +} + +int SkParse::Count(const char str[], char separator) +{ + char c; + int count = 0; + goto skipLeading; + do { + count++; + do { + if ((c = *str++) == '\0') + goto goHome; + } while (c != separator); +skipLeading: + do { + if ((c = *str++) == '\0') + goto goHome; + } while (c == separator); + } while (true); +goHome: + return count; +} + +const char* SkParse::FindHex(const char str[], uint32_t* value) +{ + SkASSERT(str); + str = skip_ws(str); + + if (!is_hex(*str)) + return nil; + + U32 n = 0; + int max_digits = 8; + int digit; + + while ((digit = to_hex(*str)) >= 0) + { + if (--max_digits < 0) + return nil; + n = (n << 4) | digit; + str += 1; + } + + if (*str == 0 || is_ws(*str)) + { + if (value) + *value = n; + return str; + } + return false; +} + +const char* SkParse::FindS32(const char str[], int32_t* value) +{ + SkASSERT(str); + str = skip_ws(str); + + int sign = 0; + if (*str == '-') + { + sign = -1; + str += 1; + } + + if (!is_digit(*str)) + return nil; + + int n = 0; + while (is_digit(*str)) + { + n = 10*n + *str - '0'; + str += 1; + } + if (value) + *value = (n ^ sign) - sign; + return str; +} + +const char* SkParse::FindMSec(const char str[], SkMSec* value) +{ + SkASSERT(str); + str = skip_ws(str); + + int sign = 0; + if (*str == '-') + { + sign = -1; + str += 1; + } + + if (!is_digit(*str)) + return nil; + + int n = 0; + while (is_digit(*str)) + { + n = 10*n + *str - '0'; + str += 1; + } + int remaining10s = 3; + if (*str == '.') { + str++; + while (is_digit(*str)) + { + n = 10*n + *str - '0'; + str += 1; + if (--remaining10s == 0) + break; + } + } + while (--remaining10s >= 0) + n *= 10; + if (value) + *value = (n ^ sign) - sign; + return str; +} + +const char* SkParse::FindScalar(const char str[], SkScalar* value) +{ + SkASSERT(str); + str = skip_ws(str); + + int sign = 0; + if (*str == '-') + { + sign = -1; + str += 1; + } + + if (!is_digit(*str) && *str != '.') + return nil; + + int n = 0; + while (is_digit(*str)) + { + n = 10*n + *str - '0'; + if (n > 0x7FFF) + return nil; + str += 1; + } + n <<= 16; + + if (*str == '.') + { + static const int gFractions[] = { (1 << 24) / 10, (1 << 24) / 100, (1 << 24) / 1000, + (1 << 24) / 10000, (1 << 24) / 100000 }; + str += 1; + int d = 0; + const int* fraction = gFractions; + const int* end = &fraction[SK_ARRAY_COUNT(gFractions)]; + while (is_digit(*str) && fraction < end) + d += (*str++ - '0') * *fraction++; + d += 0x80; // round + n += d >> 8; + } + while (is_digit(*str)) + str += 1; + if (value) + { + n = (n ^ sign) - sign; // apply the sign + *value = SkFixedToScalar(n); + } + return str; +} + +const char* SkParse::FindScalars(const char str[], SkScalar value[], int count) +{ + SkASSERT(count >= 0); + + if (count > 0) + { + for (;;) + { + str = SkParse::FindScalar(str, value); + if (--count == 0 || str == nil) + break; + + // keep going + str = skip_sep(str); + if (value) + value += 1; + } + } + return str; +} + +static bool lookup_str(const char str[], const char** table, int count) +{ + while (--count >= 0) + if (!strcmp(str, table[count])) + return true; + return false; +} + +bool SkParse::FindBool(const char str[], bool* value) +{ + static const char* gYes[] = { "yes", "1", "true" }; + static const char* gNo[] = { "no", "0", "false" }; + + if (lookup_str(str, gYes, SK_ARRAY_COUNT(gYes))) + { + if (value) *value = true; + return true; + } + else if (lookup_str(str, gNo, SK_ARRAY_COUNT(gNo))) + { + if (value) *value = false; + return true; + } + return false; +} + +int SkParse::FindList(const char target[], const char list[]) +{ + size_t len = strlen(target); + int index = 0; + + for (;;) + { + const char* end = strchr(list, ','); + size_t entryLen; + + if (end == nil) // last entry + entryLen = strlen(list); + else + entryLen = end - list; + + if (entryLen == len && memcmp(target, list, len) == 0) + return index; + if (end == nil) + break; + + list = end + 1; // skip the ',' + index += 1; + } + return -1; +} + +#ifdef SK_SUPPORT_UNITTEST +void SkParse::UnitTest() +{ + // !!! additional parse tests go here + SkParse::TestColor(); +} +#endif |