Blame gtk/gtktextbufferserialize.c

Packit Service fb6fa5
/* gtktextbufferserialize.c
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * Copyright (C) 2001 Havoc Pennington
Packit Service fb6fa5
 * Copyright (C) 2004 Nokia Corporation
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is free software; you can redistribute it and/or
Packit Service fb6fa5
 * modify it under the terms of the GNU Library General Public
Packit Service fb6fa5
 * License as published by the Free Software Foundation; either
Packit Service fb6fa5
 * version 2 of the License, or (at your option) any later version.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This library is distributed in the hope that it will be useful,
Packit Service fb6fa5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service fb6fa5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service fb6fa5
 * Library General Public License for more details.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * You should have received a copy of the GNU Library General Public
Packit Service fb6fa5
 * License along with this library; if not, write to the
Packit Service fb6fa5
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit Service fb6fa5
 * Boston, MA 02111-1307, USA.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
/* FIXME: We should use other error codes for the
Packit Service fb6fa5
 * parts that deal with the format errors
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#include "config.h"
Packit Service fb6fa5
Packit Service fb6fa5
#include <stdio.h>
Packit Service fb6fa5
#include <string.h>
Packit Service fb6fa5
#include <stdlib.h>
Packit Service fb6fa5
Packit Service fb6fa5
#undef GDK_PIXBUF_DISABLE_DEPRECATED
Packit Service fb6fa5
#include "gdk-pixbuf/gdk-pixdata.h"
Packit Service fb6fa5
#include "gtktextbufferserialize.h"
Packit Service fb6fa5
#include "gtkintl.h"
Packit Service fb6fa5
#include "gtkalias.h"
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct
Packit Service fb6fa5
{
Packit Service fb6fa5
  GString *tag_table_str;
Packit Service fb6fa5
  GString *text_str;
Packit Service fb6fa5
  GHashTable *tags;
Packit Service fb6fa5
  GtkTextIter start, end;
Packit Service fb6fa5
Packit Service fb6fa5
  gint n_pixbufs;
Packit Service fb6fa5
  GList *pixbufs;
Packit Service fb6fa5
  gint tag_id;
Packit Service fb6fa5
  GHashTable *tag_id_tags;
Packit Service fb6fa5
} SerializationContext;
Packit Service fb6fa5
Packit Service fb6fa5
static gchar *
Packit Service fb6fa5
serialize_value (GValue *value)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (g_value_type_transformable (value->g_type, G_TYPE_STRING))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GValue text_value = { 0 };
Packit Service fb6fa5
      gchar *tmp;
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_init (&text_value, G_TYPE_STRING);
Packit Service fb6fa5
      g_value_transform (value, &text_value);
Packit Service fb6fa5
Packit Service fb6fa5
      tmp = g_markup_escape_text (g_value_get_string (&text_value), -1);
Packit Service fb6fa5
      g_value_unset (&text_value);
Packit Service fb6fa5
Packit Service fb6fa5
      return tmp;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (value->g_type == GDK_TYPE_COLOR)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GdkColor *color = g_value_get_boxed (value);
Packit Service fb6fa5
Packit Service fb6fa5
      return g_strdup_printf ("%x:%x:%x", color->red, color->green, color->blue);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (g_type_is_a (value->g_type, GDK_TYPE_DRAWABLE))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* Don't do anything */
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning ("Type %s is not serializable\n", g_type_name (value->g_type));
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return NULL;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
deserialize_value (const gchar *str,
Packit Service fb6fa5
                   GValue      *value)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (g_value_type_transformable (G_TYPE_STRING, value->g_type))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GValue text_value = { 0 };
Packit Service fb6fa5
      gboolean retval;
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_init (&text_value, G_TYPE_STRING);
Packit Service fb6fa5
      g_value_set_static_string (&text_value, str);
Packit Service fb6fa5
Packit Service fb6fa5
      retval = g_value_transform (&text_value, value);
Packit Service fb6fa5
      g_value_unset (&text_value);
Packit Service fb6fa5
Packit Service fb6fa5
      return retval;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (value->g_type == G_TYPE_BOOLEAN)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean v;
Packit Service fb6fa5
Packit Service fb6fa5
      v = strcmp (str, "TRUE") == 0;
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_set_boolean (value, v);
Packit Service fb6fa5
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (value->g_type == G_TYPE_INT)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gchar *tmp;
Packit Service fb6fa5
      int v;
Packit Service fb6fa5
Packit Service fb6fa5
      v = strtol (str, &tmp, 10);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tmp == NULL || tmp == str)
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_set_int (value, v);
Packit Service fb6fa5
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (value->g_type == G_TYPE_DOUBLE)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gchar *tmp;
Packit Service fb6fa5
      gdouble v;
Packit Service fb6fa5
Packit Service fb6fa5
      v = g_ascii_strtod (str, &tmp);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tmp == NULL || tmp == str)
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_set_double (value, v);
Packit Service fb6fa5
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (value->g_type == GDK_TYPE_COLOR)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GdkColor color;
Packit Service fb6fa5
      const gchar *old;
Packit Service fb6fa5
      gchar *tmp;
Packit Service fb6fa5
Packit Service fb6fa5
      old = str;
Packit Service fb6fa5
      color.red = strtol (old, &tmp, 16);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tmp == NULL || tmp == old)
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      old = tmp;
Packit Service fb6fa5
      if (*old++ != ':')
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      color.green = strtol (old, &tmp, 16);
Packit Service fb6fa5
      if (tmp == NULL || tmp == old)
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      old = tmp;
Packit Service fb6fa5
      if (*old++ != ':')
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      color.blue = strtol (old, &tmp, 16);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tmp == NULL || tmp == old || *tmp != '\0')
Packit Service fb6fa5
	return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_set_boxed (value, &color;;
Packit Service fb6fa5
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (G_VALUE_HOLDS_ENUM (value))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GEnumClass *class = G_ENUM_CLASS (g_type_class_peek (value->g_type));
Packit Service fb6fa5
      GEnumValue *enum_value;
Packit Service fb6fa5
Packit Service fb6fa5
      enum_value = g_enum_get_value_by_name (class, str);
Packit Service fb6fa5
Packit Service fb6fa5
      if (enum_value)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_value_set_enum (value, enum_value->value);
Packit Service fb6fa5
	  return TRUE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_warning ("Type %s can not be deserialized\n", g_type_name (value->g_type));
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return FALSE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
/* Checks if a param is set, or if it's the default value */
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
is_param_set (GObject    *object,
Packit Service fb6fa5
              GParamSpec *pspec,
Packit Service fb6fa5
              GValue     *value)
Packit Service fb6fa5
{
Packit Service fb6fa5
  /* We need to special case some attributes here */
Packit Service fb6fa5
  if (strcmp (pspec->name, "background-gdk") == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean is_set;
Packit Service fb6fa5
Packit Service fb6fa5
      g_object_get (object, "background-set", &is_set, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
      if (is_set)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
Packit Service fb6fa5
Packit Service fb6fa5
	  g_object_get_property (object, pspec->name, value);
Packit Service fb6fa5
Packit Service fb6fa5
	  return TRUE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (strcmp (pspec->name, "foreground-gdk") == 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean is_set;
Packit Service fb6fa5
Packit Service fb6fa5
      g_object_get (object, "foreground-set", &is_set, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
      if (is_set)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
Packit Service fb6fa5
Packit Service fb6fa5
	  g_object_get_property (object, pspec->name, value);
Packit Service fb6fa5
Packit Service fb6fa5
	  return TRUE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gboolean is_set;
Packit Service fb6fa5
      gchar *is_set_name;
Packit Service fb6fa5
Packit Service fb6fa5
      is_set_name = g_strdup_printf ("%s-set", pspec->name);
Packit Service fb6fa5
Packit Service fb6fa5
      if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), is_set_name) == NULL)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_free (is_set_name);
Packit Service fb6fa5
	  return FALSE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_object_get (object, is_set_name, &is_set, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!is_set)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      g_free (is_set_name);
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  g_free (is_set_name);
Packit Service fb6fa5
Packit Service fb6fa5
	  g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
Packit Service fb6fa5
Packit Service fb6fa5
	  g_object_get_property (object, pspec->name, value);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (g_param_value_defaults (pspec, value))
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      g_value_unset (value);
Packit Service fb6fa5
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	}
Packit Service fb6fa5
      return TRUE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
serialize_tag (gpointer key,
Packit Service fb6fa5
               gpointer data,
Packit Service fb6fa5
               gpointer user_data)
Packit Service fb6fa5
{
Packit Service fb6fa5
  SerializationContext *context = user_data;
Packit Service fb6fa5
  GtkTextTag *tag = data;
Packit Service fb6fa5
  gchar *tag_name;
Packit Service fb6fa5
  gint tag_id;
Packit Service fb6fa5
  GParamSpec **pspecs;
Packit Service fb6fa5
  guint n_pspecs;
Packit Service fb6fa5
  int i;
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append (context->tag_table_str, "  
Packit Service fb6fa5
Packit Service fb6fa5
  /* Handle anonymous tags */
Packit Service fb6fa5
  if (tag->name)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      tag_name = g_markup_escape_text (tag->name, -1);
Packit Service fb6fa5
      g_string_append_printf (context->tag_table_str, "name=\"%s\"", tag_name);
Packit Service fb6fa5
      g_free (tag_name);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      tag_id = GPOINTER_TO_INT (g_hash_table_lookup (context->tag_id_tags, tag));
Packit Service fb6fa5
Packit Service fb6fa5
      g_string_append_printf (context->tag_table_str, "id=\"%d\"", tag_id);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append_printf (context->tag_table_str, " priority=\"%d\">\n", tag->priority);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Serialize properties */
Packit Service fb6fa5
  pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (tag), &n_pspecs);
Packit Service fb6fa5
Packit Service fb6fa5
  for (i = 0; i < n_pspecs; i++)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GValue value = { 0 };
Packit Service fb6fa5
      gchar *tmp, *tmp2;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!(pspecs[i]->flags & G_PARAM_READABLE) ||
Packit Service fb6fa5
	  !(pspecs[i]->flags & G_PARAM_WRITABLE))
Packit Service fb6fa5
	continue;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!is_param_set (G_OBJECT (tag), pspecs[i], &value))
Packit Service fb6fa5
	continue;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Now serialize the attr */
Packit Service fb6fa5
      tmp2 = serialize_value (&value);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tmp2)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  tmp = g_markup_escape_text (pspecs[i]->name, -1);
