]> granicus.if.org Git - graphviz/commitdiff
VML plugin: replace 'gvputs(… html_string(…))' with 'xml_escape' functionality
authorMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 23 Oct 2021 20:06:20 +0000 (13:06 -0700)
committerMatthew Fernandez <matthew.fernandez@gmail.com>
Sat, 30 Oct 2021 02:36:03 +0000 (19:36 -0700)
This is further work towards unifying the XML escaping code (#1868). This change
has no functional impact but makes this processing slightly more efficient
(escaped text is emitted directly into the target file/stream instead of first
constructed in an intermediate buffer) and thread safe (a static buffer is no
longer used for escaping). The latter is not so significant as other factors
make it still unsafe to call into this plugin with multiple threads.

plugin/core/gvrender_core_vml.c

index 088c6f02cb863c86504eb2d584f33f46e5ccc677..e6314a529ac64a24a1254e04a4d3b5de02efbceb 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <common/macros.h>
 #include <common/const.h>
+#include <common/types.h>
+#include <common/utils.h>
 
 #include <gvc/gvplugin_render.h>
 #include <gvc/gvplugin_device.h>
@@ -28,35 +30,6 @@ typedef enum { FORMAT_VML, FORMAT_VMLZ, } format_type;
 
 unsigned int  graphHeight,graphWidth;
 
-/*  this is a direct copy fromlib/common/labels.c  */
-static int xml_isentity(char *s)
-{
-    s++;                       /* already known to be '&' */
-    if (*s == ';') { // '&;' is not a valid entity
-       return 0;
-    }
-    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 void vml_bzptarray(GVJ_t * job, pointf * A, int n)
 {
     int i;
@@ -124,129 +97,27 @@ static void vml_grfill(GVJ_t * job, int filled)
     }
 }
 
-/*  html_string is a modified version of xml_string  */
-static char *html_string(char *s)
-{
-    static char *buf = NULL;
-    static size_t bufsize = 0;
-    char *p, *sub, *prev = NULL;
-    size_t len, pos = 0;
-    int temp,cnt,remaining=0;
-    char workstr[16];
-    uint64_t charnum=0;
-    unsigned char byte;
-    unsigned char mask;
-
-
-    if (!buf) {
-       bufsize = 64;
-       buf = gmalloc(bufsize);
-    }
-    p = buf;
-    while (s && *s) {
-       if (pos > (bufsize - 8)) {
-           bufsize *= 2;
-           buf = grealloc(buf, bufsize);
-           p = buf + pos;
-       }
-       /* escape '&' only if not part of a legal entity sequence */
-       if (*s == '&' && !(xml_isentity(s))) {
-           sub = "&amp;";
-           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 = "&lt;";
-           len = 4;
-       }
-       else if (*s == '>') {
-           sub = "&gt;";
-           len = 4;
-       }
-       else if (*s == '-') {   /* can't be used in xml comment strings */
-           sub = "&#45;";
-           len = 5;
-       }
-       else if (*s == ' ' && prev && *prev == ' ') {
-           /* substitute 2nd and subsequent spaces with required_spaces */
-           sub = "&#160;";  /* inkscape doesn't recognise &nbsp; */
-           len = 6;
-       }
-       else if (*s == '"') {
-           sub = "&quot;";
-           len = 6;
-       }
-       else if (*s == '\'') {
-           sub = "&#39;";
-           len = 5;
-       }
-       else if ((unsigned char)*s > 127) {
-            byte=(unsigned char)*s;
-            cnt=0;
-            for (mask=127; mask < byte; mask=mask >>1){
-              cnt++;
-              byte=byte & mask;
-            }
-            if (cnt>1){
-              charnum=byte;
-              remaining=cnt-1;
-            }else{
-              charnum=charnum<<6;
-              charnum+=byte;
-              remaining--;
-            }
-            if (remaining>0){
-              s++;
-              continue;
-            }           
-            /* we will build the html value right-to-left
-             * (least significant-to-most)  */
-            workstr[15]=';';
-            sub=&workstr[14];
-            len=3; /*  &#  + ;  */
-            do {
-              temp=(int)(charnum%10);
-              *(sub--)=(char)((int)'0'+ temp);
-              charnum/=10;
-              len++;
-              if (len>12){      /* 12 is arbitrary, but clearly in error  */
-                fprintf(stderr, "Error during conversion to \"UTF-8\".  Quiting.\n");
-                exit(1);
-              }
-            } while (charnum>0);
-            *(sub--)='#';
-            *(sub)='&';
-       }
-       else {
-           sub = s;
-           len = 1;
-       }
-       while (len--) {
-           *p++ = *sub++;
-           pos++;
-       }
-       prev = s;
-       s++;
-    }
-    *p = '\0';
-    return buf;
+// wrapper around `xml_escape` to set flags for HTML escaping
+static void html_puts(GVJ_t *job, const char *s) {
+  const xml_flags_t flags = {.dash = 1, .nbsp = 1, .utf8 = 1};
+  (void)xml_escape(s, flags, (int(*)(void*, const char*))gvputs, job);
 }
+
 static void vml_comment(GVJ_t * job, char *str)
 {
     gvputs(job, "      <!-- ");
-    gvputs(job, html_string(str));
+    html_puts(job, str);
     gvputs(job, " -->\n");
 }
 static void vml_begin_job(GVJ_t * job)
 {
     gvputs(job, "<HTML>\n");
     gvputs(job, "\n<!-- Generated by ");
-    gvputs(job, html_string(job->common->info[0]));
+    html_puts(job, job->common->info[0]);
     gvputs(job, " version ");
-    gvputs(job, html_string(job->common->info[1]));
+    html_puts(job, job->common->info[1]);
     gvputs(job, " (");
-    gvputs(job, html_string(job->common->info[2]));
+    html_puts(job, job->common->info[2]);
     gvputs(job, ")\n-->\n");
 }
 
@@ -265,7 +136,7 @@ static void vml_begin_graph(GVJ_t * job)
     name = agnameof(obj->u.g);
     if (name[0]) {
         gvputs(job, "<TITLE>");
-       gvputs(job, html_string(name));
+        html_puts(job, name);
         gvputs(job, "</TITLE>");
     }
     gvprintf(job, "<!-- Pages: %d -->\n", job->pagesArraySize.x * job->pagesArraySize.y);
@@ -354,12 +225,21 @@ vml_begin_anchor(GVJ_t * job, char *href, char *tooltip, char *target, char *id)
     (void)id;
 
     gvputs(job, "<a");
-    if (href && href[0])
-       gvprintf(job, " href=\"%s\"", html_string(href));
-    if (tooltip && tooltip[0])
-       gvprintf(job, " title=\"%s\"", html_string(tooltip));
-    if (target && target[0])
-       gvprintf(job, " target=\"%s\"", html_string(target));
+    if (href && href[0]) {
+       gvputs(job, " href=\"");
+       html_puts(job, href);
+       gvputs(job, "\"");
+    }
+    if (tooltip && tooltip[0]) {
+       gvputs(job, " title=\"");
+       html_puts(job, tooltip);
+       gvputs(job, "\"");
+    }
+    if (target && target[0]) {
+       gvputs(job, " target=\"");
+       html_puts(job, target);
+       gvputs(job, "\"");
+    }
     gvputs(job, ">\n");
 }
 
@@ -439,7 +319,7 @@ static void vml_textspan(GVJ_t * job, pointf p, textspan_t * span)
        assert(0);              /* internal error */
     }
     gvputs(job, "\"><center>");
-    gvputs(job, html_string(span->str));
+    html_puts(job, span->str);
     gvputs(job, "</center></v:textbox>\n"); 
     gvputs(job, "</v:rect>\n");
 }