/* -*- Mode: C; c-basic-offset: 4 -*- */ /* Dia -- an diagram creation/manipulation program * Copyright (C) 1998 Alexander Larsson * * xfig-import.c: xfig import filter for dia * Copyright (C) 2001 Lars Clausen * based on the dxf-import code * Copyright (C) 2000 Steffen Macke * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include /* Information used here is taken from the FIG Format 3.2 specification Some items left unspecified in the specifications are taken from the XFig source v. 3.2.3c */ #include #include #include #include #include #include #include #include "intl.h" #include "message.h" #include "geometry.h" #include "filter.h" #include "object.h" #include "properties.h" #include "propinternals.h" #include "group.h" #include "create.h" #include "xfig.h" #define BUFLEN 512 static Color fig_colors[FIG_MAX_USER_COLORS]; gboolean import_fig(const gchar *filename, DiagramData *dia, void* user_data); /** Eats the rest of the line. */ static void eat_line(FILE *file) { char buf[BUFLEN]; do { if (fgets(buf, BUFLEN, file) == NULL) { return; } if (buf[strlen(buf)-1] == '\n') return; } while (!feof(file)); } /** Skip past FIG comments (lines starting with #) and empty lines. * Returns TRUE if there is more in the file to read. */ static int skip_comments(FILE *file) { int ch; while (!feof(file)) { if ((ch = fgetc(file)) == EOF) { return FALSE; } if (ch == '\n') continue; else if (ch == '#') { eat_line(file); continue; } else { ungetc(ch, file); return TRUE; } } return FALSE; } static Color fig_color(int color_index) { if (color_index <= -1) return color_black; /* Default color */ else if (color_index < FIG_MAX_DEFAULT_COLORS) return fig_default_colors[color_index]; else if (color_index < FIG_MAX_USER_COLORS) return fig_colors[color_index-FIG_MAX_DEFAULT_COLORS]; else { message_error(_("Color index %d too high, only 512 colors allowed. Using black instead."), color_index); return color_black; } } static Color fig_area_fill_color(int area_fill, int color_index) { Color col; col = fig_color(color_index); if (area_fill == -1) return col; if (area_fill >= 0 && area_fill <= 20) { if (color_index == -1 || color_index == 0) { col.red = 0xff*(20-area_fill)/20; col.green = 0xff*(20-area_fill)/20; col.blue = 0xff*(20-area_fill)/20; } else { col.red = (col.red*area_fill)/20; col.green = (col.green*area_fill)/20; col.blue = (col.blue*area_fill)/20; } } else if (area_fill > 20 && area_fill <= 40) { /* White and black area illegal here */ col.red += (0xff-col.red)*(area_fill-20)/20; col.green += (0xff-col.green)*(area_fill-20)/20; col.blue += (0xff-col.blue)*(area_fill-20)/20; } else { message_warning(_("Patterns are not supported by Dia")); } return col; } static PropDescription xfig_simple_prop_descs_line[] = { { "line_width", PROP_TYPE_REAL }, { "line_colour", PROP_TYPE_COLOUR }, PROP_DESC_END}; static LineStyle fig_line_style_to_dia(int line_style) { switch (line_style) { case 0: return LINESTYLE_SOLID; case 1: return LINESTYLE_DASHED; case 2: return LINESTYLE_DOTTED; case 3: return LINESTYLE_DASH_DOT; case 4: return LINESTYLE_DASH_DOT_DOT; case 5: message_warning(_("Triple-dotted lines are not supported by Dia, " "using double-dotted")); return LINESTYLE_DASH_DOT_DOT; default: message_error(_("Line style %d should not appear\n"), line_style); return LINESTYLE_SOLID; } } static void fig_simple_properties(DiaObject *obj, int line_style, float dash_length, int thickness, int pen_color, int fill_color, int area_fill) { GPtrArray *props = prop_list_from_descs(xfig_simple_prop_descs_line, pdtpp_true); RealProperty *rprop; ColorProperty *cprop; g_assert(props->len == 2); rprop = g_ptr_array_index(props,0); rprop->real_data = thickness/FIG_ALT_UNIT; cprop = g_ptr_array_index(props,1); cprop->color_data = fig_color(pen_color); if (line_style != -1) { LinestyleProperty *lsprop = (LinestyleProperty *)make_new_prop("line_style", PROP_TYPE_LINESTYLE, PROP_FLAG_DONT_SAVE); lsprop->dash = dash_length/FIG_ALT_UNIT; lsprop->style = fig_line_style_to_dia(line_style); g_ptr_array_add(props,lsprop); } if (area_fill == -1) { BoolProperty *bprop = (BoolProperty *)make_new_prop("show_background", PROP_TYPE_BOOL,PROP_FLAG_DONT_SAVE); bprop->bool_data = FALSE; g_ptr_array_add(props,bprop); } else { ColorProperty *cprop = (ColorProperty *)make_new_prop("fill_colour", PROP_TYPE_COLOUR, PROP_FLAG_DONT_SAVE); cprop->color_data = fig_area_fill_color(area_fill, fill_color); g_ptr_array_add(props,cprop); } obj->ops->set_props(obj, props); prop_list_free(props); } static int fig_read_n_points(FILE *file, int n, Point **points) { int i; GArray *points_list = g_array_sized_new(FALSE, FALSE, sizeof(Point), n); for (i = 0; i < n; i++) { int x,y; Point p; if (fscanf(file, " %d %d ", &x, &y) != 2) { message_error(_("Error while reading %dth of %d points: %s\n"), i, n, strerror(errno)); g_array_free(points_list, TRUE); return FALSE; } p.x = x/FIG_UNIT; p.y = y/FIG_UNIT; g_array_append_val(points_list, p); } fscanf(file, "\n"); *points = (Point *)points_list->data; g_array_free(points_list, FALSE); return TRUE; } static Arrow * fig_read_arrow(FILE *file) { int arrow_type, style; real thickness, width, height; Arrow *arrow; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%d %d %lf %lf %lf\n", &arrow_type, &style, &thickness, &width, &height) != 5) { message_error(_("Error while reading arrowhead\n")); setlocale(LC_NUMERIC,old_locale); return NULL; } setlocale(LC_NUMERIC,old_locale); arrow = g_new(Arrow, 1); switch (arrow_type) { case 0: arrow->type = ARROW_LINES; break; case 1: arrow->type = (style?ARROW_FILLED_TRIANGLE:ARROW_HOLLOW_TRIANGLE); break; case 2: arrow->type = (style?ARROW_FILLED_CONCAVE:ARROW_BLANKED_CONCAVE); break; case 3: arrow->type = (style?ARROW_FILLED_DIAMOND:ARROW_HOLLOW_DIAMOND); break; default: message_error(_("Unknown arrow type %d\n"), arrow_type); g_free(arrow); return NULL; } arrow->width = width/FIG_UNIT; arrow->length = height/FIG_UNIT; return arrow; } static gchar * fig_fix_text(gchar *text) { int i, j; int asciival; GError *err = NULL; gchar *converted; gboolean needs_conversion = FALSE; for (i = 0, j = 0; text[i] != 0; i++, j++) { if (text[i] == '\\') { sscanf(text+i+1, "%3o", &asciival); text[j] = asciival; i+=3; needs_conversion = TRUE; } else { text[j] = text[i]; } } /* Strip final newline */ text[j-1] = 0; if (text[j-2] == '\001') { text[j-2] = 0; } if (needs_conversion) { /* Crudely assuming that fig uses Latin-1 */ converted = g_convert(text, strlen(text), "UTF-8", "ISO-8859-1", NULL, NULL, &err); if (err != NULL) { printf("Error converting %s: %s\n", text, err->message); return text; } if (!g_utf8_validate(converted, -1, NULL)) { printf("Fails to validate %s\n", converted); return text; } if (text != converted) g_free(text); return converted; } else return text; } static char * fig_read_text_line(FILE *file) { char *text_buf; int text_alloc, text_len; getc(file); text_alloc = 80; text_buf = (char *)g_malloc(text_alloc*sizeof(char)); text_len = 0; while (fgets(text_buf+text_len, text_alloc-text_len, file) != NULL) { if (strlen(text_buf) < text_alloc-1) break; text_len = text_alloc; text_alloc *= 2; text_buf = (char *)g_realloc(text_buf, text_alloc*sizeof(char)); } text_buf = fig_fix_text(text_buf); return text_buf; } static GList *depths[FIG_MAX_DEPTHS]; /* If there's something in the compound stack, we ignore the depth field, as it will be determined by the group anyway */ static GSList *compound_stack = NULL; /* When collection compounds, this is the *highest* depth an element is found at. Since Dia groups are of one level, we put them all at that level. Best we can do now. */ static int compound_depth; /** Add an object at a given depth. This function checks for depth limits * and updates the compound depth if needed. * * @param newobj An object to add. If we're inside a compound, this * doesn't really add the object. * @param depth A depth as in the Fig format, max 999 */ static void add_at_depth(DiaObject *newobj, int depth) { if (depth < 0 || depth >= FIG_MAX_DEPTHS) { message_error(_("Depth %d of of range, only 0-%d allowed.\n"), depth, FIG_MAX_DEPTHS-1); depth = FIG_MAX_DEPTHS - 1; } if (compound_stack == NULL) depths[depth] = g_list_append(depths[depth], newobj); else if (compound_depth > depth) compound_depth = depth; } static DiaObject * fig_read_ellipse(FILE *file) { int sub_type; int line_style; int thickness; int pen_color; int fill_color; int depth; int pen_style; int area_fill; real style_val; int direction; real angle; int center_x, center_y; int radius_x, radius_y; int start_x, start_y; int end_x, end_y; DiaObject *newobj = NULL; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%d %d %d %d %d %d %d %d %lf %d %lf %d %d %d %d %d %d %d %d\n", &sub_type, &line_style, &thickness, &pen_color, &fill_color, &depth, &pen_style, &area_fill, &style_val, &direction, &angle, ¢er_x, ¢er_y, &radius_x, &radius_y, &start_x, &start_y, &end_x, &end_y) < 19) { message_error(_("Couldn't read ellipse info: %s\n"), strerror(errno)); setlocale(LC_NUMERIC, old_locale); return NULL; } setlocale(LC_NUMERIC, old_locale); /* Curiously, the sub_type doesn't matter, as all info can be extracted this way */ newobj = create_standard_ellipse((center_x-radius_x)/FIG_UNIT, (center_y-radius_y)/FIG_UNIT, (2*radius_x)/FIG_UNIT, (2*radius_y)/FIG_UNIT); if (newobj == NULL) return NULL; fig_simple_properties(newobj, line_style, style_val, thickness, pen_color, fill_color, area_fill); /* Pen style field (not used) */ /* Style_val (size of dots and dashes) in 1/80 inch */ /* Direction (not used) */ /* Angle -- can't rotate yet */ /* Depth field */ add_at_depth(newobj, depth); return newobj; } static DiaObject * fig_read_polyline(FILE *file) { int sub_type; int line_style; int thickness; int pen_color; int fill_color; int depth; int pen_style; int area_fill; real style_val; int join_style; int cap_style; int radius; int forward_arrow, backward_arrow; Arrow *forward_arrow_info = NULL, *backward_arrow_info = NULL; int npoints; Point *points; GPtrArray *props = g_ptr_array_new(); DiaObject *newobj = NULL; int flipped = 0; char *image_file = NULL; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%d %d %d %d %d %d %d %d %lf %d %d %d %d %d %d\n", &sub_type, &line_style, &thickness, &pen_color, &fill_color, &depth, &pen_style, &area_fill, &style_val, &join_style, &cap_style, &radius, &forward_arrow, &backward_arrow, &npoints) != 15) { message_error(_("Couldn't read polyline info: %s\n"), strerror(errno)); goto exit; } if (forward_arrow == 1) { forward_arrow_info = fig_read_arrow(file); } if (backward_arrow == 1) { backward_arrow_info = fig_read_arrow(file); } if (sub_type == 5) { /* image has image name before npoints */ /* Despite what the specs say */ if (fscanf(file, " %d", &flipped) != 1) { message_error(_("Couldn't read flipped bit: %s\n"), strerror(errno)); goto exit; } image_file = fig_read_text_line(file); } if (!fig_read_n_points(file, npoints, &points)) { goto exit; } switch (sub_type) { case 4: { RealProperty *rprop = (RealProperty *)make_new_prop("corner_radius", PROP_TYPE_REAL,PROP_FLAG_DONT_SAVE); if (radius < 0) { message_warning(_("Negative corner radius, negating")); rprop->real_data = -radius/FIG_ALT_UNIT; } else { rprop->real_data = radius/FIG_ALT_UNIT; } g_ptr_array_add(props,rprop); } /* Notice fallthrough */ case 2: /* box */ if (points[0].x > points[2].x) { real tmp = points[0].x; points[0].x = points[2].x; points[2].x = tmp; } if (points[0].y > points[2].y) { real tmp = points[0].y; points[0].y = points[2].y; points[2].y = tmp; } newobj = create_standard_box(points[0].x, points[0].y, points[2].x-points[0].x, points[2].y-points[0].y); if (newobj == NULL) goto exit; newobj->ops->set_props(newobj, props); break; case 5: /* imported-picture bounding-box) */ newobj = create_standard_image(points[0].x, points[0].y, points[2].x-points[0].x, points[2].y-points[0].y, image_file); if (newobj == NULL) goto exit; break; case 1: /* polyline */ newobj = create_standard_polyline(npoints, points, forward_arrow_info, backward_arrow_info); if (newobj == NULL) goto exit; break; case 3: /* polygon */ newobj = create_standard_polygon(npoints, points); if (newobj == NULL) goto exit; break; default: message_error(_("Unknown polyline subtype: %d\n"), sub_type); goto exit; } fig_simple_properties(newobj, line_style, style_val, thickness, pen_color, fill_color, area_fill); /* Pen style field (not used) */ /* Style_val (size of dots and dashes) in 1/80 inch*/ /* Join style */ /* Cap style */ /* Depth field */ add_at_depth(newobj, depth); exit: setlocale(LC_NUMERIC, old_locale); prop_list_free(props); g_free(forward_arrow_info); g_free(backward_arrow_info); g_free(image_file); return newobj; } #define TENSION 0.25 static BezPoint *transform_spline(int npoints, Point *points, gboolean closed) { BezPoint *bezpoints = g_new(BezPoint, npoints); int i; Point vector; for (i = 0; i < npoints; i++) { bezpoints[i].p3 = points[i]; bezpoints[i].type = BEZ_CURVE_TO; } bezpoints[0].type = BEZ_MOVE_TO; bezpoints[0].p1 = points[0]; for (i = 1; i < npoints-1; i++) { bezpoints[i].p2 = points[i]; bezpoints[i+1].p1 = points[i]; vector = points[i-1]; point_sub(&vector, &points[i+1]); point_scale(&vector, -TENSION); point_sub(&bezpoints[i].p2, &vector); point_add(&bezpoints[i+1].p1, &vector); } if (closed) { bezpoints[npoints-1].p2 = points[i]; bezpoints[1].p1 = points[i]; vector = points[npoints-2]; point_sub(&vector, &points[1]); point_scale(&vector, -TENSION); point_sub(&bezpoints[npoints-1].p2, &vector); point_add(&bezpoints[1].p1, &vector); } else { bezpoints[1].p1 = points[0]; bezpoints[npoints-1].p2 = bezpoints[npoints-1].p3; } return bezpoints; } /* The XFig 'X-Splines' seem to be a generalization of cubic B-Splines * and Catmull-Rom splines. * Our Beziers, if Beziers they are, have the basis matrix M_bez * [-1 3 -3 1] * [ 3 -6 3 0] * [-3 3 0 0] * [ 1 0 0 0] * * The basis matrix for cubic B-Splines according to Hearn & Baker (M_b) * [-1 3 -3 1] * [ 3 -6 3 0]*1/6 * [-3 0 3 0] * [ 1 4 1 0] * So the transformation matrix (M_bez^-1)*M_b should be * [ 1 4 1 0] * [ 0 4 2 0]*1/6 * [ 0 2 4 0] * [ 0 1 4 1] * * The basis matrix for Catmull-Rom splines (M_c) is: * [-s 2-s s-2 s] * [2s s-3 3-2s -s] * [-s 0 s 0] * [ 0 1 0 0] where s = (1-t)/2 and t = 0, so s = 1/2: * [ -.5 1.5 -1.5 .5] * [ 1 -2.5 2 -.5] * [ -.5 0 .5 0] * [ 0 1 4 1] * Thus, the transformation matrix for the interpolated splines should be * (M_bez^-1)*M_c * The conversion matrix should then be: * [0 1 4 1] * [-1/6 1 4+1/6 1] * [0 1/6 5 5/6] * [0 0 5 1] * or * [ 0 6 24 6] * [-1 6 25 6]*1/6 * [ 0 1 30 5] * [ 0 0 30 5] */ static real matrix_bspline_to_bezier[4][4] = {{1/6.0, 4/6.0, 1/6.0, 0}, {0, 4/6.0, 2/6.0, 0}, {0, 2/6.0, 4/6.0, 0}, {0, 1/6.0, 4/6.0, 1/6.0}}; static real matrix_catmull_to_bezier[4][4] = {{0, 1, 4, 1}, {-1/6.0, 1, 25/26.0, 1}, {0, 1, 5, 5/6.0}, {0, 0, 5, 5/6.0}}; static DiaObject * fig_read_spline(FILE *file) { int sub_type; int line_style; int thickness; int pen_color; int fill_color; int depth; int pen_style; int area_fill; real style_val; int cap_style; int forward_arrow, backward_arrow; Arrow *forward_arrow_info = NULL, *backward_arrow_info = NULL; int npoints; Point *points; GPtrArray *props = g_ptr_array_new(); DiaObject *newobj = NULL; BezPoint *bezpoints; int i; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%d %d %d %d %d %d %d %d %lf %d %d %d %d\n", &sub_type, &line_style, &thickness, &pen_color, &fill_color, &depth, &pen_style, &area_fill, &style_val, &cap_style, &forward_arrow, &backward_arrow, &npoints) != 13) { message_error(_("Couldn't read spline info: %s\n"), strerror(errno)); goto exit; } if (forward_arrow == 1) { forward_arrow_info = fig_read_arrow(file); } if (backward_arrow == 1) { backward_arrow_info = fig_read_arrow(file); } if (!fig_read_n_points(file, npoints, &points)) { goto exit; } switch (sub_type) { case 0: /* Open approximated spline */ case 1: /* Closed approximated spline */ message_warning(_("Cannot convert approximated spline yet.")); goto exit; case 2: /* Open interpolated spline */ case 3: /* Closed interpolated spline */ /* Despite what the Fig description says, interpolated splines now also have the line with spline info from the X-spline */ case 4: /* Open X-spline */ case 5: /* Closed X-spline */ { double f; gboolean interpolated = TRUE; for (i = 0; i < npoints; i++) { if (fscanf(file, " %lf ", &f) != 1) { message_error(_("Couldn't read spline info: %s\n"), strerror(errno)); goto exit; } if (f != -1.0 && f != 0.0) { message_warning(_("Cannot convert approximated spline yet.")); interpolated = FALSE; } } if (!interpolated) goto exit; /* Matrix-based conversion not ready yet. */ #if 0 if (sub_type%2 == 0) { bezpoints = fig_transform_spline(npoints, points, FALSE, f); newobj = create_standard_bezierline(npoints, bezpoints, forward_arrow_info, backward_arrow_info); } else { points = g_renew(Point, points, npoints+1); points[npoints] = points[0]; npoints++; bezpoints = fig_transform_spline(npoints, points, TRUE, f); newobj = create_standard_beziergon(npoints, bezpoints); } #else if (sub_type%2 == 0) { bezpoints = transform_spline(npoints, points, FALSE); newobj = create_standard_bezierline(npoints, bezpoints, forward_arrow_info, backward_arrow_info); } else { points = g_renew(Point, points, npoints+1); points[npoints] = points[0]; npoints++; bezpoints = transform_spline(npoints, points, TRUE); newobj = create_standard_beziergon(npoints, bezpoints); } #endif } if (newobj == NULL) goto exit; break; default: message_error(_("Unknown spline subtype: %d\n"), sub_type); goto exit; } fig_simple_properties(newobj, line_style, style_val, thickness, pen_color, fill_color, area_fill); /* Pen style field (not used) */ /* Style_val (size of dots and dashes) in 1/80 inch*/ /* Cap style */ /* Depth field */ add_at_depth(newobj, depth); exit: setlocale(LC_NUMERIC, old_locale); prop_list_free(props); g_free(forward_arrow_info); g_free(backward_arrow_info); g_free(points); return newobj; } static DiaObject * fig_read_arc(FILE *file) { int sub_type; int line_style; int thickness; int pen_color; int fill_color; int depth; int pen_style; int area_fill; real style_val; int cap_style; int direction; int forward_arrow, backward_arrow; Arrow *forward_arrow_info = NULL, *backward_arrow_info = NULL; DiaObject *newobj = NULL; real center_x, center_y; int x1, y1; int x2, y2; int x3, y3; real radius; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%d %d %d %d %d %d %d %d %lf %d %d %d %d %lf %lf %d %d %d %d %d %d\n", &sub_type, &line_style, &thickness, &pen_color, &fill_color, &depth, &pen_style, &area_fill, &style_val, &cap_style, &direction, &forward_arrow, &backward_arrow, ¢er_x, ¢er_y, &x1, &y1, &x2, &y2, &x3, &y3) != 21) { message_error(_("Couldn't read arc info: %s\n"), strerror(errno)); goto exit; } if (forward_arrow == 1) { forward_arrow_info = fig_read_arrow(file); } if (backward_arrow == 1) { backward_arrow_info = fig_read_arrow(file); } radius = sqrt((x1-center_x)*(x1-center_x)+(y1-center_y)*(y1-center_y))/FIG_UNIT; switch (sub_type) { case 0: /* We can't do pie-wedge properly yet */ case 1: newobj = create_standard_arc(x1/FIG_UNIT, y1/FIG_UNIT, x3/FIG_UNIT, y3/FIG_UNIT, radius, forward_arrow_info, backward_arrow_info); if (newobj == NULL) goto exit; break; default: message_error(_("Unknown polyline subtype: %d\n"), sub_type); goto exit; } fig_simple_properties(newobj, line_style, style_val, thickness, pen_color, fill_color, area_fill); /* Pen style field (not used) */ /* Style_val (size of dots and dashes) in 1/80 inch*/ /* Join style */ /* Cap style */ /* Depth field */ add_at_depth(newobj, depth); exit: setlocale(LC_NUMERIC, old_locale); g_free(forward_arrow_info); g_free(backward_arrow_info); return newobj; } static PropDescription xfig_text_descs[] = { { "text", PROP_TYPE_TEXT }, PROP_DESC_END /* Can't do the angle */ /* Height and length are ignored */ /* Flags */ }; static DiaObject * fig_read_text(FILE *file) { GPtrArray *props = NULL; TextProperty *tprop; DiaObject *newobj = NULL; int sub_type; int color; int depth; int pen_style; int font; real font_size; real angle; int font_flags; real height; real length; int x, y; char *text_buf = NULL; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, " %d %d %d %d %d %lf %lf %d %lf %lf %d %d", &sub_type, &color, &depth, &pen_style, &font, &font_size, &angle, &font_flags, &height, &length, &x, &y) != 12) { message_error(_("Couldn't read text info: %s\n"), strerror(errno)); setlocale(LC_NUMERIC, old_locale); return NULL; } /* Skip one space exactly */ text_buf = fig_read_text_line(file); newobj = create_standard_text(x/FIG_UNIT, y/FIG_UNIT); if (newobj == NULL) goto exit; props = prop_list_from_descs(xfig_text_descs,pdtpp_true); tprop = g_ptr_array_index(props,0); tprop->text_data = g_strdup(text_buf); /*g_free(text_buf); */ tprop->attr.alignment = sub_type; tprop->attr.position.x = x/FIG_UNIT; tprop->attr.position.y = y/FIG_UNIT; if (font_flags & 4) { switch (font) { case 0: tprop->attr.font = dia_font_new_from_legacy_name("Times-Roman"); break; case 1: tprop->attr.font = dia_font_new_from_legacy_name("Times-Roman"); break; case 2: tprop->attr.font = dia_font_new_from_legacy_name("Times-Bold"); break; case 3: tprop->attr.font = dia_font_new_from_legacy_name("Times-Italic"); break; case 4: tprop->attr.font = dia_font_new_from_legacy_name("Helvetica"); break; case 5: tprop->attr.font = dia_font_new_from_legacy_name("Courier"); break; default: message_warning("Can't find LaTeX font nr. %d, using sans\n", font); tprop->attr.font = dia_font_new_from_legacy_name("Helvetica"); } } else { if (font == -1) { /* "Default font" - wazzat? */ tprop->attr.font = dia_font_new_from_legacy_name("Times Roman"); } else if (font < 0 || font > 34) { message_warning("Can't find Postscript font nr. %d, using sans\n", font); tprop->attr.font = dia_font_new_from_legacy_name("Helvetica"); } else { tprop->attr.font = dia_font_new_from_legacy_name(fig_fonts[font]); } } tprop->attr.height = font_size*3.54/72.0; tprop->attr.color = fig_color(color); newobj->ops->set_props(newobj, props); /* Depth field */ add_at_depth(newobj, depth); exit: setlocale(LC_NUMERIC, old_locale); if (text_buf != NULL) g_free(text_buf); if (props != NULL) prop_list_free(props); return newobj; } static gboolean fig_read_object(FILE *file) { int objecttype; DiaObject *item = NULL; if (fscanf(file, "%d ", &objecttype) != 1) { if (!feof(file)) { message_error(_("Couldn't identify FIG object: %s\n"), strerror(errno)); } return FALSE; } switch (objecttype) { case -6: { /* End of compound */ if (compound_stack == NULL) { message_error(_("Compound end outside compound\n")); return FALSE; } /* Make group item with these items */ item = create_standard_group((GList*)compound_stack->data); compound_stack = g_slist_remove(compound_stack, compound_stack->data); if (compound_stack == NULL) { depths[compound_depth] = g_list_append(depths[compound_depth], item); } break; } case 0: { /* Color pseudo-object. */ int colornumber; int colorvalues; Color color; if (fscanf(file, " %d #%xd", &colornumber, &colorvalues) != 2) { message_error(_("Couldn't read color: %s\n"), strerror(errno)); return FALSE; } if (colornumber < 32 || colornumber > FIG_MAX_USER_COLORS) { message_error(_("Color number %d out of range 0..%d. Discarding color.\n"), colornumber, FIG_MAX_USER_COLORS); return FALSE; } color.red = ((colorvalues & 0x00ff0000)>>16) / 255.0; color.green = ((colorvalues & 0x0000ff00)>>8) / 255.0; color.blue = (colorvalues & 0x000000ff) / 255.0; fig_colors[colornumber-32] = color; break; } case 1: { /* Ellipse which is a generalization of circle. */ item = fig_read_ellipse(file); if (item == NULL) { return FALSE; } break; } case 2: /* Polyline which includes polygon and box. */ item = fig_read_polyline(file); if (item == NULL) { return FALSE; } break; case 3: /* Spline which includes closed/open control/interpolated spline. */ item = fig_read_spline(file); if (item == NULL) { return FALSE; } break; case 4: /* Text. */ item = fig_read_text(file); if (item == NULL) { return FALSE; } break; case 5: /* Arc. */ item = fig_read_arc(file); if (item == NULL) { return FALSE; } break; case 6: {/* Compound object which is composed of one or more objects. */ int dummy; if (fscanf(file, " %d %d %d %d\n", &dummy, &dummy, &dummy, &dummy) != 4) { message_error(_("Couldn't read group extend: %s\n"), strerror(errno)); return FALSE; } /* Group extends don't really matter */ if (compound_stack == NULL) compound_depth = FIG_MAX_DEPTHS - 1; compound_stack = g_slist_append(compound_stack, NULL); return TRUE; break; } default: message_error(_("Unknown object type %d\n"), objecttype); return FALSE; break; } if (compound_stack != NULL && item != NULL) { /* We're building a compound */ GList *compound = (GList *)compound_stack->data; compound = g_list_append(compound, item); compound_stack->data = compound; } return TRUE; } static int fig_read_line_choice(FILE *file, char *choice1, char *choice2) { char buf[BUFLEN]; if (!fgets(buf, BUFLEN, file)) { return -1; } buf[strlen(buf)-1] = 0; /* Remove trailing newline */ g_strstrip(buf); /* And any other whitespace */ if (!g_strcasecmp(buf, choice1)) return 0; if (!g_strcasecmp(buf, choice2)) return 1; message_warning(_("`%s' is not one of `%s' or `%s'\n"), buf, choice1, choice2); return 0; } static int fig_read_paper_size(FILE *file, DiagramData *dia) { char buf[BUFLEN]; int paper; if (!fgets(buf, BUFLEN, file)) { message_error(_("Error reading paper size: %s\n"), strerror(errno)); return FALSE; } buf[strlen(buf)-1] = 0; /* Remove trailing newline */ g_strstrip(buf); /* And any other whitespace */ if ((paper = find_paper(buf)) != -1) { get_paper_info(&dia->paper, paper, NULL); return TRUE; } message_warning(_("Unknown paper size `%s', using default\n"), buf); return TRUE; } int figversion; static int fig_read_meta_data(FILE *file, DiagramData *dia) { if (figversion >= 300) { /* Might exist earlier */ int portrait; if ((portrait = fig_read_line_choice(file, "Portrait", "Landscape")) == -1) { message_error(_("Error reading paper orientation: %s\n"), strerror(errno)); return FALSE; } dia->paper.is_portrait = portrait; } if (figversion >= 300) { /* Might exist earlier */ int justify; if ((justify = fig_read_line_choice(file, "Center", "Flush Left")) == -1) { message_error(_("Error reading justification: %s\n"), strerror(errno)); return FALSE; } /* Don't know what to do with this */ } if (figversion >= 300) { /* Might exist earlier */ int units; if ((units = fig_read_line_choice(file, "Metric", "Inches")) == -1) { message_error(_("Error reading units: %s\n"), strerror(errno)); return FALSE; } /* Don't know what to do with this */ } if (figversion >= 302) { if (!fig_read_paper_size(file, dia)) return FALSE; } { real mag; char* old_locale; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%lf\n", &mag) != 1) { message_error(_("Error reading magnification: %s\n"), strerror(errno)); setlocale(LC_NUMERIC, old_locale); return FALSE; } setlocale(LC_NUMERIC, old_locale); dia->paper.scaling = mag/100; } if (figversion >= 302) { int multiple; if ((multiple = fig_read_line_choice(file, "Single", "Multiple")) == -1) { message_error(_("Error reading multipage indicator: %s\n"), strerror(errno)); return FALSE; } /* Don't know what to do with this */ } { int transparent; if (fscanf(file, "%d\n", &transparent) != 1) { message_error(_("Error reading transparent color: %s\n"), strerror(errno)); return FALSE; } /* Don't know what to do with this */ } if (!skip_comments(file)) { if (!feof(file)) { message_error(_("Error reading FIG file: %s\n"), strerror(errno)); } else { message_error(_("Premature end of FIG file\n")); } return FALSE; } { int resolution, coord_system; if (fscanf(file, "%d %d\n", &resolution, &coord_system) != 2) { message_error(_("Error reading resolution: %s\n"), strerror(errno)); return FALSE; } /* Don't know what to do with this */ } return TRUE; } /* imports the given fig-file, returns TRUE if successful */ gboolean import_fig(const gchar *filename, DiagramData *dia, void* user_data) { FILE *figfile; int figmajor, figminor; int i; for (i = 0; i < FIG_MAX_USER_COLORS; i++) { fig_colors[i] = color_black; } for (i = 0; i < FIG_MAX_DEPTHS; i++) { depths[i] = NULL; } figfile = g_fopen(filename,"r"); if(figfile == NULL){ message_error(_("Couldn't open: '%s' for reading.\n"), dia_message_filename(filename)); return FALSE; } /* First check magic bytes */ if (fscanf(figfile, "#FIG %d.%d\n", &figmajor, &figminor) != 2) { message_error(_("Doesn't look like a Fig file: %s\n"), strerror(errno)); fclose(figfile); return FALSE; } if (figmajor != 3 || figminor != 2) { message_warning(_("This is a FIG version %d.%d file, I may not understand it\n"), figmajor, figminor); } figversion = figmajor*100+figminor; if (!skip_comments(figfile)) { if (!feof(figfile)) { message_error(_("Error reading FIG file: %s\n"), strerror(errno)); } else { message_error(_("Premature end of FIG file\n")); } fclose(figfile); return FALSE; } if (!fig_read_meta_data(figfile, dia)) { fclose(figfile); return FALSE; } compound_stack = NULL; do { if (!skip_comments(figfile)) { if (!feof(figfile)) { message_error(_("Error reading FIG file: %s\n"), strerror(errno)); } else { break; } } if (! fig_read_object(figfile)) { fclose(figfile); break; } } while (TRUE); /* Now we can reorder for the depth fields */ for (i = 0; i < FIG_MAX_DEPTHS; i++) { if (depths[i] != NULL) layer_add_objects_first(dia->active_layer, depths[i]); } return TRUE; } /* interface from filter.h */ static const gchar *extensions[] = {"fig", NULL }; DiaImportFilter xfig_import_filter = { N_("XFig File Format"), extensions, import_fig };