From 3ffb1b9f69526aada2b9dfe6ef19d74212cb89d4 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 6 Aug 2023 22:36:47 -0400 Subject: [PATCH] io-svg.c: first attempt at handling content after an XInclude It turns out that gtk3 (but not gtk4) will sometimes wrap its tag with a tag that specifies some opacity; see gtk/gtkicontheme.c in the gtk+-3.0 sources. Currently we are keeping everything before the tag and dropping everything after it, which results in mismatched tags because we keep the and then chop off the . I've hacked something together that looks like it works but it needs a post-sleep reread. --- io-svg.c | 62 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/io-svg.c b/io-svg.c index 2d43227..fde78ca 100644 --- 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 * and tags, and then replace the original - * element with the result. Life is a little easier because the - * closing 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 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 tag. */ gchar* svg_open_start = g_strstr_len(decoded, 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 tag; we'll usually overwrite an 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, + ""); + 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 */ + if (after_xi_element >= buffer+buf_size) { + /* The document ends right after the XInclude (with no closing + 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; } -- 2.43.2