X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2Fsvgtiny.c;h=bd9aeaa89486ddc873249744feed390d78042801;hb=f293a45e808b444b5a3b8b989b76fdc20566d3c9;hp=137f2b065d9afed42440342a3c24d781e8bcf112;hpb=461d400085eba848898d74c92a820b5e3e1d6c49;p=libsvgtiny.git diff --git a/src/svgtiny.c b/src/svgtiny.c index 137f2b0..bd9aeaa 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -42,12 +42,12 @@ static svgtiny_code svgtiny_parse_poly(dom_element *poly, struct svgtiny_parse_state state, bool polygon); static svgtiny_code svgtiny_parse_text(dom_element *text, struct svgtiny_parse_state state); -static void svgtiny_parse_position_attributes(const dom_element *node, +static void svgtiny_parse_position_attributes(dom_element *node, const struct svgtiny_parse_state state, float *x, float *y, float *width, float *height); -static void svgtiny_parse_paint_attributes(const dom_element *node, +static void svgtiny_parse_paint_attributes(dom_element *node, struct svgtiny_parse_state *state); -static void svgtiny_parse_font_attributes(const dom_element *node, +static void svgtiny_parse_font_attributes(dom_element *node, struct svgtiny_parse_state *state); static void svgtiny_parse_transform_attributes(dom_element *node, struct svgtiny_parse_state *state); @@ -56,6 +56,52 @@ static svgtiny_code svgtiny_add_path(float *p, unsigned int n, static void _svgtiny_parse_color(const char *s, svgtiny_colour *c, struct svgtiny_parse_state *state); +/** + * Set the local externally-stored parts of a parse state. + * Call this in functions that made a new state on the stack. + * Doesn't make own copy of global state, such as the interned string list. + */ +static void svgtiny_setup_state_local(struct svgtiny_parse_state *state) +{ + if (state->gradient_x1 != NULL) { + dom_string_ref(state->gradient_x1); + } + if (state->gradient_y1 != NULL) { + dom_string_ref(state->gradient_y1); + } + if (state->gradient_x2 != NULL) { + dom_string_ref(state->gradient_x2); + } + if (state->gradient_y2 != NULL) { + dom_string_ref(state->gradient_y2); + } +} + +/** + * Cleanup the local externally-stored parts of a parse state. + * Call this in functions that made a new state on the stack. + * Doesn't cleanup global state, such as the interned string list. + */ +static void svgtiny_cleanup_state_local(struct svgtiny_parse_state *state) +{ + if (state->gradient_x1 != NULL) { + dom_string_unref(state->gradient_x1); + state->gradient_x1 = NULL; + } + if (state->gradient_y1 != NULL) { + dom_string_unref(state->gradient_y1); + state->gradient_y1 = NULL; + } + if (state->gradient_x2 != NULL) { + dom_string_unref(state->gradient_x2); + state->gradient_x2 = NULL; + } + if (state->gradient_y2 != NULL) { + dom_string_unref(state->gradient_y2); + state->gradient_y2 = NULL; + } +} + /** * Create a new svgtiny_diagram structure. @@ -106,6 +152,11 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, UNUSED(url); + state.gradient_x1 = NULL; + state.gradient_y1 = NULL; + state.gradient_x2 = NULL; + state.gradient_y2 = NULL; + parser = dom_xml_parser_create(NULL, NULL, ignore_msg, NULL, &document); @@ -137,6 +188,12 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, dom_node_unref(document); return svgtiny_LIBDOM_ERROR; } + if (svg == NULL) { + /* no root svg element */ + dom_node_unref(document); + return svgtiny_SVG_ERROR; + } + exc = dom_node_get_node_name(svg, &svg_name); if (exc != DOM_NO_ERR) { dom_node_unref(svg); @@ -205,14 +262,7 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, dom_node_unref(document); cleanup: - if (state.gradient_x1 != NULL) - dom_string_unref(state.gradient_x1); - if (state.gradient_x2 != NULL) - dom_string_unref(state.gradient_x2); - if (state.gradient_y1 != NULL) - dom_string_unref(state.gradient_y1); - if (state.gradient_y2 != NULL) - dom_string_unref(state.gradient_y2); + svgtiny_cleanup_state_local(&state); #define SVGTINY_STRING_ACTION2(s,n) \ if (state.interned_##s != NULL) \ dom_string_unref(state.interned_##s); @@ -234,6 +284,8 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg, dom_element *child; dom_exception exc; + svgtiny_setup_state_local(&state); + svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height); svgtiny_parse_paint_attributes(svg, &state); svgtiny_parse_font_attributes(svg, &state); @@ -241,6 +293,7 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg, exc = dom_element_get_attribute(svg, state.interned_viewBox, &view_box); if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } @@ -265,6 +318,7 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg, exc = dom_node_get_first_child(svg, (dom_node **) (void *) &child); if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } while (child != NULL) { @@ -282,6 +336,7 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg, exc = dom_node_get_node_name(child, &nodename); if (exc != DOM_NO_ERR) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (dom_string_caseless_isequal(state.interned_svg, @@ -321,17 +376,20 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg, } if (code != svgtiny_OK) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return code; } exc = dom_node_get_next_sibling(child, (dom_node **) (void *) &next); dom_node_unref(child); if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } child = next; } + svgtiny_cleanup_state_local(&state); return svgtiny_OK; } @@ -346,14 +404,19 @@ svgtiny_code svgtiny_parse_svg(dom_element *svg, svgtiny_code svgtiny_parse_path(dom_element *path, struct svgtiny_parse_state state) { + svgtiny_code err; dom_string *path_d_str; dom_exception exc; char *s, *path_d; - float *p; + float *p; /* path elemets */ + unsigned int palloc; /* number of path elements allocated */ unsigned int i; float last_x = 0, last_y = 0; float last_cubic_x = 0, last_cubic_y = 0; float last_quad_x = 0, last_quad_y = 0; + float subpath_first_x = 0, subpath_first_y = 0; + + svgtiny_setup_state_local(&state); svgtiny_parse_paint_attributes(path, &state); svgtiny_parse_transform_attributes(path, &state); @@ -363,25 +426,44 @@ svgtiny_code svgtiny_parse_path(dom_element *path, if (exc != DOM_NO_ERR) { state.diagram->error_line = -1; /* path->line; */ state.diagram->error_message = "path: error retrieving d attribute"; + svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } if (path_d_str == NULL) { state.diagram->error_line = -1; /* path->line; */ state.diagram->error_message = "path: missing d attribute"; + svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } - s = path_d = strndup(dom_string_data(path_d_str), - dom_string_byte_length(path_d_str)); + /* empty path is permitted it just disables the path */ + palloc = dom_string_byte_length(path_d_str); + if (palloc == 0) { + svgtiny_cleanup_state_local(&state); + return svgtiny_OK; + } + + /* local copy of the path data allowing in-place modification */ + s = path_d = strndup(dom_string_data(path_d_str), palloc); dom_string_unref(path_d_str); if (s == NULL) { + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } - /* allocate space for path: it will never have more elements than d */ - p = malloc(sizeof p[0] * strlen(s)); - if (!p) { + + /* ensure path element allocation is sensibly bounded */ + if (palloc < 8) { + palloc = 8; + } else if (palloc > 64) { + palloc = palloc / 2; + } + + /* allocate initial space for path elements */ + p = malloc(sizeof p[0] * palloc); + if (p == NULL) { free(path_d); + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } @@ -396,6 +478,24 @@ svgtiny_code svgtiny_parse_path(dom_element *path, float x, y, x1, y1, x2, y2, rx, ry, rotation, large_arc, sweep; int n; + /* Ensure there is sufficient space for path elements */ +#define ALLOC_PATH_ELEMENTS(NUM_ELEMENTS) \ + do { \ + if ((palloc - i) < NUM_ELEMENTS) { \ + float *tp; \ + palloc = (palloc * 2) + (palloc / 2); \ + tp = realloc(p, sizeof p[0] * palloc); \ + if (tp == NULL) { \ + free(p); \ + free(path_d); \ + svgtiny_cleanup_state_local(&state); \ + return svgtiny_OUT_OF_MEMORY; \ + } \ + p = tp; \ + } \ + } while(0) + + /* moveto (M, m), lineto (L, l) (2 arguments) */ if (sscanf(s, " %1[MmLl] %f %f %n", command, &x, &y, &n) == 3) { /*LOG(("moveto or lineto"));*/ @@ -404,11 +504,16 @@ svgtiny_code svgtiny_parse_path(dom_element *path, else plot_command = svgtiny_PATH_LINE; do { + ALLOC_PATH_ELEMENTS(3); p[i++] = plot_command; if ('a' <= *command) { x += last_x; y += last_y; } + if (plot_command == svgtiny_PATH_MOVE) { + subpath_first_x = x; + subpath_first_y = y; + } p[i++] = last_cubic_x = last_quad_x = last_x = x; p[i++] = last_cubic_y = last_quad_y = last_y @@ -420,13 +525,19 @@ svgtiny_code svgtiny_parse_path(dom_element *path, /* closepath (Z, z) (no arguments) */ } else if (sscanf(s, " %1[Zz] %n", command, &n) == 1) { /*LOG(("closepath"));*/ + ALLOC_PATH_ELEMENTS(1); + p[i++] = svgtiny_PATH_CLOSE; s += n; + last_cubic_x = last_quad_x = last_x = subpath_first_x; + last_cubic_y = last_quad_y = last_y = subpath_first_y; /* horizontal lineto (H, h) (1 argument) */ } else if (sscanf(s, " %1[Hh] %f %n", command, &x, &n) == 2) { /*LOG(("horizontal lineto"));*/ do { + ALLOC_PATH_ELEMENTS(3); + p[i++] = svgtiny_PATH_LINE; if (*command == 'h') x += last_x; @@ -440,6 +551,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, } else if (sscanf(s, " %1[Vv] %f %n", command, &y, &n) == 2) { /*LOG(("vertical lineto"));*/ do { + ALLOC_PATH_ELEMENTS(3); + p[i++] = svgtiny_PATH_LINE; if (*command == 'v') y += last_y; @@ -454,6 +567,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x1, &y1, &x2, &y2, &x, &y, &n) == 7) { /*LOG(("curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; if (*command == 'c') { x1 += last_x; @@ -478,6 +593,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x2, &y2, &x, &y, &n) == 5) { /*LOG(("shorthand/smooth curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_cubic_x); y1 = last_y + (last_y - last_cubic_y); @@ -502,6 +619,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x1, &y1, &x, &y, &n) == 5) { /*LOG(("quadratic Bezier curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; last_quad_x = x1; last_quad_y = y1; @@ -527,6 +646,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &x, &y, &n) == 3) { /*LOG(("shorthand/smooth quadratic Bezier curveto"));*/ do { + ALLOC_PATH_ELEMENTS(7); + p[i++] = svgtiny_PATH_BEZIER; x1 = last_x + (last_x - last_quad_x); y1 = last_y + (last_y - last_quad_y); @@ -553,6 +674,8 @@ svgtiny_code svgtiny_parse_path(dom_element *path, &rx, &ry, &rotation, &large_arc, &sweep, &x, &y, &n) == 8) { do { + ALLOC_PATH_ELEMENTS(3); + p[i++] = svgtiny_PATH_LINE; if (*command == 'a') { x += last_x; @@ -578,10 +701,28 @@ svgtiny_code svgtiny_parse_path(dom_element *path, if (i <= 4) { /* no real segments in path */ free(p); + svgtiny_cleanup_state_local(&state); return svgtiny_OK; } - return svgtiny_add_path(p, i, &state); + /* resize path element array to not be over allocated */ + if (palloc != i) { + float *tp; + + /* try the resize, if it fails just continue to use the old + * allocation + */ + tp = realloc(p, sizeof p[0] * i); + if (tp != NULL) { + p = tp; + } + } + + err = svgtiny_add_path(p, i, &state); + + svgtiny_cleanup_state_local(&state); + + return err; } @@ -594,17 +735,22 @@ svgtiny_code svgtiny_parse_path(dom_element *path, svgtiny_code svgtiny_parse_rect(dom_element *rect, struct svgtiny_parse_state state) { + svgtiny_code err; float x, y, width, height; float *p; + svgtiny_setup_state_local(&state); + svgtiny_parse_position_attributes(rect, state, &x, &y, &width, &height); svgtiny_parse_paint_attributes(rect, &state); svgtiny_parse_transform_attributes(rect, &state); p = malloc(13 * sizeof p[0]); - if (!p) + if (!p) { + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; + } p[0] = svgtiny_PATH_MOVE; p[1] = x; @@ -620,7 +766,11 @@ svgtiny_code svgtiny_parse_rect(dom_element *rect, p[11] = y + height; p[12] = svgtiny_PATH_CLOSE; - return svgtiny_add_path(p, 13, &state); + err = svgtiny_add_path(p, 13, &state); + + svgtiny_cleanup_state_local(&state); + + return err; } @@ -631,30 +781,39 @@ svgtiny_code svgtiny_parse_rect(dom_element *rect, svgtiny_code svgtiny_parse_circle(dom_element *circle, struct svgtiny_parse_state state) { + svgtiny_code err; float x = 0, y = 0, r = -1; float *p; dom_string *attr; dom_exception exc; + svgtiny_setup_state_local(&state); + exc = dom_element_get_attribute(circle, state.interned_cx, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { x = svgtiny_parse_length(attr, state.viewport_width, state); } dom_string_unref(attr); exc = dom_element_get_attribute(circle, state.interned_cy, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { y = svgtiny_parse_length(attr, state.viewport_height, state); } dom_string_unref(attr); exc = dom_element_get_attribute(circle, state.interned_r, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { r = svgtiny_parse_length(attr, state.viewport_width, state); } @@ -666,14 +825,19 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle, if (r < 0) { state.diagram->error_line = -1; /* circle->line; */ state.diagram->error_message = "circle: r missing or negative"; + svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } - if (r == 0) + if (r == 0) { + svgtiny_cleanup_state_local(&state); return svgtiny_OK; + } p = malloc(32 * sizeof p[0]); - if (!p) + if (!p) { + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; + } p[0] = svgtiny_PATH_MOVE; p[1] = x + r; @@ -707,8 +871,12 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle, p[29] = x + r; p[30] = y; p[31] = svgtiny_PATH_CLOSE; + + err = svgtiny_add_path(p, 32, &state); + + svgtiny_cleanup_state_local(&state); - return svgtiny_add_path(p, 32, &state); + return err; } @@ -719,38 +887,49 @@ svgtiny_code svgtiny_parse_circle(dom_element *circle, svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse, struct svgtiny_parse_state state) { + svgtiny_code err; float x = 0, y = 0, rx = -1, ry = -1; float *p; dom_string *attr; dom_exception exc; + svgtiny_setup_state_local(&state); + exc = dom_element_get_attribute(ellipse, state.interned_cx, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { x = svgtiny_parse_length(attr, state.viewport_width, state); } dom_string_unref(attr); exc = dom_element_get_attribute(ellipse, state.interned_cy, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { y = svgtiny_parse_length(attr, state.viewport_height, state); } dom_string_unref(attr); exc = dom_element_get_attribute(ellipse, state.interned_rx, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { rx = svgtiny_parse_length(attr, state.viewport_width, state); } dom_string_unref(attr); exc = dom_element_get_attribute(ellipse, state.interned_ry, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { ry = svgtiny_parse_length(attr, state.viewport_width, state); } @@ -763,14 +942,19 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse, state.diagram->error_line = -1; /* ellipse->line; */ state.diagram->error_message = "ellipse: rx or ry missing " "or negative"; + svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } - if (rx == 0 || ry == 0) + if (rx == 0 || ry == 0) { + svgtiny_cleanup_state_local(&state); return svgtiny_OK; + } p = malloc(32 * sizeof p[0]); - if (!p) + if (!p) { + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; + } p[0] = svgtiny_PATH_MOVE; p[1] = x + rx; @@ -805,7 +989,11 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse, p[30] = y; p[31] = svgtiny_PATH_CLOSE; - return svgtiny_add_path(p, 32, &state); + err = svgtiny_add_path(p, 32, &state); + + svgtiny_cleanup_state_local(&state); + + return err; } @@ -816,38 +1004,49 @@ svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse, svgtiny_code svgtiny_parse_line(dom_element *line, struct svgtiny_parse_state state) { + svgtiny_code err; float x1 = 0, y1 = 0, x2 = 0, y2 = 0; float *p; dom_string *attr; dom_exception exc; + svgtiny_setup_state_local(&state); + exc = dom_element_get_attribute(line, state.interned_x1, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { x1 = svgtiny_parse_length(attr, state.viewport_width, state); } dom_string_unref(attr); exc = dom_element_get_attribute(line, state.interned_y1, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { y1 = svgtiny_parse_length(attr, state.viewport_height, state); } dom_string_unref(attr); exc = dom_element_get_attribute(line, state.interned_x2, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { x2 = svgtiny_parse_length(attr, state.viewport_width, state); } dom_string_unref(attr); exc = dom_element_get_attribute(line, state.interned_y2, &attr); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (attr != NULL) { y2 = svgtiny_parse_length(attr, state.viewport_height, state); } @@ -857,8 +1056,10 @@ svgtiny_code svgtiny_parse_line(dom_element *line, svgtiny_parse_transform_attributes(line, &state); p = malloc(7 * sizeof p[0]); - if (!p) + if (!p) { + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; + } p[0] = svgtiny_PATH_MOVE; p[1] = x1; @@ -868,7 +1069,11 @@ svgtiny_code svgtiny_parse_line(dom_element *line, p[5] = y2; p[6] = svgtiny_PATH_CLOSE; - return svgtiny_add_path(p, 7, &state); + err = svgtiny_add_path(p, 7, &state); + + svgtiny_cleanup_state_local(&state); + + return err; } @@ -882,24 +1087,30 @@ svgtiny_code svgtiny_parse_line(dom_element *line, svgtiny_code svgtiny_parse_poly(dom_element *poly, struct svgtiny_parse_state state, bool polygon) { + svgtiny_code err; dom_string *points_str; dom_exception exc; char *s, *points; float *p; unsigned int i; + svgtiny_setup_state_local(&state); + svgtiny_parse_paint_attributes(poly, &state); svgtiny_parse_transform_attributes(poly, &state); exc = dom_element_get_attribute(poly, state.interned_points, &points_str); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } if (points_str == NULL) { state.diagram->error_line = -1; /* poly->line; */ state.diagram->error_message = "polyline/polygon: missing points attribute"; + svgtiny_cleanup_state_local(&state); return svgtiny_SVG_ERROR; } @@ -907,12 +1118,15 @@ svgtiny_code svgtiny_parse_poly(dom_element *poly, dom_string_byte_length(points_str)); dom_string_unref(points_str); /* read points attribute */ - if (s == NULL) + if (s == NULL) { + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; + } /* allocate space for path: it will never have more elements than s */ p = malloc(sizeof p[0] * strlen(s)); if (!p) { free(points); + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } @@ -942,7 +1156,11 @@ svgtiny_code svgtiny_parse_poly(dom_element *poly, free(points); - return svgtiny_add_path(p, i, &state); + err = svgtiny_add_path(p, i, &state); + + svgtiny_cleanup_state_local(&state); + + return err; } @@ -958,6 +1176,8 @@ svgtiny_code svgtiny_parse_text(dom_element *text, dom_node *child; dom_exception exc; + svgtiny_setup_state_local(&state); + svgtiny_parse_position_attributes(text, state, &x, &y, &width, &height); svgtiny_parse_font_attributes(text, &state); @@ -972,8 +1192,10 @@ svgtiny_code svgtiny_parse_text(dom_element *text, style.font_size.value.length.value *= state.ctm.a;*/ exc = dom_node_get_first_child(text, &child); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { return svgtiny_LIBDOM_ERROR; + svgtiny_cleanup_state_local(&state); + } while (child != NULL) { dom_node *next; dom_node_type nodetype; @@ -982,6 +1204,7 @@ svgtiny_code svgtiny_parse_text(dom_element *text, exc = dom_node_get_node_type(child, &nodetype); if (exc != DOM_NO_ERR) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (nodetype == DOM_ELEMENT_NODE) { @@ -989,6 +1212,7 @@ svgtiny_code svgtiny_parse_text(dom_element *text, exc = dom_node_get_node_name(child, &nodename); if (exc != DOM_NO_ERR) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } if (dom_string_caseless_isequal(nodename, @@ -1001,16 +1225,22 @@ svgtiny_code svgtiny_parse_text(dom_element *text, dom_string *content; if (shape == NULL) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return svgtiny_OUT_OF_MEMORY; } exc = dom_text_get_whole_text(child, &content); if (exc != DOM_NO_ERR) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; } - shape->text = strndup(dom_string_data(content), - dom_string_byte_length(content)); - dom_string_unref(content); + if (content != NULL) { + shape->text = strndup(dom_string_data(content), + dom_string_byte_length(content)); + dom_string_unref(content); + } else { + shape->text = strdup(""); + } shape->text_x = px; shape->text_y = py; state.diagram->shape_count++; @@ -1018,15 +1248,20 @@ svgtiny_code svgtiny_parse_text(dom_element *text, if (code != svgtiny_OK) { dom_node_unref(child); + svgtiny_cleanup_state_local(&state); return code; } exc = dom_node_get_next_sibling(child, &next); dom_node_unref(child); - if (exc != DOM_NO_ERR) + if (exc != DOM_NO_ERR) { + svgtiny_cleanup_state_local(&state); return svgtiny_LIBDOM_ERROR; + } child = next; } + svgtiny_cleanup_state_local(&state); + return svgtiny_OK; } @@ -1035,7 +1270,7 @@ svgtiny_code svgtiny_parse_text(dom_element *text, * Parse x, y, width, and height attributes, if present. */ -void svgtiny_parse_position_attributes(const dom_element *node, +void svgtiny_parse_position_attributes(dom_element *node, const struct svgtiny_parse_state state, float *x, float *y, float *width, float *height) { @@ -1127,7 +1362,7 @@ float svgtiny_parse_length(dom_string *s, int viewport_size, * Parse paint attributes, if present. */ -void svgtiny_parse_paint_attributes(const dom_element *node, +void svgtiny_parse_paint_attributes(dom_element *node, struct svgtiny_parse_state *state) { dom_string *attr; @@ -1234,8 +1469,6 @@ static void _svgtiny_parse_color(const char *s, svgtiny_colour *c, *rparen = 0; svgtiny_find_gradient(id, state); free(id); - fprintf(stderr, "linear_gradient_stop_count %i\n", - state->linear_gradient_stop_count); if (state->linear_gradient_stop_count == 0) *c = svgtiny_TRANSPARENT; else if (state->linear_gradient_stop_count == 1) @@ -1264,7 +1497,7 @@ void svgtiny_parse_color(dom_string *s, svgtiny_colour *c, * Parse font attributes, if present. */ -void svgtiny_parse_font_attributes(const dom_element *node, +void svgtiny_parse_font_attributes(dom_element *node, struct svgtiny_parse_state *state) { /* TODO: Implement this, it never used to be */ @@ -1338,23 +1571,23 @@ void svgtiny_parse_transform(char *s, float *ma, float *mb, a = d = 1; b = c = 0; e = f = 0; - if (sscanf(s, "matrix (%f %f %f %f %f %f) %n", - &a, &b, &c, &d, &e, &f, &n) == 6) + if ((sscanf(s, " matrix (%f %f %f %f %f %f ) %n", + &a, &b, &c, &d, &e, &f, &n) == 6) && (n > 0)) ; - else if (sscanf(s, "translate (%f %f) %n", - &e, &f, &n) == 2) + else if ((sscanf(s, " translate (%f %f ) %n", + &e, &f, &n) == 2) && (n > 0)) ; - else if (sscanf(s, "translate (%f) %n", - &e, &n) == 1) + else if ((sscanf(s, " translate (%f ) %n", + &e, &n) == 1) && (n > 0)) ; - else if (sscanf(s, "scale (%f %f) %n", - &a, &d, &n) == 2) + else if ((sscanf(s, " scale (%f %f ) %n", + &a, &d, &n) == 2) && (n > 0)) ; - else if (sscanf(s, "scale (%f) %n", - &a, &n) == 1) + else if ((sscanf(s, " scale (%f ) %n", + &a, &n) == 1) && (n > 0)) d = a; - else if (sscanf(s, "rotate (%f %f %f) %n", - &angle, &x, &y, &n) == 3) { + else if ((sscanf(s, " rotate (%f %f %f ) %n", + &angle, &x, &y, &n) == 3) && (n > 0)) { angle = angle / 180 * M_PI; a = cos(angle); b = sin(angle); @@ -1362,19 +1595,19 @@ void svgtiny_parse_transform(char *s, float *ma, float *mb, d = cos(angle); e = -x * cos(angle) + y * sin(angle) + x; f = -x * sin(angle) - y * cos(angle) + y; - } else if (sscanf(s, "rotate (%f) %n", - &angle, &n) == 1) { + } else if ((sscanf(s, " rotate (%f ) %n", + &angle, &n) == 1) && (n > 0)) { angle = angle / 180 * M_PI; a = cos(angle); b = sin(angle); c = -sin(angle); d = cos(angle); - } else if (sscanf(s, "skewX (%f) %n", - &angle, &n) == 1) { + } else if ((sscanf(s, " skewX (%f ) %n", + &angle, &n) == 1) && (n > 0)) { angle = angle / 180 * M_PI; c = tan(angle); - } else if (sscanf(s, "skewY (%f) %n", - &angle, &n) == 1) { + } else if ((sscanf(s, " skewY (%f ) %n", + &angle, &n) == 1) && (n > 0)) { angle = angle / 180 * M_PI; b = tan(angle); } else