]> gitweb.michael.orlitzky.com - libsvgtiny.git/commitdiff
Cleanup length parsing
authorVincent Sanders <vince@kyllikki.org>
Sat, 15 Jun 2024 14:41:07 +0000 (15:41 +0100)
committerVincent Sanders <vince@kyllikki.org>
Mon, 24 Jun 2024 08:57:24 +0000 (09:57 +0100)
remove the incorrect use of atof and use an API that does not require the string to be copied to terminate with a null

src/svgtiny.c
src/svgtiny_gradient.c
src/svgtiny_internal.h
src/svgtiny_parse.c

index a450985086ad3fe0a8f5624d6c04e551158e7614..61909a2d9b09827a2094b542730451dbd89e8705 100644 (file)
@@ -1294,7 +1294,10 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               x = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &x);
        }
        dom_string_unref(attr);
 
@@ -1304,7 +1307,10 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               y = svgtiny_parse_length(attr, state.viewport_height, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_height,
+                                    &y);
        }
        dom_string_unref(attr);
 
@@ -1314,7 +1320,10 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               r = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &r);
        }
        dom_string_unref(attr);
 
@@ -1400,7 +1409,10 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               x = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &x);
        }
        dom_string_unref(attr);
 
@@ -1410,7 +1422,10 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               y = svgtiny_parse_length(attr, state.viewport_height, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_height,
+                                    &y);
        }
        dom_string_unref(attr);
 
@@ -1420,7 +1435,10 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               rx = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &rx);
        }
        dom_string_unref(attr);
 
@@ -1430,7 +1448,10 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               ry = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &ry);
        }
        dom_string_unref(attr);
 
@@ -1517,7 +1538,10 @@ svgtiny_code svgtiny_parse_line(dom_element *line,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               x1 = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &x1);
        }
        dom_string_unref(attr);
 
@@ -1527,7 +1551,10 @@ svgtiny_code svgtiny_parse_line(dom_element *line,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               y1 = svgtiny_parse_length(attr, state.viewport_height, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_height,
+                                    &y1);
        }
        dom_string_unref(attr);
 
@@ -1537,7 +1564,10 @@ svgtiny_code svgtiny_parse_line(dom_element *line,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               x2 = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    &x2);
        }
        dom_string_unref(attr);
 
@@ -1547,7 +1577,10 @@ svgtiny_code svgtiny_parse_line(dom_element *line,
                return svgtiny_LIBDOM_ERROR;
        }
        if (attr != NULL) {
-               y2 = svgtiny_parse_length(attr, state.viewport_height, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_height,
+                                    &y2);
        }
        dom_string_unref(attr);
 
@@ -1769,84 +1802,45 @@ void svgtiny_parse_position_attributes(dom_element *node,
 
        exc = dom_element_get_attribute(node, state.interned_x, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               *x = svgtiny_parse_length(attr, state.viewport_width, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    x);
                dom_string_unref(attr);
        }
 
        exc = dom_element_get_attribute(node, state.interned_y, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               *y = svgtiny_parse_length(attr, state.viewport_height, state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_height,
+                                    y);
                dom_string_unref(attr);
        }
 
        exc = dom_element_get_attribute(node, state.interned_width, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               *width = svgtiny_parse_length(attr, state.viewport_width,
-                                             state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_width,
+                                    width);
                dom_string_unref(attr);
        }
 
        exc = dom_element_get_attribute(node, state.interned_height, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               *height = svgtiny_parse_length(attr, state.viewport_height,
-                                              state);
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state.viewport_height,
+                                    height);
                dom_string_unref(attr);
        }
 }
 
 