Packit Service fb6fa5
	  g_string_append_printf (context->tag_table_str, "   
Packit Service fb6fa5
	  g_free (tmp);
Packit Service fb6fa5
Packit Service fb6fa5
	  tmp = g_markup_escape_text (g_type_name (pspecs[i]->value_type), -1);
Packit Service fb6fa5
	  g_string_append_printf (context->tag_table_str, "type=\"%s\" value=\"%s\" />\n", tmp, tmp2);
Packit Service fb6fa5
Packit Service fb6fa5
	  g_free (tmp);
Packit Service fb6fa5
	  g_free (tmp2);
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_unset (&value);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_free (pspecs);
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append (context->tag_table_str, "  </tag>\n");
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
serialize_tags (SerializationContext *context)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_string_append (context->tag_table_str, " <text_view_markup>\n");
Packit Service fb6fa5
  g_string_append (context->tag_table_str, " <tags>\n");
Packit Service fb6fa5
  g_hash_table_foreach (context->tags, serialize_tag, context);
Packit Service fb6fa5
  g_string_append (context->tag_table_str, " </tags>\n");
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
#if 0
Packit Service fb6fa5
static void
Packit Service fb6fa5
dump_tag_list (const gchar *str,
Packit Service fb6fa5
               GList       *list)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_print ("%s: ", str);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!list)
Packit Service fb6fa5
    g_print ("(empty)");
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      while (list)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_print ("%s ", ((GtkTextTag *)list->data)->name);
Packit Service fb6fa5
	  list = list->next;
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  g_print ("\n");
Packit Service fb6fa5
}
Packit Service fb6fa5
#endif
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
find_list_delta (GSList  *old_list,
Packit Service fb6fa5
                 GSList  *new_list,
Packit Service fb6fa5
		 GList  **added,
Packit Service fb6fa5
                 GList  **removed)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GSList *tmp;
Packit Service fb6fa5
  GList *tmp_added, *tmp_removed;
Packit Service fb6fa5
Packit Service fb6fa5
  tmp_added = NULL;
Packit Service fb6fa5
  tmp_removed = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Find added tags */
Packit Service fb6fa5
  tmp = new_list;
Packit Service fb6fa5
  while (tmp)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!g_slist_find (old_list, tmp->data))
Packit Service fb6fa5
	tmp_added = g_list_prepend (tmp_added, tmp->data);
Packit Service fb6fa5
Packit Service fb6fa5
      tmp = tmp->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  *added = tmp_added;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Find removed tags */
Packit Service fb6fa5
  tmp = old_list;
Packit Service fb6fa5
  while (tmp)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!g_slist_find (new_list, tmp->data))
Packit Service fb6fa5
	tmp_removed = g_list_prepend (tmp_removed, tmp->data);
Packit Service fb6fa5
Packit Service fb6fa5
      tmp = tmp->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* We reverse the list here to match the xml semantics */
Packit Service fb6fa5
  *removed = g_list_reverse (tmp_removed);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
serialize_section_header (GString     *str,
Packit Service fb6fa5
			  const gchar *name,
Packit Service fb6fa5
			  gint         length)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_if_fail (strlen (name) == 26);
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append (str, name);
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append_c (str, length >> 24);
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append_c (str, (length >> 16) & 0xff);
Packit Service fb6fa5
  g_string_append_c (str, (length >> 8) & 0xff);
Packit Service fb6fa5
  g_string_append_c (str, length & 0xff);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
serialize_text (GtkTextBuffer        *buffer,
Packit Service fb6fa5
                SerializationContext *context)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextIter iter, old_iter;
Packit Service fb6fa5
  GSList *tag_list, *new_tag_list;
Packit Service fb6fa5
  GSList *active_tags;
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append (context->text_str, "<text>");
Packit Service fb6fa5
Packit Service fb6fa5
  iter = context->start;
Packit Service fb6fa5
  tag_list = NULL;
Packit Service fb6fa5
  active_tags = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  do
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GList *added, *removed;
Packit Service fb6fa5
      GList *tmp;
Packit Service fb6fa5
      gchar *tmp_text, *escaped_text;
Packit Service fb6fa5
Packit Service fb6fa5
      new_tag_list = gtk_text_iter_get_tags (&iter);
Packit Service fb6fa5
      find_list_delta (tag_list, new_tag_list, &added, &removed);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Handle removed tags */
Packit Service fb6fa5
      for (tmp = removed; tmp; tmp = tmp->next)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  GtkTextTag *tag = tmp->data;
Packit Service fb6fa5
Packit Service fb6fa5
          /* Only close the tag if we didn't close it before (by using
Packit Service fb6fa5
           * the stack logic in the while() loop below)
Packit Service fb6fa5
           */
Packit Service fb6fa5
          if (g_slist_find (active_tags, tag))
Packit Service fb6fa5
            {
Packit Service fb6fa5
              g_string_append (context->text_str, "</apply_tag>");
Packit Service fb6fa5
Packit Service fb6fa5
              /* Drop all tags that were opened after this one (which are
Packit Service fb6fa5
               * above this on in the stack)
Packit Service fb6fa5
               */
Packit Service fb6fa5
              while (active_tags->data != tag)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  added = g_list_prepend (added, active_tags->data);
Packit Service fb6fa5
                  active_tags = g_slist_remove (active_tags, active_tags->data);
Packit Service fb6fa5
                  g_string_append_printf (context->text_str, "</apply_tag>");
Packit Service fb6fa5
                }
Packit Service fb6fa5
Packit Service fb6fa5
              active_tags = g_slist_remove (active_tags, active_tags->data);
Packit Service fb6fa5
            }
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      /* Handle added tags */
Packit Service fb6fa5
      for (tmp = added; tmp; tmp = tmp->next)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  GtkTextTag *tag = tmp->data;
Packit Service fb6fa5
	  gchar *tag_name;
Packit Service fb6fa5
Packit Service fb6fa5
	  /* Add it to the tag hash table */
Packit Service fb6fa5
	  g_hash_table_insert (context->tags, tag, tag);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (tag->name)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      tag_name = g_markup_escape_text (tag->name, -1);
Packit Service fb6fa5
Packit Service fb6fa5
	      g_string_append_printf (context->text_str, "<apply_tag name=\"%s\">", tag_name);
Packit Service fb6fa5
	      g_free (tag_name);
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	  else
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      gpointer tag_id;
Packit Service fb6fa5
Packit Service fb6fa5
	      /* We've got an anonymous tag, find out if it's been
Packit Service fb6fa5
		 used before */
Packit Service fb6fa5
	      if (!g_hash_table_lookup_extended (context->tag_id_tags, tag, NULL, &tag_id))
Packit Service fb6fa5
		{
Packit Service fb6fa5
		  tag_id = GINT_TO_POINTER (context->tag_id++);
Packit Service fb6fa5
Packit Service fb6fa5
		  g_hash_table_insert (context->tag_id_tags, tag, tag_id);
Packit Service fb6fa5
		}
