--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: buster
User: release.debian....@packages.debian.org
Usertags: pu
While 3.2.7a-5+deb10u2 is currently in proposed-updates I prepared
another update (deb10u3) fixing CVE-2019-19746 and CVE-2019-19797 as
well as 6 further segfaults, which are only in upstream tracker and
don't have a CVE:
https://sourceforge.net/p/mcj/tickets/58
https://sourceforge.net/p/mcj/tickets/59
https://sourceforge.net/p/mcj/tickets/61
https://sourceforge.net/p/mcj/tickets/62
https://sourceforge.net/p/mcj/tickets/78
https://sourceforge.net/p/mcj/tickets/79
According to security-tracker CVE-2019-19746 is "unimportant" and
CVE-2019-19797 is tagged "no DSA", so I didn't send this to the
security team, but request a point release update.
Hopefully the second patch isn't too big for a point release, but
since upstream fixed several segfaults with this, it won't be a good
idea to extract only parts from it to fix only CVE-2019-19797 but keep
the root cause of all these segfaults...
Attached you'll find a patch agains 3.2.7a-5+deb10u2.
Greetings
Roland
diff -Nru fig2dev-3.2.7a/debian/changelog fig2dev-3.2.7a/debian/changelog
--- fig2dev-3.2.7a/debian/changelog 2019-12-04 22:12:49.000000000 +0100
+++ fig2dev-3.2.7a/debian/changelog 2020-01-07 19:53:09.000000000 +0100
@@ -1,3 +1,13 @@
+fig2dev (1:3.2.7a-5+deb10u3) buster; urgency=medium
+
+ * 42_CVE-2019-19746: Reject huge arrow types causing integer overflow.
+ This fixes CVE-2019-19746 (Closes: #946628).
+ * 43_fgets2getline: Replace most calls to fgets() by getline() in
+ read.c. This fixes CVE-2019-19797 and several other segfaults
+ (Closes: #946866).
+
+ -- Roland Rosenfeld <rol...@debian.org> Tue, 07 Jan 2020 19:53:09 +0100
+
fig2dev (1:3.2.7a-5+deb10u2) buster; urgency=medium
* 41_CVE-2019-19555: Allow Fig v2 text strings ending with multiple ^A.
diff -Nru fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch
--- fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch 1970-01-01 01:00:00.000000000 +0100
+++ fig2dev-3.2.7a/debian/patches/42_CVE-2019-19746.patch 2020-01-07 19:53:09.000000000 +0100
@@ -0,0 +1,44 @@
+From: Thomas Loimer <thomas.loi...@tuwien.ac.at>
+Date: Tue Dec 10 13:17:36 2019 +0100
+Bug: https://sourceforge.net/p/mcj/tickets/57
+Bug-Debian: https://bugs.debian.org/946628
+Origin: https://sourceforge.net/p/mcj/fig2dev/ci/3065abc7b4f740ed6532322843531317de782a26/
+Subject: Reject huge arrow types causing integer overflow.
+ This fixes CVE-2019-19746
+
+--- a/fig2dev/arrow.c
++++ b/fig2dev/arrow.c
+@@ -1,9 +1,10 @@
+ /*
+ * Fig2dev: Translate Fig code to various Devices
+- * Copyright (c) 1985 by Supoj Sutantavibul
+ * Copyright (c) 1991 by Micah Beck
+- * Parts Copyright (c) 1989-2002 by Brian V. Smith
+- * Parts Copyright (c) 2015-2018 by Thomas Loimer
++ * 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
++ *
+ *
+ * Any party obtaining a copy of these files is granted, free of charge, a
+ * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
+@@ -78,7 +79,9 @@ make_arrow(int type, int style, double t
+ {
+ F_arrow *a;
+
+- if (style < 0 || style > 1 || type < 0 || (type + 1) * 2 > NUMARROWS)
++ if (style < 0 || style > 1 || type < 0 ||
++ /* beware of int overflow */
++ type > NUMARROWS || (type + 1) * 2 > NUMARROWS)
+ return NULL;
+ if (NULL == (Arrow_malloc(a))) {
+ put_msg(Err_mem);
+@@ -90,7 +93,7 @@ make_arrow(int type, int style, double t
+
+ a->type = type;
+ a->style = style;
+- a->thickness = thickness*THICK_SCALE;
++ a->thickness = thickness * THICK_SCALE;
+ a->wid = wid;
+ a->ht = ht;
+ return a;
diff -Nru fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch
--- fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch 1970-01-01 01:00:00.000000000 +0100
+++ fig2dev-3.2.7a/debian/patches/43_fgets2getline.patch 2020-01-07 19:53:09.000000000 +0100
@@ -0,0 +1,1717 @@
+From: Thomas Loimer <thomas.loi...@tuwien.ac.at>
+Date: Sun Jan 5 19:22:12 2020 +0100
+Bug: https://sourceforge.net/p/mcj/tickets/58
+Bug: https://sourceforge.net/p/mcj/tickets/59
+Bug: https://sourceforge.net/p/mcj/tickets/61
+Bug: https://sourceforge.net/p/mcj/tickets/62
+Bug: https://sourceforge.net/p/mcj/tickets/67
+Bug: https://sourceforge.net/p/mcj/tickets/78
+Bug: https://sourceforge.net/p/mcj/tickets/79
+Bug-Debian: https://bugs.debian.org/946866
+Origin: https://sourceforge.net/p/mcj/fig2dev/ci/41b9bb838a3d544539f6e68aa4f87d70ef7d45ce/
+Subject: 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.
+
+ This fixes CVE-2019-19797
+
+--- a/fig2dev/fig2dev.c
++++ b/fig2dev/fig2dev.c
+@@ -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) */
+--- a/fig2dev/fig2dev.h
++++ b/fig2dev/fig2dev.h
+@@ -95,7 +95,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 char *Fig_color_names[]; /* hex names for Fig colors */
+--- a/fig2dev/read.c
++++ b/fig2dev/read.c
+@@ -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 (INVALID_ELLIPSE(e)) {
+@@ -781,7 +862,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;
+ }
+@@ -798,8 +879,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;
+@@ -886,7 +968,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;
+@@ -907,40 +989,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;
+ }
+@@ -948,45 +1028,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);
+@@ -1000,21 +1082,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;
+@@ -1023,8 +1106,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);
+ }
+ }
+
+@@ -1036,9 +1119,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;
+ }
+@@ -1046,9 +1129,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;
+ }
+@@ -1077,7 +1160,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;
+ }
+@@ -1089,7 +1172,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;
+@@ -1111,58 +1195,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;
+ }
+@@ -1170,9 +1254,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;
+ };
+@@ -1186,15 +1270,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;
+ };
+@@ -1224,9 +1308,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;
+ }
+@@ -1249,9 +1333,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;
+ }
+@@ -1264,9 +1348,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;
+@@ -1289,13 +1373,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;
+@@ -1303,32 +1411,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 */
+@@ -1338,89 +1515,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)
+@@ -1431,11 +1525,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;
+ }
+@@ -1443,18 +1537,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 */
+@@ -1483,55 +1578,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
+@@ -1688,15 +1792,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);
+ }
+--- a/fig2dev/read1_3.c
++++ b/fig2dev/read1_3.c
+@@ -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);
diff -Nru fig2dev-3.2.7a/debian/patches/series fig2dev-3.2.7a/debian/patches/series
--- fig2dev-3.2.7a/debian/patches/series 2019-12-04 22:12:49.000000000 +0100
+++ fig2dev-3.2.7a/debian/patches/series 2020-01-07 19:53:09.000000000 +0100
@@ -13,3 +13,5 @@
38_omit_showpage.patch
40_circle_arrowhead.patch
41_CVE-2019-19555.patch
+42_CVE-2019-19746.patch
+43_fgets2getline.patch
signature.asc
Description: PGP signature
--- End Message ---