[gthumb] fixed crash when embedded data contains invalid utf8 values



commit 43c7faef8bf5f5bcad826a1b83d7ad5c0ab5c004
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun Nov 2 11:56:43 2014 +0100

    fixed crash when embedded data contains invalid utf8 values

 extensions/comments/gth-comment.c      |   35 ++++++++++++++++++------
 extensions/exiv2_tools/exiv2-utils.cpp |   21 ++++++++++++---
 gthumb/dom.c                           |   46 +++++++++++++++++++++++++++----
 gthumb/dom.h                           |    2 +
 gthumb/glib-utils.c                    |   36 +++++++++++++++++++++++++
 gthumb/glib-utils.h                    |    2 +
 gthumb/gth-file-data.c                 |    3 +-
 gthumb/gth-file-properties.c           |   10 +++++--
 gthumb/gth-string-list.c               |   11 +++++++-
 gthumb/gth-string-list.h               |    3 ++
 10 files changed, 145 insertions(+), 24 deletions(-)
---
diff --git a/extensions/comments/gth-comment.c b/extensions/comments/gth-comment.c
index e76e17d..8e22be0 100644
--- a/extensions/comments/gth-comment.c
+++ b/extensions/comments/gth-comment.c
@@ -638,8 +638,12 @@ gth_comment_update_from_general_attributes (GthFileData *file_data)
        if (metadata != NULL) {
                text = g_file_info_get_attribute_string (file_data->info, "comment::note");
                if (! dom_str_equal (gth_metadata_get_formatted (metadata), text)) {
-                       gth_comment_set_note (comment, gth_metadata_get_formatted (metadata));
-                       write_comment = TRUE;
+                       char *value = _g_utf8_try_from_any (gth_metadata_get_formatted (metadata));
+                       if (value != NULL) {
+                               gth_comment_set_note (comment, value);
+                               g_free (value);
+                               write_comment = TRUE;
+                       }
                }
        }
 
@@ -647,8 +651,12 @@ gth_comment_update_from_general_attributes (GthFileData *file_data)
        if (metadata != NULL) {
                text = g_file_info_get_attribute_string (file_data->info, "comment::caption");
                if (! dom_str_equal (gth_metadata_get_formatted (metadata), text)) {
-                       gth_comment_set_caption (comment, gth_metadata_get_formatted (metadata));
-                       write_comment = TRUE;
+                       char *value = _g_utf8_try_from_any (gth_metadata_get_formatted (metadata));
+                       if (value != NULL) {
+                               gth_comment_set_caption (comment, value);
+                               g_free (value);
+                               write_comment = TRUE;
+                       }
                }
        }
 
@@ -656,8 +664,12 @@ gth_comment_update_from_general_attributes (GthFileData *file_data)
        if (metadata != NULL) {
                text = g_file_info_get_attribute_string (file_data->info, "comment::place");
                if (! dom_str_equal (gth_metadata_get_formatted (metadata), text)) {
-                       gth_comment_set_place (comment, gth_metadata_get_formatted (metadata));
-                       write_comment = TRUE;
+                       char *value = _g_utf8_try_from_any (gth_metadata_get_formatted (metadata));
+                       if (value != NULL) {
+                               gth_comment_set_place (comment, value);
+                               g_free (value);
+                               write_comment = TRUE;
+                       }
                }
        }
 
@@ -680,12 +692,17 @@ gth_comment_update_from_general_attributes (GthFileData *file_data)
        if (categories != NULL) {
                metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, 
"comment::categories");
                comment_categories = gth_metadata_get_string_list (metadata);
-               if (! gth_string_list_equal (categories, comment_categories)) {
+               if (! gth_string_list_equal_custom (categories, comment_categories, (GCompareFunc) 
dom_str_find)) {
                        GList *scan;
 
                        gth_comment_clear_categories (comment);
-                       for (scan = gth_string_list_get_list (categories); scan; scan = scan->next)
-                               gth_comment_add_category (comment, scan->data);
+                       for (scan = gth_string_list_get_list (categories); scan; scan = scan->next) {
+                               char *value = _g_utf8_try_from_any (scan->data);
+                               if (value != NULL) {
+                                       gth_comment_add_category (comment, value);
+                                       g_free (value);
+                               }
+                       }
                        write_comment = TRUE;
                }
        }