Packit Service fb6fa5
Packit Service fb6fa5
	      g_string_append_printf (context->text_str, "<apply_tag id=\"%d\">", GPOINTER_TO_INT (tag_id));
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  active_tags = g_slist_prepend (active_tags, tag);
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      g_slist_free (tag_list);
Packit Service fb6fa5
      tag_list = new_tag_list;
Packit Service fb6fa5
Packit Service fb6fa5
      g_list_free (added);
Packit Service fb6fa5
      g_list_free (removed);
Packit Service fb6fa5
Packit Service fb6fa5
      old_iter = iter;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Now try to go to either the next tag toggle, or if a pixbuf appears */
Packit Service fb6fa5
      while (TRUE)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  gunichar ch = gtk_text_iter_get_char (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (ch == 0xFFFC)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      GdkPixbuf *pixbuf = gtk_text_iter_get_pixbuf (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
	      if (pixbuf)
Packit Service fb6fa5
		{
Packit Service fb6fa5
		  /* Append the text before the pixbuf */
Packit Service fb6fa5
		  tmp_text = gtk_text_iter_get_slice (&old_iter, &iter);
Packit Service fb6fa5
		  escaped_text = g_markup_escape_text (tmp_text, -1);
Packit Service fb6fa5
		  g_free (tmp_text);
Packit Service fb6fa5
Packit Service fb6fa5
		  /* Forward so we don't get the 0xfffc char */
Packit Service fb6fa5
		  gtk_text_iter_forward_char (&iter);
Packit Service fb6fa5
		  old_iter = iter;
Packit Service fb6fa5
Packit Service fb6fa5
		  g_string_append (context->text_str, escaped_text);
Packit Service fb6fa5
		  g_free (escaped_text);
Packit Service fb6fa5
Packit Service fb6fa5
		  g_string_append_printf (context->text_str, "<pixbuf index=\"%d\" />", context->n_pixbufs);
Packit Service fb6fa5
Packit Service fb6fa5
		  context->n_pixbufs++;
Packit Service fb6fa5
		  context->pixbufs = g_list_prepend (context->pixbufs, pixbuf);
Packit Service fb6fa5
		}
Packit Service fb6fa5
	    }
Packit Service fb6fa5
          else if (ch == 0)
Packit Service fb6fa5
            {
Packit Service fb6fa5
                break;
Packit Service fb6fa5
            }
Packit Service fb6fa5
	  else
Packit Service fb6fa5
	    gtk_text_iter_forward_char (&iter);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (gtk_text_iter_toggles_tag (&iter, NULL))
Packit Service fb6fa5
	    break;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      /* We might have moved too far */
Packit Service fb6fa5
      if (gtk_text_iter_compare (&iter, &context->end) > 0)
Packit Service fb6fa5
	iter = context->end;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Append the text */
Packit Service fb6fa5
      tmp_text = gtk_text_iter_get_slice (&old_iter, &iter);
Packit Service fb6fa5
      escaped_text = g_markup_escape_text (tmp_text, -1);
Packit Service fb6fa5
      g_free (tmp_text);
Packit Service fb6fa5
Packit Service fb6fa5
      g_string_append (context->text_str, escaped_text);
Packit Service fb6fa5
      g_free (escaped_text);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  while (!gtk_text_iter_equal (&iter, &context->end));
Packit Service fb6fa5
Packit Service fb6fa5
  /* Close any open tags */
Packit Service fb6fa5
  for (tag_list = active_tags; tag_list; tag_list = tag_list->next)
Packit Service fb6fa5
    g_string_append (context->text_str, "</apply_tag>");
Packit Service fb6fa5
Packit Service fb6fa5
  g_slist_free (active_tags);
Packit Service fb6fa5
  g_string_append (context->text_str, "</text>\n</text_view_markup>\n");
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
serialize_pixbufs (SerializationContext *context,
Packit Service fb6fa5
		   GString              *text)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GList *list;
Packit Service fb6fa5
Packit Service fb6fa5
  for (list = context->pixbufs; list != NULL; list = list->next)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GdkPixbuf *pixbuf = list->data;
Packit Service fb6fa5
      GdkPixdata pixdata;
Packit Service fb6fa5
      guint8 *tmp;
Packit Service fb6fa5
      guint len;
Packit Service fb6fa5
Packit Service fb6fa5
      gdk_pixdata_from_pixbuf (&pixdata, pixbuf, FALSE);
Packit Service fb6fa5
      tmp = gdk_pixdata_serialize (&pixdata, &len;;
Packit Service fb6fa5
Packit Service fb6fa5
      serialize_section_header (text, "GTKTEXTBUFFERPIXBDATA-0001", len);
Packit Service fb6fa5
      g_string_append_len (text, (gchar *) tmp, len);
Packit Service fb6fa5
      g_free (tmp);
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
guint8 *
Packit Service fb6fa5
_gtk_text_buffer_serialize_rich_text (GtkTextBuffer     *register_buffer,
Packit Service fb6fa5
                                      GtkTextBuffer     *content_buffer,
Packit Service fb6fa5
                                      const GtkTextIter *start,
Packit Service fb6fa5
                                      const GtkTextIter *end,
Packit Service fb6fa5
                                      gsize             *length,
Packit Service fb6fa5
                                      gpointer           user_data)
Packit Service fb6fa5
{
Packit Service fb6fa5
  SerializationContext context;
Packit Service fb6fa5
  GString *text;
Packit Service fb6fa5
Packit Service fb6fa5
  context.tags = g_hash_table_new (NULL, NULL);
Packit Service fb6fa5
  context.text_str = g_string_new (NULL);
Packit Service fb6fa5
  context.tag_table_str = g_string_new (NULL);
Packit Service fb6fa5
  context.start = *start;
Packit Service fb6fa5
  context.end = *end;
Packit Service fb6fa5
  context.n_pixbufs = 0;
Packit Service fb6fa5
  context.pixbufs = NULL;
Packit Service fb6fa5
  context.tag_id = 0;
Packit Service fb6fa5
  context.tag_id_tags = g_hash_table_new (NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  /* We need to serialize the text before the tag table so we know
Packit Service fb6fa5
     what tags are used */
Packit Service fb6fa5
  serialize_text (content_buffer, &context);
Packit Service fb6fa5
  serialize_tags (&context);
Packit Service fb6fa5
Packit Service fb6fa5
  text = g_string_new (NULL);
Packit Service fb6fa5
  serialize_section_header (text, "GTKTEXTBUFFERCONTENTS-0001",
Packit Service fb6fa5
                            context.tag_table_str->len + context.text_str->len);
Packit Service fb6fa5
Packit Service fb6fa5
  g_string_append_len (text, context.tag_table_str->str, context.tag_table_str->len);
Packit Service fb6fa5
  g_string_append_len (text, context.text_str->str, context.text_str->len);
Packit Service fb6fa5
Packit Service fb6fa5
  context.pixbufs = g_list_reverse (context.pixbufs);
Packit Service fb6fa5
  serialize_pixbufs (&context, text);
Packit Service fb6fa5
Packit Service fb6fa5
  g_hash_table_destroy (context.tags);
Packit Service fb6fa5
  g_list_free (context.pixbufs);
Packit Service fb6fa5
  g_string_free (context.text_str, TRUE);
Packit Service fb6fa5
  g_string_free (context.tag_table_str, TRUE);
Packit Service fb6fa5
  g_hash_table_destroy (context.tag_id_tags);
Packit Service fb6fa5
Packit Service fb6fa5
  *length = text->len;
Packit Service fb6fa5
Packit Service fb6fa5
  return (guint8 *) g_string_free (text, FALSE);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
typedef enum
Packit Service fb6fa5
{
Packit Service fb6fa5
  STATE_START,
Packit Service fb6fa5
  STATE_TEXT_VIEW_MARKUP,
Packit Service fb6fa5
  STATE_TAGS,
Packit Service fb6fa5
  STATE_TAG,
Packit Service fb6fa5
  STATE_ATTR,
Packit Service fb6fa5
  STATE_TEXT,
Packit Service fb6fa5
  STATE_APPLY_TAG,
Packit Service fb6fa5
  STATE_PIXBUF
Packit Service fb6fa5
} ParseState;
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct
Packit Service fb6fa5
{
Packit Service fb6fa5
  gchar *text;
Packit Service fb6fa5
  GdkPixbuf *pixbuf;
Packit Service fb6fa5
  GSList *tags;
Packit Service fb6fa5
} TextSpan;
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextTag *tag;
Packit Service fb6fa5
  gint prio;
Packit Service fb6fa5
} TextTagPrio;
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct
Packit Service fb6fa5
{
Packit Service fb6fa5
  GSList *states;
Packit Service fb6fa5
Packit Service fb6fa5
  GList *headers;
Packit Service fb6fa5
Packit Service fb6fa5
  GtkTextBuffer *buffer;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Tags that are defined in <tag> elements */
Packit Service fb6fa5
  GHashTable *defined_tags;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Tags that are anonymous */
Packit Service fb6fa5
  GHashTable *anonymous_tags;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Tag name substitutions */
Packit Service fb6fa5
  GHashTable *substitutions;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Current tag */
Packit Service fb6fa5
  GtkTextTag *current_tag;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Priority of current tag */
Packit Service fb6fa5
  gint current_tag_prio;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Id of current tag */
Packit Service fb6fa5
  gint current_tag_id;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Tags and their priorities */
Packit Service fb6fa5
  GList *tag_priorities;
Packit Service fb6fa5
Packit Service fb6fa5
  GSList *tag_stack;
Packit Service fb6fa5
Packit Service fb6fa5
  GList *spans;
Packit Service fb6fa5
Packit Service fb6fa5
  gboolean create_tags;
Packit Service fb6fa5
Packit Service fb6fa5
  gboolean parsed_text;
Packit Service fb6fa5
  gboolean parsed_tags;
Packit Service fb6fa5
} ParseInfo;
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
set_error (GError              **err,
Packit Service fb6fa5
           GMarkupParseContext  *context,
Packit Service fb6fa5
           int                   error_domain,
Packit Service fb6fa5
           int                   error_code,
Packit Service fb6fa5
           const char           *format,
Packit Service fb6fa5
           ...)
Packit Service fb6fa5
{
Packit Service fb6fa5
  int line, ch;
Packit Service fb6fa5
  va_list args;
Packit Service fb6fa5
  char *str;
Packit Service fb6fa5
Packit Service fb6fa5
  g_markup_parse_context_get_position (context, &line, &ch);
Packit Service fb6fa5
Packit Service fb6fa5
  va_start (args, format);
Packit Service fb6fa5
  str = g_strdup_vprintf (format, args);
Packit Service fb6fa5
  va_end (args);
Packit Service fb6fa5
Packit Service fb6fa5
  g_set_error (err, error_domain, error_code,
Packit Service fb6fa5
               ("Line %d character %d: %s"),
Packit Service fb6fa5
               line, ch, str);
Packit Service fb6fa5
Packit Service fb6fa5
  g_free (str);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
push_state (ParseInfo  *info,
Packit Service fb6fa5
            ParseState  state)
Packit Service fb6fa5
{
Packit Service fb6fa5
  info->states = g_slist_prepend (info->states, GINT_TO_POINTER (state));
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
pop_state (ParseInfo *info)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_if_fail (info->states != NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  info->states = g_slist_remove (info->states, info->states->data);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static ParseState
Packit Service fb6fa5
peek_state (ParseInfo *info)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_return_val_if_fail (info->states != NULL, STATE_START);
Packit Service fb6fa5
Packit Service fb6fa5
  return GPOINTER_TO_INT (info->states->data);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
check_id_or_name (GMarkupParseContext  *context,
Packit Service fb6fa5
		  const gchar          *element_name,
Packit Service fb6fa5
		  const gchar         **attribute_names,
Packit Service fb6fa5
		  const gchar         **attribute_values,
Packit Service fb6fa5
		  gint                 *id,
Packit Service fb6fa5
		  const gchar         **name,
Packit Service fb6fa5
		  GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gboolean has_id = FALSE;
Packit Service fb6fa5
  gboolean has_name = FALSE;
Packit Service fb6fa5
  int i;
Packit Service fb6fa5
Packit Service fb6fa5
  *id = 0;
Packit Service fb6fa5
  *name = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  for (i = 0; attribute_names[i] != NULL; i++)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (strcmp (attribute_names[i], "name") == 0)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  *name = attribute_values[i];
Packit Service fb6fa5
Packit Service fb6fa5
	  if (has_id)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context,
Packit Service fb6fa5
			 G_MARKUP_ERROR,
Packit Service fb6fa5
			 G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("Both \"id\" and \"name\" were found on the <%s> element"),
Packit Service fb6fa5
			 element_name);
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  if (has_name)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context,
Packit Service fb6fa5
			 G_MARKUP_ERROR,
Packit Service fb6fa5
			 G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("The attribute \"%s\" was found twice on the <%s> element"),
Packit Service fb6fa5
			 "name", element_name);
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  has_name = TRUE;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else if (strcmp (attribute_names[i], "id") == 0)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  gchar *tmp;
Packit Service fb6fa5
Packit Service fb6fa5
	  if (has_name)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context,
Packit Service fb6fa5
			 G_MARKUP_ERROR,
Packit Service fb6fa5
			 G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("Both \"id\" and \"name\" were found on the <%s> element"),
Packit Service fb6fa5
			 element_name);
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  if (has_id)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context,
Packit Service fb6fa5
			 G_MARKUP_ERROR,
Packit Service fb6fa5
			 G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("The attribute \"%s\" was found twice on the <%s> element"),
Packit Service fb6fa5
			 "id", element_name);
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  has_id = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
	  /* Try parsing the integer */
Packit Service fb6fa5
	  *id = strtol (attribute_values[i], &tmp, 10);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (tmp == NULL || tmp == attribute_values[i])
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context,
Packit Service fb6fa5
			 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("<%s> element has invalid ID \"%s\""), attribute_values[i]);
Packit Service fb6fa5
	      return FALSE;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	}
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (!has_id && !has_name)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      set_error (error, context,
Packit Service fb6fa5
		 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		 _("<%s> element has neither a \"name\" nor an \"id\" attribute"), element_name);
Packit Service fb6fa5
      return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct
Packit Service fb6fa5
{
Packit Service fb6fa5
  const char  *name;
Packit Service fb6fa5
  const char **retloc;
Packit Service fb6fa5
} LocateAttr;
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
locate_attributes (GMarkupParseContext  *context,
Packit Service fb6fa5
                   const char           *element_name,
Packit Service fb6fa5
                   const char          **attribute_names,
Packit Service fb6fa5
                   const char          **attribute_values,
Packit Service fb6fa5
		   gboolean              allow_unknown_attrs,
Packit Service fb6fa5
                   GError              **error,
Packit Service fb6fa5
                   const char           *first_attribute_name,
Packit Service fb6fa5
                   const char          **first_attribute_retloc,
Packit Service fb6fa5
                   ...)
Packit Service fb6fa5
{
Packit Service fb6fa5
  va_list args;
Packit Service fb6fa5
  const char *name;
Packit Service fb6fa5
  const char **retloc;
Packit Service fb6fa5
  int n_attrs;
Packit Service fb6fa5
#define MAX_ATTRS 24
Packit Service fb6fa5
  LocateAttr attrs[MAX_ATTRS];
Packit Service fb6fa5
  gboolean retval;
Packit Service fb6fa5
  int i;
Packit Service fb6fa5
Packit Service fb6fa5
  g_return_val_if_fail (first_attribute_name != NULL, FALSE);
Packit Service fb6fa5
  g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
  retval = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
  n_attrs = 1;
Packit Service fb6fa5
  attrs[0].name = first_attribute_name;
Packit Service fb6fa5
  attrs[0].retloc = first_attribute_retloc;
Packit Service fb6fa5
  *first_attribute_retloc = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  va_start (args, first_attribute_retloc);
Packit Service fb6fa5
Packit Service fb6fa5
  name = va_arg (args, const char*);
Packit Service fb6fa5
  retloc = va_arg (args, const char**);
Packit Service fb6fa5
Packit Service fb6fa5
  while (name != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_return_val_if_fail (retloc != NULL, FALSE);
Packit Service fb6fa5
Packit Service fb6fa5
      g_assert (n_attrs < MAX_ATTRS);
Packit Service fb6fa5
Packit Service fb6fa5
      attrs[n_attrs].name = name;
Packit Service fb6fa5
      attrs[n_attrs].retloc = retloc;
Packit Service fb6fa5
      n_attrs += 1;
Packit Service fb6fa5
      *retloc = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      name = va_arg (args, const char*);
Packit Service fb6fa5
      retloc = va_arg (args, const char**);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  va_end (args);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!retval)
Packit Service fb6fa5
    return retval;
Packit Service fb6fa5
Packit Service fb6fa5
  i = 0;
Packit Service fb6fa5
  while (attribute_names[i])
Packit Service fb6fa5
    {
Packit Service fb6fa5
      int j;
Packit Service fb6fa5
      gboolean found;
Packit Service fb6fa5
Packit Service fb6fa5
      found = FALSE;
Packit Service fb6fa5
      j = 0;
Packit Service fb6fa5
      while (j < n_attrs)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          if (strcmp (attrs[j].name, attribute_names[i]) == 0)
Packit Service fb6fa5
            {
Packit Service fb6fa5
              retloc = attrs[j].retloc;
Packit Service fb6fa5
Packit Service fb6fa5
              if (*retloc != NULL)
Packit Service fb6fa5
                {
Packit Service fb6fa5
                  set_error (error, context,
Packit Service fb6fa5
                             G_MARKUP_ERROR,
Packit Service fb6fa5
                             G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                             _("Attribute \"%s\" repeated twice on the same <%s> element"),
Packit Service fb6fa5
                             attrs[j].name, element_name);
Packit Service fb6fa5
                  retval = FALSE;
Packit Service fb6fa5
                  goto out;
Packit Service fb6fa5
                }
Packit Service fb6fa5
Packit Service fb6fa5
              *retloc = attribute_values[i];
Packit Service fb6fa5
              found = TRUE;
Packit Service fb6fa5
            }
Packit Service fb6fa5
Packit Service fb6fa5
          ++j;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      if (!found && !allow_unknown_attrs)
Packit Service fb6fa5
        {
Packit Service fb6fa5
          set_error (error, context,
Packit Service fb6fa5
                     G_MARKUP_ERROR,
Packit Service fb6fa5
                     G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                     _("Attribute \"%s\" is invalid on <%s> element in this context"),
Packit Service fb6fa5
                     attribute_names[i], element_name);
Packit Service fb6fa5
          retval = FALSE;
Packit Service fb6fa5
          goto out;
Packit Service fb6fa5
        }
Packit Service fb6fa5
Packit Service fb6fa5
      ++i;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
 out:
Packit Service fb6fa5
  return retval;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
check_no_attributes (GMarkupParseContext  *context,
Packit Service fb6fa5
                     const char           *element_name,
Packit Service fb6fa5
                     const char          **attribute_names,
Packit Service fb6fa5
                     const char          **attribute_values,
Packit Service fb6fa5
                     GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (attribute_names[0] != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      set_error (error, context,
Packit Service fb6fa5
                 G_MARKUP_ERROR,
Packit Service fb6fa5
                 G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                 _("Attribute \"%s\" is invalid on <%s> element in this context"),
Packit Service fb6fa5
                 attribute_names[0], element_name);
Packit Service fb6fa5
      return FALSE;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static GtkTextTag *
Packit Service fb6fa5
tag_exists (GMarkupParseContext *context,
Packit Service fb6fa5
	    const gchar         *name,
Packit Service fb6fa5
	    gint                 id,
Packit Service fb6fa5
	    ParseInfo           *info,
Packit Service fb6fa5
	    GError             **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const gchar *real_name;
Packit Service fb6fa5
Packit Service fb6fa5
  if (info->create_tags)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      /* If we have an anonymous tag, just return it directly */
Packit Service fb6fa5
      if (!name)
Packit Service fb6fa5
	return g_hash_table_lookup (info->anonymous_tags,
Packit Service fb6fa5
				    GINT_TO_POINTER (id));
Packit Service fb6fa5
Packit Service fb6fa5
      /* First, try the substitutions */
Packit Service fb6fa5
      real_name = g_hash_table_lookup (info->substitutions, name);
Packit Service fb6fa5
Packit Service fb6fa5
      if (real_name)
Packit Service fb6fa5
	return gtk_text_tag_table_lookup (info->buffer->tag_table, real_name);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Next, try the list of defined tags */
Packit Service fb6fa5
      if (g_hash_table_lookup (info->defined_tags, name) != NULL)
Packit Service fb6fa5
	return gtk_text_tag_table_lookup (info->buffer->tag_table, name);
Packit Service fb6fa5
Packit Service fb6fa5
      set_error (error, context,
Packit Service fb6fa5
		 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		 _("Tag \"%s\" has not been defined."), name);
Packit Service fb6fa5
Packit Service fb6fa5
      return NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkTextTag *tag;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!name)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  set_error (error, context,
Packit Service fb6fa5
		     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		     _("Anonymous tag found and tags can not be created."));
Packit Service fb6fa5
	  return NULL;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      tag = gtk_text_tag_table_lookup (info->buffer->tag_table, name);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tag)
Packit Service fb6fa5
	return tag;
Packit Service fb6fa5
Packit Service fb6fa5
      set_error (error, context,
Packit Service fb6fa5
		 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		 _("Tag \"%s\" does not exist in buffer and tags can not be created."), name);
Packit Service fb6fa5
Packit Service fb6fa5
      return NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
typedef struct
Packit Service fb6fa5
{
Packit Service fb6fa5
  const gchar *id;
Packit Service fb6fa5
  gint length;
Packit Service fb6fa5
  const gchar *start;
Packit Service fb6fa5
} Header;
Packit Service fb6fa5
Packit Service fb6fa5
static GdkPixbuf *
Packit Service fb6fa5
get_pixbuf_from_headers (GList   *headers,
Packit Service fb6fa5
                         int      id,
Packit Service fb6fa5
                         GError **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  Header *header;
Packit Service fb6fa5
  GdkPixdata pixdata;
Packit Service fb6fa5
  GdkPixbuf *pixbuf;
Packit Service fb6fa5
Packit Service fb6fa5
  header = g_list_nth_data (headers, id);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!header)
Packit Service fb6fa5
    return NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!gdk_pixdata_deserialize (&pixdata, header->length,
Packit Service fb6fa5
                                (const guint8 *) header->start, error))
Packit Service fb6fa5
    return NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  pixbuf = gdk_pixbuf_from_pixdata (&pixdata, TRUE, error);
Packit Service fb6fa5
Packit Service fb6fa5
  return pixbuf;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
parse_apply_tag_element (GMarkupParseContext  *context,
Packit Service fb6fa5
			 const gchar          *element_name,
Packit Service fb6fa5
			 const gchar         **attribute_names,
Packit Service fb6fa5
			 const gchar         **attribute_values,
Packit Service fb6fa5
			 ParseInfo            *info,
Packit Service fb6fa5
			 GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const gchar *name, *priority;
Packit Service fb6fa5
  gint id;
Packit Service fb6fa5
  GtkTextTag *tag;
Packit Service fb6fa5
Packit Service fb6fa5
  g_assert (peek_state (info) == STATE_TEXT ||
Packit Service fb6fa5
	    peek_state (info) == STATE_APPLY_TAG);
Packit Service fb6fa5
Packit Service fb6fa5
  if (ELEMENT_IS ("apply_tag"))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!locate_attributes (context, element_name, attribute_names, attribute_values, TRUE, error,
Packit Service fb6fa5
			      "priority", &priority, NULL))
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!check_id_or_name (context, element_name, attribute_names, attribute_values,
Packit Service fb6fa5
			     &id, &name, error))
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
      tag = tag_exists (context, name, id, info, error);
Packit Service fb6fa5
Packit Service fb6fa5
      if (!tag)
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      info->tag_stack = g_slist_prepend (info->tag_stack, tag);
Packit Service fb6fa5
Packit Service fb6fa5
      push_state (info, STATE_APPLY_TAG);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else if (ELEMENT_IS ("pixbuf"))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      int int_id;
Packit Service fb6fa5
      GdkPixbuf *pixbuf;
Packit Service fb6fa5
      TextSpan *span;
Packit Service fb6fa5
      const gchar *pixbuf_id;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!locate_attributes (context, element_name, attribute_names, attribute_values, FALSE, error,
Packit Service fb6fa5
			      "index", &pixbuf_id, NULL))
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      int_id = atoi (pixbuf_id);
Packit Service fb6fa5
      pixbuf = get_pixbuf_from_headers (info->headers, int_id, error);
Packit Service fb6fa5
Packit Service fb6fa5
      span = g_new0 (TextSpan, 1);
Packit Service fb6fa5
      span->pixbuf = pixbuf;
Packit Service fb6fa5
      span->tags = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
      info->spans = g_list_prepend (info->spans, span);
Packit Service fb6fa5
Packit Service fb6fa5
      if (!pixbuf)
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      push_state (info, STATE_PIXBUF);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    set_error (error, context,
Packit Service fb6fa5
	       G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
	       _("Element <%s> is not allowed below <%s>"),
Packit Service fb6fa5
	       element_name, peek_state(info) == STATE_TEXT ? "text" : "apply_tag");
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
parse_attr_element (GMarkupParseContext  *context,
Packit Service fb6fa5
		    const gchar          *element_name,
Packit Service fb6fa5
		    const gchar         **attribute_names,
Packit Service fb6fa5
		    const gchar         **attribute_values,
Packit Service fb6fa5
		    ParseInfo            *info,
Packit Service fb6fa5
		    GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const gchar *name, *type, *value;
Packit Service fb6fa5
  GType gtype;
Packit Service fb6fa5
  GValue gvalue = { 0 };
Packit Service fb6fa5
  GParamSpec *pspec;
Packit Service fb6fa5
Packit Service fb6fa5
  g_assert (peek_state (info) == STATE_TAG);
Packit Service fb6fa5
Packit Service fb6fa5
  if (ELEMENT_IS ("attr"))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!locate_attributes (context, element_name, attribute_names, attribute_values, FALSE, error,
Packit Service fb6fa5
			      "name", &name, "type", &type, "value", &value, NULL))
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      gtype = g_type_from_name (type);
Packit Service fb6fa5
Packit Service fb6fa5
      if (gtype == G_TYPE_INVALID)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  set_error (error, context,
Packit Service fb6fa5
		     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		     _("\"%s\" is not a valid attribute type"), type);
Packit Service fb6fa5
	  return;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      if (!(pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (info->current_tag), name)))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  set_error (error, context,
Packit Service fb6fa5
		     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		     _("\"%s\" is not a valid attribute name"), name);
