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