diff options
author | John Mark Bell <jmb@netsurf-browser.org> | 2009-02-14 19:24:40 +0000 |
---|---|---|
committer | John Mark Bell <jmb@netsurf-browser.org> | 2009-02-14 19:24:40 +0000 |
commit | ca3293e0332bbd9fe63d6cd6bc215f048132bd08 (patch) | |
tree | 29065b3081e1df0bbb274dbe8647e6494c76ab64 /src/utils/utils.c | |
parent | 0068331a1d6989ef523fca0753bd9ad943232cdf (diff) | |
download | libcss-ca3293e0332bbd9fe63d6cd6bc215f048132bd08.tar.gz libcss-ca3293e0332bbd9fe63d6cd6bc215f048132bd08.tar.bz2 |
Make fpmath stuff public.
Un-inline string->fixed conversion routine.
svn path=/trunk/libcss/; revision=6513
Diffstat (limited to 'src/utils/utils.c')
-rw-r--r-- | src/utils/utils.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/utils/utils.c b/src/utils/utils.c new file mode 100644 index 0000000..a8d0cb5 --- /dev/null +++ b/src/utils/utils.c @@ -0,0 +1,122 @@ +/* + * This file is part of LibCSS. + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + * Copyright 2007-9 John-Mark Bell <jmb@netsurf-browser.org> + */ + +#include "utils/utils.h" + +css_fixed number_from_css_string(const css_string *string, + bool int_only, size_t *consumed) +{ + size_t len; + const uint8_t *ptr; + int sign = 1; + int32_t intpart = 0; + int32_t fracpart = 0; + int32_t pwr = 1; + + if (string == NULL || string->len == 0 || consumed == NULL) + return 0; + + len = string->len; + ptr = string->data; + + /* number = [+-]? ([0-9]+ | [0-9]* '.' [0-9]+) */ + + /* Extract sign, if any */ + if (ptr[0] == '-') { + sign = -1; + len--; + ptr++; + } else if (ptr[0] == '+') { + len--; + ptr++; + } + + /* Ensure we have either a digit or a '.' followed by a digit */ + if (len == 0) { + *consumed = 0; + return 0; + } else { + if (ptr[0] == '.') { + if (len == 1 || ptr[1] < '0' || '9' < ptr[1]) { + *consumed = 0; + return 0; + } + } else if (ptr[0] < '0' || '9' < ptr[0]) { + *consumed = 0; + return 0; + } + } + + /* Now extract intpart, assuming base 10 */ + while (len > 0) { + /* Stop on first non-digit */ + if (ptr[0] < '0' || '9' < ptr[0]) + break; + + /* Prevent overflow of 'intpart'; proper clamping below */ + if (intpart < (1 << 22)) { + intpart *= 10; + intpart += ptr[0] - '0'; + } + ptr++; + len--; + } + + /* And fracpart, again, assuming base 10 */ + if (int_only == false && len > 1 && ptr[0] == '.' && + ('0' <= ptr[1] && ptr[1] <= '9')) { + ptr++; + len--; + + while (len > 0) { + if (ptr[0] < '0' || '9' < ptr[0]) + break; + + if (pwr < 1000000) { + pwr *= 10; + fracpart *= 10; + fracpart += ptr[0] - '0'; + } + ptr++; + len--; + } + fracpart = ((1 << 10) * fracpart + pwr/2) / pwr; + if (fracpart >= (1 << 10)) { + intpart++; + fracpart &= (1 << 10) - 1; + } + } + + *consumed = ptr - string->data; + + if (sign > 0) { + /* If the result is larger than we can represent, + * then clamp to the maximum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = (1 << 21) - 1; + fracpart = (1 << 10) - 1; + } + } + else { + /* If the negated result is smaller than we can represent + * then clamp to the minimum value we can store. */ + if (intpart >= (1 << 21)) { + intpart = -(1 << 21); + fracpart = 0; + } + else { + intpart = -intpart; + if (fracpart) { + fracpart = (1 << 10) - fracpart; + intpart--; + } + } + } + + return (intpart << 10) | fracpart; +} + |