Packit Service fb6fa5
	  return;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_init (&gvalue, gtype);
Packit Service fb6fa5
Packit Service fb6fa5
      if (!deserialize_value (value, &gvalue))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  set_error (error, context,
Packit Service fb6fa5
		     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		     _("\"%s\" could not be converted to a value of type \"%s\" for attribute \"%s\""),
Packit Service fb6fa5
		     value, type, name);
Packit Service fb6fa5
	  return;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      if (g_param_value_validate (pspec, &gvalue))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  set_error (error, context,
Packit Service fb6fa5
		     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		     _("\"%s\" is not a valid value for attribute \"%s\""),
Packit Service fb6fa5
		     value, name);
Packit Service fb6fa5
	  g_value_unset (&gvalue);
Packit Service fb6fa5
	  return;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      g_object_set_property (G_OBJECT (info->current_tag),
Packit Service fb6fa5
			     name, &gvalue);
Packit Service fb6fa5
Packit Service fb6fa5
      g_value_unset (&gvalue);
Packit Service fb6fa5
Packit Service fb6fa5
      push_state (info, STATE_ATTR);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      set_error (error, context,
Packit Service fb6fa5
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                 _("Element <%s> is not allowed below <%s>"),
Packit Service fb6fa5
                 element_name, "tag");
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static gchar *
Packit Service fb6fa5
get_tag_name (ParseInfo   *info,
Packit Service fb6fa5
	      const gchar *tag_name)
