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
css__number_from_lwc_string(lwc_string * string,bool int_only,size_t * consumed)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
css__number_from_string(const uint8_t * data,size_t len,bool int_only,size_t * consumed)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 ((uint32_t)intpart << 10) | fracpart;
131 }
132
133