[gimp] Bug 711241 - Broken or unknown metadata tag should not cancel...



commit 33a8d68117a1ade59279102935ca128a25ec04d3
Author: Michael Natterer <mitch gimp org>
Date:   Mon Nov 11 00:11:43 2013 +0100

    Bug 711241 - Broken or unknown metadata tag should not cancel...
    
    ...the whole metadata loading
    
    Don't drop non-utf8 values from gexiv2 when serializing to XML,
    instead, base64 encode them. This should be robust against whatever
    garbage data is in tags.

 libgimpbase/gimpmetadata.c |   98 ++++++++++++++++++++++++++++++++------------
 1 files changed, 71 insertions(+), 27 deletions(-)
---
diff --git a/libgimpbase/gimpmetadata.c b/libgimpbase/gimpmetadata.c
index 55e8baa..73ff2fc 100644
--- a/libgimpbase/gimpmetadata.c
+++ b/libgimpbase/gimpmetadata.c
@@ -205,6 +205,7 @@ gimp_metadata_duplicate (GimpMetadata *metadata)
 typedef struct
 {
   gchar         name[1024];
+  gboolean      base64;
   GimpMetadata *metadata;
 } GimpMetadataParseData;
 
@@ -240,10 +241,14 @@ gimp_metadata_deserialize_start_element (GMarkupParseContext *context,
   if (! strcmp (element_name, "tag"))
     {
       const gchar *name;
+      const gchar *encoding;
 
       name = gimp_metadata_attribute_name_to_value (attribute_names,
                                                     attribute_values,
                                                     "name");
+      encoding = gimp_metadata_attribute_name_to_value (attribute_names,
+                                                        attribute_values,
+                                                        "encoding");
 
       if (! name)
         {
@@ -254,6 +259,8 @@ gimp_metadata_deserialize_start_element (GMarkupParseContext *context,
 
       strncpy (parse_data->name, name, sizeof (parse_data->name));
       parse_data->name[sizeof (parse_data->name) - 1] = 0;
+
+      parse_data->base64 = (encoding && ! strcmp (encoding, "base64"));
     }
 }
 
@@ -281,9 +288,26 @@ gimp_metadata_deserialize_text (GMarkupParseContext  *context,
     {
       gchar *value = g_strndup (text, text_len);
 
-      gexiv2_metadata_set_tag_string (parse_data->metadata,
-                                      parse_data->name,
-                                      value);
+      if (parse_data->base64)
+        {
+          guchar *decoded;
+          gsize   len;
+
+          decoded = g_base64_decode (value, &len);
+
+          if (decoded[len - 1] == '\0')
+            gexiv2_metadata_set_tag_string (parse_data->metadata,
+                                            parse_data->name,
+                                            (const gchar *) decoded);
+
+          g_free (decoded);
+        }
+      else
+        {
+          gexiv2_metadata_set_tag_string (parse_data->metadata,
+                                          parse_data->name,
+                                          value);
+        }
 
       g_free (value);
     }
@@ -341,17 +365,51 @@ gimp_metadata_deserialize (const gchar *metadata_xml)
 
 static gchar *
 gimp_metadata_escape (const gchar *name,
-                      const gchar *value)
+                      const gchar *value,
+                      gboolean    *base64)
 {
   if (! g_utf8_validate (value, -1, NULL))
     {
-      g_printerr ("Invalid UTF-8 in metadata value %s: %s\n", name, value);
-      return NULL;
+      gchar *encoded;
+
+      encoded = g_base64_encode ((const guchar *) value, strlen (value) + 1);
+
+      g_printerr ("Invalid UTF-8 in metadata value %s, encoding as base64: %s\n",
+                  name, encoded);
+
+      *base64 = TRUE;
+
+      return encoded;
     }
 
+  *base64 = FALSE;
+
   return g_markup_escape_text (value, -1);
 }
 
+static void
+gimp_metadata_append_tag (GString     *string,
+                          const gchar *name,
+                          gchar       *value,
+                          gboolean     base64)
+{
+  if (value)
+    {
+      if (base64)
+        {
+          g_string_append_printf (string, "  <tag name=\"%s\" encoding=\"base64\">%s</tag>\n",
+                                  name, value);
+        }
+      else
+        {
+          g_string_append_printf (string, "  <tag name=\"%s\">%s</tag>\n",
+                                  name, value);
+        }
+
+      g_free (value);
+    }
+}
+
 /**
  * gimp_metadata_serialize:
  * @metadata: A #GimpMetadata instance.
@@ -372,6 +430,7 @@ gimp_metadata_serialize (GimpMetadata *metadata)
   gchar   **xmp_data  = NULL;
   gchar    *value;
   gchar    *escaped;
+  gboolean  base64;
   gint      i;
 
   g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), NULL);
@@ -388,15 +447,10 @@ gimp_metadata_serialize (GimpMetadata *metadata)
       for (i = 0; exif_data[i] != NULL; i++)
         {
           value = gexiv2_metadata_get_tag_string (metadata, exif_data[i]);
-          escaped = gimp_metadata_escape (exif_data[i], value);
+          escaped = gimp_metadata_escape (exif_data[i], value, &base64);
           g_free (value);
 
-          if (escaped)
-            {
-              g_string_append_printf (string, "  <tag name=\"%s\">%s</tag>\n",
-                                      exif_data[i], escaped);
-              g_free (escaped);
-            }
+          gimp_metadata_append_tag (string, exif_data[i], escaped, base64);
         }
 
       g_strfreev (exif_data);
@@ -409,15 +463,10 @@ gimp_metadata_serialize (GimpMetadata *metadata)
       for (i = 0; xmp_data[i] != NULL; i++)
         {
           value = gexiv2_metadata_get_tag_string (metadata, xmp_data[i]);
-          escaped = gimp_metadata_escape (xmp_data[i], value);
+          escaped = gimp_metadata_escape (xmp_data[i], value, &base64);
           g_free (value);
 
-          if (escaped)
-            {
-              g_string_append_printf (string, "  <tag name=\"%s\">%s</tag>\n",
-                                      xmp_data[i], escaped);
-              g_free (escaped);
-            }
+          gimp_metadata_append_tag (string, xmp_data[i], escaped, base64);
         }
 
       g_strfreev (xmp_data);
@@ -430,15 +479,10 @@ gimp_metadata_serialize (GimpMetadata *metadata)
       for (i = 0; iptc_data[i] != NULL; i++)
         {
           value = gexiv2_metadata_get_tag_string (metadata, iptc_data[i]);
-          escaped = gimp_metadata_escape (iptc_data[i], value);
+          escaped = gimp_metadata_escape (iptc_data[i], value, &base64);
           g_free (value);
 
-          if (escaped)
-            {
-              g_string_append_printf (string, "  <tag name=\"%s\">%s</tag>\n",
-                                      iptc_data[i], escaped);
-              g_free (escaped);
-            }
+          gimp_metadata_append_tag (string, iptc_data[i], escaped, base64);
         }
 
       g_strfreev (iptc_data);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]