SHA256
1
0
forked from pool/transfig
transfig/CVE-2019-19797.patch

1837 lines
55 KiB
Diff
Raw Normal View History

Based on 41b9bb838a3d544539f6e68aa4f87d70ef7d45ce Mon Sep 17 00:00:00 2001
From: Thomas Loimer <thomas.loimer@tuwien.ac.at>
Date: Sun, 5 Jan 2020 19:22:12 +0100
Subject: [PATCH] Replace most calls to fgets() by getline() in read.c
Also, fig files version 1.4 must begin with `#FIG 1.4`. Previously, a `#` in the
first line was sufficient to detect at least a version 1.4 fig file.
Move some variables with file scope into functions.
This commit fixes tickets #58, #59, #61, #62, #67, #78 and #79.
In fig2dev/lib/, replacements are provided for some library functions used in
fig2dev, e.g., strncasecmp(), strrchr(), etc. The getline() function was
introduced more recently than any of the functions provided in fig2dev/lib.
Nevertheless, for getline() a replacement function is not provided. It seems,
that all the replacement functions do not work, but nobody noticed. Therefore,
only provide a replacement function for getline() if that turns out to
be useful.
The replacement functions do not work, because a header file providing the
necessary function declarations is missing.
---
configure.ac | 1
fig2dev/fig2dev.c | 4
fig2dev/fig2dev.h | 4
fig2dev/read.c | 908 +++++++++++++++++++++++++++-----------------------
fig2dev/read1_3.c | 12
fig2dev/tests/read.at | 29 +
6 files changed, 534 insertions(+), 424 deletions(-)
--- configure.ac
+++ configure.ac 2020-01-21 11:31:32.048794834 +0000
@@ -327,6 +327,7 @@ dnl Just provide our own pi
# example.
AC_HEADER_STDBOOL
AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
#
# Checks for library functions.
--- fig2dev/fig2dev.c
+++ fig2dev/fig2dev.c 2020-01-21 11:31:32.048794834 +0000
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -81,7 +81,7 @@ bool bgspec = false; /* flag to say -g
bool support_i18n = false;
#endif
char gif_transparent[20]="\0"; /* GIF transp color hex name (e.g. #ff00dd) */
-char papersize[20]; /* paper size */
+char papersize[]; /* paper size */
char boundingbox[64]; /* boundingbox */
char lang[40]; /* selected output language */
RGB background; /* background (if specified by -g) */
--- fig2dev/fig2dev.h
+++ fig2dev/fig2dev.h 2020-01-21 11:31:32.048794834 +0000
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -101,7 +101,7 @@ extern bool bgspec; /* flag to say -g w
extern bool support_i18n;
#endif
extern char gif_transparent[];/* GIF transp color hex name (e.g. #ff00dd) */
-extern char papersize[]; /* paper size */
+extern char papersize[16]; /* paper size */
extern char boundingbox[]; /* boundingbox */
extern char lang[]; /* selected output language */
extern const char *Fig_color_names[]; /* hex names for Fig colors */
--- fig2dev/read.c
+++ fig2dev/read.c 2020-01-21 11:31:32.048794834 +0000
@@ -3,7 +3,7 @@
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
* Parts Copyright (c) 1989-2015 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -45,28 +45,34 @@ extern F_arrow *make_arrow(int type, int
User_color user_colors[MAX_USR_COLS]; /* fig2dev.h */
int user_col_indx[MAX_USR_COLS]; /* fig2dev.h */
int num_usr_cols; /* fig2dev.h */
-int num_object; /* read1_3.c */
/* flags, psfonts.h, genps.c */
int v2_flag; /* Protocol V2.0 or higher */
int v21_flag; /* Protocol V2.1 or higher */
int v30_flag; /* Protocol V3.0 or higher */
int v32_flag; /* Protocol V3.2 or higher */
-static void read_colordef(void);
-static F_ellipse *read_ellipseobject(void);
-static F_line *read_lineobject(FILE *fp);
-static F_text *read_textobject(FILE *fp);
-static F_spline *read_splineobject(FILE *fp);
-static F_arc *read_arcobject(FILE *fp);
-static F_compound *read_compoundobject(FILE *fp);
+static void read_colordef(char *line, int line_no);
+static F_ellipse *read_ellipseobject(char *line, int line_no);
+static F_line *read_lineobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_text *read_textobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_spline *read_splineobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_arc *read_arcobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static F_compound *read_compoundobject(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
static F_comment *attach_comments(void);
-static void count_lines_correctly(FILE *fp);
-static void init_pats_used(void);
-static int read_objects(FILE *fp, F_compound *obj);
-static int get_line(FILE *fp);
-static void skip_line(FILE *fp);
-static int backslash_count(char cp[], int start);
-static int save_comment(void);
+static void count_lines_correctly(FILE *fp, int *line_no);
+static void init_pats_used(void);
+static int read_objects(FILE *fp, F_compound *obj);
+static ssize_t get_line(FILE *fp, char **restrict line,
+ size_t *line_len, int *line_no);
+static void skip_line(FILE *fp);
+static ptrdiff_t backslash_count(const char *restrict cp,
+ ptrdiff_t start);
+
static char Err_incomp[] = "Incomplete %s object at line %d.";
static char Err_invalid[] = "Invalid %s object at line %d.";
static char Err_arrow[] = "Invalid %s arrow at line %d.";
@@ -77,9 +83,6 @@ static char Err_arrow[] = "Invalid %s ar
/* max number of comments that can be stored with each object */
#define MAXCOMMENTS 100
-static int gif_colnum = 0;
-static char buf[BUFSIZ];
-static int line_no = 0;
static char *comments[MAXCOMMENTS]; /* comments saved for current object */
static int numcom; /* current comment index */
static bool com_alloc = false; /* whether or not the comment array
@@ -148,7 +151,6 @@ readfp_fig(FILE *fp, F_compound *obj)
char c;
int i, status;
- num_object = 0;
num_usr_cols = 0;
init_pats_used();
@@ -157,15 +159,14 @@ readfp_fig(FILE *fp, F_compound *obj)
/* initialize the comment array */
if (!com_alloc)
for (i = 0; i < MAXCOMMENTS; ++i)
- comments[i] = (char *) NULL;
+ comments[i] = (char *)NULL;
com_alloc = true;
- memset((char*)obj, '\0', COMOBJ_SIZE);
+ memset((void *)obj, '\0', COMOBJ_SIZE);
/* read first character to see if it is "#" (#FIG 1.4 and newer) */
c = fgetc(fp);
if (feof(fp))
return -2;
- memset((char*)obj, '\0', COMOBJ_SIZE);
/* put the character back */
ungetc(c, fp);
if (c == '#')
@@ -185,25 +186,30 @@ read_objects(FILE *fp, F_compound *obj)
F_spline *s, *ls = NULL;
F_arc *a, *la = NULL;
F_compound *c, *lc = NULL;
- int object, coord_sys, len;
-
- memset((char*)obj, '\0', COMOBJ_SIZE);
-
- (void) fgets(buf, BUFSIZ, fp); /* get the version line */
- if (strncmp(buf, "#FIG ", 5)) {
- put_msg("Incorrect format string in first line of input file.");
+ bool objects = false;
+ int object, coord_sys;
+ int line_no;
+ int gif_colnum = 0;
+ char *line;
+ char buf[16];
+ size_t line_len = 256;
+
+ /* Get the 15 chars of the first line.
+ Use fgets(), because get_line() would store the line as a comment */
+ if (fgets(buf, sizeof buf, fp) == NULL) {
+ put_msg("Could not read input file.");
return -1;
}
+ /* seek to the end of the first line */
+ if (strchr(buf, '\n') == NULL) {
+ int c;
+ do
+ c = fgetc(fp);
+ while (c != '\n' && c != EOF);
+ }
- /* remove newline and any carriage return (from a PC, perhaps) */
- len = strlen(buf);
- if (buf[len-1] == '\n') {
- if (buf[len-2] == '\r')
- buf[len-2] = '\0';
- else
- buf[len-1] = '\0';
- } else { /* fgets() only stops at newline and end-of-file */
- put_msg("File is truncated at first line.");
+ if (strncmp(buf, "#FIG ", 5)) {
+ put_msg("Incorrect format string in first line of input file.");
return -1;
}
@@ -211,49 +217,65 @@ read_objects(FILE *fp, F_compound *obj)
v2_flag = (!strncmp(buf, "#FIG 2", 6) || !strncmp(buf, "#FIG 3", 6));
/* v21_flag is for version 2.1 or higher */
v21_flag = (!strncmp(buf, "#FIG 2.1", 8) || !strncmp(buf, "#FIG 3", 6));
- /* version 2.2 was only beta - 3.0 is the official release (they are identical) */
+ /* version 2.2 was only beta - 3.0 is the official release
+ (they are identical) */
v30_flag = (!strncmp(buf, "#FIG 3", 6) || !strncmp(buf, "#FIG 2.2", 8));
- /* version 3.2 contains paper size, magnif, multiple page and transparent color
- in Fig file */
+ /* version 3.2 contains paper size, magnif, multiple page
+ and transparent color in Fig file */
v32_flag = (!strncmp(buf, "#FIG 3.2", 8));
if (strncmp(&buf[5], PACKAGE_VERSION, 3) > 0) {
- put_msg("Fig file format (%s) newer than this version of fig2dev (%s), exiting",
- &buf[5], PACKAGE_VERSION);
- exit(1);
+ put_msg("Fig file format (%s) newer than this version of fig2dev (%s), exiting",
+ &buf[5], PACKAGE_VERSION);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((v2_flag | v21_flag | v30_flag | v32_flag) == 0 &&
+ strncmp(buf, "#FIG 1.4", 8)) {
+ put_msg("Cannot determine fig file format from string '%s'.",
+ &buf[5]);
+ exit(EXIT_FAILURE);
+ }
+
+ if ((line = malloc(line_len)) == NULL) {
+ put_msg(Err_mem);
+ return -1;
}
+ line_no = 1;
if (v30_flag) {
/* read the orientation spec (landscape/portrait) */
- line_no=1;
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at landscape/portrait specification.");
+ free(line);
return -1;
}
/* but set only if the user didn't specify the orientation
on the command line */
if (!orientspec)
- landscape = !strncasecmp(buf,"land",4);
+ landscape = !strncasecmp(line, "land", 4);
/* now read the metric/inches spec OR centering spec */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at metric/inches or centering specification.");
+ free(line);
return -1;
}
/* read justification spec */
- if ((strncasecmp(buf,"center",6) == 0) ||
- (strncasecmp(buf,"flush",5) == 0)) {
+ if ((strncasecmp(line, "center", 6) == 0) ||
+ (strncasecmp(line, "flush", 5) == 0)) {
/* but set only if user didn't specify it */
if (!centerspec)
- center = strncasecmp(buf,"flush",5);
+ center = strncasecmp(line, "flush", 5);
/* now read metric/inches spec */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at metric/inches specification.");
+ free(line);
return -1;
}
}
/* read metric/inches spec */
/* if metric, scale magnification to correct for xfig display error */
- if (strncasecmp(buf,"metric", 6) == 0) {
+ if (strncasecmp(line, "metric", 6) == 0) {
metric = 1;
} else {
metric = 0;
@@ -261,56 +283,67 @@ read_objects(FILE *fp, F_compound *obj)
/* new stuff in 3.2 */
if (v32_flag) {
- char *p;
/* read the paper size */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at paper size specification.");
+ free(line);
return -1;
}
if (!paperspec) {
- strcpy(papersize,buf);
- /* and truncate at first blank, if any */
- if ((p=strchr(papersize,' ')))
+ char *p;
+ /* truncate at first blank, if any */
+ if ((p = strchr(line, ' ')))
*p = '\0';
+ if (strlen(line) + 1 > sizeof papersize) {
+ put_msg("Invalid paper size specification at line %d: %s",
+ line_no, line);
+ free(line);
+ return -1;
+ }
+ strcpy(papersize, line);
}
/* read the magnification */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at magnification specification.");
+ free(line);
return -1;
}
- /* if the users hasn't specified a magnification on the command line,
- use the one in the file */
+ /* if the users hasn't specified a magnification on
+ the command line, use the one in the file */
if (!magspec) {
- mag = atof(buf)/100.0;
+ mag = atof(line)/100.0;
if (mag <= 0.)
mag = 1.;
fontmag = mag;
}
/* read the multiple page flag */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at multiple page specification.");
+ free(line);
return -1;
}
if (!multispec)
- multi_page = (strncasecmp(buf,"multiple",8) == 0);
+ multi_page = (strncasecmp(line, "multiple", 8) == 0);
/* Read the GIF transparent color. */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at transparent color specification.");
+ free(line);
return -1;
}
if (!transspec) {
- gif_colnum = atoi(buf);
+ gif_colnum = atoi(line);
if (gif_colnum < -3) {
put_msg("Invalid color number for transparent color.");
+ free(line);
return -1;
}
/* if standard color, get the name from the array */
/* for user colors, wait till we've read in the file to get the value */
if (gif_colnum < NUM_STD_COLS && gif_colnum >= 0)
- strcpy(gif_transparent,Fig_color_names[gif_colnum]);
+ strcpy(gif_transparent, Fig_color_names[gif_colnum]);
}
}
} else {
@@ -329,17 +362,20 @@ read_objects(FILE *fp, F_compound *obj)
}
/* now read for resolution and coord_sys (coord_sys is not used) */
- if (get_line(fp) < 0) {
+ if (get_line(fp, &line, &line_len, &line_no) < 0) {
put_msg("File is truncated at resolution specification.");
+ free(line);
return -1;
}
- if (sscanf(buf,"%lf%d\n", &ppi, &coord_sys) != 2) {
+ if (sscanf(line, "%lf%d", &ppi, &coord_sys) != 2) {
put_msg("Incomplete resolution information at line %d.", line_no);
+ free(line);
return -1;
}
if (ppi <= 0.) {
put_msg("Invalid resolution information (%g) at line %d.",
ppi, line_no);
+ free(line);
return -1;
}
@@ -349,24 +385,28 @@ read_objects(FILE *fp, F_compound *obj)
/* attach any comments found thus far to the whole figure */
obj->comments = attach_comments();
- while (get_line(fp) > 0) {
- if (sscanf(buf, "%d", &object) != 1) {
+ while (get_line(fp, &line, &line_len, &line_no) > 0) {
+ if (sscanf(line, "%d", &object) != 1) {
put_msg("Incorrect format at line %d.", line_no);
+ free(line);
return -1;
}
switch (object) {
case OBJ_COLOR_DEF:
- read_colordef();
- if (num_object) {
+ if (objects) {
put_msg("Color definitions must come before other objects (line %d).",
line_no);
- return (-1);
+ free(line);
+ return -1;
}
- ++num_usr_cols;
+ read_colordef(line, line_no);
break;
case OBJ_POLYLINE :
- if ((l = read_lineobject(fp)) == NULL)
+ if ((l = read_lineobject(fp, &line, &line_len, &line_no)) ==
+ NULL) {
+ free(line);
return -1;
+ }
#ifdef V4_0
if ((l->pic != NULL) && (l->pic->figure != NULL)) {
if (lc)
@@ -388,79 +428,97 @@ read_objects(FILE *fp, F_compound *obj)
ll = (ll->next = l);
else
ll = obj->lines = l;
- num_object++;
+ objects = true;
break;
#endif /* V4_0 */
case OBJ_SPLINE :
- if ((s = read_splineobject(fp)) == NULL) {
+ if ((s = read_splineobject(fp, &line, &line_len, &line_no))
+ == NULL) {
+ free(line);
return -1;
- }
+ }
if (v32_flag){ /* s is a line */
if (ll)
ll = (ll->next = (F_line *) s);
else
ll = obj->lines = (F_line *) s;
- num_object++;
+ objects = true;
break;
}
if (ls)
ls = (ls->next = s);
else
ls = obj->splines = s;
- num_object++;
+ objects = true;
break;
case OBJ_ELLIPSE :
- if ((e = read_ellipseobject()) == NULL)
+ if ((e = read_ellipseobject(line, line_no)) == NULL) {
+ free(line);
return -1;
+ }
if (le)
le = (le->next = e);
else
le = obj->ellipses = e;
- num_object++;
+ objects = true;
break;
case OBJ_ARC :
- if ((a = read_arcobject(fp)) == NULL)
+ if ((a = read_arcobject(fp, &line, &line_len, &line_no)) ==
+ NULL) {
+ free(line);
return -1;
+ }
if (la)
la = (la->next = a);
else
la = obj->arcs = a;
- num_object++;
+ objects = true;
break;
case OBJ_TEXT :
- if ((t = read_textobject(fp)) == NULL)
+ if ((t = read_textobject(fp, &line, &line_len, &line_no)) ==
+ NULL) {
+ free(line);
return -1;
+ }
if (lt)
lt = (lt->next = t);
else
lt = obj->texts = t;
- num_object++;
+ objects = true;
break;
case OBJ_COMPOUND :
- if ((c = read_compoundobject(fp)) == NULL)
+ if ((c = read_compoundobject(fp, &line, &line_len,&line_no))
+ == NULL) {
+ free(line);
return -1;
+ }
if (lc)
lc = (lc->next = c);
else
lc = obj->compounds = c;
- num_object++;
+ objects = true;
break;
default :
put_msg("Incorrect object code at line %d.", line_no);
+ free(line);
return -1;
} /* switch */
- } /* while (get_line(fp)) */
+ } /* while (get_line(...)) */
+ free(line);
/* if user color was requested for GIF transparent color, get the
rgb values from the user color array now that we've read them in */
if (gif_colnum >= NUM_STD_COLS) {
int i;
- for (i=0; i<num_usr_cols; ++i)
+ /* read_colordef() counted, but ignored too many user colors */
+ if (num_usr_cols > MAX_USR_COLS)
+ num_usr_cols = MAX_USR_COLS;
+ for (i=0; i < num_usr_cols; ++i)
if (user_col_indx[i] == gif_colnum)
break;
if (i < num_usr_cols)
- sprintf(gif_transparent,"#%2x%2x%2x",
- user_colors[i].r,user_colors[i].g,user_colors[i].b);
+ sprintf(gif_transparent, "#%2x%2x%2x",
+ user_colors[i].r, user_colors[i].g, user_colors[i].b);
}
if (feof(fp))
@@ -474,55 +532,72 @@ read_objects(FILE *fp, F_compound *obj)
} /* read_objects */
static void
-read_colordef(void)
+read_colordef(char *line, int line_no)
{
- int c;
- unsigned int r,g,b;
+ int c;
+ unsigned int r,g,b;
- if ((sscanf(buf, "%*d %d #%2x%2x%2x", &c, &r, &g, &b) != 4) ||
- (c < NUM_STD_COLS)) {
- buf[strlen(buf)-1]='\0'; /* remove the newline */
- put_msg("Invalid color definition: %s, setting to black (#00000).",buf);
- r=g=b=0;
- }
- user_col_indx[num_usr_cols] = c;
- user_colors[num_usr_cols].r = r;
- user_colors[num_usr_cols].g = g;
- user_colors[num_usr_cols].b = b;
+ if (num_usr_cols >= MAX_USR_COLS) {
+ if (num_usr_cols == MAX_USR_COLS) {
+ put_msg("Maximum number of color definitions (%d) exceeded at line %d.",
+ MAX_USR_COLS, line_no);
+ ++num_usr_cols;
+ }
+ /* ignore additional colors */
+ return;
+ }
+ if (sscanf(line, "%*d %d #%2x%2x%2x", &c, &r, &g, &b) != 4) {
+ if (c >= NUM_STD_COLS && c < NUM_STD_COLS + MAX_USR_COLS) {
+ put_msg("Invalid color definition at line %d: %s, setting to black (#00000).",
+ line_no, line);
+ r = g = b = 0;
+ } else {
+ put_msg("User color number at line %d out of range (%d), should be between %d and %d.",
+ line_no, c, NUM_STD_COLS,
+ NUM_STD_COLS + MAX_USR_COLS - 1);
+ return;
+ }
+ }
+ user_col_indx[num_usr_cols] = c;
+ user_colors[num_usr_cols].r = r;
+ user_colors[num_usr_cols].g = g;
+ user_colors[num_usr_cols].b = b;
+ ++num_usr_cols;
}
static void
-fix_and_note_color(int *color)
+fix_and_note_color(int *color, int line_no)
{
- int i;
- if (*color < DEFAULT) {
- put_msg("Invalid color number %d at line %d, using default color.",
- *color, line_no);
- *color = DEFAULT;
- return;
- }
- if (*color < NUM_STD_COLS) {
- if (*color >= BLACK_COLOR) {
- std_color_used[*color] = true;
+ int i;
+
+ if (*color < DEFAULT) {
+ put_msg("Invalid color number %d at line %d, using default color.",
+ *color, line_no);
+ *color = DEFAULT;
+ return;
}
- return;
- }
- for (i=0; i<num_usr_cols; ++i)
- if (*color == user_col_indx[i]) {
- *color = i + NUM_STD_COLS;
+ if (*color < NUM_STD_COLS) {
+ if (*color >= BLACK_COLOR) {
+ std_color_used[*color] = true;
+ }
return;
}
- put_msg("Cannot locate user color %d, using default color at line %d.",
- *color, line_no);
- *color = DEFAULT;
- return;
+ for (i = 0; i < MIN(num_usr_cols, MAX_USR_COLS); ++i)
+ if (*color == user_col_indx[i]) {
+ *color = i + NUM_STD_COLS;
+ return;
+ }
+ put_msg("Cannot locate user color %d, using default color at line %d.",
+ *color, line_no);
+ *color = DEFAULT;
+ return;
}
static void
-note_fill(int fill, int *color)
+note_fill(int fill, int *color, int line_no)
{
if (fill != UNFILLED) {
- fix_and_note_color(color);
+ fix_and_note_color(color, line_no);
if (fill >= NUMSHADES + NUMTINTS) {
pattern_used[fill - NUMSHADES - NUMTINTS] = true;
pats_used = true;
@@ -531,7 +606,7 @@ note_fill(int fill, int *color)
}
static F_arc *
-read_arcobject(FILE *fp)
+read_arcobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
F_arc *a;
int n, fa, ba;
@@ -548,7 +623,7 @@ read_arcobject(FILE *fp)
a->back_arrow = NULL;
a->next = NULL;
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%lf%lf%d%d%d%d%d%d\n",
+ n = sscanf(*line,"%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%lf%lf%d%d%d%d%d%d",
&a->type, &a->style, &a->thickness,
&a->pen_color, &a->fill_color, &a->depth, &a->pen, &a->fill_style,
&a->style_val, &a->cap_style,
@@ -558,7 +633,7 @@ read_arcobject(FILE *fp)
&a->point[1].x, &a->point[1].y,
&a->point[2].x, &a->point[2].y);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d\n",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d%d%lf%lf%d%d%d%d%d%d",
&a->type, &a->style, &a->thickness,
&a->pen_color, &a->depth, &a->pen, &a->fill_style,
&a->style_val, &a->direction, &fa, &ba,
@@ -570,45 +645,45 @@ read_arcobject(FILE *fp)
a->cap_style = 0; /* butt line cap */
}
if ((v30_flag && n != 21) || (!v30_flag && n != 19)) {
- put_msg(Err_incomp, "arc", line_no);
+ put_msg(Err_incomp, "arc", *line_no);
free(a);
return NULL;
}
a->thickness *= round(THICK_SCALE);
a->fill_style = FILL_CONVERT(a->fill_style);
if (INVALID_ARC(a)) {
- put_msg(Err_invalid, "arc", line_no);
+ put_msg(Err_invalid, "arc", *line_no);
free(a);
return NULL;
}
- fix_and_note_color(&a->pen_color);
- note_fill(a->fill_style, &a->fill_color);
+ fix_and_note_color(&a->pen_color, *line_no);
+ note_fill(a->fill_style, &a->fill_color, *line_no);
if (fa) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "arc", line_no);
+ put_msg(Err_incomp, "arc", *line_no);
free(a);
return NULL;
}
if ((a->for_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "forward", line_no);
+ put_msg(Err_arrow, "forward", *line_no);
free(a);
return NULL;
}
}
if (ba) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "arc", line_no);
+ put_msg(Err_incomp, "arc", *line_no);
free(a);
return NULL;
}
if ((a->back_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "backward", line_no);
+ put_msg(Err_arrow, "backward", *line_no);
free(a);
return NULL;
}
@@ -618,7 +693,8 @@ read_arcobject(FILE *fp)
}
static F_compound *
-read_compoundobject(FILE *fp)
+read_compoundobject(FILE *fp, char **restrict line, size_t *line_len,
+ int *line_no)
{
F_arc *a, *la = NULL;
F_ellipse *e, *le = NULL;
@@ -638,22 +714,23 @@ read_compoundobject(FILE *fp)
com->next = NULL;
com->comments = attach_comments(); /* attach any comments */
- n = sscanf(buf, "%*d%d%d%d%d\n", &com->nwcorner.x, &com->nwcorner.y,
+ n = sscanf(*line, "%*d%d%d%d%d", &com->nwcorner.x, &com->nwcorner.y,
&com->secorner.x, &com->secorner.y);
if (n != 4) {
- put_msg(Err_incomp, "compound", line_no);
+ put_msg(Err_incomp, "compound", *line_no);
free(com);
return NULL;
}
- while (get_line(fp) > 0) {
- if (sscanf(buf, "%d", &object) != 1) {
- put_msg(Err_incomp, "compound", line_no);
+ while (get_line(fp, line, line_len, line_no) > 0) {
+ if (sscanf(*line, "%d", &object) != 1) {
+ put_msg(Err_incomp, "compound", *line_no);
free_compound(&com);
return NULL;
- }
+ }
switch (object) {
case OBJ_POLYLINE :
- if ((l = read_lineobject(fp)) == NULL) {
+ if ((l = read_lineobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
#ifdef V4_0
@@ -674,7 +751,8 @@ read_compoundobject(FILE *fp)
#endif /* V4_0 */
break;
case OBJ_SPLINE :
- if ((s = read_splineobject(fp)) == NULL) {
+ if ((s = read_splineobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
if (v32_flag){ /* s is a line */
@@ -690,7 +768,7 @@ read_compoundobject(FILE *fp)
ls = com->splines = s;
break;
case OBJ_ELLIPSE :
- if ((e = read_ellipseobject()) == NULL) {
+ if ((e = read_ellipseobject(*line, *line_no)) == NULL) {
return NULL;
}
if (le)
@@ -699,7 +777,8 @@ read_compoundobject(FILE *fp)
le = com->ellipses = e;
break;
case OBJ_ARC :
- if ((a = read_arcobject(fp)) == NULL) {
+ if ((a = read_arcobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
if (la)
@@ -708,7 +787,8 @@ read_compoundobject(FILE *fp)
la = com->arcs = a;
break;
case OBJ_TEXT :
- if ((t = read_textobject(fp)) == NULL) {
+ if ((t = read_textobject(fp, line, line_len, line_no)) ==
+ NULL) {
return NULL;
}
if (lt)
@@ -717,7 +797,8 @@ read_compoundobject(FILE *fp)
lt = com->texts = t;
break;
case OBJ_COMPOUND :
- if ((c = read_compoundobject(fp)) == NULL) {
+ if ((c = read_compoundobject(fp, line, line_len, line_no))
+ == NULL) {
return NULL;
}
if (lc)
@@ -728,7 +809,7 @@ read_compoundobject(FILE *fp)
case OBJ_END_COMPOUND :
return com;
default :
- put_msg("Wrong object code at line %d", line_no);
+ put_msg("Wrong object code at line %d", *line_no);
return NULL;
} /* switch */
}
@@ -739,7 +820,7 @@ read_compoundobject(FILE *fp)
}
static F_ellipse *
-read_ellipseobject(void)
+read_ellipseobject(char *line, int line_no)
{
F_ellipse *e;
int n;
@@ -749,7 +830,7 @@ read_ellipseobject(void)
e->pen = 0;
e->next = NULL;
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d\n",
+ n = sscanf(line, "%*d%d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
&e->type, &e->style, &e->thickness,
&e->pen_color, &e->fill_color, &e->depth, &e->pen, &e->fill_style,
&e->style_val, &e->direction, &e->angle,
@@ -758,7 +839,7 @@ read_ellipseobject(void)
&e->start.x, &e->start.y,
&e->end.x, &e->end.y);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d\n",
+ n = sscanf(line, "%*d%d%d%d%d%d%d%d%lf%d%lf%d%d%d%d%d%d%d%d",
&e->type, &e->style, &e->thickness,
&e->pen_color, &e->depth, &e->pen, &e->fill_style,
&e->style_val, &e->direction, &e->angle,
@@ -773,7 +854,7 @@ read_ellipseobject(void)
free(e);
return NULL;
}
- fix_and_note_color(&e->pen_color);
+ fix_and_note_color(&e->pen_color, line_no);
e->thickness *= round(THICK_SCALE);
e->fill_style = FILL_CONVERT(e->fill_style);
if (e->radiuses.x < 0)
@@ -785,7 +866,7 @@ read_ellipseobject(void)
free(e);
return NULL;
}
- note_fill(e->fill_style, &e->fill_color);
+ note_fill(e->fill_style, &e->fill_color, line_no);
e->comments = attach_comments(); /* attach any comments */
return e;
}
@@ -804,8 +885,9 @@ read_ellipseobject(void)
*/
static int
sanitize_lineobject(
- F_line *l, /* the line */
- F_point *p /* the last point of the line */
+ F_line *l, /* the line */
+ F_point *p, /* the last point of the line */
+ int line_no
)
{
F_point *q;
@@ -912,7 +994,7 @@ sanitize_lineobject(
}
static F_line *
-read_lineobject(FILE *fp)
+read_lineobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
F_line *l;
F_point *o = NULL, *p, *q;
@@ -933,40 +1015,38 @@ read_lineobject(FILE *fp)
l->pic = NULL;
l->comments = NULL;
- sscanf(buf,"%*d%d",&l->type); /* get the line type */
+ sscanf(*line, "%*d%d", &l->type); /* get the line type */
radius_flag = v30_flag || v21_flag || (v2_flag && l->type == T_ARC_BOX);
if (radius_flag) {
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d%d%d",
&l->type,&l->style,&l->thickness,&l->pen_color,&l->fill_color,
&l->depth,&l->pen,&l->fill_style,&l->style_val,
&l->join_style,&l->cap_style,
&l->radius,&fa,&ba,&npts);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d%d",
- &l->type,&l->style,&l->thickness,&l->pen_color,
- &l->depth,&l->pen,&l->fill_style,&l->style_val,&l->radius,&fa, &ba);
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d%d",
+ &l->type,&l->style,&l->thickness,&l->pen_color,&l->depth,
+ &l->pen,&l->fill_style,&l->style_val,&l->radius,&fa, &ba);
l->fill_color = l->pen_color;
}
}
/* old format uses pen for radius of arc-box corners */
else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d",
&l->type,&l->style,&l->thickness,&l->pen_color,
&l->depth,&l->pen,&l->fill_style,&l->style_val,&fa,&ba);
l->fill_color = l->pen_color;
- if (l->type == T_ARC_BOX)
- {
- l->radius = (int) l->pen;
+ if (l->type == T_ARC_BOX) {
+ l->radius = l->pen;
l->pen = 0;
- }
- else
+ } else
l->radius = 0;
}
if ((!radius_flag && n!=10) ||
(radius_flag && ((!v30_flag && n!=11)||(v30_flag && n!=15)))) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free(l);
return NULL;
}
@@ -974,45 +1054,47 @@ read_lineobject(FILE *fp)
l->thickness *= round(THICK_SCALE);
l->fill_style = FILL_CONVERT(l->fill_style);
if (INVALID_LINE(l)) {
- put_msg(Err_invalid, "line", line_no);
+ put_msg(Err_invalid, "line", *line_no);
free(l);
return NULL;
}
- note_fill(l->fill_style, &l->fill_color);
- fix_and_note_color(&l->pen_color);
+ note_fill(l->fill_style, &l->fill_color, *line_no);
+ fix_and_note_color(&l->pen_color, *line_no);
if (fa) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free(l);
return NULL;
}
if ((l->for_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "forward", line_no);
+ put_msg(Err_arrow, "forward", *line_no);
free(l);
return NULL;
}
}
if (ba) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free_linestorage(l);
return NULL;
}
if ((l->back_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "backward", line_no);
+ put_msg(Err_arrow, "backward", *line_no);
free_linestorage(l);
return NULL;
}
}
if (l->type == T_PIC_BOX) {
- char file[BUFSIZ], *c;
+ char *file, *c;
+ int pos;
size_t len;
+ ssize_t chars;
if ((Pic_malloc(l->pic)) == NULL) {
free(l);
@@ -1026,21 +1108,22 @@ read_lineobject(FILE *fp)
XpmCreateXpmImageFromBuffer("", &l->pic->xpmimage, NULL);
#endif
- /* %[^\n]: really, read until first '\0' in buf */
- if (get_line(fp) < 0 || sscanf(buf, "%d %[^\n]",
- &l->pic->flipped, file) != 2) {
- put_msg(Err_incomp, "picture", line_no);
- free(l);
- return NULL;
+ if ((chars = get_line(fp, line, line_len, line_no)) < 0 ||
+ sscanf(*line, "%d %n", &l->pic->flipped, &pos) != 1) {
+ put_msg(Err_incomp, "picture", *line_no);
+ free(l);
+ return NULL;
}
+ file = *line + pos;
+ len = chars - pos; /* strlen(file) */
+
/* if there is a path in the .fig filename, and the path of the
* imported picture filename is NOT absolute, prepend the
* .fig file path to it
*/
if (from && (c = strrchr(from, '/')) && file[0] != '/') {
- if ((l->pic->file = malloc((size_t)(c - from + 2) +
- (len = strlen(file)))) ==
- NULL) {
+ if ((l->pic->file = malloc((size_t)(c - from + 2) + len)) ==
+ NULL) {
put_msg(Err_mem);
free(l); /* Points not read yet. */
return NULL;
@@ -1049,8 +1132,8 @@ read_lineobject(FILE *fp)
memcpy(l->pic->file + (c - from + 1), file, len + 1);
} else {
/* either absolute picture path or no path in .fig filename */
- l->pic->file = malloc(len = strlen(file) + 1);
- memcpy(l->pic->file, file, len);
+ l->pic->file = malloc(len + 1);
+ memcpy(l->pic->file, file, len + 1);
}
}
@@ -1062,9 +1145,9 @@ read_lineobject(FILE *fp)
p->next = NULL;
/* read first point of line */
- ++line_no;
+ ++(*line_no);
if (fscanf(fp, "%d%d", &p->x, &p->y) != 2) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free_linestorage(l);
return NULL;
}
@@ -1072,9 +1155,9 @@ read_lineobject(FILE *fp)
if (!v30_flag)
npts = 1000000;
for (--npts; npts > 0; --npts) {
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if (fscanf(fp, "%d%d", &x, &y) != 2) {
- put_msg(Err_incomp, "line", line_no);
+ put_msg(Err_incomp, "line", *line_no);
free_linestorage(l);
return NULL;
}
@@ -1103,7 +1186,7 @@ read_lineobject(FILE *fp)
l->last[1].y = o->y;
}
- if (sanitize_lineobject(l, p)) {
+ if (sanitize_lineobject(l, p, *line_no)) {
free_linestorage(l);
return NULL;
}
@@ -1115,7 +1198,8 @@ read_lineobject(FILE *fp)
}
static F_spline *
-read_splineobject(FILE *fp)
+read_splineobject(FILE *fp, char **restrict line, size_t *line_len,
+ int *line_no)
{
F_spline *s;
F_line *l;
@@ -1137,58 +1221,58 @@ read_splineobject(FILE *fp)
s->next = NULL;
if (v30_flag) {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%d%lf%d%d%d%d",
&s->type, &s->style, &s->thickness,
&s->pen_color, &s->fill_color,
&s->depth, &s->pen, &s->fill_style, &s->style_val,
&s->cap_style, &fa, &ba, &npts);
} else {
- n = sscanf(buf, "%*d%d%d%d%d%d%d%d%lf%d%d",
+ n = sscanf(*line, "%*d%d%d%d%d%d%d%d%lf%d%d",
&s->type, &s->style, &s->thickness, &s->pen_color,
&s->depth, &s->pen, &s->fill_style, &s->style_val, &fa, &ba);
s->fill_color = s->pen_color;
s->cap_style = 0; /* butt line cap */
}
if ((v30_flag && n != 13) || (!v30_flag && n != 10)) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free(s);
return NULL;
}
s->thickness *= round(THICK_SCALE);
s->fill_style = FILL_CONVERT(s->fill_style);
if (INVALID_SPLINE(s)) {
- put_msg(Err_invalid, "spline", line_no);
+ put_msg(Err_invalid, "spline", *line_no);
free(s);
return NULL;
}
- note_fill(s->fill_style, &s->fill_color);
- fix_and_note_color(&s->pen_color);
+ note_fill(s->fill_style, &s->fill_color, *line_no);
+ fix_and_note_color(&s->pen_color, *line_no);
if (fa) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free(s);
return NULL;
}
if ((s->for_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "forward", line_no);
+ put_msg(Err_arrow, "forward", *line_no);
free(s);
return NULL;
}
}
if (ba) {
- if (get_line(fp) < 0 ||
- sscanf(buf, "%d%d%lf%lf%lf",
+ if (get_line(fp, line, line_len, line_no) < 0 ||
+ sscanf(*line, "%d%d%lf%lf%lf",
&type, &style, &thickness, &wid, &ht) != 5) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
if ((s->back_arrow = make_arrow(type, style, thickness, wid, ht))
== NULL) {
- put_msg(Err_arrow, "backward", line_no);
+ put_msg(Err_arrow, "backward", *line_no);
free_splinestorage(s);
return NULL;
}
@@ -1196,9 +1280,9 @@ read_splineobject(FILE *fp)
/* Read points */
/* read first point of line */
- ++line_no;
+ ++(*line_no);
if ((n = fscanf(fp, "%d%d", &x, &y)) != 2) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
};
@@ -1212,15 +1296,15 @@ read_splineobject(FILE *fp)
if (!v30_flag)
npts = 1000000;
if (npts < 2) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
for (--npts; npts > 0; --npts) {
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if (fscanf(fp, "%d%d", &x, &y) != 2) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
};
@@ -1250,9 +1334,9 @@ read_splineobject(FILE *fp)
ptr = s->controls;
while (ptr) { /* read controls */
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if ((n = fscanf(fp, "%lf", &control_s)) != 1) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
@@ -1275,9 +1359,9 @@ read_splineobject(FILE *fp)
}
/* Read controls from older versions */
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if ((n = fscanf(fp, "%lf%lf%lf%lf", &lx, &ly, &rx, &ry)) != 4) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
free_splinestorage(s);
return NULL;
}
@@ -1290,9 +1374,9 @@ read_splineobject(FILE *fp)
cp->rx = rx; cp->ry = ry;
while (--c) {
/* keep track of newlines for line counter */
- count_lines_correctly(fp);
+ count_lines_correctly(fp, line_no);
if (fscanf(fp, "%lf%lf%lf%lf", &lx, &ly, &rx, &ry) != 4) {
- put_msg(Err_incomp, "spline", line_no);
+ put_msg(Err_incomp, "spline", *line_no);
cp->next = NULL;
free_splinestorage(s);
return NULL;
@@ -1315,13 +1399,37 @@ read_splineobject(FILE *fp)
return s;
}
+static char *
+find_end(const char *str, int v30flag)
+{
+ const char endmark[] = "\\001";
+ char *end;
+
+ if (v30flag) {
+ /* A string is terminated with the literal '\001',
+ and 8-bit characters may be represented as \xxx */
+ end = strstr(str, endmark);
+ /* is this not '\\001', or '\\\\001', etc? */
+ while (end && backslash_count(str, end - str) % 2 == 0)
+ end = strstr(end + 3, endmark);
+ } else {
+ /* The text object is terminated by a CONTROL-A.
+ If there is no CONTROL-A on this line, then this
+ must be a multi-line text object. */
+ end = strchr(str, '\1');
+ }
+ return end;
+}
+
+
static F_text *
-read_textobject(FILE *fp)
+read_textobject(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
F_text *t;
- int n, ignore = 0;
- char s[BUFSIZ], s_temp[BUFSIZ], junk[2];
- int more, len, l;
+ bool freestart = false;
+ int i, n;
+ char *end, *start;
+ size_t len;
Text_malloc(t);
t->font = 0;
@@ -1329,32 +1437,101 @@ read_textobject(FILE *fp)
t->comments = NULL;
t->next = NULL;
- if (v30_flag) { /* order of parms is more like other objects now,
- string is now terminated with the literal '\001',
- and 8-bit characters are represented as \xxx */
-
- n = sscanf(buf, "%*d%d%d%d%d%d%lf%lf%d%lf%lf%d%d%[^\n]",
- &t->type, &t->color, &t->depth, &t->pen,
- &t->font, &t->size, &t->angle,
- &t->flags, &t->height, &t->length,
- &t->base_x, &t->base_y, s);
+ n = sscanf(*line, "%*d%d%d%d%d%d%lf%lf%d%lf%lf%d%d %n",
+ &t->type, &t->color, &t->depth, &t->pen, &t->font,
+ &t->size, &t->angle, &t->flags, &t->height, &t->length,
+ &t->base_x, &t->base_y, &i);
+ if (n != 12) {
+ put_msg(Err_incomp, "text", *line_no);
+ free(t);
+ return NULL;
+ }
+ start = *line + i;
+ end = find_end(start, v30_flag);
+
+ if (end) {
+ *end = '\0';
+ len = end - start;
} else {
- /* The text object is terminated by a CONTROL-A, so we read
- everything up to the CONTROL-A and then read that character.
- If we do not find the CONTROL-A on this line then this must
- be a multi-line text object and we will have to read more. */
-
- n = sscanf(buf,"%*d%d%d%lf%d%d%d%lf%d%lf%lf%d%d%[^\1]%1[\1]",
- &t->type, &t->font, &t->size, &t->pen,
- &t->color, &t->depth, &t->angle,
- &t->flags, &t->height, &t->length,
- &t->base_x, &t->base_y, s, junk);
- }
- if ((n != 14) && (n != 13)) {
- put_msg(Err_incomp, "text", line_no);
- free(t);
- return NULL;
+ ssize_t chars;
+ char *next;
+
+ len = strlen(start);
+ start[len++] = '\n'; /* put back the newline */
+
+ /* allocate plenty of space */
+ next = malloc(len + BUFSIZ);
+ if (next == NULL) {
+ put_msg(Err_mem);
+ free(t);
+ return NULL;
+ }
+ memcpy(next, start, len);
+
+ while ((chars = getline(line, line_len, fp)) != -1) {
+ ++(*line_no);
+ end = find_end(*line, v30_flag);
+ if (end) {
+ *end = '\0';
+ next = realloc(next, len + end - *line + 1);
+ memcpy(next + len, *line, end - *line + 1);
+ len += end - *line;
+ break;
+ } else {
+ if (**line + chars - 1 == '\n' && chars > 1 &&
+ **line + chars - 2 == '\r')
+ (*line)[chars-- - 2] = '\n';
+ next = realloc(next, len + chars + 1);
+ memcpy(next + len, *line, chars + 1);
+ len += chars;
+ }
+ }
+ start = next;
+ freestart = true;
+ }
+
+ /* convert any \xxx to characters */
+ if (v30_flag && (end = strchr(start, '\\'))) {
+ unsigned char num;
+ char *c = start;
+ size_t l;
+
+ len = end - start;
+ l = len;
+ while (c[l] != '\0') {
+ if (c[l] == '\\') {
+ /* convert 3 digit octal value */
+ if (isdigit(c[l+1]) && c[l+2] != '\0' &&
+ c[l+3] != '\0') {
+ if (sscanf(c+l+1, "%3hho", &num) != 1) {
+ put_msg("Error in parsing text string on line %d",
+ *line_no);
+ return NULL;
+ }
+ /* no check of unsigned char overflow */
+ c[len++] = num;
+ l += 3;
+ } else {
+ /* an escaped char is un-escaped */
+ c[len++] = c[++l];
+ }
+ } else {
+ c[len++] = c[l];
+ }
+ ++l;
+ }
+ c[len] = '\0'; /* terminate */
+ }
+
+ t->cstring = malloc(len + 1);
+ if (t->cstring == NULL) {
+ put_msg(Err_mem);
+ free(t);
+ return NULL;
}
+ memcpy(t->cstring, start, len + 1);
+ if (freestart)
+ free(start);
if (font_size != 0.0) {
/* scale length/height of text by ratio of requested font size to actual size */
@@ -1364,89 +1541,6 @@ read_textobject(FILE *fp)
}
if (t->size <= 0.0)
t->size = (float) DEFAULT_FONT_SIZE;
- more = 0;
- if (!v30_flag && n == 13)
- more = 1; /* in older xfig there is more if ^A wasn't found yet */
- else if (v30_flag) { /* in 3.0 there is more if \001 wasn't found */
- len = strlen(s);
- if ((strcmp(&s[len-4],"\\001") == 0) && /* if we find '\000' */
- !(backslash_count(s, len-5) % 2)) { /* and not '\\000' */
- more = 0; /* then there are no more lines */
- s[len-4]='\0'; /* and get rid of the '\001' */
- } else {
- more = 1;
- s[len++]='\n'; /* put back the end of line char */
- s[len] = '\0'; /* and terminate it */
- }
- }
- if (more) {
- /* Read in the subsequent lines of the text if there are more */
- do {
- ++line_no; /* As is done in get_line */
- if (fgets(s_temp, BUFSIZ, fp) == NULL)
- break;
- len = strlen(s_temp)-1; /* ignore newline */
- if (len > 0 && s_temp[len-1] == '\r') { /* strip any trailing CR */
- s_temp[len-1] = '\0';
- len--;
- }
- if (v30_flag) {
- if ((strncmp(&s_temp[len-4],"\\001",4) == 0) &&
- !(backslash_count(s_temp, len-5) % 2)) {
- n=0; /* found the '\001', set n to stop */
- s_temp[len-4]='\0'; /* and get rid of the '\001' */
- } else {
- n=1; /* keep going (more lines) */
- }
- } else {
- n = sscanf(buf, "%[^\1]%[\1]", s_temp, junk);
- }
- /* Safety check */
- if (strlen(s)+1 + strlen(s_temp)+1 > BUFSIZ) {
- /* Too many characters. Ignore the rest. */
- ignore = 1;
- }
- if (!ignore)
- strcat(s, s_temp);
- } while (n == 1);
- }
-
- if (v30_flag) { /* now convert any \xxx to ascii characters */
- if (strchr(s,'\\')) {
- unsigned int num;
- len = strlen(s);
- for (l=0,n=0; l < len; ++l) {
- if (s[l]=='\\') {
- /* a backslash, see if a digit follows */
- if (l < len && isdigit(s[l+1])) {
- /* yes, scan for 3 digit octal value */
- if (sscanf(&s[l+1],"%3o",&num)!=1) {
- put_msg("Error in parsing text string on line %d",
- line_no);
- return NULL;
- }
- buf[n++]= (unsigned char) num; /* put char in */
- l += 3; /* skip over digits */
- } else {
- buf[n++] = s[++l]; /* some other escaped character */
- }
- } else {
- buf[n++] = s[l]; /* ordinary character */
- }
- }
- buf[n]='\0'; /* terminate */
- strcpy(s,buf); /* copy back to s */
- }
- }
- if (strlen(s) == 0)
- (void)strcpy(s, " ");
- t->cstring = calloc((unsigned)(strlen(s)), sizeof(char));
- if (NULL == t->cstring) {
- put_msg(Err_mem);
- free(t);
- return NULL;
- }
- (void)strcpy(t->cstring, s+1);
if (!v21_flag && (t->font == 0 || t->font == DEFAULT))
t->flags = ((t->flags != DEFAULT) ? t->flags : 0)
@@ -1457,11 +1551,11 @@ read_textobject(FILE *fp)
| PSFONT_TEXT;
if (INVALID_TEXT(t)) {
- put_msg(Err_invalid, "text", line_no);
+ put_msg(Err_invalid, "text", *line_no);
free_text(&t);
return NULL;
}
- fix_and_note_color(&t->color);
+ fix_and_note_color(&t->color, *line_no);
t->comments = attach_comments(); /* attach any comments */
return t;
}
@@ -1469,18 +1563,19 @@ read_textobject(FILE *fp)
/* count consecutive backslashes backwards */
-static int
-backslash_count(char cp[], int start)
+static ptrdiff_t
+backslash_count(const char *restrict cp, ptrdiff_t start)
{
- int i, count = 0;
+ ptrdiff_t i;
+ ptrdiff_t count = 0;
- for(i=start; i>=0; i--) {
- if (cp[i] == '\\')
- count++;
- else
- break;
- }
- return count;
+ for(i = start; i >= 0; --i) {
+ if (cp[i] == '\\')
+ ++count;
+ else
+ break;
+ }
+ return count;
}
/* attach comments in linked list */
@@ -1509,55 +1604,64 @@ attach_comments(void)
return icomp;
}
+/* save a comment line to be stored with the *subsequent* object */
+
static int
-get_line(FILE *fp)
+save_comment(char *restrict line, size_t len)
{
- int len;
- while (1) {
- if (NULL == fgets(buf, BUFSIZ, fp)) {
- return -1;
- }
- ++line_no;
- if (*buf == '#') { /* save any comments */
- if (save_comment() < 0)
- return -1;
- /* skip empty lines */
- } else if (*buf != '\n' || !(*buf == '\r' && buf[1] == '\n')) {
- len = strlen(buf);
- /* remove newline and possibly a carriage return */
- if (buf[len-1] == '\n')
- buf[len - (buf[len-2] == '\r' ? 2 : 1)] = '\0';
- return 1;
- }
- }
-}
+ int i;
-/* save a comment line to be stored with the *subsequent* object */
+ /* skip too many comment lines */
+ if (numcom == MAXCOMMENTS)
+ return 2;
+
+ /* remove one leading blank from the comment, if there is one */
+ i = 1;
+ if (line[i] == ' ')
+ i = 2;
+
+ /* see if we've allocated space for this comment */
+ if (comments[numcom])
+ free(comments[numcom]);
+ if ((comments[numcom] = malloc(len + (1 - i))) == NULL)
+ return -1;
-static int
-save_comment(void)
+ strcpy(comments[numcom++], &line[i]);
+ return 1;
+}
+
+static ssize_t
+get_line(FILE *fp, char **restrict line, size_t *line_len, int *line_no)
{
- int i;
+ ssize_t chars;
- /* skip too many comment lines */
- if (numcom == MAXCOMMENTS)
- return 2;
- i=strlen(buf);
- /* see if we've allocated space for this comment */
- if (comments[numcom])
- free(comments[numcom]);
- if ((comments[numcom] = malloc(i+1)) == NULL)
- return -1;
- /* remove any newline */
- if (buf[i-1] == '\n')
- buf[i-1] = '\0';
- i=1;
- if (buf[1] == ' ') /* remove one leading blank from the comment, if there is one */
- i=2;
- strcpy(comments[numcom++], &buf[i]);
- return 1;
+ while ((chars = getline(line, line_len, fp)) != -1) {
+ ++(*line_no);
+ /* skip empty lines */
+ if (**line == '\n' || (**line == '\r' &&
+ chars == 2 && (*line)[1] == '\n'))
+ continue;
+ /* remove newline and possibly a carriage return */
+ if ((*line)[chars-1] == '\n') {
+ chars -= (*line)[chars - 2] == '\r' ? 2 : 1;
+ (*line)[chars] = '\0';
+ }
+ /* save any comments */
+ if (**line == '#') {
+ if (save_comment(*line, (size_t)chars) < 0)
+ return -1;
+ continue;
+ }
+ /* return the line */
+ return chars;
+ }
+ /* chars == -1 */
+ return chars;
+ /* getline() only fails with EINVAL, and probably ENOMEM from malloc().
+ No use to check for errno. */
}
+
/* skip to the end of the current line and any subsequent blank lines */
static void
@@ -1714,15 +1818,15 @@ static int pop() {
*/
static void
-count_lines_correctly(FILE *fp)
+count_lines_correctly(FILE *fp, int *line_no)
{
int cc;
do {
- cc = getc(fp);
- if (cc == '\n') {
- ++line_no;
- cc=getc(fp);
- }
+ cc = getc(fp);
+ if (cc == '\n') {
+ ++(*line_no);
+ cc=getc(fp);
+ }
} while (cc == ' ' || cc == '\t');
ungetc(cc,fp);
}
--- fig2dev/read1_3.c
+++ fig2dev/read1_3.c 2020-01-21 11:31:32.048794834 +0000
@@ -2,8 +2,8 @@
* Fig2dev: Translate Fig code to various Devices
* Copyright (c) 1991 by Micah Beck
* Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
- * Parts Copyright (c) 1989-2012 by Brian V. Smith
- * Parts Copyright (c) 2015-2019 by Thomas Loimer
+ * Parts Copyright (c) 1989-2015 by Brian V. Smith
+ * Parts Copyright (c) 2015-2020 by Thomas Loimer
*
* Any party obtaining a copy of these files is granted, free of charge, a
* full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -51,8 +51,6 @@
extern F_arrow *forward_arrow(void), *backward_arrow(void);
extern int figure_modified;
-//extern int line_no;
-extern int num_object;
static F_ellipse *read_ellipseobject(FILE *fp);
static F_line *read_lineobject(FILE *fp);
@@ -103,7 +101,6 @@ read_1_3_objects(FILE *fp, F_compound *o
ll = (ll->next = l);
else
ll = obj->lines = l;
- num_object++;
break;
case OBJ_SPLINE :
if ((s = read_splineobject(fp)) == NULL) return(-1);
@@ -111,7 +108,6 @@ read_1_3_objects(FILE *fp, F_compound *o
ls = (ls->next = s);
else
ls = obj->splines = s;
- num_object++;
break;
case OBJ_ELLIPSE :
if ((e = read_ellipseobject(fp)) == NULL) return(-1);
@@ -119,7 +115,6 @@ read_1_3_objects(FILE *fp, F_compound *o
le = (le->next = e);
else
le = obj->ellipses = e;
- num_object++;
break;
case OBJ_ARC :
if ((a = read_arcobject(fp)) == NULL) return(-1);
@@ -127,7 +122,6 @@ read_1_3_objects(FILE *fp, F_compound *o
la = (la->next = a);
else
la = obj->arcs = a;
- num_object++;
break;
case OBJ_TEXT :
if ((t = read_textobject(fp)) == NULL) return(-1);
@@ -135,7 +129,6 @@ read_1_3_objects(FILE *fp, F_compound *o
lt = (lt->next = t);
else
lt = obj->texts = t;
- num_object++;
break;
case OBJ_COMPOUND :
if ((c = read_compoundobject(fp)) == NULL) return(-1);
@@ -143,7 +136,6 @@ read_1_3_objects(FILE *fp, F_compound *o
lc = (lc->next = c);
else
lc = obj->compounds = c;
- num_object++;
break;
default:
put_msg("Incorrect object code %d", object);
--- fig2dev/tests/read.at
+++ fig2dev/tests/read.at 2020-01-21 11:31:32.048794834 +0000
@@ -2,7 +2,7 @@ dnl Fig2dev: Translate Fig code to vario
dnl Copyright (c) 1991 by Micah Beck
dnl Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
dnl Parts Copyright (c) 1989-2015 by Brian V. Smith
-dnl Parts Copyright (c) 2015-2019 by Thomas Loimer
+dnl Parts Copyright (c) 2015-2020 by Thomas Loimer
dnl
dnl Any party obtaining a copy of these files is granted, free of charge, a
dnl full and unrestricted irrevocable, world-wide, paid up, royalty-free,
@@ -14,7 +14,7 @@ dnl party to do so, with the only requir
dnl and this permission notice remain intact.
dnl read.at
-dnl Author: Thomas Loimer, 2017-2019
+dnl Author: Thomas Loimer, 2017-2020
AT_BANNER([Sanitize and harden input.])
@@ -279,7 +279,7 @@ AT_CHECK([fig2dev -L box <<EOF
3 0 0 0 0 0 0 0 0. 0 1
0
EOF
-],1,ignore,[Incomplete spline object at line 3.
+],1,ignore,[Incomplete spline object at line 4.
])
AT_CLEANUP
@@ -287,7 +287,7 @@ AT_SETUP([allow last line without newlin
AT_KEYWORDS([read.c])
AT_CHECK([AS_ECHO_N(['#FIG 2
0']) | fig2dev -L box],
-1, ignore, [Incomplete resolution information at line 1.
+1, ignore, [Incomplete resolution information at line 2.
])
AT_CLEANUP
@@ -299,7 +299,7 @@ AT_CHECK([fig2dev -L box <<EOF
2 1 1 1 -1 50 0 0 0. 0 0
0
EOF
-], 1, ignore, [Incomplete line object at line 3.
+], 1, ignore, [Incomplete line object at line 4.
])
AT_CLEANUP
@@ -345,7 +345,7 @@ AT_CHECK([fig2dev -L pict2e <<EOF
2 1 1 1 -502350 50 0 0 0. 0 0
0 0 100 100 9999 0
EOF
-],0,ignore-nolog,[Invalid color number -502350 at line 2, using default color.
+],0,ignore-nolog,[Invalid color number -502350 at line 3, using default color.
])
AT_CLEANUP
@@ -387,9 +387,22 @@ AT_KEYWORDS([read.c])
AT_CHECK([fig2dev -L box <<EOF
#FIG 2
1200 2
-4 2 0 0 1 0 0 390 306 110 376 639 5 Text
+4 2 0 0 1 0 0 0 6 110 376 639 5 Text
EOF
-], 1, ignore, [Invalid text object at line 2.
+], 0, ignore)
+AT_CLEANUP
+
+AT_SETUP([reject too long papersize specification])
+AT_KEYWORDS([read.c])
+AT_CHECK([fig2dev -L box <<EOF
+#FIG 3.2
+Landscape
+Center
+Inches
+Papersize_name_too_long
+EOF
+], 1, ignore,
+ [Invalid paper size specification at line 5: Papersize_name_too_long
])
AT_CLEANUP