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)
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));
}
}
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));
}
}
val = agget(n, GXL_TYPE);
if (!EMPTY(val)) {
tabover(gxlFile);
- fprintf(gxlFile, "\t<type xlink:href=\"%s\">\n", val);
+ fprintf(gxlFile, "\t<type xlink:href=\"%s\">\n", xml_url_string(val));
tabover(gxlFile);
fprintf(gxlFile, "\t</type>\n");
}
locatorVal += 13;
tabover(gxlFile);
- fprintf(gxlFile, "\t<attr name=\"%s\">\n", sym->name);
+ fprintf(gxlFile, "\t<attr name=\"%s\">\n", xml_string(sym->name));
tabover(gxlFile);
fprintf(gxlFile, "\t\t<locator xlink:href=\"%s\"/>\n",
- locatorVal);
+ xml_url_string(locatorVal));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
} else {
tabover(gxlFile);
- if (isGraph)
- fprintf(gxlFile, "\t<attr name=\"%s\" kind=\"%s\">\n",
- sym->name, name);
- else
- fprintf(gxlFile,
- "\t<attr name=\"%s:%s\" kind=\"%s\">\n", name,
- sym->name, name);
+ if (isGraph) {
+ fprintf(gxlFile, "\t<attr name=\"%s\" ", xml_string(sym->name));
+ fprintf(gxlFile, "kind=\"%s\">\n", xml_string(name));
+ }
+ else {
+ fprintf(gxlFile, "\t<attr name=\"%s:", xml_string(name));
+ fprintf(gxlFile, "%s\" kind=\"", xml_string(sym->name));
+ fprintf(gxlFile, "%s\">\n", xml_string(name));
+ }
tabover(gxlFile);
- fprintf(gxlFile, "\t\t<string>");
- escapeForXML(gxlFile, sym->defval);
- fprintf(gxlFile, "</string>\n");
+ fprintf(gxlFile, "\t\t<string>%s</string>\n", xml_string(sym->defval));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
}
}
tabover(gxlFile);
- fprintf(gxlFile, "\t<attr name=\"%s\" kind=\"%s\">\n",
- ((sym->name) + GXL_COMP_LEN), name);
+ fprintf(gxlFile, "\t<attr name=\"%s\" ", xml_string(((sym->name) + 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</attr>\n");
}
tabover(gxlFile);
fprintf(gxlFile, "\t<attr name=\"name\">\n");
tabover(gxlFile);
- fprintf(gxlFile, "\t\t<string>%s</string>\n", name);
+ fprintf(gxlFile, "\t\t<string>%s</string>\n", xml_string(name));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
}
tabover(gxlFile);
fprintf(gxlFile, "\t<attr name=\"key\">\n");
tabover(gxlFile);
- fprintf(gxlFile, "\t\t<string>%s</string>\n", p);
+ fprintf(gxlFile, "\t\t<string>%s</string>\n", xml_string(p));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
rv = TRUE;
tabover(gxlFile);
fprintf(gxlFile, "\t<attr name=\"%s\">\n",
- sym->name);
+ xml_string(sym->name));
tabover(gxlFile);
fprintf(gxlFile,
"\t\t<locator xlink:href=\"%s\"/>\n",
- locatorVal);
+ xml_url_string(locatorVal));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
} else {
tabover(gxlFile);
fprintf(gxlFile, "\t<attr name=\"%s\">\n",
- sym->name);
+ xml_string(sym->name));
tabover(gxlFile);
- fprintf(gxlFile, "\t\t<string>");
- escapeForXML(gxlFile, data->str[sym->id]);
- fprintf(gxlFile, "</string>\n");
+ fprintf(gxlFile, "\t\t<string>%s</string>\n", xml_string(data->str[sym->id]));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
}
tabover(gxlFile);
fprintf(gxlFile, "\t<attr name=\"%s\">\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</attr>\n");
}
tabover(gxlFile);
fprintf(gxlFile, "\t<attr name=\"name\">\n");
tabover(gxlFile);
- fprintf(gxlFile, "\t\t<string>%s</string>\n", name);
+ fprintf(gxlFile, "\t\t<string>%s</string>\n", xml_string(name));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
}
val = agget(e, name);
if (val && val[0]) {
tabover(gxlFile);
- fprintf(gxlFile, "\t<attr name=\"%s\">\n", name);
+ fprintf(gxlFile, "\t<attr name=\"%s\">\n", xml_string(name));
tabover(gxlFile);
- fprintf(gxlFile, "\t\t<string>");
- escapeForXML(gxlFile, val);
- fprintf(gxlFile, "</string>\n");
+ fprintf(gxlFile, "\t\t<string>%s</string>\n", xml_string(val));
tabover(gxlFile);
fprintf(gxlFile, "\t</attr>\n");
}
Level++;
tabover(gxlFile);
- fprintf(gxlFile, "<edge from=\"%s\" to=\"%s\"", nodeID(stp, t),
- nodeID(stp, h));
+ fprintf(gxlFile, "<edge from=\"%s\" ", nodeID(stp, t));
+ fprintf(gxlFile, "to=\"%s\"", nodeID(stp, h));
edgeAttrs(gxlFile, e);
if (stp->directed) {