X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsvgtiny.c;h=63c7cc2bf70d26bc9e21f16e17ab2fb9a58a5160;hb=ccc89083064d413c6785e1b740cf8e23c2eb4cfa;hp=8fa09a5bdd6e66ed2cdbdcb01d690af3f277e0f3;hpb=b300ddf3f867664d932e1bb56c2d4afc96b87967;p=libsvgtiny.git diff --git a/src/svgtiny.c b/src/svgtiny.c index 8fa09a5..63c7cc2 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -3,6 +3,7 @@ * Licensed under the MIT License, * http://opensource.org/licenses/mit-license.php * Copyright 2008-2009 James Bursa + * Copyright 2012 Daniel Silverstone */ #include @@ -12,8 +13,10 @@ #include #include #include -#include -#include + +#include +#include + #include "svgtiny.h" #include "svgtiny_internal.h" @@ -23,30 +26,30 @@ #define KAPPA 0.5522847498 -static svgtiny_code svgtiny_parse_svg(xmlNode *svg, +static svgtiny_code svgtiny_parse_svg(dom_element *svg, struct svgtiny_parse_state state); -static svgtiny_code svgtiny_parse_path(xmlNode *path, +static svgtiny_code svgtiny_parse_path(dom_element *path, struct svgtiny_parse_state state); -static svgtiny_code svgtiny_parse_rect(xmlNode *rect, +static svgtiny_code svgtiny_parse_rect(dom_element *rect, struct svgtiny_parse_state state); -static svgtiny_code svgtiny_parse_circle(xmlNode *circle, +static svgtiny_code svgtiny_parse_circle(dom_element *circle, struct svgtiny_parse_state state); -static svgtiny_code svgtiny_parse_ellipse(xmlNode *ellipse, +static svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse, struct svgtiny_parse_state state); -static svgtiny_code svgtiny_parse_line(xmlNode *line, +static svgtiny_code svgtiny_parse_line(dom_element *line, struct svgtiny_parse_state state); -static svgtiny_code svgtiny_parse_poly(xmlNode *poly, +static svgtiny_code svgtiny_parse_poly(dom_element *poly, struct svgtiny_parse_state state, bool polygon); -static svgtiny_code svgtiny_parse_text(xmlNode *text, +static svgtiny_code svgtiny_parse_text(dom_element *text, struct svgtiny_parse_state state); -static void svgtiny_parse_position_attributes(const xmlNode *node, +static void svgtiny_parse_position_attributes(const dom_element *node, const struct svgtiny_parse_state state, float *x, float *y, float *width, float *height); -static void svgtiny_parse_paint_attributes(const xmlNode *node, +static void svgtiny_parse_paint_attributes(const dom_element *node, struct svgtiny_parse_state *state); -static void svgtiny_parse_font_attributes(const xmlNode *node, +static void svgtiny_parse_font_attributes(const dom_element *node, struct svgtiny_parse_state *state); -static void svgtiny_parse_transform_attributes(xmlNode *node, +static void svgtiny_parse_transform_attributes(dom_element *node, struct svgtiny_parse_state *state); static svgtiny_code svgtiny_add_path(float *p, unsigned int n, struct svgtiny_parse_state *state); @@ -60,18 +63,21 @@ struct svgtiny_diagram *svgtiny_create(void) { struct svgtiny_diagram *diagram; - diagram = malloc(sizeof *diagram); + diagram = calloc(sizeof(*diagram), 1); if (!diagram) return 0; - diagram->shape = 0; - diagram->shape_count = 0; - diagram->error_line = 0; - diagram->error_message = 0; - return diagram; + free(diagram); + return NULL; } +static void ignore_msg(uint32_t severity, void *ctx, const char *msg, ...) +{ + UNUSED(severity); + UNUSED(ctx); + UNUSED(msg); +} /** * Parse a block of memory into a svgtiny_diagram. @@ -81,8 +87,13 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, const char *buffer, size_t size, const char *url, int viewport_width, int viewport_height) { - xmlDoc *document; - xmlNode *svg; + dom_document *document; + dom_exception exc; + dom_xml_parser *parser; + dom_xml_error err; + dom_element *svg; + dom_string *svg_name; + lwc_string *svg_name_lwc; struct svgtiny_parse_state state; float x, y, width, height; svgtiny_code code; @@ -91,26 +102,79 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, assert(buffer); assert(url); - /* parse XML to tree */ - document = xmlReadMemory(buffer, size, url, 0, - XML_PARSE_NONET | XML_PARSE_COMPACT); - if (!document) - return svgtiny_LIBXML_ERROR; + UNUSED(url); + + parser = dom_xml_parser_create(NULL, NULL, + ignore_msg, NULL, &document); + + if (parser == NULL) + return svgtiny_LIBDOM_ERROR; - /*xmlDebugDumpDocument(stderr, document);*/ + err = dom_xml_parser_parse_chunk(parser, (uint8_t *)buffer, size); + if (err != DOM_XML_OK) { + dom_node_unref(document); + dom_xml_parser_destroy(parser); + return svgtiny_LIBDOM_ERROR; + } + + err = dom_xml_parser_completed(parser); + if (err != DOM_XML_OK) { + dom_node_unref(document); + dom_xml_parser_destroy(parser); + return svgtiny_LIBDOM_ERROR; + } + + /* We're done parsing, drop the parser. + * We now own the document entirely. + */ + dom_xml_parser_destroy(parser); /* find root element */ - svg = xmlDocGetRootElement(document); - if (!svg) - return svgtiny_NOT_SVG; - if (strcmp((const char *) svg->name, "svg") != 0) + exc = dom_document_get_document_element(document, &svg); + if (exc != DOM_NO_ERR) { + dom_node_unref(document); + return svgtiny_LIBDOM_ERROR; + } + exc = dom_node_get_node_name(svg, &svg_name); + if (exc != DOM_NO_ERR) { + dom_node_unref(svg); + dom_node_unref(document); + return svgtiny_LIBDOM_ERROR; + } + if (lwc_intern_string("svg", 3 /* SLEN("svg") */, + &svg_name_lwc) != lwc_error_ok) { + dom_string_unref(svg_name); + dom_node_unref(svg); + dom_node_unref(document); + return svgtiny_LIBDOM_ERROR; + } + if (!dom_string_caseless_lwc_isequal(svg_name, svg_name_lwc)) { + lwc_string_unref(svg_name_lwc); + dom_string_unref(svg_name); + dom_node_unref(svg); + dom_node_unref(document); return svgtiny_NOT_SVG; + } + + lwc_string_unref(svg_name_lwc); + dom_string_unref(svg_name); /* get graphic dimensions */ state.diagram = diagram; state.document = document; state.viewport_width = viewport_width; state.viewport_height = viewport_height; + +#define SVGTINY_STRING_ACTION(s) \ + if (dom_string_create_interned((const uint8_t *) #s, \ + strlen(#s), &state.interned_##s) \ + != DOM_NO_ERR) { \ + code = svgtiny_LIBDOM_ERROR; \ + goto cleanup; \ + } +#include "svgtiny_strings.h" +#undef SVGTINY_STRING_ACTION + svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height); diagram->width = width; diagram->height = height; @@ -134,9 +198,15 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, /* parse tree */ code = svgtiny_parse_svg(svg, state); - /* free XML tree */ - xmlFreeDoc(document); + dom_node_unref(svg); + dom_node_unref(document); +cleanup: +#define SVGTINY_STRING_ACTION(s) \ + if (state.interned_##s != NULL) \ + dom_string_unref(state.interned_##s); +//#include "svgtiny_strings.h" +#undef SVGTINY_STRING_ACTION return code; } @@ -145,21 +215,27 @@ svgtiny_code svgtiny_parse(struct svgtiny_diagram *diagram, * Parse a or element node. */ -svgtiny_code svgtiny_parse_svg(xmlNode *svg, +svgtiny_code svgtiny_parse_svg(dom_element *svg, struct svgtiny_parse_state state) { float x, y, width, height; - xmlAttr *view_box; - xmlNode *child; + dom_string *view_box; + dom_element *child; + dom_exception exc; svgtiny_parse_position_attributes(svg, state, &x, &y, &width, &height); svgtiny_parse_paint_attributes(svg, &state); svgtiny_parse_font_attributes(svg, &state); - /* parse viewBox */ - view_box = xmlHasProp(svg, (const xmlChar *) "viewBox"); + exc = dom_element_get_attribute(svg, state.interned_viewBox, + &view_box); + if (exc != DOM_NO_ERR) { + return svgtiny_LIBDOM_ERROR; + } + if (view_box) { - const char *s = (const char *) view_box->children->content; + char *s = strndup(dom_string_data(view_box), + dom_string_length(view_box)); float min_x, min_y, vwidth, vheight; if (sscanf(s, "%f,%f,%f,%f", &min_x, &min_y, &vwidth, &vheight) == 4 || @@ -170,41 +246,78 @@ svgtiny_code svgtiny_parse_svg(xmlNode *svg, state.ctm.e += -min_x * state.ctm.a; state.ctm.f += -min_y * state.ctm.d; } + free(s); + dom_string_unref(view_box); } svgtiny_parse_transform_attributes(svg, &state); - for (child = svg->children; child; child = child->next) { + exc = dom_node_get_first_child(svg, &child); + if (exc != DOM_NO_ERR) { + return svgtiny_LIBDOM_ERROR; + } + while (child != NULL) { + dom_element *next; + dom_node_type nodetype; svgtiny_code code = svgtiny_OK; - if (child->type == XML_ELEMENT_NODE) { - const char *name = (const char *) child->name; - if (strcmp(name, "svg") == 0) + exc = dom_node_get_node_type(child, &nodetype); + if (exc != DOM_NO_ERR) { + dom_node_unref(child); + return svgtiny_LIBDOM_ERROR; + } + if (nodetype == DOM_ELEMENT_NODE) { + dom_string *nodename; + exc = dom_node_get_node_name(child, &nodename); + if (exc != DOM_NO_ERR) { + dom_node_unref(child); + return svgtiny_LIBDOM_ERROR; + } + if (dom_string_caseless_isequal(state.interned_svg, + nodename)) code = svgtiny_parse_svg(child, state); - else if (strcmp(name, "g") == 0) + else if (dom_string_caseless_isequal(state.interned_g, + nodename)) code = svgtiny_parse_svg(child, state); - else if (strcmp(name, "a") == 0) + else if (dom_string_caseless_isequal(state.interned_a, + nodename)) code = svgtiny_parse_svg(child, state); - else if (strcmp(name, "path") == 0) + else if (dom_string_caseless_isequal(state.interned_path, + nodename)) code = svgtiny_parse_path(child, state); - else if (strcmp(name, "rect") == 0) + else if (dom_string_caseless_isequal(state.interned_rect, + nodename)) code = svgtiny_parse_rect(child, state); - else if (strcmp(name, "circle") == 0) + else if (dom_string_caseless_isequal(state.interned_circle, + nodename)) code = svgtiny_parse_circle(child, state); - else if (strcmp(name, "ellipse") == 0) + else if (dom_string_caseless_isequal(state.interned_ellipse, + nodename)) code = svgtiny_parse_ellipse(child, state); - else if (strcmp(name, "line") == 0) + else if (dom_string_caseless_isequal(state.interned_line, + nodename)) code = svgtiny_parse_line(child, state); - else if (strcmp(name, "polyline") == 0) + else if (dom_string_caseless_isequal(state.interned_polyline, + nodename)) code = svgtiny_parse_poly(child, state, false); - else if (strcmp(name, "polygon") == 0) + else if (dom_string_caseless_isequal(state.interned_polygon, + nodename)) code = svgtiny_parse_poly(child, state, true); - else if (strcmp(name, "text") == 0) + else if (dom_string_caseless_isequal(state.interned_text, + nodename)) code = svgtiny_parse_text(child, state); + dom_string_unref(nodename); } - - if (code != svgtiny_OK) + if (code != svgtiny_OK) { + dom_node_unref(child); return code; + } + exc = dom_node_get_next_sibling(child, &next); + dom_node_unref(child); + if (exc != DOM_NO_ERR) { + return svgtiny_LIBDOM_ERROR; + } + child = next; } return svgtiny_OK; @@ -218,7 +331,7 @@ svgtiny_code svgtiny_parse_svg(xmlNode *svg, * http://www.w3.org/TR/SVG11/paths#PathElement */ -svgtiny_code svgtiny_parse_path(xmlNode *path, +svgtiny_code svgtiny_parse_path(dom_element *path, struct svgtiny_parse_state state) { char *s, *path_d; @@ -450,7 +563,7 @@ svgtiny_code svgtiny_parse_path(xmlNode *path, * http://www.w3.org/TR/SVG11/shapes#RectElement */ -svgtiny_code svgtiny_parse_rect(xmlNode *rect, +svgtiny_code svgtiny_parse_rect(dom_element *rect, struct svgtiny_parse_state state) { float x, y, width, height; @@ -487,7 +600,7 @@ svgtiny_code svgtiny_parse_rect(xmlNode *rect, * Parse a element node. */ -svgtiny_code svgtiny_parse_circle(xmlNode *circle, +svgtiny_code svgtiny_parse_circle(dom_element *circle, struct svgtiny_parse_state state) { float x = 0, y = 0, r = -1; @@ -563,7 +676,7 @@ svgtiny_code svgtiny_parse_circle(xmlNode *circle, * Parse an element node. */ -svgtiny_code svgtiny_parse_ellipse(xmlNode *ellipse, +svgtiny_code svgtiny_parse_ellipse(dom_element *ellipse, struct svgtiny_parse_state state) { float x = 0, y = 0, rx = -1, ry = -1; @@ -643,7 +756,7 @@ svgtiny_code svgtiny_parse_ellipse(xmlNode *ellipse, * Parse a element node. */ -svgtiny_code svgtiny_parse_line(xmlNode *line, +svgtiny_code svgtiny_parse_line(dom_element *line, struct svgtiny_parse_state state) { float x1 = 0, y1 = 0, x2 = 0, y2 = 0; @@ -692,7 +805,7 @@ svgtiny_code svgtiny_parse_line(xmlNode *line, * http://www.w3.org/TR/SVG11/shapes#PolygonElement */ -svgtiny_code svgtiny_parse_poly(xmlNode *poly, +svgtiny_code svgtiny_parse_poly(dom_element *poly, struct svgtiny_parse_state state, bool polygon) { char *s, *points; @@ -752,12 +865,12 @@ svgtiny_code svgtiny_parse_poly(xmlNode *poly, * Parse a or element node. */ -svgtiny_code svgtiny_parse_text(xmlNode *text, +svgtiny_code svgtiny_parse_text(dom_element *text, struct svgtiny_parse_state state) { float x, y, width, height; float px, py; - xmlNode *child; + dom_element *child; svgtiny_parse_position_attributes(text, state, &x, &y, &width, &height); @@ -802,7 +915,7 @@ svgtiny_code svgtiny_parse_text(xmlNode *text, * Parse x, y, width, and height attributes, if present. */ -void svgtiny_parse_position_attributes(const xmlNode *node, +void svgtiny_parse_position_attributes(const dom_element *node, const struct svgtiny_parse_state state, float *x, float *y, float *width, float *height) { @@ -876,7 +989,7 @@ float svgtiny_parse_length(const char *s, int viewport_size, * Parse paint attributes, if present. */ -void svgtiny_parse_paint_attributes(const xmlNode *node, +void svgtiny_parse_paint_attributes(const dom_element *node, struct svgtiny_parse_state *state) { const xmlAttr *attr; @@ -994,7 +1107,7 @@ void svgtiny_parse_color(const char *s, svgtiny_colour *c, * Parse font attributes, if present. */ -void svgtiny_parse_font_attributes(const xmlNode *node, +void svgtiny_parse_font_attributes(const dom_element *node, struct svgtiny_parse_state *state) { const xmlAttr *attr; @@ -1021,7 +1134,7 @@ void svgtiny_parse_font_attributes(const xmlNode *node, * http://www.w3.org/TR/SVG11/coords#TransformAttribute */ -void svgtiny_parse_transform_attributes(xmlNode *node, +void svgtiny_parse_transform_attributes(dom_element *node, struct svgtiny_parse_state *state) { char *transform;