-/**
- * Parse a length as a number of pixels.
- */
-
-static float _svgtiny_parse_length(const char *s, int viewport_size,
-                                  const struct svgtiny_parse_state state)
-{
-       int num_length = strspn(s, "0123456789+-.");
-       const char *unit = s + num_length;
-       float n = atof((const char *) s);
-       float font_size = 20; /*css_len2px(&state.style.font_size.value.length, 0);*/
-
-       UNUSED(state);
-
-       if (unit[0] == 0) {
-               return n;
-       } else if (unit[0] == '%') {
-               return n / 100.0 * viewport_size;
-       } else if (unit[0] == 'e' && unit[1] == 'm') {
-               return n * font_size;
-       } else if (unit[0] == 'e' && unit[1] == 'x') {
-               return n / 2.0 * font_size;
-       } else if (unit[0] == 'p' && unit[1] == 'x') {
-               return n;
-       } else if (unit[0] == 'p' && unit[1] == 't') {
-               return n * 1.25;
-       } else if (unit[0] == 'p' && unit[1] == 'c') {
-               return n * 15.0;
-       } else if (unit[0] == 'm' && unit[1] == 'm') {
-               return n * 3.543307;
-       } else if (unit[0] == 'c' && unit[1] == 'm') {
-               return n * 35.43307;
-       } else if (unit[0] == 'i' && unit[1] == 'n') {
-               return n * 90;
-       }
-
-       return 0;
-}
-
-float svgtiny_parse_length(dom_string *s, int viewport_size,
-                          const struct svgtiny_parse_state state)
-{
-       char *ss = strndup(dom_string_data(s), dom_string_byte_length(s));
-       float ret = _svgtiny_parse_length(ss, viewport_size, state);
-       free(ss);
-       return ret;
-}
-
 /**
  * Parse paint attributes, if present.
  */