Packit Service fb6fa5
{
Packit Service fb6fa5
  gchar *name;
Packit Service fb6fa5
  gint i;
Packit Service fb6fa5
Packit Service fb6fa5
  name = g_strdup (tag_name);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!info->create_tags)
Packit Service fb6fa5
    return name;
Packit Service fb6fa5
Packit Service fb6fa5
  i = 0;
Packit Service fb6fa5
Packit Service fb6fa5
  while (gtk_text_tag_table_lookup (info->buffer->tag_table, name) != NULL)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_free (name);
Packit Service fb6fa5
      name = g_strdup_printf ("%s-%d", tag_name, ++i);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (i != 0)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_hash_table_insert (info->substitutions, g_strdup (tag_name), g_strdup (name));
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return name;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
parse_tag_element (GMarkupParseContext  *context,
Packit Service fb6fa5
		   const gchar          *element_name,
Packit Service fb6fa5
		   const gchar         **attribute_names,
Packit Service fb6fa5
		   const gchar         **attribute_values,
Packit Service fb6fa5
		   ParseInfo            *info,
Packit Service fb6fa5
		   GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const gchar *name, *priority;
Packit Service fb6fa5
  gchar *tag_name;
Packit Service fb6fa5
  gint id;
Packit Service fb6fa5
  gint prio;
Packit Service fb6fa5
  gchar *tmp;
Packit Service fb6fa5
Packit Service fb6fa5
  g_assert (peek_state (info) == STATE_TAGS);
Packit Service fb6fa5
Packit Service fb6fa5
  if (ELEMENT_IS ("tag"))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!locate_attributes (context, element_name, attribute_names, attribute_values, TRUE, error,
Packit Service fb6fa5
			      "priority", &priority, NULL))
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      if (!check_id_or_name (context, element_name, attribute_names, attribute_values,
Packit Service fb6fa5
			     &id, &name, error))
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      if (name)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  if (g_hash_table_lookup (info->defined_tags, name) != NULL)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context,
Packit Service fb6fa5
			 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("Tag \"%s\" already defined"), name);