diff --git a/extensions/exiv2_tools/exiv2-utils.cpp b/extensions/exiv2_tools/exiv2-utils.cpp
index 4254ea2..70a1533 100644
--- a/extensions/exiv2_tools/exiv2-utils.cpp
+++ b/extensions/exiv2_tools/exiv2-utils.cpp
@@ -39,7 +39,7 @@
 using namespace std;
 
 
-#define INVALID_VALUE "---"
+#define INVALID_VALUE N_("(invalid value)")
 
 
 /* Some bits of information may be contained in more than one metadata tag.
@@ -451,6 +451,8 @@ set_attribute_from_metadata (GFileInfo  *info,
        char *formatted_value;
        char *raw_value;
        char *type_name;
+       char *formatted_value_utf8;
+       char *raw_value_utf8;
 
        if (metadata == NULL)
                return;
@@ -462,14 +464,19 @@ set_attribute_from_metadata (GFileInfo  *info,
                      "value-type", &type_name,
                      NULL);
 
+       formatted_value_utf8 = _g_utf8_try_from_any (formatted_value);
+       raw_value_utf8 = _g_utf8_try_from_any (raw_value);
+
        set_file_info (info,
                       attribute,
                       description,
-                      formatted_value,
-                      raw_value,
+                      formatted_value_utf8,
+                      raw_value_utf8,
                       NULL,
                       type_name);
 
+       g_free (raw_value_utf8);
+       g_free (formatted_value_utf8);
        g_free (description);
        g_free (formatted_value);
        g_free (raw_value);
@@ -528,11 +535,16 @@ set_string_list_attribute_from_tagset (GFileInfo  *info,
 
        if (GTH_IS_METADATA (metadata) && (gth_metadata_get_data_type (GTH_METADATA (metadata)) != 
GTH_METADATA_TYPE_STRING_LIST)) {
                char           *raw;
+               char           *utf8_raw;
                char          **keywords;
                GthStringList  *string_list;
 
                g_object_get (metadata, "raw", &raw, NULL);
-               keywords = g_strsplit (raw, ",", -1);
+               utf8_raw = _g_utf8_try_from_any (raw);
+               if (utf8_raw == NULL)
+                       return;
+
+               keywords = g_strsplit (utf8_raw, ",", -1);
                string_list = gth_string_list_new_from_strv (keywords);
                metadata = (GObject *) gth_metadata_new_for_string_list (string_list);
                g_file_info_set_attribute_object (info, attribute, metadata);
@@ -541,6 +553,7 @@ set_string_list_attribute_from_tagset (GFileInfo  *info,
                g_object_unref (string_list);
                g_strfreev (keywords);
                g_free (raw);
+               g_free (utf8_raw);
        }
        else
                g_file_info_set_attribute_object (info, attribute, metadata);
diff --git a/gthumb/dom.c b/gthumb/dom.c
index a0b0c5a..4adb11b 100644
--- a/gthumb/dom.c
+++ b/gthumb/dom.c
@@ -71,7 +71,22 @@ _g_xml_attribute_quote (char *value)
 
        g_return_val_if_fail (value != NULL, NULL);
 
-       escaped = g_markup_escape_text (value, -1);
+       if (! g_utf8_validate (value, -1, NULL)) {
+               char *temp;
+
+               temp = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
+               if (temp == NULL)
+                       temp = g_utf16_to_utf8 ((gunichar2 *) value, -1, NULL, NULL, NULL);
+
+               if (temp != NULL) {
+                       escaped = g_markup_escape_text (temp, -1);
+                       g_free (temp);
+               }
+               else
+                       escaped = g_strdup (value);
+       }
+       else
+               escaped = g_markup_escape_text (value, -1);
 
        dest = g_string_new ("\"");
        for (p = escaped; (*p); p++) {
@@ -700,12 +715,20 @@ dom_domizable_load_from_element (DomDomizable *self,
 
 
 /* GMarkupParser converts \r into \n, this function compares two strings
- * treating \r characters as they were equal to \n */
+ * treating \r characters as they were equal to \n.  Furthermore treats invalid
+ * utf8 strings as null values. */
 gboolean
 dom_str_equal (const char *a,
               const char *b)
 {
        const char *ai, *bi;
+       gboolean    a_valid, b_valid;
+
+       if ((a != NULL) && ! g_utf8_validate (a, -1, NULL))
+               a = NULL;
+
+       if ((b != NULL) && ! g_utf8_validate (b, -1, NULL))
+               b = NULL;
 
        if ((a == NULL) && (b == NULL))
                return TRUE;
@@ -713,6 +736,9 @@ dom_str_equal (const char *a,
        if ((a == NULL) || (b == NULL))
                return FALSE;
 
+       if (g_utf8_collate (a, b) == 0)
+               return TRUE;
+
        ai = a;
        bi = b;
        while ((*ai != '\0') && (*bi != '\0')) {
@@ -728,12 +754,12 @@ dom_str_equal (const char *a,
                        /* \r\n equal to \n */
 
                        if ((*ai == '\r') && (*(ai + 1) == '\n') && (*bi == '\n') && (*(bi + 1) != '\n'))
-                               ai++;
+                               ai = g_utf8_next_char (ai);
                        if ((*bi == '\r') && (*(bi + 1) == '\n') && (*ai == '\n') && (*(ai + 1) != '\n'))
-                               ai++;
+                               ai = g_utf8_next_char (ai);
                }
-               ai++;
-               bi++;
+               ai = g_utf8_next_char (ai);
+               bi = g_utf8_next_char (bi);
        }
 
        /* 'end of string' equal to \n and to \r\n */
@@ -744,3 +770,11 @@ dom_str_equal (const char *a,
                || ((*ai == '\0') && (*bi == '\r') && (*(bi + 1) == '\n') && (*(bi + 2) == '\0'))
                || ((*bi == '\0') && (*ai == '\r') && (*(ai + 1) == '\n') && (*(ai + 2) == '\0')));
 }
+
+
+int
+dom_str_find (const char *a,
+              const char *b)
+{
+       return dom_str_equal (a, b) ? 0 : -1;
+}
diff --git a/gthumb/dom.h b/gthumb/dom.h
index ebc7c50..69d33ef 100644
--- a/gthumb/dom.h
+++ b/gthumb/dom.h
@@ -187,6 +187,8 @@ void          dom_domizable_load_from_element       (DomDomizable  *self,
 
 gboolean      dom_str_equal                         (const char    *a,
                                                     const char    *b);
+int           dom_str_find                         (const char    *a,
+                                                    const char    *b);
 
 G_END_DECLS
 
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index 897413f..0225dcd 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -1029,6 +1029,42 @@ _g_utf8_remove_extension (const char *str)
 }
 
 
+char *
+_g_utf8_try_from_any (const char *str)
+{
+       char *utf8_str;
+
+       if (str == NULL)
+               return NULL;
+
+       if (! g_utf8_validate (str, -1, NULL)) {
+               utf8_str = g_locale_to_utf8 (str, -1, NULL, NULL, NULL);
+               if (utf8_str == NULL)
+                       utf8_str = g_utf16_to_utf8 ((gunichar2 *) str, -1, NULL, NULL, NULL);
+       }
+       else
+               utf8_str = g_strdup (str);
+
+       return utf8_str;
+}
+
+
+char *
+_g_utf8_from_any (const char *str)
+{
+       char *utf8_str;
+
+       if (str == NULL)
+               return NULL;
+
+       utf8_str = _g_utf8_try_from_any (str);
+       if (utf8_str == NULL)
+               utf8_str = g_strdup (_("(invalid value)"));
+
+       return utf8_str;
+}
+
+
 static int
 remove_from_file_list_and_get_position (GList **file_list,
                                        GFile  *file)
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index 3c3ee61..a7eb2d3 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -191,6 +191,8 @@ char **         _g_utf8_strsplit                 (const char  *string,
 char *          _g_utf8_strstrip                 (const char  *str);
 gboolean        _g_utf8_all_spaces               (const char  *utf8_string);
 char *          _g_utf8_remove_extension         (const char  *str);
+char *          _g_utf8_try_from_any             (const char  *str);
+char *          _g_utf8_from_any                 (const char  *str);
 GList *         _g_list_insert_list_before       (GList       *list1,
                                                  GList       *sibling,
                                                  GList       *list2);
diff --git a/gthumb/gth-file-data.c b/gthumb/gth-file-data.c
index ebc4228..de447ae 100644
--- a/gthumb/gth-file-data.c
+++ b/gthumb/gth-file-data.c
@@ -526,8 +526,9 @@ char *
 gth_file_data_get_attribute_as_string (GthFileData *file_data,
                                       const char  *id)
 {
-       char    *value = NULL;
        GObject *obj;
+       char    *value = NULL;
+       char    *utf8_value;
 
        switch (g_file_info_get_attribute_type (file_data->info, id)) {
        case G_FILE_ATTRIBUTE_TYPE_OBJECT:
diff --git a/gthumb/gth-file-properties.c b/gthumb/gth-file-properties.c
index 496dcff..cf70853 100644
--- a/gthumb/gth-file-properties.c
+++ b/gthumb/gth-file-properties.c
@@ -171,13 +171,17 @@ gth_file_properties_real_set_file (GthPropertyView *base,
                }
 
                if (value != NULL) {
+                       char *utf8_value;
                        char *tmp_value;
 
-                       if (g_utf8_strlen (value, -1) > MAX_ATTRIBUTE_LENGTH)
-                               g_utf8_strncpy (g_utf8_offset_to_pointer (value, MAX_ATTRIBUTE_LENGTH - 1), 
"…", 1);
-                       tmp_value = _g_utf8_replace (value, "[\r\n]", " ");
+                       utf8_value = _g_utf8_from_any (value);
+                       if (g_utf8_strlen (utf8_value, -1) > MAX_ATTRIBUTE_LENGTH)
+                               g_utf8_strncpy (g_utf8_offset_to_pointer (utf8_value, MAX_ATTRIBUTE_LENGTH - 
1), "…", 1);
+                       tmp_value = _g_utf8_replace (utf8_value, "[\r\n]", " ");
                        g_free (value);
                        value = tmp_value;
+
+                       g_free (utf8_value);
                }
                tooltip = g_markup_printf_escaped ("%s: %s", _(info->display_name), value);
 
diff --git a/gthumb/gth-string-list.c b/gthumb/gth-string-list.c
index 8c01062..ab1cb8d 100644
--- a/gthumb/gth-string-list.c
+++ b/gthumb/gth-string-list.c
@@ -149,6 +149,15 @@ gboolean
 gth_string_list_equal (GthStringList  *list1,
                       GthStringList  *list2)
 {
+       return gth_string_list_equal_custom (list1, list2, (GCompareFunc) strcmp);
+}
+
+
+gboolean
+gth_string_list_equal_custom (GthStringList  *list1,
+                             GthStringList  *list2,
+                             GCompareFunc    compare_func)
+{
        GList *keys1;
        GList *keys2;
        GList *scan;
@@ -165,7 +174,7 @@ gth_string_list_equal (GthStringList  *list1,
                return FALSE;
 
        for (scan = keys1; scan; scan = scan->next)
-               if (! g_list_find_custom (keys2, scan->data, (GCompareFunc) strcmp))
+               if (! g_list_find_custom (keys2, scan->data, compare_func))
                        return FALSE;
 
        return TRUE;
diff --git a/gthumb/gth-string-list.h b/gthumb/gth-string-list.h
index cfb63f4..b9fd1f2 100644
--- a/gthumb/gth-string-list.h
+++ b/gthumb/gth-string-list.h
@@ -58,6 +58,9 @@ char *            gth_string_list_join                (GthStringList  *list,
                                                       const char     *separator);
 gboolean          gth_string_list_equal               (GthStringList  *list1,
                                                       GthStringList  *list2);
+gboolean         gth_string_list_equal_custom        (GthStringList  *list1,
+                                                      GthStringList  *list2,
+                                                      GCompareFunc    compare_func);
 void              gth_string_list_append              (GthStringList  *list1,
                                                       GthStringList  *list2);
 void              gth_string_list_concat              (GthStringList  *list1,


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