summaryrefslogtreecommitdiff
path: root/src/utils/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/utils.c')
-rw-r--r--src/utils/utils.c122
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;
+}
+