Packit Service fb6fa5
	      return;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      prio = strtol (priority, &tmp, 10);
Packit Service fb6fa5
Packit Service fb6fa5
      if (tmp == NULL || tmp == priority)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  set_error (error, context,
Packit Service fb6fa5
		     G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
		     _("Tag \"%s\" has invalid priority \"%s\""), name, priority);
Packit Service fb6fa5
	  return;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      if (name)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  tag_name = get_tag_name (info, name);
Packit Service fb6fa5
	  info->current_tag = gtk_text_tag_new (tag_name);
Packit Service fb6fa5
	  g_free (tag_name);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  info->current_tag = gtk_text_tag_new (NULL);
Packit Service fb6fa5
	  info->current_tag_id = id;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      info->current_tag_prio = prio;
Packit Service fb6fa5
Packit Service fb6fa5
      push_state (info, STATE_TAG);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      set_error (error, context,
Packit Service fb6fa5
                 G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                 _("Element <%s> is not allowed below <%s>"),
Packit Service fb6fa5
                 element_name, "tags");
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
start_element_handler (GMarkupParseContext  *context,
Packit Service fb6fa5
		       const gchar          *element_name,
Packit Service fb6fa5
		       const gchar         **attribute_names,
Packit Service fb6fa5
		       const gchar         **attribute_values,
Packit Service fb6fa5
		       gpointer              user_data,
Packit Service fb6fa5
		       GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  ParseInfo *info = user_data;
Packit Service fb6fa5
Packit Service fb6fa5
  switch (peek_state (info))
Packit Service fb6fa5
    {
Packit Service fb6fa5
    case STATE_START:
Packit Service fb6fa5
      if (ELEMENT_IS ("text_view_markup"))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  if (!check_no_attributes (context, element_name,
Packit Service fb6fa5
				    attribute_names, attribute_values, error))
Packit Service fb6fa5
	    return;
Packit Service fb6fa5
Packit Service fb6fa5
	  push_state (info, STATE_TEXT_VIEW_MARKUP);
Packit Service fb6fa5
	  break;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
        set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                   _("Outermost element in text must be <text_view_markup> not <%s>"),
Packit Service fb6fa5
                   element_name);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TEXT_VIEW_MARKUP:
Packit Service fb6fa5
      if (ELEMENT_IS ("tags"))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  if (info->parsed_tags)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("A <%s> element has already been specified"), "tags");
Packit Service fb6fa5
	      return;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!check_no_attributes (context, element_name,
Packit Service fb6fa5
				    attribute_names, attribute_values, error))
Packit Service fb6fa5
	    return;
Packit Service fb6fa5
Packit Service fb6fa5
	  push_state (info, STATE_TAGS);
Packit Service fb6fa5
	  break;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else if (ELEMENT_IS ("text"))
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  if (info->parsed_text)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("A <%s> element has already been specified"), "text");
Packit Service fb6fa5
	      return;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
	  else if (!info->parsed_tags)
Packit Service fb6fa5
	    {
Packit Service fb6fa5
	      set_error (error, context, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
			 _("A <text> element can't occur before a <tags> element"));
Packit Service fb6fa5
	      return;
Packit Service fb6fa5
	    }
Packit Service fb6fa5
Packit Service fb6fa5
	  if (!check_no_attributes (context, element_name,
Packit Service fb6fa5
				    attribute_names, attribute_values, error))
Packit Service fb6fa5
	    return;
Packit Service fb6fa5
Packit Service fb6fa5
	  push_state (info, STATE_TEXT);
Packit Service fb6fa5
	  break;
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	set_error (error, context,
Packit Service fb6fa5
		   G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                 _("Element <%s> is not allowed below <%s>"),
Packit Service fb6fa5
		   element_name, "text_view_markup");
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TAGS:
Packit Service fb6fa5
      parse_tag_element (context, element_name,
Packit Service fb6fa5
			 attribute_names, attribute_values,
Packit Service fb6fa5
			 info, error);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TAG:
Packit Service fb6fa5
      parse_attr_element (context, element_name,
Packit Service fb6fa5
			  attribute_names, attribute_values,
Packit Service fb6fa5
			  info, error);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TEXT:
Packit Service fb6fa5
    case STATE_APPLY_TAG:
Packit Service fb6fa5
      parse_apply_tag_element (context, element_name,
Packit Service fb6fa5
			       attribute_names, attribute_values,
Packit Service fb6fa5
			       info, error);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      g_assert_not_reached ();
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gint
Packit Service fb6fa5
sort_tag_prio (TextTagPrio *a,
Packit Service fb6fa5
	       TextTagPrio *b)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (a->prio < b->prio)
Packit Service fb6fa5
    return -1;
Packit Service fb6fa5
  else if (a->prio > b->prio)
