Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of LibCSS.
  3.  * Licensed under the MIT License,
  4.  *                http://www.opensource.org/licenses/mit-license.php
  5.  * Copyright 2007-9 John-Mark Bell <jmb@netsurf-browser.org>
  6.  */
  7.  
  8. #include "utils/utils.h"
  9.  
  10. css_fixed css__number_from_lwc_string(lwc_string *string,
  11.                 bool int_only, size_t *consumed)
  12. {
  13.         if (string == NULL || lwc_string_length(string) == 0 ||
  14.                         consumed == NULL)
  15.                 return 0;
  16.  
  17.         return css__number_from_string(
  18.                         (uint8_t *)lwc_string_data(string),
  19.                         lwc_string_length(string),
  20.                         int_only,
  21.                         consumed);
  22. }
  23.  
  24. css_fixed css__number_from_string(const uint8_t *data, size_t len,
  25.                 bool int_only, size_t *consumed)
  26. {
  27.         const uint8_t *ptr = data;
  28.         int sign = 1;
  29.         int32_t intpart = 0;
  30.         int32_t fracpart = 0;
  31.         int32_t pwr = 1;
  32.  
  33.         if (data == NULL || len == 0 || consumed == NULL)
  34.                 return 0;
  35.  
  36.         /* number = [+-]? ([0-9]+ | [0-9]* '.' [0-9]+) */
  37.  
  38.         /* Extract sign, if any */
  39.         if (ptr[0] == '-') {
  40.                 sign = -1;
  41.                 len--;
  42.                 ptr++;
  43.         } else if (ptr[0] == '+') {
  44.                 len--;
  45.                 ptr++;
  46.         }
  47.  
  48.         /* Ensure we have either a digit or a '.' followed by a digit */
  49.         if (len == 0) {
  50.                 *consumed = 0;
  51.                 return 0;
  52.         } else {
  53.                 if (ptr[0] == '.') {
  54.                         if (len == 1 || ptr[1] < '0' || '9' < ptr[1]) {
  55.                                 *consumed = 0;
  56.                                 return 0;
  57.                         }
  58.                 } else if (ptr[0] < '0' || '9' < ptr[0]) {
  59.                         *consumed = 0;
  60.                         return 0;
  61.                 }
  62.         }
  63.  
  64.         /* Now extract intpart, assuming base 10 */
  65.         while (len > 0) {
  66.                 /* Stop on first non-digit */
  67.                 if (ptr[0] < '0' || '9' < ptr[0])
  68.                         break;
  69.  
  70.                 /* Prevent overflow of 'intpart'; proper clamping below */
  71.                 if (intpart < (1 << 22)) {
  72.                         intpart *= 10;
  73.                         intpart += ptr[0] - '0';
  74.                 }
  75.                 ptr++;
  76.                 len--;
  77.         }
  78.  
  79.         /* And fracpart, again, assuming base 10 */
  80.         if (int_only == false && len > 1 && ptr[0] == '.' &&
  81.                         ('0' <= ptr[1] && ptr[1] <= '9')) {
  82.                 ptr++;
  83.                 len--;
  84.  
  85.                 while (len > 0) {
  86.                         if (ptr[0] < '0' || '9' < ptr[0])
  87.                                 break;
  88.  
  89.                         if (pwr < 1000000) {
  90.                                 pwr *= 10;
  91.                                 fracpart *= 10;
  92.                                 fracpart += ptr[0] - '0';
  93.                         }
  94.                         ptr++;
  95.                         len--;
  96.                 }
  97.                 fracpart = ((1 << 10) * fracpart + pwr/2) / pwr;
  98.                 if (fracpart >= (1 << 10)) {
  99.                         intpart++;
  100.                         fracpart &= (1 << 10) - 1;
  101.                 }
  102.         }
  103.  
  104.         *consumed = ptr - data;
  105.  
  106.         if (sign > 0) {
  107.                 /* If the result is larger than we can represent,
  108.                  * then clamp to the maximum value we can store. */
  109.                 if (intpart >= (1 << 21)) {
  110.                         intpart = (1 << 21) - 1;
  111.                         fracpart = (1 << 10) - 1;
  112.                 }
  113.         }
  114.         else {
  115.                 /* If the negated result is smaller than we can represent
  116.                  * then clamp to the minimum value we can store. */
  117.                 if (intpart >= (1 << 21)) {
  118.                         intpart = -(1 << 21);
  119.                         fracpart = 0;
  120.                 }
  121.                 else {
  122.                         intpart = -intpart;
  123.                         if (fracpart) {
  124.                                 fracpart = (1 << 10) - fracpart;
  125.                                 intpart--;
  126.                         }
  127.                 }
  128.         }
  129.  
  130.         return (intpart << 10) | fracpart;
  131. }
  132.  
  133.