Home | History | Annotate | Download | only in utils
      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