Packit Service fb6fa5
    return 1;
Packit Service fb6fa5
  else
Packit Service fb6fa5
    return 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
end_element_handler (GMarkupParseContext  *context,
Packit Service fb6fa5
		     const gchar          *element_name,
Packit Service fb6fa5
		     gpointer              user_data,
Packit Service fb6fa5
		     GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  ParseInfo *info = user_data;
Packit Service fb6fa5
  gchar *tmp;
Packit Service fb6fa5
  GList *list;
Packit Service fb6fa5
Packit Service fb6fa5
  switch (peek_state (info))
Packit Service fb6fa5
    {
Packit Service fb6fa5
    case STATE_TAGS:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_TEXT_VIEW_MARKUP);
Packit Service fb6fa5
Packit Service fb6fa5
      info->parsed_tags = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Sort list and add the tags */
Packit Service fb6fa5
      info->tag_priorities = g_list_sort (info->tag_priorities,
Packit Service fb6fa5
					  (GCompareFunc)sort_tag_prio);
Packit Service fb6fa5
      list = info->tag_priorities;
Packit Service fb6fa5
      while (list)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  TextTagPrio *prio = list->data;
Packit Service fb6fa5
Packit Service fb6fa5
	  if (info->create_tags)
Packit Service fb6fa5
	    gtk_text_tag_table_add (info->buffer->tag_table, prio->tag);
Packit Service fb6fa5
Packit Service fb6fa5
	  g_object_unref (prio->tag);
Packit Service fb6fa5
	  prio->tag = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
	  list = list->next;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TAG:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_TAGS);
Packit Service fb6fa5
Packit Service fb6fa5
      if (info->current_tag->name)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  /* Add tag to defined tags hash */
Packit Service fb6fa5
	  tmp = g_strdup (info->current_tag->name);
Packit Service fb6fa5
	  g_hash_table_insert (info->defined_tags,
Packit Service fb6fa5
			       tmp, tmp);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  g_hash_table_insert (info->anonymous_tags,
Packit Service fb6fa5
			       GINT_TO_POINTER (info->current_tag_id),
Packit Service fb6fa5
			       info->current_tag);
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      if (info->create_tags)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  TextTagPrio *prio;
Packit Service fb6fa5
Packit Service fb6fa5
	  /* add the tag to the list */
Packit Service fb6fa5
	  prio = g_new0 (TextTagPrio, 1);
Packit Service fb6fa5
	  prio->prio = info->current_tag_prio;
Packit Service fb6fa5
	  prio->tag = info->current_tag;
Packit Service fb6fa5
Packit Service fb6fa5
 	  info->tag_priorities = g_list_prepend (info->tag_priorities, prio);
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      info->current_tag = NULL;
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_ATTR:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_TAG);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_APPLY_TAG:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_APPLY_TAG ||
Packit Service fb6fa5
		peek_state (info) == STATE_TEXT);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Pop tag */
Packit Service fb6fa5
      info->tag_stack = g_slist_delete_link (info->tag_stack,
Packit Service fb6fa5
					     info->tag_stack);
Packit Service fb6fa5
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TEXT:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_TEXT_VIEW_MARKUP);
Packit Service fb6fa5
Packit Service fb6fa5
      info->spans = g_list_reverse (info->spans);
Packit Service fb6fa5
      info->parsed_text = TRUE;
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TEXT_VIEW_MARKUP:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_START);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_PIXBUF:
Packit Service fb6fa5
      pop_state (info);
Packit Service fb6fa5
      g_assert (peek_state (info) == STATE_APPLY_TAG ||
Packit Service fb6fa5
		peek_state (info) == STATE_TEXT);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      g_assert_not_reached ();
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
all_whitespace (const char *text,
Packit Service fb6fa5
                int         text_len)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const char *p;
Packit Service fb6fa5
  const char *end;
Packit Service fb6fa5
Packit Service fb6fa5
  p = text;
Packit Service fb6fa5
  end = text + text_len;
Packit Service fb6fa5
Packit Service fb6fa5
  while (p != end)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (!g_ascii_isspace (*p))
Packit Service fb6fa5
        return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
      p = g_utf8_next_char (p);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return TRUE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
