<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -41,8 +41,9 @@ struct GiggleDiffViewPriv {
 	GtkTextMark *search_mark;
 	gchar       *search_term;
 
-	int	     current_hunk;
+	int          current_hunk;
 	GArray      *files, *hunks;
+	GtkTextTag  *invalid_char;
 
 	/* last run job */
 	GiggleJob   *job;
@@ -56,6 +57,7 @@ struct GiggleDiffViewFile {
 struct GiggleDiffViewHunk {
 	unsigned     file;
 	char        *text;
+	GArray      *errors;
 };
 
 static void       giggle_diff_view_searchable_init (GiggleSearchableIface *iface);
@@ -90,7 +92,8 @@ diff_view_get_hunk (GiggleDiffViewPriv *priv,
 static void
 diff_view_reset_hunks (GiggleDiffViewPriv *priv)
 {
-	unsigned i;
+	GiggleDiffViewHunk *hunk;
+	unsigned            i;
 
 	for (i = 0; i &lt; priv-&gt;files-&gt;len; ++i) {
 		g_free (diff_view_get_file (priv, i)-&gt;filename);
@@ -98,7 +101,12 @@ diff_view_reset_hunks (GiggleDiffViewPriv *priv)
 	}
 
 	for (i = 0; i &lt; priv-&gt;hunks-&gt;len; ++i) {
-		g_free (diff_view_get_hunk (priv, i)-&gt;text);
+		hunk = diff_view_get_hunk (priv, i);
+
+		if (hunk-&gt;errors)
+			g_array_free (hunk-&gt;errors, TRUE);
+
+		g_free (hunk-&gt;text);
 	}
 
 	g_array_set_size (priv-&gt;files, 0);
@@ -160,10 +168,59 @@ diff_view_get_property (GObject    *object,
 }
 
 static void
+diff_view_insert_text (GiggleDiffView *view,
+		       GtkTextIter    *iter,
+		       const char     *text,
+		       gssize          len)
+{
+	GiggleDiffViewPriv *priv = GET_PRIV (view);
+	GtkTextBuffer      *buffer;
+	const char         *end;
+	char               *hex;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+
+	if (len &lt; 0)
+		len = strlen (text);
+
+	while (!g_utf8_validate (text, len, &amp;end)) {
+		/* FIXME: try to create some combined character */
+		hex = g_strdup_printf (&quot;&lt;%02x&gt;&quot;, ((int) *end) &amp; 255);
+
+		gtk_text_buffer_insert (buffer, iter, text, end - text);
+		gtk_text_buffer_insert_with_tags (buffer, iter, hex, -1,
+						  priv-&gt;invalid_char, NULL);
+
+		len -= (end - text + 1);
+		text = (end + 1);
+
+		g_free (hex);
+	}
+
+	gtk_text_buffer_insert (buffer, iter, text, len);
+}
+
+static void
+diff_view_set_text (GiggleDiffView *view,
+		    const char     *text,
+		    gssize          len)
+{
+	GtkTextIter    start, end;
+	GtkTextBuffer *buffer;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
+	gtk_text_buffer_get_bounds (buffer, &amp;start, &amp;end);
+	gtk_text_buffer_delete (buffer, &amp;start, &amp;end);
+
+	diff_view_insert_text (view, &amp;start, text, len);
+}
+
+static void
 diff_view_set_current_hunk (GiggleDiffView *view,
 			    int             hunk_index)
 {
 	GiggleDiffViewPriv *priv = GET_PRIV (view);
+	int                 hunk_offset, i;
 	GiggleDiffViewHunk *hunk = NULL;
 	GiggleDiffViewFile *file = NULL;
 	GtkTextBuffer      *buffer;
@@ -184,10 +241,24 @@ diff_view_set_current_hunk (GiggleDiffView *view,
 
 	if (file) {
 		gtk_text_buffer_get_end_iter (buffer, &amp;iter);
-		gtk_text_buffer_insert (buffer, &amp;iter, file-&gt;header, -1);
+		diff_view_insert_text (view, &amp;iter, file-&gt;header, -1);
 
-		gtk_text_buffer_get_end_iter (buffer, &amp;iter);
-		gtk_text_buffer_insert (buffer, &amp;iter, hunk-&gt;text, -1);
+		hunk_offset = gtk_text_iter_get_offset (&amp;iter);
+		diff_view_insert_text (view, &amp;iter, hunk-&gt;text, -1);
+
+		if (hunk-&gt;errors) {
+			for (i = 0; i &lt; hunk-&gt;errors-&gt;len; i += 2) {
+				int first = g_array_index (hunk-&gt;errors, int, i);
+				int last = g_array_index (hunk-&gt;errors, int, i + 1);
+
+				GtkTextIter start = iter, end = iter;
+
+				gtk_text_iter_set_offset (&amp;start, first + hunk_offset);
+				gtk_text_iter_set_offset (&amp;end, last + hunk_offset);
+
+				gtk_text_buffer_apply_tag (buffer, priv-&gt;invalid_char, &amp;start, &amp;end);
+			}
+		}
 	}
 }
 
@@ -210,14 +281,38 @@ diff_view_set_property (GObject      *object,
 }
 
 static void
+diff_view_style_set (GtkWidget *widget,
+		     GtkStyle  *prev)
+{
+	GiggleDiffViewPriv *priv = GET_PRIV (widget);
+	static const GdkColor red = { 0, 0xffff, 0, 0 };
+	GdkColor *error_color;
+
+	GTK_WIDGET_CLASS (giggle_diff_view_parent_class)-&gt;style_set (widget, prev);
+	gtk_widget_style_get (widget, &quot;error-underline-color&quot;, &amp;error_color, NULL);
+
+	if (!error_color)
+		error_color = gdk_color_copy (&amp;red);
+
+	g_object_set (priv-&gt;invalid_char,
+		      &quot;foreground-gdk&quot;, &amp;widget-&gt;style-&gt;base[GTK_STATE_NORMAL],
+		      &quot;background-gdk&quot;, error_color, &quot;style&quot;, PANGO_STYLE_ITALIC, NULL);
+
+	gdk_color_free (error_color);
+}
+
+static void
 giggle_diff_view_class_init (GiggleDiffViewClass *class)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (class);
+	GObjectClass   *object_class = G_OBJECT_CLASS (class);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 
 	object_class-&gt;finalize     = diff_view_finalize;
 	object_class-&gt;set_property = diff_view_set_property;
 	object_class-&gt;get_property = diff_view_get_property;
 
+	widget_class-&gt;style_set    = diff_view_style_set;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_CURRENT_FILE,
@@ -354,6 +449,8 @@ giggle_diff_view_init (GiggleDiffView *diff_view)
 								 &quot;search-mark&quot;,
 								 &amp;iter, FALSE);
 
+		priv-&gt;invalid_char = gtk_text_buffer_create_tag (buffer, NULL, NULL);
+
 		g_object_unref (buffer);
 	}
 
@@ -369,6 +466,8 @@ diff_view_append_hunk (GiggleDiffViewPriv  *priv,
 		       GtkTextIter         *end)
 {
 	GiggleDiffViewHunk *hunk;
+	GtkTextIter         iter;
+	int                 first, last;
 
 	if (gtk_text_iter_compare (start, end) &lt; 0) {
 		g_array_set_size (priv-&gt;hunks, priv-&gt;hunks-&gt;len + 1);
@@ -376,6 +475,30 @@ diff_view_append_hunk (GiggleDiffViewPriv  *priv,
 		hunk = diff_view_get_hunk (priv, priv-&gt;hunks-&gt;len - 1);
 		hunk-&gt;text = gtk_text_buffer_get_text (buffer, start, end, FALSE);
 		hunk-&gt;file = priv-&gt;files-&gt;len - 1;
+
+		iter = *start;
+
+		if (gtk_text_iter_has_tag (&amp;iter, priv-&gt;invalid_char) ||
+		    gtk_text_iter_forward_to_tag_toggle (&amp;iter, priv-&gt;invalid_char)) {
+			hunk-&gt;errors = g_array_new (FALSE, FALSE, sizeof first);
+
+			while (gtk_text_iter_compare (&amp;iter, end) &lt; 0) {
+				first = gtk_text_iter_get_offset (&amp;iter)
+				      - gtk_text_iter_get_offset (start);
+
+				if (!gtk_text_iter_forward_to_tag_toggle (&amp;iter, priv-&gt;invalid_char))
+					break;
+
+				last = gtk_text_iter_get_offset (&amp;iter)
+				     - gtk_text_iter_get_offset (start);
+
+				g_array_append_val (hunk-&gt;errors, first);
+				g_array_append_val (hunk-&gt;errors, last);
+
+				if (!gtk_text_iter_forward_to_tag_toggle (&amp;iter, priv-&gt;invalid_char))
+					break;
+			}
+		}
 	}
 }
 
@@ -483,11 +606,7 @@ diff_view_job_callback (GiggleGit *git,
 		gtk_dialog_run (GTK_DIALOG (dialog));
 		gtk_widget_destroy (dialog);
 	} else {
-		gtk_text_buffer_set_text (
-			gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)),
-			giggle_git_diff_get_result (GIGGLE_GIT_DIFF (job)),
-			-1);
-
+		diff_view_set_text (view, giggle_git_diff_get_result (GIGGLE_GIT_DIFF (job)), -1);
 		diff_view_parse_patch (view);
 
 		if (priv-&gt;search_term) {</diff>
      <filename>src/giggle-diff-view.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>790f54ed3705b70869f91da7fe3ad120f5bbcb42</id>
    </parent>
  </parents>
  <author>
    <name>Mathias Hasselmann</name>
    <email>hasselmm@gnome.org</email>
  </author>
  <url>http://github.com/hasselmm/giggle/commit/3ecc564aff10d86c0224a0e2618af03ae9f991e7</url>
  <id>3ecc564aff10d86c0224a0e2618af03ae9f991e7</id>
  <committed-date>2009-03-03T16:10:44-08:00</committed-date>
  <authored-date>2009-03-03T16:10:44-08:00</authored-date>
  <message>Detect invalid characters in diff view; Fixes: GB#573382

Signed-off-by: Mathias Hasselmann &lt;hasselmm@gnome.org&gt;</message>
  <tree>3519b70ef1079ba7c1ae53c69642684bb9a48f9c</tree>
  <committer>
    <name>Mathias Hasselmann</name>
    <email>hasselmm@gnome.org</email>
  </committer>
</commit>
