From aa02cbad1d1e4efad576682c70b83a893844d3ee Mon Sep 17 00:00:00 2001 From: Emden Gansner Date: Thu, 10 May 2012 17:54:34 -0400 Subject: [PATCH] Fix bug 2229 --- cmd/tools/gv2gxl.c | 191 ++++++++++++++++++++++++++++++++------------- 1 file changed, 135 insertions(+), 56 deletions(-) diff --git a/cmd/tools/gv2gxl.c b/cmd/tools/gv2gxl.c index 53cd04ee3..89a5a2b8b 100644 --- a/cmd/tools/gv2gxl.c +++ b/cmd/tools/gv2gxl.c @@ -141,26 +141,109 @@ static int legalGXLName(char *id) return 1; } -static void escapeForXML(FILE * gxlFile, char *value) -{ - char c; - - while ((c = *value++)) { - switch (c) { - case '>': - fputs(">", gxlFile); - break; - case '<': - fputs("<", gxlFile); - break; - case '&': - fputs("&", gxlFile); - break; - default: - putc(c, gxlFile); - break; +/* return true if *s points to &[A-Za-z]*; (e.g. Ç ) + * or &#[0-9]*; (e.g. & ) + * or &#x[0-9a-fA-F]*; (e.g. 水 ) + */ +static int xml_isentity(char *s) +{ + s++; /* already known to be '&' */ + if (*s == '#') { + s++; + if (*s == 'x' || *s == 'X') { + s++; + while ((*s >= '0' && *s <= '9') + || (*s >= 'a' && *s <= 'f') + || (*s >= 'A' && *s <= 'F')) + s++; + } else { + while (*s >= '0' && *s <= '9') + s++; } + } else { + while ((*s >= 'a' && *s <= 'z') + || (*s >= 'A' && *s <= 'Z')) + s++; } + if (*s == ';') + return 1; + return 0; +} + +static char *_xml_string(char *s, int notURL) +{ + static char *buf = NULL; + static int bufsize = 0; + char *p, *sub, *prev = NULL; + int len, pos = 0; + + if (!buf) { + bufsize = 64; + buf = N_NEW(bufsize, char); + } + + p = buf; + while (s && *s) { + if (pos > (bufsize - 8)) { + bufsize *= 2; + buf = realloc(buf, bufsize); + p = buf + pos; + } + /* escape '&' only if not part of a legal entity sequence */ + if (*s == '&' && !(xml_isentity(s))) { + sub = "&"; + len = 5; + } + /* '<' '>' are safe to substitute even if string is already UTF-8 coded + * since UTF-8 strings won't contain '<' or '>' */ + else if (*s == '<') { + sub = "<"; + len = 4; + } + else if (*s == '>') { + sub = ">"; + len = 4; + } + else if ((*s == '-') && notURL) { /* can't be used in xml comment strings */ + sub = "-"; + len = 5; + } + else if (*s == ' ' && prev && *prev == ' ' && notURL) { + /* substitute 2nd and subsequent spaces with required_spaces */ + sub = " "; /* inkscape doesn't recognise   */ + len = 6; + } + else if (*s == '"') { + sub = """; + len = 6; + } + else if (*s == '\'') { + sub = "'"; + len = 5; + } + else { + sub = s; + len = 1; + } + while (len--) { + *p++ = *sub++; + pos++; + } + prev = s; + s++; + } + *p = '\0'; + return buf; +} + +static char *xml_string(char *s) +{ + return _xml_string(s,1); +} + +static char *xml_url_string(char *s) +{ + return _xml_string(s,0); } static int isGxlGrammar(char *name) @@ -280,11 +363,11 @@ static void graphAttrs(FILE * gxlFile, Agraph_t * g) val = agget(g, GXL_ROLE); if (!EMPTY(val)) { - fprintf(gxlFile, " role=\"%s\"", val); + fprintf(gxlFile, " role=\"%s\"", xml_string(val)); } val = agget(g, GXL_HYPER); if (!EMPTY(val)) { - fprintf(gxlFile, " hypergraph=\"%s\"", val); + fprintf(gxlFile, " hypergraph=\"%s\"", xml_string(val)); } } @@ -294,15 +377,15 @@ static void edgeAttrs(FILE * gxlFile, Agedge_t * e) val = agget(e, GXL_ID); if (!EMPTY(val)) { - fprintf(gxlFile, " id=\"%s\"", val); + fprintf(gxlFile, " id=\"%s\"", xml_string(val)); } val = agget(e, GXL_FROM); if (!EMPTY(val)) { - fprintf(gxlFile, " fromorder=\"%s\"", val); + fprintf(gxlFile, " fromorder=\"%s\"", xml_string(val)); } val = agget(e, GXL_TO); if (!EMPTY(val)) { - fprintf(gxlFile, " toorder=\"%s\"", val); + fprintf(gxlFile, " toorder=\"%s\"", xml_string(val)); } } @@ -314,7 +397,7 @@ static void printHref(FILE * gxlFile, void *n) val = agget(n, GXL_TYPE); if (!EMPTY(val)) { tabover(gxlFile); - fprintf(gxlFile, "\t\n", val); + fprintf(gxlFile, "\t\n", xml_url_string(val)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -347,25 +430,25 @@ writeDict(Agraph_t * g, FILE * gxlFile, char *name, Dict_t * dict, locatorVal += 13; tabover(gxlFile); - fprintf(gxlFile, "\t\n", sym->name); + fprintf(gxlFile, "\t\n", xml_string(sym->name)); tabover(gxlFile); fprintf(gxlFile, "\t\t\n", - locatorVal); + xml_url_string(locatorVal)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } else { tabover(gxlFile); - if (isGraph) - fprintf(gxlFile, "\t\n", - sym->name, name); - else - fprintf(gxlFile, - "\t\n", name, - sym->name, name); + if (isGraph) { + fprintf(gxlFile, "\tname)); + fprintf(gxlFile, "kind=\"%s\">\n", xml_string(name)); + } + else { + fprintf(gxlFile, "\tname)); + fprintf(gxlFile, "%s\">\n", xml_string(name)); + } tabover(gxlFile); - fprintf(gxlFile, "\t\t"); - escapeForXML(gxlFile, sym->defval); - fprintf(gxlFile, "\n"); + fprintf(gxlFile, "\t\t%s\n", xml_string(sym->defval)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -381,10 +464,10 @@ writeDict(Agraph_t * g, FILE * gxlFile, char *name, Dict_t * dict, } tabover(gxlFile); - fprintf(gxlFile, "\t\n", - ((sym->name) + GXL_COMP_LEN), name); + fprintf(gxlFile, "\tname) + GXL_COMP_LEN))); + fprintf(gxlFile, "kind=\"%s\">\n", xml_string(name)); tabover(gxlFile); - fprintf(gxlFile, "\t\t%s\n", sym->defval); + fprintf(gxlFile, "\t\t%s\n", xml_string(sym->defval)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -461,7 +544,7 @@ writeHdr(gxlstate_t * stp, Agraph_t * g, FILE * gxlFile, int top) tabover(gxlFile); fprintf(gxlFile, "\t\n"); tabover(gxlFile); - fprintf(gxlFile, "\t\t%s\n", name); + fprintf(gxlFile, "\t\t%s\n", xml_string(name)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -514,7 +597,7 @@ static int writeEdgeName(Agedge_t * e, FILE * gxlFile, int terminate) tabover(gxlFile); fprintf(gxlFile, "\t\n"); tabover(gxlFile); - fprintf(gxlFile, "\t\t%s\n", p); + fprintf(gxlFile, "\t\t%s\n", xml_string(p)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); rv = TRUE; @@ -559,21 +642,19 @@ writeNondefaultAttr(void *obj, FILE * gxlFile, Dict_t * defdict) tabover(gxlFile); fprintf(gxlFile, "\t\n", - sym->name); + xml_string(sym->name)); tabover(gxlFile); fprintf(gxlFile, "\t\t\n", - locatorVal); + xml_url_string(locatorVal)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } else { tabover(gxlFile); fprintf(gxlFile, "\t\n", - sym->name); + xml_string(sym->name)); tabover(gxlFile); - fprintf(gxlFile, "\t\t"); - escapeForXML(gxlFile, data->str[sym->id]); - fprintf(gxlFile, "\n"); + fprintf(gxlFile, "\t\t%s\n", xml_string(data->str[sym->id])); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -585,9 +666,9 @@ writeNondefaultAttr(void *obj, FILE * gxlFile, Dict_t * defdict) tabover(gxlFile); fprintf(gxlFile, "\t\n", - ((sym->name) + GXL_COMP_LEN)); + xml_string(((sym->name) + GXL_COMP_LEN))); tabover(gxlFile); - fprintf(gxlFile, "\t\t%s\n", data->str[sym->id]); + fprintf(gxlFile, "\t\t%s\n", xml_string(data->str[sym->id])); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -623,7 +704,7 @@ writeNode(gxlstate_t * stp, Agnode_t * n, FILE * gxlFile, Dict_t * d) tabover(gxlFile); fprintf(gxlFile, "\t\n"); tabover(gxlFile); - fprintf(gxlFile, "\t\t%s\n", name); + fprintf(gxlFile, "\t\t%s\n", xml_string(name)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -642,11 +723,9 @@ static void writePort(Agedge_t * e, FILE * gxlFile, char *name) val = agget(e, name); if (val && val[0]) { tabover(gxlFile); - fprintf(gxlFile, "\t\n", name); + fprintf(gxlFile, "\t\n", xml_string(name)); tabover(gxlFile); - fprintf(gxlFile, "\t\t"); - escapeForXML(gxlFile, val); - fprintf(gxlFile, "\n"); + fprintf(gxlFile, "\t\t%s\n", xml_string(val)); tabover(gxlFile); fprintf(gxlFile, "\t\n"); } @@ -676,8 +755,8 @@ writeEdge(gxlstate_t * stp, Agedge_t * e, FILE * gxlFile, Dict_t * d) Level++; tabover(gxlFile); - fprintf(gxlFile, "directed) { -- 2.50.1