text_handler (GMarkupParseContext  *context,
Packit Service fb6fa5
	      const gchar          *text,
Packit Service fb6fa5
	      gsize                 text_len,
Packit Service fb6fa5
	      gpointer              user_data,
Packit Service fb6fa5
	      GError              **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  ParseInfo *info = user_data;
Packit Service fb6fa5
  TextSpan *span;
Packit Service fb6fa5
Packit Service fb6fa5
  if (all_whitespace (text, text_len) &&
Packit Service fb6fa5
      peek_state (info) != STATE_TEXT &&
Packit Service fb6fa5
      peek_state (info) != STATE_APPLY_TAG)
Packit Service fb6fa5
    return;
Packit Service fb6fa5
Packit Service fb6fa5
  switch (peek_state (info))
Packit Service fb6fa5
    {
Packit Service fb6fa5
    case STATE_START:
Packit Service fb6fa5
      g_assert_not_reached (); /* gmarkup shouldn't do this */
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    case STATE_TEXT:
Packit Service fb6fa5
    case STATE_APPLY_TAG:
Packit Service fb6fa5
      if (text_len == 0)
Packit Service fb6fa5
	return;
Packit Service fb6fa5
Packit Service fb6fa5
      span = g_new0 (TextSpan, 1);
Packit Service fb6fa5
      span->text = g_strndup (text, text_len);
Packit Service fb6fa5
      span->tags = g_slist_copy (info->tag_stack);
Packit Service fb6fa5
Packit Service fb6fa5
      info->spans = g_list_prepend (info->spans, span);
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    default:
Packit Service fb6fa5
      g_assert_not_reached ();
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
parse_info_init (ParseInfo     *info,
Packit Service fb6fa5
		 GtkTextBuffer *buffer,
Packit Service fb6fa5
		 gboolean       create_tags,
Packit Service fb6fa5
		 GList         *headers)
Packit Service fb6fa5
{
Packit Service fb6fa5
  info->states = g_slist_prepend (NULL, GINT_TO_POINTER (STATE_START));
Packit Service fb6fa5
Packit Service fb6fa5
  info->create_tags = create_tags;
Packit Service fb6fa5
  info->headers = headers;
Packit Service fb6fa5
  info->defined_tags = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
Packit Service fb6fa5
  info->substitutions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
Packit Service fb6fa5
  info->anonymous_tags = g_hash_table_new_full (NULL, NULL, NULL, NULL);
Packit Service fb6fa5
  info->tag_stack = NULL;
Packit Service fb6fa5
  info->spans = NULL;
Packit Service fb6fa5
  info->parsed_text = FALSE;
Packit Service fb6fa5
  info->parsed_tags = FALSE;
Packit Service fb6fa5
  info->current_tag = NULL;
Packit Service fb6fa5
  info->current_tag_prio = -1;
Packit Service fb6fa5
  info->tag_priorities = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  info->buffer = buffer;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
text_span_free (TextSpan *span)
Packit Service fb6fa5
{
Packit Service fb6fa5
  g_free (span->text);
Packit Service fb6fa5
  g_slist_free (span->tags);
Packit Service fb6fa5
  g_free (span);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
parse_info_free (ParseInfo *info)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GList *list;
Packit Service fb6fa5
Packit Service fb6fa5
  g_slist_free (info->tag_stack);
Packit Service fb6fa5
  g_slist_free (info->states);
Packit Service fb6fa5
Packit Service fb6fa5
  g_hash_table_destroy (info->substitutions);
Packit Service fb6fa5
  g_hash_table_destroy (info->defined_tags);
Packit Service fb6fa5
Packit Service fb6fa5
  if (info->current_tag)
Packit Service fb6fa5
    g_object_unref (info->current_tag);
Packit Service fb6fa5
Packit Service fb6fa5
  list = info->spans;
Packit Service fb6fa5
  while (list)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      text_span_free (list->data);
Packit Service fb6fa5
Packit Service fb6fa5
      list = list->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  g_list_free (info->spans);
Packit Service fb6fa5
Packit Service fb6fa5
  list = info->tag_priorities;
Packit Service fb6fa5
  while (list)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      TextTagPrio *prio = list->data;
Packit Service fb6fa5
Packit Service fb6fa5
      if (prio->tag)
Packit Service fb6fa5
	g_object_unref (prio->tag);
Packit Service fb6fa5
      g_free (prio);
Packit Service fb6fa5
Packit Service fb6fa5
      list = list->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
  g_list_free (info->tag_priorities);
Packit Service fb6fa5
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
insert_text (ParseInfo   *info,
Packit Service fb6fa5
	     GtkTextIter *iter)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkTextIter start_iter;
Packit Service fb6fa5
  GtkTextMark *mark;
Packit Service fb6fa5
  GList *tmp;
Packit Service fb6fa5
  GSList *tags;
Packit Service fb6fa5
Packit Service fb6fa5
  start_iter = *iter;
Packit Service fb6fa5
Packit Service fb6fa5
  mark = gtk_text_buffer_create_mark (info->buffer, "deserialize_insert_point",
Packit Service fb6fa5
  				      &start_iter, TRUE);
Packit Service fb6fa5
Packit Service fb6fa5
  tmp = info->spans;
Packit Service fb6fa5
  while (tmp)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      TextSpan *span = tmp->data;
Packit Service fb6fa5
Packit Service fb6fa5
      if (span->text)
Packit Service fb6fa5
	gtk_text_buffer_insert (info->buffer, iter, span->text, -1);
Packit Service fb6fa5
      else
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  gtk_text_buffer_insert_pixbuf (info->buffer, iter, span->pixbuf);
Packit Service fb6fa5
	  g_object_unref (span->pixbuf);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      gtk_text_buffer_get_iter_at_mark (info->buffer, &start_iter, mark);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Apply tags */
Packit Service fb6fa5
      tags = span->tags;
Packit Service fb6fa5
      while (tags)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  GtkTextTag *tag = tags->data;
Packit Service fb6fa5
Packit Service fb6fa5
	  gtk_text_buffer_apply_tag (info->buffer, tag,
Packit Service fb6fa5
				     &start_iter, iter);
Packit Service fb6fa5
Packit Service fb6fa5
	  tags = tags->next;
Packit Service fb6fa5
	}
Packit Service fb6fa5
Packit Service fb6fa5
      gtk_text_buffer_move_mark (info->buffer, mark, iter);
Packit Service fb6fa5
Packit Service fb6fa5
      tmp = tmp->next;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_text_buffer_delete_mark (info->buffer, mark);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
static int
Packit Service fb6fa5
read_int (const guchar *start)
Packit Service fb6fa5
{
Packit Service fb6fa5
  int result;
Packit Service fb6fa5
Packit Service fb6fa5
  result =
Packit Service fb6fa5
    start[0] << 24 |
Packit Service fb6fa5
    start[1] << 16 |
Packit Service fb6fa5
    start[2] << 8 |
Packit Service fb6fa5
    start[3];
Packit Service fb6fa5
Packit Service fb6fa5
  return result;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
header_is (Header      *header,
Packit Service fb6fa5
           const gchar *id)
Packit Service fb6fa5
{
Packit Service fb6fa5
  return (strncmp (header->id, id, strlen (id)) == 0);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static GList *
Packit Service fb6fa5
read_headers (const gchar *start,
Packit Service fb6fa5
	      gint         len,
Packit Service fb6fa5
	      GError     **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  int i = 0;
Packit Service fb6fa5
  int section_len;
Packit Service fb6fa5
  Header *header;
Packit Service fb6fa5
  GList *headers = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
  while (i < len)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      if (i + 30 >= len)
Packit Service fb6fa5
	goto error;
Packit Service fb6fa5
Packit Service fb6fa5
      if (strncmp (start + i, "GTKTEXTBUFFERCONTENTS-0001", 26) == 0 ||
Packit Service fb6fa5
	  strncmp (start + i, "GTKTEXTBUFFERPIXBDATA-0001", 26) == 0)
Packit Service fb6fa5
	{
Packit Service fb6fa5
	  section_len = read_int ((const guchar *) start + i + 26);
Packit Service fb6fa5
Packit Service fb6fa5
	  if (i + 30 + section_len > len)
Packit Service fb6fa5
	    goto error;
Packit Service fb6fa5
Packit Service fb6fa5
	  header = g_new0 (Header, 1);
Packit Service fb6fa5
	  header->id = start + i;
Packit Service fb6fa5
	  header->length = section_len;
Packit Service fb6fa5
	  header->start = start + i + 30;
Packit Service fb6fa5
Packit Service fb6fa5
	  i += 30 + section_len;
Packit Service fb6fa5
Packit Service fb6fa5
	  headers = g_list_prepend (headers, header);
Packit Service fb6fa5
	}
Packit Service fb6fa5
      else
Packit Service fb6fa5
	break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return g_list_reverse (headers);
Packit Service fb6fa5
Packit Service fb6fa5
 error:
Packit Service fb6fa5
  g_list_foreach (headers, (GFunc) g_free, NULL);
Packit Service fb6fa5
  g_list_free (headers);
Packit Service fb6fa5
Packit Service fb6fa5
  g_set_error_literal (error,
Packit Service fb6fa5
                       G_MARKUP_ERROR,
Packit Service fb6fa5
                       G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                       _("Serialized data is malformed"));
Packit Service fb6fa5
Packit Service fb6fa5
  return NULL;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
deserialize_text (GtkTextBuffer *buffer,
Packit Service fb6fa5
		  GtkTextIter   *iter,
Packit Service fb6fa5
		  const gchar   *text,
Packit Service fb6fa5
		  gint           len,
Packit Service fb6fa5
		  gboolean       create_tags,
Packit Service fb6fa5
		  GError       **error,
Packit Service fb6fa5
		  GList         *headers)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GMarkupParseContext *context;
Packit Service fb6fa5
  ParseInfo info;
Packit Service fb6fa5
  gboolean retval = FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  static const GMarkupParser rich_text_parser = {
Packit Service fb6fa5
    start_element_handler,
Packit Service fb6fa5
    end_element_handler,
Packit Service fb6fa5
    text_handler,
Packit Service fb6fa5
    NULL,
Packit Service fb6fa5
    NULL
Packit Service fb6fa5
  };
Packit Service fb6fa5
Packit Service fb6fa5
  parse_info_init (&info, buffer, create_tags, headers);
Packit Service fb6fa5
Packit Service fb6fa5
  context = g_markup_parse_context_new (&rich_text_parser,
Packit Service fb6fa5
                                        0, &info, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!g_markup_parse_context_parse (context,
Packit Service fb6fa5
                                     text,
Packit Service fb6fa5
                                     len,
Packit Service fb6fa5
                                     error))
Packit Service fb6fa5
    goto out;
Packit Service fb6fa5
Packit Service fb6fa5
  if (!g_markup_parse_context_end_parse (context, error))
Packit Service fb6fa5
    goto out;
Packit Service fb6fa5
Packit Service fb6fa5
  retval = TRUE;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Now insert the text */
Packit Service fb6fa5
  insert_text (&info, iter);
Packit Service fb6fa5
Packit Service fb6fa5
 out:
Packit Service fb6fa5
  parse_info_free (&info;;
Packit Service fb6fa5
Packit Service fb6fa5
  g_markup_parse_context_free (context);
Packit Service fb6fa5
Packit Service fb6fa5
  return retval;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
gboolean
Packit Service fb6fa5
_gtk_text_buffer_deserialize_rich_text (GtkTextBuffer *register_buffer,
Packit Service fb6fa5
                                        GtkTextBuffer *content_buffer,
Packit Service fb6fa5
                                        GtkTextIter   *iter,
Packit Service fb6fa5
                                        const guint8  *text,
Packit Service fb6fa5
                                        gsize          length,
Packit Service fb6fa5
                                        gboolean       create_tags,
Packit Service fb6fa5
                                        gpointer       user_data,
Packit Service fb6fa5
                                        GError       **error)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GList *headers;
Packit Service fb6fa5
  Header *header;
Packit Service fb6fa5
  gboolean retval;
Packit Service fb6fa5
Packit Service fb6fa5
  headers = read_headers ((gchar *) text, length, error);
Packit Service fb6fa5
Packit Service fb6fa5
  if (!headers)
Packit Service fb6fa5
    return FALSE;
Packit Service fb6fa5
Packit Service fb6fa5
  header = headers->data;
Packit Service fb6fa5
  if (!header_is (header, "GTKTEXTBUFFERCONTENTS-0001"))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      g_set_error_literal (error,
Packit Service fb6fa5
                           G_MARKUP_ERROR,
Packit Service fb6fa5
                           G_MARKUP_ERROR_PARSE,
Packit Service fb6fa5
                           _("Serialized data is malformed. First section isn't GTKTEXTBUFFERCONTENTS-0001"));
Packit Service fb6fa5
Packit Service fb6fa5
      retval = FALSE;
Packit Service fb6fa5
      goto out;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  retval = deserialize_text (content_buffer, iter,
Packit Service fb6fa5
			     header->start, header->length,
Packit Service fb6fa5
			     create_tags, error, headers->next);
Packit Service fb6fa5
Packit Service fb6fa5
 out:
Packit Service fb6fa5
  g_list_foreach (headers, (GFunc)g_free, NULL);
Packit Service fb6fa5
  g_list_free (headers);
Packit Service fb6fa5
Packit Service fb6fa5
  return retval;
Packit Service fb6fa5
}