LineInfo* line_info_load_and_apply_from_xmlfile(const gchar *filename, LineInfo* info) { xmlDocPtr doc = xmlDoParseFile(filename); xmlNodePtr node, root; xmlChar *tmp; int i; if (!doc) { g_warning("parse error for %s", filename); return NULL; } /* skip (emacs) comments */ root = doc->xmlRootNode; while (root && (root->type != XML_ELEMENT_NODE)) root = root->next; if (!root) return NULL; if (xmlIsBlankNode(root)) return NULL; i = 0; for (node = root->xmlChildrenNode; node != NULL; node = node->next) { if (xmlIsBlankNode(node)) continue; else if (node->type != XML_ELEMENT_NODE) continue; else if (!strcmp((char*)node->name, "name")) { tmp = xmlNodeGetContent(node); /* g_free(info->name);*/ info->name = g_strdup((char*)tmp); /* fprintf( stderr, "New shape of type: `%s'\n", info->name ); */ xmlFree(tmp); } else if ( !strcmp((char*)node->name, "icon")) { tmp = xmlNodeGetContent(node); g_free(info->icon_filename); info->icon_filename = custom_get_relative_filename(filename, (char*)tmp); xmlFree(tmp); } else if ( !strcmp((char*)node->name, "type")) { info->type = line_info_get_line_type(filename, node); } else if ( !strcmp((char*)node->name, "line-style")) { info->line_style = line_info_get_line_style(filename, node); } else if ( !strcmp((char*)node->name, "dash-length")) { info->dashlength = line_info_get_as_float(filename, node); } else if ( !strcmp((char*)node->name, "line-width")) { info->line_width = line_info_get_as_float(filename, node); } else if ( !strcmp((char*)node->name, "corner-radius")) { info->corner_radius = line_info_get_as_float(filename, node); } else if ( !strcmp((char*)node->name, "arrows")) { line_info_get_arrows(filename, node, info); } else if ( !strcmp((char*)node->name, "line-color")) { line_info_get_line_color(filename, node, info); } } return( info ); }
/*! * \brief Contructor for ShapeInfo from file * * Load the full shape info from file potentially reusing the preloaded * ShapeInfo loaded by shape_typeinfo_load() * * \extends _ShapeInfo */ static ShapeInfo * load_shape_info(const gchar *filename, ShapeInfo *preload) { xmlErrorPtr error_xml = NULL; xmlDocPtr doc = xmlDoParseFile(filename, &error_xml); xmlNsPtr shape_ns, svg_ns; xmlNodePtr node, root, ext_node = NULL; ShapeInfo *info; gchar *tmp; int i; if (!doc) { g_warning("Custom shape parser error for %s\n%s", filename, error_xml ? error_xml->message : ""); return NULL; } /* skip (emacs) comments */ root = doc->xmlRootNode; while (root && (root->type != XML_ELEMENT_NODE)) root = root->next; if (!root) return NULL; if (xmlIsBlankNode(root)) return NULL; if (!(shape_ns = xmlSearchNsByHref(doc, root, (const xmlChar *)"http://www.daa.com.au/~james/dia-shape-ns"))) { xmlFreeDoc(doc); g_warning("could not find shape namespace"); return NULL; } if (!(svg_ns = xmlSearchNsByHref(doc, root, (const xmlChar *)"http://www.w3.org/2000/svg"))) { xmlFreeDoc(doc); g_warning("could not find svg namespace"); return NULL; } if (root->ns != shape_ns || xmlStrcmp(root->name, (const xmlChar *)"shape")) { g_warning("root element was %s -- expecting shape", root->name); xmlFreeDoc(doc); return NULL; } if (preload) info = preload; else info = g_new0(ShapeInfo, 1); info->loaded = TRUE; info->shape_bounds.top = DBL_MAX; info->shape_bounds.left = DBL_MAX; info->shape_bounds.bottom = -DBL_MAX; info->shape_bounds.right = -DBL_MAX; info->aspect_type = SHAPE_ASPECT_FREE; info->default_width = 0.0; info->default_height = 0.0; info->main_cp = -1; info->object_flags = 0; i = 0; for (node = root->xmlChildrenNode; node != NULL; node = node->next) { if (xmlIsBlankNode(node)) continue; if (node->type != XML_ELEMENT_NODE) continue; if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"name")) { tmp = (gchar *) xmlNodeGetContent(node); if (preload) { if (strcmp (tmp, info->name) != 0) g_warning ("Shape(preload) '%s' can't change name '%s'", info->name, tmp); /* the key name is already used as key in name_to_info */ } else { g_free(info->name); info->name = g_strdup(tmp); } xmlFree(tmp); } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"icon")) { tmp = (gchar *) xmlNodeGetContent(node); if (preload) { if (strstr (info->icon, tmp) == NULL) /* the left including the absolute path */ g_warning ("Shape(preload) '%s' can't change icon '%s'", info->icon, tmp); /* the key name is already used as key in name_to_info */ } else { g_free(info->icon); info->icon = custom_get_relative_filename(filename, tmp); } xmlFree(tmp); } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"connections")) { GArray *arr = g_array_new(FALSE, FALSE, sizeof(Point)); xmlNodePtr pt_node; for (pt_node = node->xmlChildrenNode; pt_node != NULL; pt_node = pt_node->next) { if (xmlIsBlankNode(pt_node)) continue; if (pt_node->ns == shape_ns && !xmlStrcmp(pt_node->name, (const xmlChar *)"point")) { Point pt = { 0.0, 0.0 }; xmlChar *str; str = xmlGetProp(pt_node, (const xmlChar *)"x"); if (str) { pt.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(pt_node, (const xmlChar *)"y"); if (str) { pt.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } g_array_append_val(arr, pt); str = xmlGetProp(pt_node, (const xmlChar *)"main"); if (str && str[0] != '\0') { if (info->main_cp != -1) { message_warning("More than one main connection point in %s. Only the first one will be used.\n", info->name); } else { info->main_cp = i; } xmlFree(str); } } i++; } info->nconnections = arr->len; info->connections = (Point *)arr->data; g_array_free(arr, FALSE); } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"can-parent")) { info->object_flags |= DIA_OBJECT_CAN_PARENT; } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"textbox")) { xmlChar *str; str = xmlGetProp(node, (const xmlChar *)"x1"); if (str) { info->text_bounds.left = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"y1"); if (str) { info->text_bounds.top = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"x2"); if (str) { info->text_bounds.right = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"y2"); if (str) { info->text_bounds.bottom = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } info->resize_with_text = TRUE; str = xmlGetProp(node, (const xmlChar *)"resize"); if (str) { info->resize_with_text = TRUE; if (!xmlStrcmp(str,(const xmlChar *)"no")) info->resize_with_text = FALSE; xmlFree(str); } info->text_align = ALIGN_CENTER; str = xmlGetProp(node, (const xmlChar *)"align"); if (str) { if (!xmlStrcmp(str, (const xmlChar *)"left")) info->text_align = ALIGN_LEFT; else if (!xmlStrcmp(str, (const xmlChar *)"right")) info->text_align = ALIGN_RIGHT; xmlFree(str); } info->has_text = TRUE; } else if (node->ns == shape_ns && !xmlStrcmp(node->name, (const xmlChar *)"aspectratio")) { tmp = (gchar *) xmlGetProp(node, (const xmlChar *)"type"); if (tmp) { if (!strcmp(tmp, "free")) info->aspect_type = SHAPE_ASPECT_FREE; else if (!strcmp(tmp, "fixed")) info->aspect_type = SHAPE_ASPECT_FIXED; else if (!strcmp(tmp, "range")) { xmlChar *str; info->aspect_type = SHAPE_ASPECT_RANGE; info->aspect_min = 0.0; info->aspect_max = G_MAXFLOAT; str = xmlGetProp(node, (const xmlChar *)"min"); if (str) { info->aspect_min = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"max"); if (str) { info->aspect_max = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } if (info->aspect_max < info->aspect_min) { real asp = info->aspect_max; info->aspect_max = info->aspect_min; info->aspect_min = asp; } } xmlFree(tmp); } } else if (node->ns == shape_ns && (!xmlStrcmp(node->name, (const xmlChar *)"default-width") || !xmlStrcmp(node->name, (const xmlChar *)"default-height"))) { int j = 0; DiaUnitDef ud; gdouble val = 0.0; int unit_ssize = 0; int ssize = 0; tmp = (gchar *) xmlNodeGetContent(node); ssize = strlen(tmp); val = g_ascii_strtod(tmp, NULL); for (ud = units[j]; ud.name; ud = units[++j]) { unit_ssize = strlen(ud.unit); if (ssize > unit_ssize && !strcmp(tmp+(ssize-unit_ssize), ud.unit)) { val *= (ud.factor / 28.346457); break; } } if (!xmlStrcmp(node->name, (const xmlChar *)"default-width")) { info->default_width = val; } else { info->default_height = val; } xmlFree(tmp); } else if (node->ns == svg_ns && !xmlStrcmp(node->name, (const xmlChar *)"svg")) { DiaSvgStyle s = { 1.0, DIA_SVG_COLOUR_FOREGROUND, 1.0, DIA_SVG_COLOUR_NONE, 1.0, DIA_SVG_LINECAPS_DEFAULT, DIA_SVG_LINEJOIN_DEFAULT, DIA_SVG_LINESTYLE_DEFAULT, 1.0 }; dia_svg_parse_style(node, &s, -1); parse_svg_node(info, node, svg_ns, &s, filename); update_bounds(info); } else if (!xmlStrcmp(node->name, (const xmlChar *)"ext_attributes")) { ext_node = node; } } /*MC 11/03 parse ext attributes if any & prepare prop tables */ custom_setup_properties (info, ext_node); xmlFreeDoc(doc); return info; }
/*! * \brief Parse the SVG node from a shape file * * Fill the ShapeInfo display list with GraphicElement each got from * a single node within the shape's SVG part. * * \extends _ShapeInfo */ static void parse_svg_node(ShapeInfo *info, xmlNodePtr node, xmlNsPtr svg_ns, DiaSvgStyle *style, const gchar *filename) { xmlChar *str; /* walk SVG node ... */ for (node = node->xmlChildrenNode; node != NULL; node = node->next) { GraphicElement *el = NULL; DiaSvgStyle s; if (xmlIsBlankNode(node)) continue; if (node->type != XML_ELEMENT_NODE || node->ns != svg_ns) continue; dia_svg_style_init (&s, style); dia_svg_parse_style(node, &s, -1); if (!xmlStrcmp(node->name, (const xmlChar *)"line")) { GraphicElementLine *line = g_new0(GraphicElementLine, 1); el = (GraphicElement *)line; line->type = GE_LINE; str = xmlGetProp(node, (const xmlChar *)"x1"); if (str) { line->p1.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"y1"); if (str) { line->p1.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"x2"); if (str) { line->p2.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"y2"); if (str) { line->p2.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } } else if (!xmlStrcmp(node->name, (const xmlChar *)"polyline")) { GraphicElementPoly *poly; GArray *arr = g_array_new(FALSE, FALSE, sizeof(real)); real val, *rarr; gchar *tmp; int i; str = xmlGetProp(node, (const xmlChar *)"points"); tmp = (gchar *) str; while (tmp[0] != '\0') { /* skip junk */ while (tmp[0] != '\0' && !g_ascii_isdigit(tmp[0]) && tmp[0]!='.'&&tmp[0]!='-') tmp++; if (tmp[0] == '\0') break; val = g_ascii_strtod(tmp, &tmp); g_array_append_val(arr, val); } xmlFree(str); val = 0; if (arr->len % 2 == 1) g_array_append_val(arr, val); poly = g_malloc0(sizeof(GraphicElementPoly) + arr->len/2*sizeof(Point)); el = (GraphicElement *)poly; poly->type = GE_POLYLINE; poly->npoints = arr->len / 2; rarr = (real *)arr->data; for (i = 0; i < poly->npoints; i++) { poly->points[i].x = rarr[2*i]; poly->points[i].y = rarr[2*i+1]; } g_array_free(arr, TRUE); } else if (!xmlStrcmp(node->name, (const xmlChar *)"polygon")) { GraphicElementPoly *poly; GArray *arr = g_array_new(FALSE, FALSE, sizeof(real)); real val, *rarr; char *tmp; int i; str = xmlGetProp(node, (const xmlChar *)"points"); tmp = (char *) str; while (tmp[0] != '\0') { /* skip junk */ while (tmp[0] != '\0' && !g_ascii_isdigit(tmp[0]) && tmp[0]!='.'&&tmp[0]!='-') tmp++; if (tmp[0] == '\0') break; val = g_ascii_strtod(tmp, &tmp); g_array_append_val(arr, val); } xmlFree(str); val = 0; if (arr->len % 2 == 1) g_array_append_val(arr, val); poly = g_malloc0(sizeof(GraphicElementPoly) + arr->len/2*sizeof(Point)); el = (GraphicElement *)poly; poly->type = GE_POLYGON; poly->npoints = arr->len / 2; rarr = (real *)arr->data; for (i = 0; i < poly->npoints; i++) { poly->points[i].x = rarr[2*i]; poly->points[i].y = rarr[2*i+1]; } g_array_free(arr, TRUE); } else if (!xmlStrcmp(node->name, (const xmlChar *)"rect")) { GraphicElementRect *rect = g_new0(GraphicElementRect, 1); real corner_radius = 0.0; el = (GraphicElement *)rect; rect->type = GE_RECT; str = xmlGetProp(node, (const xmlChar *)"x"); if (str) { rect->corner1.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } else rect->corner1.x = 0; str = xmlGetProp(node, (const xmlChar *)"y"); if (str) { rect->corner1.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } else rect->corner1.y = 0; str = xmlGetProp(node, (const xmlChar *)"width"); if (str) { rect->corner2.x = rect->corner1.x + g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"height"); if (str) { rect->corner2.y = rect->corner1.y + g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"rx"); if (str) { corner_radius = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"ry"); if (str) { if(corner_radius != 0.0) { /* calculate the mean value of rx and ry */ corner_radius = (corner_radius+g_ascii_strtod((gchar *) str, NULL))/2; } else { corner_radius = g_ascii_strtod((gchar *) str, NULL); } xmlFree(str); } rect->corner_radius = corner_radius; } else if (!xmlStrcmp(node->name, (const xmlChar *)"text")) { GraphicElementText *text = g_new(GraphicElementText, 1); el = (GraphicElement *)text; text->type = GE_TEXT; text->object = NULL; str = xmlGetProp(node, (const xmlChar *)"x"); if (str) { text->anchor.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } else text->anchor.x = 0; str = xmlGetProp(node, (const xmlChar *)"y"); if (str) { text->anchor.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } else text->anchor.y = 0; str = xmlGetProp(node, (const xmlChar *)"font-size"); if (str) { text->s.font_height = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } else text->s.font_height = 0.8; str = xmlNodeGetContent(node); if (str) { text->string = g_strdup((gchar *) str); xmlFree(str); } else text->string = g_strdup(""); } else if (!xmlStrcmp(node->name, (const xmlChar *)"circle")) { GraphicElementEllipse *ellipse = g_new0(GraphicElementEllipse, 1); el = (GraphicElement *)ellipse; ellipse->type = GE_ELLIPSE; str = xmlGetProp(node, (const xmlChar *)"cx"); if (str) { ellipse->center.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"cy"); if (str) { ellipse->center.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"r"); if (str) { ellipse->width = ellipse->height = 2 * g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } } else if (!xmlStrcmp(node->name, (const xmlChar *)"ellipse")) { GraphicElementEllipse *ellipse = g_new0(GraphicElementEllipse, 1); el = (GraphicElement *)ellipse; ellipse->type = GE_ELLIPSE; str = xmlGetProp(node, (const xmlChar *)"cx"); if (str) { ellipse->center.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"cy"); if (str) { ellipse->center.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"rx"); if (str) { ellipse->width = 2 * g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"ry"); if (str) { ellipse->height = 2 * g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } } else if (!xmlStrcmp(node->name, (const xmlChar *)"path")) { str = xmlGetProp(node, (const xmlChar *)"d"); if (str) { parse_path(info, (char *) str, &s, filename); xmlFree(str); } } else if (!xmlStrcmp(node->name, (const xmlChar *)"image")) { GraphicElementImage *image = g_new0(GraphicElementImage, 1); el = (GraphicElement *)image; image->type = GE_IMAGE; str = xmlGetProp(node, (const xmlChar *)"x"); if (str) { image->topleft.x = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"y"); if (str) { image->topleft.y = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"width"); if (str) { image->width = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"height"); if (str) { image->height = g_ascii_strtod((gchar *) str, NULL); xmlFree(str); } str = xmlGetProp(node, (const xmlChar *)"xlink:href"); if (!str) /* this doesn't look right but it appears to work w/o namespace --hb */ str = xmlGetProp(node, (const xmlChar *)"href"); if (str) { gchar *imgfn = NULL; const char* data = strchr((char *)str, ','); /* first check for inlined data */ if (data) { GdkPixbuf *pixbuf = pixbuf_decode_base64 (data+1); if (pixbuf) { image->image = dia_image_new_from_pixbuf (pixbuf); g_object_unref (pixbuf); } } else { imgfn = g_filename_from_uri((gchar *) str, NULL, NULL); if (!imgfn) /* despite it's name it ensures an absolute filename */ imgfn = custom_get_relative_filename(filename, (gchar *) str); image->image = dia_image_load(imgfn); } if (!image->image) g_debug("failed to load image file %s", imgfn ? imgfn : "(data:)"); g_free(imgfn); xmlFree(str); } /* w/o the image we would crash later */ if (!image->image) image->image = dia_image_get_broken(); } else if (!xmlStrcmp(node->name, (const xmlChar *)"g")) { if (!is_subshape(node)) { /* add elements from the group element */ parse_svg_node(info, node, svg_ns, &s, filename); } else { /* add elements from the group element, but make it a subshape */ GraphicElementSubShape *subshape = g_new0(GraphicElementSubShape, 1); ShapeInfo* tmpinfo = g_new0(ShapeInfo, 1); xmlChar *v_anchor_attr = xmlGetProp(node, (const xmlChar*)"v_anchor"); xmlChar *h_anchor_attr = xmlGetProp(node, (const xmlChar*)"h_anchor"); parse_svg_node(tmpinfo, node, svg_ns, &s, filename); tmpinfo->shape_bounds.top = DBL_MAX; tmpinfo->shape_bounds.left = DBL_MAX; tmpinfo->shape_bounds.bottom = -DBL_MAX; tmpinfo->shape_bounds.right = -DBL_MAX; update_bounds( tmpinfo ); update_bounds( info ); subshape->half_width = (tmpinfo->shape_bounds.right-tmpinfo->shape_bounds.left) / 2.0; subshape->half_height = (tmpinfo->shape_bounds.bottom-tmpinfo->shape_bounds.top) / 2.0; subshape->center.x = tmpinfo->shape_bounds.left + subshape->half_width; subshape->center.y = tmpinfo->shape_bounds.top + subshape->half_height; subshape->type = GE_SUBSHAPE; subshape->display_list = tmpinfo->display_list; subshape->v_anchor_method = OFFSET_METHOD_FIXED; subshape->h_anchor_method = OFFSET_METHOD_FIXED; subshape->default_scale = 0.0; if (!v_anchor_attr || !strcmp((const char*)v_anchor_attr,"fixed.top")) subshape->v_anchor_method = OFFSET_METHOD_FIXED; else if (v_anchor_attr && !strcmp((const char*)v_anchor_attr,"fixed.bottom")) subshape->v_anchor_method = -OFFSET_METHOD_FIXED; else if (v_anchor_attr && !strcmp((const char*)v_anchor_attr,"proportional")) subshape->v_anchor_method = OFFSET_METHOD_PROPORTIONAL; else fprintf( stderr, "illegal v_anchor `%s', defaulting to fixed.top\n", v_anchor_attr ); if (!h_anchor_attr || !strcmp((const char*)h_anchor_attr,"fixed.left")) subshape->h_anchor_method = OFFSET_METHOD_FIXED; else if (h_anchor_attr && !strcmp((const char*)h_anchor_attr,"fixed.right")) subshape->h_anchor_method = -OFFSET_METHOD_FIXED; else if (h_anchor_attr && !strcmp((const char*)h_anchor_attr,"proportional")) subshape->h_anchor_method = OFFSET_METHOD_PROPORTIONAL; else fprintf( stderr, "illegal h_anchor `%s', defaulting to fixed.left\n", h_anchor_attr ); info->subshapes = g_list_append(info->subshapes, subshape); /* gfree( tmpinfo );*/ xmlFree(v_anchor_attr); xmlFree(h_anchor_attr); el = (GraphicElement *)subshape; } } if (el) { el->any.s = s; if (el->any.s.font) el->any.s.font = g_object_ref(s.font); info->display_list = g_list_append(info->display_list, el); } if (s.font) dia_font_unref (s.font); } }