]> gitweb.michael.orlitzky.com - libsvgtiny-pixbuf.git/commitdiff
io-svg.c: first attempt at handling content after an XInclude
authorMichael Orlitzky <michael@orlitzky.com>
Mon, 7 Aug 2023 02:36:47 +0000 (22:36 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Mon, 7 Aug 2023 02:36:47 +0000 (22:36 -0400)
It turns out that gtk3 (but not gtk4) will sometimes wrap its
<xi:include> tag with a <g> tag that specifies some opacity; see
gtk/gtkicontheme.c in the gtk+-3.0 sources. Currently we are keeping
everything before the <xi:include> tag and dropping everything after
it, which results in mismatched tags because we keep the <g> and then
chop off the </g>. I've hacked something together that looks like it
works but it needs a post-sleep reread.

io-svg.c

index 2d4322716d2a869c26a7f9205c98831e4da8ad4e..fde78ca39972aa1bbfa20c5ea622bb6239bef3e8 100644 (file)
--- a/io-svg.c
+++ b/io-svg.c
@@ -409,10 +409,7 @@ static void emit_prepared(SvgTinyContext* context, GdkPixbuf* pixbuf) {
  * and just see what the format of that line will be. Here we're going
  * to parse out the base64 data, decode it, strip out its opening
  * <xml> and <svg> tags, and then replace the original <xi:include>
- * element with the result. Life is a little easier because the
- * closing </svg> tag always immediately follows the XInclude; we can
- * chop the whole thing off, decode the base64 stuff, and then paste
- * the result back on the end with its own closing </svg> tag intact.
+ * element with the result.
  *
  * @param buffer
  *   A buffer containing SVG file data.
@@ -434,6 +431,7 @@ static gchar* process_gtk_symbolic_svg_xinclude(const gchar* buffer,
   gchar* xi_start;
   gchar* xi;
   gchar* xi_stop;
+  gchar* after_xi_element;
 
   xi_start = g_strstr_len(buffer, buf_size, XI_SIGNATURE);
   if (xi_start == NULL) {
@@ -442,6 +440,7 @@ static gchar* process_gtk_symbolic_svg_xinclude(const gchar* buffer,
 
   xi = xi_start + strlen(XI_SIGNATURE);
   xi_stop = g_strstr_len(xi, (buffer + buf_size) - xi, "\"");
+
   if(xi_stop == NULL) {
     /* We found the start of an XInclude, but not the end of its
        base64-encoded data? Play it safe and do nothing. */
@@ -472,30 +471,59 @@ static gchar* process_gtk_symbolic_svg_xinclude(const gchar* buffer,
    * leading <svg> tag. */
   gchar* svg_open_start = g_strstr_len(decoded, decoded_size, "<svg ");
   if (svg_open_start == NULL) {
-    /* The decoded data is not what we were expecting, Give up. */
+    /* The decoded data is not what we were expecting. Give up. */
     g_free(decoded);
     return NULL;
   }
-  else {
-    gchar* svg_open_end = g_strstr_len(svg_open_start, decoded_size, ">");
-    if (svg_open_end == NULL) {
-      /* The decoded data is not what we were expecting. Give up. */
-      g_free(decoded);
-      return NULL;
-    }
-    memset(decoded, ' ', (1 + (svg_open_end - decoded)));
+
+  gchar* svg_open_end = g_strstr_len(svg_open_start,
+                                    (decoded+decoded_size) - svg_open_start,
+                                    ">");
+  if (svg_open_end == NULL) {
+    /* The decoded data is not what we were expecting. Give up. */
+    g_free(decoded);
+    return NULL;
+  }
+
+  /* Keep in mind that we want to wipe everything up to and
+     including the <svg> tag; we'll usually overwrite an <xml> tag
+     too. */
+  memset(decoded, ' ', (1 + (svg_open_end - decoded)));
+
+  gchar* svg_close_start = g_strstr_len(svg_open_end,
+                                       (decoded+decoded_size)-svg_open_end,
+                                       "</svg>");
+  if (svg_close_start == NULL ) {
+    /* The decoded data is not what we were expecting. Give up. */
+    g_free(decoded);
+    return NULL;
   }
+  memset(svg_close_start, ' ', 6);
 
   /* We're going to keep everything up to xi_start. If the <xi:include
    * started at, say, position three, then this would compute a size
    * of three. Which is correct: we want to retain buffer[0],
    * buffer[1], and buffer[2]. */
-  gsize keep_size = xi_start - buffer;
-  *new_size = keep_size + decoded_size;
+  gsize keep_before_size = xi_start - buffer;
+
+  /* We're also going to keep everything after the XInclude element. */
+  after_xi_element = xi_stop + 3; /* They all end with "/> */
+  if (after_xi_element >= buffer+buf_size) {
+    /* The document ends right after the XInclude (with no closing
+       </svg> tag or anything)? Bail. */
+    g_free(decoded);
+    return NULL;
+  }
+
+  gsize keep_after_size = (buffer+buf_size) - after_xi_element;
 
+  *new_size = keep_before_size + decoded_size + keep_after_size;
   gchar* result = g_malloc(*new_size);
-  memcpy(result, buffer, keep_size);
-  memcpy(result+keep_size, decoded, decoded_size);
+  memcpy(result, buffer, keep_before_size);
+  memcpy(result+keep_before_size, decoded, decoded_size);
+  memcpy(result+keep_before_size+decoded_size,
+        after_xi_element,
+        keep_after_size);
   g_free(decoded);
   return result;
 }