static void parse_path(ShapeInfo *info, const char *path_str, DiaSvgStyle *s, const char* filename) { GArray *points; gchar *pathdata = (gchar *)path_str, *unparsed; gboolean closed = FALSE; Point current_point = {0.0, 0.0}; points = g_array_new(FALSE, FALSE, sizeof(BezPoint)); g_array_set_size(points, 0); do { if (!dia_svg_parse_path (points, pathdata, &unparsed, &closed, ¤t_point)) break; if (points->len > 0) { if (g_array_index(points, BezPoint, 0).type != BEZ_MOVE_TO) { message_warning (_("The file '%s' has invalid path data.\n" "svg:path data must start with moveto."), dia_message_filename(filename)); } else if (closed) { /* if there is some unclosed commands, add them as a GE_SHAPE */ GraphicElementPath *el = g_malloc(sizeof(GraphicElementPath) + points->len * sizeof(BezPoint)); el->type = GE_SHAPE; dia_svg_style_init (&el->s, s); el->npoints = points->len; memcpy((char *)el->points, points->data, points->len*sizeof(BezPoint)); info->display_list = g_list_append(info->display_list, el); } else { /* if there is some unclosed commands, add them as a GE_PATH */ GraphicElementPath *el = g_malloc(sizeof(GraphicElementPath) + points->len * sizeof(BezPoint)); el->type = GE_PATH; dia_svg_style_init (&el->s, s); el->npoints = points->len; memcpy((char *)el->points, points->data, points->len*sizeof(BezPoint)); info->display_list = g_list_append(info->display_list, el); } g_array_set_size (points, 0); } pathdata = unparsed; unparsed = NULL; } while (pathdata); g_array_free (points, TRUE); }
/** Return an absolute filename from an absolute or relative filename. * @param filename A relative or absolute filename. * @return Absolute and canonicalized filename as a newly allocated string. */ gchar * dia_get_absolute_filename (const gchar *filename) { gchar *current_dir; gchar *fullname; gchar *canonical; if (filename == NULL) return NULL; if (g_path_is_absolute(filename)) return dia_get_canonical_path(filename); current_dir = g_get_current_dir(); fullname = g_build_filename(current_dir, filename, NULL); g_free(current_dir); if (strchr(fullname, '.') == NULL) return fullname; canonical = dia_get_canonical_path(fullname); if (canonical == NULL) { message_warning(_("Too many \"..\"s in filename %s\n"), dia_message_filename(filename)); return g_strdup(filename); } g_free(fullname); return canonical; }
/** If all files produced by dia were good XML files, we wouldn't have to do * this little gymnastic. Alas, during the libxml1 days, we were outputting * files with no encoding specification (which means UTF-8 if we're in an * asciish encoding) and strings encoded in local charset (so, we wrote * broken files). * * The following logic finds if we have a broken file, and attempts to fix * it if it's possible. If the file is correct or is unrecognisable, we pass * it untouched to libxml2. * @param filename The name of the file to check. * @param default_enc The default encoding to use if none is given. * @return The filename given if it seems ok, or the name of a new file * with fixed contents, or NULL if we couldn't read the file. The * caller should free this string and unlink the file if it is not * the same as `filename'. * @bug The many gzclose-g_free-return sequences should be refactored into * an "exception handle" (goto+label). At least for people who think goto is * better than this. I dont. --hb */ static const gchar * xml_file_check_encoding(const gchar *filename, const gchar *default_enc) { int fd = g_open (filename, O_RDONLY, 0); gzFile zf = gzdopen(fd,"rb"); gchar *buf; gchar *p,*pmax; int len; gchar *tmp,*res; int uf; gboolean well_formed_utf8; static char magic_xml[] = {0x3c,0x3f,0x78,0x6d,0x6c,0x00}; /* "<?xml" in ASCII */ if (!zf) { dia_log_message("%s can not be opened for encoding check (%s)", filename, fd > 0 ? "gzdopen" : "g_open"); /* XXX perhaps we can just chicken out to libxml ? -- CC */ return filename; } p = buf = g_malloc0(BUFLEN); len = gzread(zf,buf,BUFLEN); pmax = p + len; /* first, we expect the magic <?xml string */ if ((0 != strncmp(p,magic_xml,5)) || (len < 5)) { gzclose(zf); g_free(buf); return filename; /* let libxml figure out what this is. */ } /* now, we're sure we have some asciish XML file. */ p += 5; while (((*p == 0x20)||(*p == 0x09)||(*p == 0x0d)||(*p == 0x0a)) && (p<pmax)) p++; if (p>=pmax) { /* whoops ? */ gzclose(zf); g_free(buf); return filename; } if (0 != strncmp(p,"version=\"",9)) { gzclose(zf); /* chicken out. */ g_free(buf); return filename; } p += 9; /* The header is rather well formed. */ if (p>=pmax) { /* whoops ? */ gzclose(zf); g_free(buf); return filename; } while ((*p != '"') && (p < pmax)) p++; p++; while (((*p == 0x20)||(*p == 0x09)||(*p == 0x0d)||(*p == 0x0a)) && (p<pmax)) p++; if (p>=pmax) { /* whoops ? */ gzclose(zf); g_free(buf); return filename; } if (0 == strncmp(p,"encoding=\"",10)) { gzclose(zf); /* this file has an encoding string. Good. */ g_free(buf); return filename; } /* now let's read the whole file, to see if there are offending bits. * We can call it well formed UTF-8 if the highest isn't used */ well_formed_utf8 = TRUE; do { int i; for (i = 0; i < len; i++) if (buf[i] & 0x80 || buf[i] == '&') well_formed_utf8 = FALSE; len = gzread(zf,buf,BUFLEN); } while (len > 0 && well_formed_utf8); if (well_formed_utf8) { gzclose(zf); /* this file is utf-8 compatible */ g_free(buf); return filename; } else { gzclose(zf); /* poor man's fseek */ fd = g_open (filename, O_RDONLY, 0); zf = gzdopen(fd,"rb"); len = gzread(zf,buf,BUFLEN); } if (0 != strcmp(default_enc,"UTF-8")) { message_warning(_("The file %s has no encoding specification;\n" "assuming it is encoded in %s"), dia_message_filename(filename), default_enc); } else { gzclose(zf); /* we apply the standard here. */ g_free(buf); return filename; } tmp = getenv("TMP"); if (!tmp) tmp = getenv("TEMP"); if (!tmp) tmp = "/tmp"; res = g_strconcat(tmp,G_DIR_SEPARATOR_S,"dia-xml-fix-encodingXXXXXX",NULL); uf = g_mkstemp(res); write(uf,buf,p-buf); write(uf," encoding=\"",11); write(uf,default_enc,strlen(default_enc)); write(uf,"\" ",2); write(uf,p,pmax - p); while (1) { len = gzread(zf,buf,BUFLEN); if (len <= 0) break; write(uf,buf,len); } gzclose(zf); close(uf); g_free(buf); return res; /* caller frees the name and unlinks the file. */ }
/** * A button hit in the Export Dialog */ static void file_export_response_callback(GtkWidget *fs, gint response, gpointer user_data) { char *filename; Diagram *dia; DiaExportFilter *ef; struct stat statbuf; dia = g_object_get_data (G_OBJECT (fs), "user_data"); g_assert (dia); if (response == GTK_RESPONSE_ACCEPT) { gint index; diagram_update_extents(dia); filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fs)); if (g_stat(filename, &statbuf) == 0) { GtkWidget *dialog = NULL; dialog = gtk_message_dialog_new (GTK_WINDOW(fs), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, _("File already exists")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), _("The file '%s' already exists.\n" "Do you want to overwrite it?"), dia_message_filename(filename)); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_YES) { /* if not overwrite allow to select another filename */ gtk_widget_destroy(dialog); g_free (filename); return; } gtk_widget_destroy(dialog); } index = gtk_combo_box_get_active (GTK_COMBO_BOX(user_data)); if (index >= 0) persistence_set_integer ("export-filter", index); ef = efilter_by_index (index - 1, NULL); if (!ef) ef = filter_guess_export_filter(filename); if (ef) { DiaContext *ctx = dia_context_new (_("Export")); g_object_ref(dia->data); dia_context_set_filename (ctx, filename); ef->export_func(dia->data, ctx, filename, dia->filename, ef->user_data); g_object_unref(dia->data); dia_context_release (ctx); } else message_error(_("Could not determine which export filter\n" "to use to save '%s'"), dia_message_filename(filename)); g_free (filename); } g_object_unref (dia); /* drop our diagram reference */ gtk_widget_destroy(exportdlg); }
/** Initializes a diagram with standard info and sets it to be called * 'filename'. * Returns TRUE if everything went ok, FALSE otherwise. * Will return FALSE if filename is not a legal string in the current * encoding. */ static gboolean diagram_init(Diagram *dia, const char *filename) { gchar *newfilename = NULL; GError *error = NULL; dia->data = &dia->parent_instance; /* compatibility */ dia->pagebreak_color = prefs.new_diagram.pagebreak_color; get_paper_info (&dia->data->paper, -1, &prefs.new_diagram); dia->grid.width_x = prefs.grid.x; dia->grid.width_y = prefs.grid.y; dia->grid.width_w = prefs.grid.w; dia->grid.hex_size = 1.0; dia->grid.colour = prefs.new_diagram.grid_color; dia->grid.hex = prefs.grid.hex; dia->grid.visible_x = prefs.grid.vis_x; dia->grid.visible_y = prefs.grid.vis_y; dia->grid.dynamic = prefs.grid.dynamic; dia->grid.major_lines = prefs.grid.major_lines; dia->guides.nhguides = 0; dia->guides.hguides = NULL; dia->guides.nvguides = 0; dia->guides.vguides = NULL; if (dia->filename != NULL) g_free(dia->filename); /* Make sure the filename is absolute */ if (!g_path_is_absolute(filename)) { gchar *pwd = g_get_current_dir(); newfilename = g_build_filename(pwd, filename, NULL); g_free(pwd); filename = newfilename; } /* All Diagram functions assumes filename in filesystem encoding */ dia->filename = g_filename_to_utf8(filename, -1, NULL, NULL, &error); if (error != NULL) { message_error(_("Couldn't convert filename '%s' to UTF-8: %s\n"), dia_message_filename(filename), error->message); g_error_free(error); dia->filename = g_strdup(_("Error")); return FALSE; } dia->unsaved = TRUE; dia->mollified = FALSE; dia->autosavefilename = NULL; if (dia->undo) undo_destroy(dia->undo); dia->undo = new_undo_stack(dia); if (!g_list_find(open_diagrams, dia)) open_diagrams = g_list_prepend(open_diagrams, dia); if (app_is_interactive()) layer_dialog_update_diagram_list(); g_free(newfilename); g_signal_connect (G_OBJECT(dia), "object_add", G_CALLBACK(_object_add), dia); g_signal_connect (G_OBJECT(dia), "object_remove", G_CALLBACK(_object_remove), dia); return TRUE; }
static DiaSvgRenderer * new_shape_renderer(DiagramData *data, const char *filename) { ShapeRenderer *shape_renderer; DiaSvgRenderer *renderer; FILE *file; char *point; xmlNsPtr name_space; xmlNodePtr xml_node_ptr; gint i; gchar *png_filename; char *shapename, *dirname, *fullname; char *sheetname; file = g_fopen(filename, "w"); if (file==NULL) { message_error(_("Can't open output file %s: %s\n"), dia_message_filename(filename), strerror(errno)); return NULL; } fclose(file); shape_renderer = g_object_new(SHAPE_TYPE_RENDERER, NULL); renderer = DIA_SVG_RENDERER (shape_renderer); renderer->filename = g_strdup(filename); renderer->dash_length = 1.0; renderer->dot_length = 0.2; renderer->saved_line_style = LINESTYLE_SOLID; /* keep everything unscaled, i.e. in Dia's scale default */ renderer->scale = 1.0; /* set up the root node */ renderer->doc = xmlNewDoc((const xmlChar *)"1.0"); renderer->doc->encoding = xmlStrdup((const xmlChar *)"UTF-8"); renderer->root = xmlNewDocNode(renderer->doc, NULL, (const xmlChar *)"shape", NULL); name_space = xmlNewNs(renderer->root, (const xmlChar *)"http://www.daa.com.au/~james/dia-shape-ns", NULL); renderer->svg_name_space = xmlNewNs(renderer->root, (const xmlChar *)"http://www.w3.org/2000/svg", (const xmlChar *)"svg"); renderer->doc->xmlRootNode = renderer->root; dirname = g_path_get_dirname(filename); sheetname = g_path_get_basename(dirname); shapename = g_strndup(g_basename(filename), strlen(g_basename(filename))-6); fullname = g_strdup_printf ("%s - %s", sheetname, shapename); g_free(dirname); g_free(sheetname); g_free(shapename); xmlNewChild(renderer->root, NULL, (const xmlChar *)"name", (xmlChar *) fullname); g_free(fullname); point = strrchr(filename, '.'); i = (int)(point-filename); point = g_strndup(filename, i); png_filename = g_strdup_printf("%s.png",point); g_free(point); xmlNewChild(renderer->root, NULL, (const xmlChar *)"icon", (xmlChar *) g_basename(png_filename)); g_free(png_filename); shape_renderer->connection_root = xmlNewChild(renderer->root, NULL, (const xmlChar *)"connections", NULL); xml_node_ptr = xmlNewChild(renderer->root, NULL, (const xmlChar *)"aspectratio",NULL); xmlSetProp(xml_node_ptr, (const xmlChar *)"type", (const xmlChar *)"fixed"); renderer->root = xmlNewChild(renderer->root, renderer->svg_name_space, (const xmlChar *)"svg", NULL); return renderer; }
static DiaSvgRenderer * new_svg_renderer(DiagramData *data, const char *filename) { DiaSvgRenderer *renderer; SvgRenderer *svg_renderer; FILE *file; gchar buf[512]; time_t time_now; Rectangle *extent; const char *name; xmlDtdPtr dtd; file = g_fopen(filename, "w"); if (file==NULL) { message_error(_("Can't open output file %s: %s\n"), dia_message_filename(filename), strerror(errno)); return NULL; } fclose(file); /* we need access to our base object */ renderer = DIA_SVG_RENDERER (g_object_new(SVG_TYPE_RENDERER, NULL)); renderer->filename = g_strdup(filename); renderer->dash_length = 1.0; renderer->dot_length = 0.2; renderer->saved_line_style = LINESTYLE_SOLID; /* apparently most svg readers don't like small values, especially not in the viewBox attribute */ renderer->scale = 20.0; /* set up the root node */ renderer->doc = xmlNewDoc((const xmlChar *)"1.0"); renderer->doc->encoding = xmlStrdup((const xmlChar *)"UTF-8"); renderer->doc->standalone = FALSE; dtd = xmlCreateIntSubset(renderer->doc, (const xmlChar *)"svg", (const xmlChar *)"-//W3C//DTD SVG 1.0//EN", (const xmlChar *)"http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd"); xmlAddChild((xmlNodePtr) renderer->doc, (xmlNodePtr) dtd); renderer->root = xmlNewDocNode(renderer->doc, NULL, (const xmlChar *)"svg", NULL); xmlAddSibling(renderer->doc->children, (xmlNodePtr) renderer->root); /* add namespaces to make strict parsers happy, e.g. Firefox */ svg_renderer = SVG_RENDERER (renderer); /* set the extents of the SVG document */ extent = &data->extents; g_snprintf(buf, sizeof(buf), "%dcm", (int)ceil((extent->right - extent->left))); xmlSetProp(renderer->root, (const xmlChar *)"width", (xmlChar *) buf); g_snprintf(buf, sizeof(buf), "%dcm", (int)ceil((extent->bottom - extent->top))); xmlSetProp(renderer->root, (const xmlChar *)"height", (xmlChar *) buf); g_snprintf(buf, sizeof(buf), "%d %d %d %d", (int)floor(extent->left * renderer->scale), (int)floor(extent->top * renderer->scale), (int)ceil((extent->right - extent->left) * renderer->scale), (int)ceil((extent->bottom - extent->top) * renderer->scale)); xmlSetProp(renderer->root, (const xmlChar *)"viewBox", (xmlChar *) buf); xmlSetProp(renderer->root,(const xmlChar *)"xmlns", (const xmlChar *)"http://www.w3.org/2000/svg"); xmlSetProp(renderer->root,(const xmlChar *)"xmlns", (const xmlChar *)"http://www.w3.org/2000/svg"); xmlSetProp(renderer->root,(const xmlChar *)"xmlns:xlink", (const xmlChar *)"http://www.w3.org/1999/xlink"); time_now = time(NULL); name = g_get_user_name(); #if 0 /* some comments at the top of the file ... */ xmlAddChild(renderer->root, xmlNewText("\n")); xmlAddChild(renderer->root, xmlNewComment("Dia-Version: "VERSION)); xmlAddChild(renderer->root, xmlNewText("\n")); g_snprintf(buf, sizeof(buf), "File: %s", dia->filename); xmlAddChild(renderer->root, xmlNewComment(buf)); xmlAddChild(renderer->root, xmlNewText("\n")); g_snprintf(buf, sizeof(buf), "Date: %s", ctime(&time_now)); buf[strlen(buf)-1] = '\0'; /* remove the trailing new line */ xmlAddChild(renderer->root, xmlNewComment(buf)); xmlAddChild(renderer->root, xmlNewText("\n")); g_snprintf(buf, sizeof(buf), "For: %s", name); xmlAddChild(renderer->root, xmlNewComment(buf)); xmlAddChild(renderer->root, xmlNewText("\n\n")); xmlNewChild(renderer->root, NULL, "title", dia->filename); #endif return renderer; }
/** * @param filename the file to load from or NULL for default * @param create_lazy if FALSE creates default objects for * every known type. Otherwise default objects * are created on demand * * Create all the default objects. */ gboolean dia_object_defaults_load (const gchar *filename, gboolean create_lazy) { xmlDocPtr doc; xmlNsPtr name_space; ObjectNode obj_node, layer_node; object_default_create_lazy = create_lazy; if (!defaults_hash) { defaults_hash = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, _obj_destroy); if (!create_lazy) object_registry_foreach (_obj_create, defaults_hash); } /* overload properties from file */ if (!filename) { gchar *default_filename = dia_config_filename("defaults.dia"); if (g_file_test(default_filename, G_FILE_TEST_EXISTS)) doc = xmlDiaParseFile(default_filename); else doc = NULL; g_free (default_filename); } else doc = xmlDiaParseFile(filename); if (!doc) return FALSE; name_space = xmlSearchNs(doc, doc->xmlRootNode, (const xmlChar *)"dia"); if (xmlStrcmp (doc->xmlRootNode->name, (const xmlChar *)"diagram") || (name_space == NULL)) { message_error(_("Error loading defaults '%s'.\n" "Not a Dia diagram file."), dia_message_filename(filename)); xmlFreeDoc (doc); return FALSE; } layer_node = doc->xmlRootNode->xmlChildrenNode; while (layer_node) { if ( !xmlIsBlankNode(layer_node) && 0 == xmlStrcmp(layer_node->name, (const xmlChar *)"layer")) { obj_node = layer_node->xmlChildrenNode; while (obj_node) { if (!xmlIsBlankNode(obj_node) && 0 == xmlStrcmp(obj_node->name, (const xmlChar *)"object")) { char *typestr = (char *) xmlGetProp(obj_node, (const xmlChar *)"type"); char *version = (char *) xmlGetProp(obj_node, (const xmlChar *)"version"); if (typestr) { DiaObject *obj = g_hash_table_lookup (defaults_hash, typestr); if (!obj) { if (!create_lazy) g_warning ("Unknown object '%s' while reading '%s'", typestr, filename); else { DiaObjectType *type = object_get_type (typestr); if (type) obj = type->ops->load ( obj_node, 0, filename); if (obj) g_hash_table_insert (defaults_hash, obj->type->name, obj); } } else { #if 0 /* lots of complaining about missing attributes */ object_load_props(obj, obj_node); /* leaks ?? */ #else DiaObject *def_obj; def_obj = obj->type->ops->load ( obj_node, /*version ? atoi(version) : 0,*/0, filename); if (def_obj->ops->set_props) { object_copy_props (obj, def_obj, TRUE); def_obj->ops->destroy (def_obj); } else { /* can't copy props */ g_hash_table_replace (defaults_hash, def_obj->type->name, def_obj); } #endif } if (version) xmlFree (version); xmlFree (typestr); } } obj_node = obj_node->next; } } layer_node = layer_node->next; } xmlFreeDoc(doc); return TRUE; }