-
 void svgtiny_parse_paint_attributes(dom_element *node,
                struct svgtiny_parse_state *state)
 {
@@ -1867,8 +1861,12 @@ void svgtiny_parse_paint_attributes(dom_element *node,
 
        exc = dom_element_get_attribute(node, state->interned_stroke_width, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               state->stroke_width = svgtiny_parse_length(attr,
-                                               state->viewport_width, *state);
+               float stroke_width;
+               svgtiny_parse_length(dom_string_data(attr),
+                                    dom_string_byte_length(attr),
+                                    state->viewport_width,
+                                    &stroke_width);
+               state->stroke_width = stroke_width;
                dom_string_unref(attr);
        }
 
@@ -1896,12 +1894,12 @@ void svgtiny_parse_paint_attributes(dom_element *node,
                }
                if ((s = strstr(style, "stroke-width:"))) {
                        s += 13;
-                       while (*s == ' ')
-                               s++;
-                       value = strndup(s, strcspn(s, "; "));
-                       state->stroke_width = _svgtiny_parse_length(value,
-                                               state->viewport_width, *state);
-                       free(value);
+                       float stroke_width;
+                       svgtiny_parse_length(s,
+                                            strcspn(s, "; "),
+                                            state->viewport_width,
+                                            &stroke_width);
+                       state->stroke_width = stroke_width;
                }
                free(style);
                dom_string_unref(attr);
index 4b327ddbcc2045260bb35f2f590e0fcd99478be7..e7b122287f34b95a500ae9b6d5cbe7952222a5f7 100644 (file)
@@ -61,12 +61,12 @@ void svgtiny_find_gradient(const char *id,
        grad->gradient_transform.d = 1;
        grad->gradient_transform.e = 0;
        grad->gradient_transform.f = 0;
-       
+
        exc = dom_string_create_interned((const uint8_t *) id,
                        strlen(id), &id_str);
        if (exc != DOM_NO_ERR)
                return;
-       
+
        exc = dom_document_get_element_by_id(state->document, id_str,
                                             &gradient);
        dom_string_unref(id_str);
@@ -76,16 +76,16 @@ void svgtiny_find_gradient(const char *id,
                #endif
                return;
        }
-       
+
        exc = dom_node_get_node_name(gradient, &name);
        if (exc != DOM_NO_ERR) {
                dom_node_unref(gradient);
                return;
        }
-       
+
        if (dom_string_isequal(name, state->interned_linearGradient))
                svgtiny_parse_linear_gradient(gradient, grad, state);
-       
+
        dom_node_unref(gradient);
        dom_string_unref(name);
 
@@ -110,7 +110,7 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
        dom_string *attr;
        dom_exception exc;
        dom_nodelist *stops;
-       
+
        exc = dom_element_get_attribute(linear, state->interned_href, &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
                if (dom_string_data(attr)[0] == (uint8_t) '#') {
@@ -149,16 +149,16 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
                grad->gradient_y2 = attr;
                attr = NULL;
        }
-       
+
        exc = dom_element_get_attribute(linear, state->interned_gradientUnits,
                                        &attr);
        if (exc == DOM_NO_ERR && attr != NULL) {
-               grad->gradient_user_space_on_use = 
+               grad->gradient_user_space_on_use =
                        dom_string_isequal(attr,
                                           state->interned_userSpaceOnUse);
                dom_string_unref(attr);
        }
-       
+
        exc = dom_element_get_attribute(linear,
                                        state->interned_gradientTransform,
                                        &attr);
@@ -184,7 +184,7 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
                grad->gradient_transform.f = f;
                dom_string_unref(attr);
         }
-       
+
        exc = dom_element_get_elements_by_tag_name(linear,
                                                   state->interned_stop,
                                                   &stops);
@@ -195,7 +195,7 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
                        dom_nodelist_unref(stops);
                        goto no_more_stops;
                }
-               
+
                for (stopnr = 0; stopnr < listlen; ++stopnr) {
                        dom_element *stop;
                        float offset = -1;
@@ -261,7 +261,7 @@ svgtiny_code svgtiny_parse_linear_gradient(dom_element *linear,
                        if (i == svgtiny_MAX_STOPS)
                                break;
                }
-               
+
                dom_nodelist_unref(stops);
        }
 no_more_stops:
@@ -336,27 +336,46 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
        #endif
 
        if (!grad->gradient_user_space_on_use) {
-               gradient_x0 = object_x0 +
-                               svgtiny_parse_length(grad->gradient_x1,
-                                       object_x1 - object_x0, *state);
-               gradient_y0 = object_y0 +
-                               svgtiny_parse_length(grad->gradient_y1,
-                                       object_y1 - object_y0, *state);
-               gradient_x1 = object_x0 +
-                               svgtiny_parse_length(grad->gradient_x2,
-                                       object_x1 - object_x0, *state);
-               gradient_y1 = object_y0 +
-                               svgtiny_parse_length(grad->gradient_y2,
-                                       object_y1 - object_y0, *state);
+               svgtiny_parse_length(dom_string_data(grad->gradient_x1),
+                                    dom_string_byte_length(grad->gradient_x1),
+                                    object_x1 - object_x0,
+                                    &gradient_x0);
+               gradient_x0 += object_x0;
+
+               svgtiny_parse_length(dom_string_data(grad->gradient_y1),
+                                    dom_string_byte_length(grad->gradient_y1),
+                                    object_y1 - object_y0,
+                                    &gradient_y0);
+               gradient_y0 += object_y0;
+
+               svgtiny_parse_length(dom_string_data(grad->gradient_x2),
+                                    dom_string_byte_length(grad->gradient_x2),
+                                    object_x1 - object_x0,
+                                    &gradient_x1);
+               gradient_x1 += object_x0;
+
+               svgtiny_parse_length(dom_string_data(grad->gradient_y2),
+                                    dom_string_byte_length(grad->gradient_y2),
+                                    object_y1 - object_y0,
+                                    &gradient_y1);
+               gradient_y1 += object_y0;
        } else {
-               gradient_x0 = svgtiny_parse_length(grad->gradient_x1,
-                               state->viewport_width, *state);
-               gradient_y0 = svgtiny_parse_length(grad->gradient_y1,
-                               state->viewport_height, *state);
-               gradient_x1 = svgtiny_parse_length(grad->gradient_x2,
-                               state->viewport_width, *state);
-               gradient_y1 = svgtiny_parse_length(grad->gradient_y2,
-                               state->viewport_height, *state);
+               svgtiny_parse_length(dom_string_data(grad->gradient_x1),
+                                    dom_string_byte_length(grad->gradient_x1),
+                                    state->viewport_width,
+                                    &gradient_x0);
+               svgtiny_parse_length(dom_string_data(grad->gradient_y1),
+                                    dom_string_byte_length(grad->gradient_y1),
+                                    state->viewport_height,
+                                    &gradient_y0);
+               svgtiny_parse_length(dom_string_data(grad->gradient_x2),
+                                    dom_string_byte_length(grad->gradient_x2),
+                                    state->viewport_width,
+                                    &gradient_x1);
+               svgtiny_parse_length(dom_string_data(grad->gradient_y2),
+                                    dom_string_byte_length(grad->gradient_y2),
+                                    state->viewport_height,
+                                    &gradient_y1);
        }
        gradient_dx = gradient_x1 - gradient_x0;
        gradient_dy = gradient_y1 - gradient_y0;
@@ -559,7 +578,7 @@ svgtiny_code svgtiny_add_path_linear_gradient(float *p, unsigned int n,
 
             return svgtiny_OK;
         }
-        
+
        /* render triangles */
        stop_count = grad->linear_gradient_stop_count;
        assert(2 <= stop_count);
@@ -780,4 +799,3 @@ void svgtiny_invert_matrix(float *m, float *inv)
        inv[4] = (m[2]*m[5] - m[3]*m[4]) / determinant;
        inv[5] = (m[1]*m[4] - m[0]*m[5]) / determinant;
 }
-
index c04ae66597aa3cf16ac99bc7acddab2f452e4477..1f01f1f315e2ecec91ece9a5215261f8510ce279 100644 (file)
@@ -67,8 +67,6 @@ struct svgtiny_parse_state {
 struct svgtiny_list;
 
 /* svgtiny.c */
-float svgtiny_parse_length(dom_string *s, int viewport_size,
-               const struct svgtiny_parse_state state);
 void svgtiny_parse_color(dom_string *s, svgtiny_colour *c,
                struct svgtiny_parse_state_gradient *grad,
                struct svgtiny_parse_state *state);
@@ -88,6 +86,8 @@ char *svgtiny_strndup(const char *s, size_t n);
 /* svgtiny_parse.c */
 svgtiny_code svgtiny_parse_poly_points(const char *data, size_t datalen,
                float *pointv, unsigned int *pointc);
+svgtiny_code svgtiny_parse_length(const char *text, size_t textlen,
+               int viewport_size, float *length);
 
 /* svgtiny_gradient.c */
 void svgtiny_find_gradient(const char *id,
index 890ee1bb439e5885fc88af02d8a1fd8bb5f502c6..49cbf42946b185650582f59094be662429ce1ac3 100644 (file)
@@ -343,3 +343,79 @@ svgtiny_parse_poly_points(const char *text,
 
        return svgtiny_OK;
 }
+
+
+/**
+ * Parse a length as a number of pixels.
+ */
+svgtiny_code
+svgtiny_parse_length(const char *text,
+                    size_t textlen,
+                    int viewport_size,
+                    float *length)
+{
+       svgtiny_code err;
+       float number;
+       const char *unit = NULL;
+       int unitlen;
+       float font_size = 20; /*css_len2px(&state.style.font_size.value.length, 0);*/
+
+       err = svgtiny_parse_number(text, textlen, &unit, &number);
+       if (err != svgtiny_OK) {
+               unitlen = -1;
+       } else {
+               unitlen = (text + textlen) - unit;
+       }
+
+       /* discount whitespace on the end of the unit */
+       while(unitlen > 0) {
+               if ((unit[unitlen - 1] != 0x20) &&
+                   (unit[unitlen - 1] != 0x09) &&
+                   (unit[unitlen - 1] != 0x0A) &&
+                   (unit[unitlen - 1] != 0x0D)) {
+                       break;
+               }
+               unitlen--;
+       }
+
+       /* decode the unit */
+       *length = 0;
+       switch (unitlen) {
+       case 0:
+               /* no unit, assume pixels */
+               *length = number;
+               break;
+       case 1:
+               if (unit[0] == '%') {
+                       /* percentage of viewport */
+                       *length = number / 100.0 * viewport_size;
+               }
+               break;
+
+       case 2:
+               if (unit[0] == 'e' && unit[1] == 'm') {
+                       *length = number * font_size;
+               } else if (unit[0] == 'e' && unit[1] == 'x') {
+                       *length = number / 2.0 * font_size;
+               } else if (unit[0] == 'p' && unit[1] == 'x') {
+                       *length = number;
+               } else if (unit[0] == 'p' && unit[1] == 't') {
+                       *length = number * 1.25;
+               } else if (unit[0] == 'p' && unit[1] == 'c') {
+                       *length = number * 15.0;
+               } else if (unit[0] == 'm' && unit[1] == 'm') {
+                       *length = number * 3.543307;
+               } else if (unit[0] == 'c' && unit[1] == 'm') {
+                       *length = number * 35.43307;
+               } else if (unit[0] == 'i' && unit[1] == 'n') {
+                       *length = number * 90;
+               }
+               break;
+
+       default:
+               /* unknown unit */
+               break;
+       }
+
+       return svgtiny_OK;
+}