Blame gegl/gegl-xml.c

Packit Service 2781ba
/* This file is part of GEGL
Packit Service 2781ba
 *
Packit Service 2781ba
 * GEGL is free software; you can redistribute it and/or
Packit Service 2781ba
 * modify it under the terms of the GNU Lesser General Public
Packit Service 2781ba
 * License as published by the Free Software Foundation; either
Packit Service 2781ba
 * version 3 of the License, or (at your option) any later version.
Packit Service 2781ba
 *
Packit Service 2781ba
 * GEGL is distributed in the hope that it will be useful,
Packit Service 2781ba
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2781ba
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 2781ba
 * Lesser General Public License for more details.
Packit Service 2781ba
 *
Packit Service 2781ba
 * You should have received a copy of the GNU Lesser General Public
Packit Service 2781ba
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Copyright 2006 Øyvind Kolås
Packit Service 2781ba
 */
Packit Service 2781ba
#include "config.h"
Packit Service 2781ba
Packit Service 2781ba
#include <glib.h>
Packit Service 2781ba
#include <glib-object.h>
Packit Service 2781ba
#include <stdlib.h>
Packit Service 2781ba
#include <stdio.h>
Packit Service 2781ba
#include <string.h>
Packit Service 2781ba
#include <limits.h>
Packit Service 2781ba
Packit Service 2781ba
#include "gegl.h"
Packit Service 2781ba
#include "gegl-types-internal.h"
Packit Service 2781ba
#include "graph/gegl-node.h"
Packit Service 2781ba
#include "graph/gegl-pad.h"
Packit Service 2781ba
#include "operation/gegl-operation.h"
Packit Service 2781ba
#include "property-types/gegl-color.h"
Packit Service 2781ba
#include "property-types/gegl-curve.h"
Packit Service 2781ba
#include "property-types/gegl-path.h"
Packit Service 2781ba
#include "property-types/gegl-paramspecs.h"
Packit Service 2781ba
#include "gegl-instrument.h"
Packit Service 2781ba
#include "gegl-xml.h"
Packit Service 2781ba
Packit Service 2781ba
#ifdef G_OS_WIN32
Packit Service 2781ba
#define realpath(a, b)    _fullpath (b, a, _MAX_PATH)
Packit Service 2781ba
#endif
Packit Service 2781ba
Packit Service 2781ba
typedef struct _ParseData ParseData;
Packit Service 2781ba
Packit Service 2781ba
enum
Packit Service 2781ba
{
Packit Service 2781ba
  STATE_NONE = 0,
Packit Service 2781ba
  STATE_TREE_NORMAL,
Packit Service 2781ba
  STATE_TREE_FIRST_CHILD
Packit Service 2781ba
};
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
struct _ParseData
Packit Service 2781ba
{
Packit Service 2781ba
  gint         state;
Packit Service 2781ba
  const gchar *path_root;
Packit Service 2781ba
  GeglNode    *gegl;
Packit Service 2781ba
  gchar       *param;/*< the param we are setting (NULL when not in <param></param>) */
Packit Service 2781ba
  GeglNode    *iter; /*< the iterator we're either connecting to input|aux of
Packit Service 2781ba
                         depending on context */
Packit Service 2781ba
  GList       *parent;/*< a stack of parents, as we are recursing into aux
Packit Service 2781ba
                         branches */
Packit Service 2781ba
  GeglCurve   *curve;/*< the curve whose points we are parsing */
Packit Service 2781ba
Packit Service 2781ba
  GHashTable  *ids;
Packit Service 2781ba
  GList       *refs;
Packit Service 2781ba
};
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/* Search a paired attribute name/value arrays for an entry with a specific
Packit Service 2781ba
 * name, return the value or null if not found.
Packit Service 2781ba
 */
Packit Service 2781ba
static const gchar *name2val (const gchar **attribute_names,
Packit Service 2781ba
                              const gchar **attribute_values,
Packit Service 2781ba
                              const gchar  *name)
Packit Service 2781ba
{
Packit Service 2781ba
  while (*attribute_names)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (!strcmp (*attribute_names, name))
Packit Service 2781ba
        {
Packit Service 2781ba
          return *attribute_values;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      attribute_names++;
Packit Service 2781ba
      attribute_values++;
Packit Service 2781ba
    }
Packit Service 2781ba
  return NULL;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void param_set (ParseData   *pd,
Packit Service 2781ba
                       GeglNode    *new,
Packit Service 2781ba
                       const gchar *param_name,
Packit Service 2781ba
                       const gchar *param_value)
Packit Service 2781ba
{
Packit Service 2781ba
  if (!strcmp (param_name, "name"))
Packit Service 2781ba
    {
Packit Service 2781ba
      g_object_set (new, param_name, param_value, NULL);
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (param_name, "id"))
Packit Service 2781ba
    {
Packit Service 2781ba
      g_hash_table_insert (pd->ids, g_strdup (param_value), new);
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (param_name, "ref"))
Packit Service 2781ba
    {
Packit Service 2781ba
      pd->refs = g_list_append (pd->refs, new);
Packit Service 2781ba
      goto set_clone_prop_as_well;
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (strcmp (param_name, "operation") &&
Packit Service 2781ba
           strcmp (param_name, "type"))
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglOperation *operation;
Packit Service 2781ba
      GParamSpec    *paramspec;
Packit Service 2781ba
set_clone_prop_as_well:
Packit Service 2781ba
Packit Service 2781ba
      operation = new->operation;
Packit Service 2781ba
      paramspec = g_object_class_find_property (G_OBJECT_GET_CLASS (operation), param_name);
Packit Service 2781ba
Packit Service 2781ba
      if (!paramspec)
Packit Service 2781ba
        {
Packit Service 2781ba
          g_warning ("property %s not found for %s",
Packit Service 2781ba
                     param_name, gegl_node_get_debug_name (new));
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (g_type_is_a (G_PARAM_SPEC_TYPE (paramspec),
Packit Service 2781ba
                            GEGL_TYPE_PARAM_FILE_PATH))
Packit Service 2781ba
        {
Packit Service 2781ba
          gchar *buf;
Packit Service 2781ba
Packit Service 2781ba
          if (g_path_is_absolute (param_value))
Packit Service 2781ba
            {
Packit Service 2781ba
              gegl_node_set (new, param_name, param_value, NULL);
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              gchar * absolute_path;
Packit Service 2781ba
              if (pd->path_root)
Packit Service 2781ba
                {
Packit Service 2781ba
                  buf = g_strdup_printf ("%s/%s", pd->path_root, param_value);
Packit Service 2781ba
                }
Packit Service 2781ba
              else
Packit Service 2781ba
                {
Packit Service 2781ba
                  buf = g_strdup_printf ("./%s", param_value);
Packit Service 2781ba
                }
Packit Service 2781ba
Packit Service 2781ba
              absolute_path = realpath (buf, NULL);
Packit Service 2781ba
              g_free (buf);
Packit Service 2781ba
              if (absolute_path)
Packit Service 2781ba
                {
Packit Service 2781ba
                  gegl_node_set (new, param_name, absolute_path, NULL);
Packit Service 2781ba
                  free (absolute_path);
Packit Service 2781ba
                }
Packit Service 2781ba
              else
Packit Service 2781ba
                {
Packit Service 2781ba
                  g_warning ("Unable to obtain absolute path for parameter %s\n",
Packit Service 2781ba
                             param_name);
Packit Service 2781ba
                }
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == G_TYPE_INT)
Packit Service 2781ba
        {
Packit Service 2781ba
          gegl_node_set (new, param_name, atoi (param_value), NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == G_TYPE_FLOAT ||
Packit Service 2781ba
               paramspec->value_type == G_TYPE_DOUBLE)
Packit Service 2781ba
        {
Packit Service 2781ba
          gegl_node_set (new, param_name, g_ascii_strtod (param_value, NULL), NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == G_TYPE_STRING)
Packit Service 2781ba
        {
Packit Service 2781ba
          gegl_node_set (new, param_name, param_value, NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == G_TYPE_BOOLEAN)
Packit Service 2781ba
        {
Packit Service 2781ba
          if (!strcmp (param_value, "true") ||
Packit Service 2781ba
              !strcmp (param_value, "TRUE") ||
Packit Service 2781ba
              !strcmp (param_value, "YES") ||
Packit Service 2781ba
              !strcmp (param_value, "yes") ||
Packit Service 2781ba
              !strcmp (param_value, "y") ||
Packit Service 2781ba
              !strcmp (param_value, "Y") ||
Packit Service 2781ba
              !strcmp (param_value, "1") ||
Packit Service 2781ba
              !strcmp (param_value, "on"))
Packit Service 2781ba
            {
Packit Service 2781ba
              gegl_node_set (new, param_name, TRUE, NULL);
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              gegl_node_set (new, param_name, FALSE, NULL);
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (g_type_is_a (paramspec->value_type, G_TYPE_ENUM))
Packit Service 2781ba
        {
Packit Service 2781ba
          GEnumClass *eclass = g_type_class_peek (paramspec->value_type);
Packit Service 2781ba
          GEnumValue *evalue = g_enum_get_value_by_nick (eclass, param_value);
Packit Service 2781ba
          gegl_node_set (new, param_name, evalue->value, NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == GEGL_TYPE_COLOR)
Packit Service 2781ba
        {
Packit Service 2781ba
          GeglColor *color = g_object_new (GEGL_TYPE_COLOR,
Packit Service 2781ba
                                           "string", param_value,
Packit Service 2781ba
                                           NULL);
Packit Service 2781ba
Packit Service 2781ba
          gegl_node_set (new, param_name, color, NULL);
Packit Service 2781ba
Packit Service 2781ba
          g_object_unref (color);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == GEGL_TYPE_CURVE)
Packit Service 2781ba
        {
Packit Service 2781ba
          if (pd->curve)
Packit Service 2781ba
            {
Packit Service 2781ba
              gegl_node_set (new, param_name, pd->curve, NULL);
Packit Service 2781ba
Packit Service 2781ba
              g_object_unref (pd->curve);
Packit Service 2781ba
              pd->curve = NULL;
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (paramspec->value_type == GEGL_TYPE_PATH)
Packit Service 2781ba
        {
Packit Service 2781ba
          GeglPath *path = gegl_path_new ();
Packit Service 2781ba
          gegl_path_parse_string (path, param_value);
Packit Service 2781ba
          gegl_node_set (new, param_name, path, NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          g_warning ("operation desired unknown parapspec type for %s",
Packit Service 2781ba
                     param_name);
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/* Check that the attributes for ELEMENT include an attribute of name NAME,
Packit Service 2781ba
 * and store it in the variable of the same name. Else report an error.
Packit Service 2781ba
 *
Packit Service 2781ba
 * eg:  { collect_attribute (value, 'key'); }
Packit Service 2781ba
 */
Packit Service 2781ba
#define collect_attribute(NAME, ELEMENT)                                \
Packit Service 2781ba
{                                                                       \
Packit Service 2781ba
  const gchar *__value = name2val (a, v, (G_STRINGIFY (NAME)));         \
Packit Service 2781ba
  if (!__value)                                                         \
Packit Service 2781ba
    {                                                                   \
Packit Service 2781ba
      *error = g_error_new (G_MARKUP_ERROR,                             \
Packit Service 2781ba
                            G_MARKUP_ERROR_MISSING_ATTRIBUTE,           \
Packit Service 2781ba
                            "Expected attribute '%s' in element '%s'",  \
Packit Service 2781ba
                            (G_STRINGIFY (NAME)),                       \
Packit Service 2781ba
                            (ELEMENT));                                 \
Packit Service 2781ba
      return;                                                           \
Packit Service 2781ba
    }                                                                   \
Packit Service 2781ba
  else                                                                  \
Packit Service 2781ba
    {                                                                   \
Packit Service 2781ba
      (NAME) = __value;                                                 \
Packit Service 2781ba
    }                                                                   \
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void start_element (GMarkupParseContext *context,
Packit Service 2781ba
                           const gchar         *element_name,
Packit Service 2781ba
                           const gchar        **attribute_names,
Packit Service 2781ba
                           const gchar        **attribute_values,
Packit Service 2781ba
                           gpointer             user_data,
Packit Service 2781ba
                           GError             **error)
Packit Service 2781ba
{
Packit Service 2781ba
  const gchar **a  = attribute_names;
Packit Service 2781ba
  const gchar **v  = attribute_values;
Packit Service 2781ba
  ParseData    *pd = user_data;
Packit Service 2781ba
Packit Service 2781ba
  if (!strcmp (element_name, "gegl") ||
Packit Service 2781ba
      !strcmp (element_name, "image"))
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglNode *new = g_object_new (GEGL_TYPE_NODE, "operation", "gegl:nop", NULL);
Packit Service 2781ba
      if (pd->gegl == NULL)
Packit Service 2781ba
        {
Packit Service 2781ba
          pd->gegl = new;
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
        }
Packit Service 2781ba
      pd->state  = STATE_TREE_NORMAL;
Packit Service 2781ba
      pd->parent = g_list_prepend (pd->parent, new);
Packit Service 2781ba
Packit Service 2781ba
      gegl_node_get_output_proxy (new, "output"); /* creates the pad if it doesn't exist */
Packit Service 2781ba
      if (pd->iter)
Packit Service 2781ba
        gegl_node_connect_from (pd->iter, "input", new, "output");
Packit Service 2781ba
      pd->iter = gegl_node_get_output_proxy (new, "output");
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "graph"))
Packit Service 2781ba
    {
Packit Service 2781ba
      /*NYI*/
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "params"))
Packit Service 2781ba
    {
Packit Service 2781ba
      /*g_warning ("go a param set");*/
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "param"))
Packit Service 2781ba
    {
Packit Service 2781ba
      const gchar *name;
Packit Service 2781ba
      if (pd->param != NULL)
Packit Service 2781ba
        g_warning ("eek, haven't cleared previous param");
Packit Service 2781ba
Packit Service 2781ba
      collect_attribute (name, "param");
Packit Service 2781ba
      pd->param = g_strdup (name);
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "curve"))
Packit Service 2781ba
    {
Packit Service 2781ba
      const gchar *ymin, *ymax;
Packit Service 2781ba
      if (pd->curve != NULL)
Packit Service 2781ba
        g_warning ("we haven't cleared previous curve");
Packit Service 2781ba
Packit Service 2781ba
      collect_attribute (ymin, "curve");
Packit Service 2781ba
      collect_attribute (ymax, "curve");
Packit Service 2781ba
Packit Service 2781ba
      pd->curve = gegl_curve_new (g_ascii_strtod (ymin, NULL),
Packit Service 2781ba
                                  g_ascii_strtod (ymax, NULL));
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "curve-point"))
Packit Service 2781ba
    {
Packit Service 2781ba
      if (!pd->curve)
Packit Service 2781ba
        g_warning ("curve not instantiated");
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          const gchar *x, *y;
Packit Service 2781ba
          collect_attribute (x, "curve-point");
Packit Service 2781ba
          collect_attribute (y, "curve-point");
Packit Service 2781ba
Packit Service 2781ba
          gegl_curve_add_point (pd->curve,
Packit Service 2781ba
                                g_ascii_strtod (x, NULL),
Packit Service 2781ba
                                g_ascii_strtod (y, NULL));
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "link") ||
Packit Service 2781ba
           !strcmp (element_name, "links") ||
Packit Service 2781ba
           !strcmp (element_name, "stack") ||
Packit Service 2781ba
           !strcmp (element_name, "launcher") ||
Packit Service 2781ba
           !strcmp (element_name, "launchers") ||
Packit Service 2781ba
           !strcmp (element_name, "source") ||
Packit Service 2781ba
           !strcmp (element_name, "destination"))
Packit Service 2781ba
    {
Packit Service 2781ba
      /* ignore */
Packit Service 2781ba
    }
Packit Service 2781ba
  else
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglNode *new;
Packit Service 2781ba
Packit Service 2781ba
      if (!strcmp (element_name, "clone"))
Packit Service 2781ba
        {
Packit Service 2781ba
          new = gegl_node_new_child (pd->gegl,
Packit Service 2781ba
                                     "operation", "gegl:clone",
Packit Service 2781ba
                                     NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (!strcmp (element_name, "layer"))
Packit Service 2781ba
        {
Packit Service 2781ba
          new = gegl_node_new_child (pd->gegl,
Packit Service 2781ba
                                     "operation", "gegl:layer",
Packit Service 2781ba
                                     NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (!strcmp (element_name, "node"))
Packit Service 2781ba
        {
Packit Service 2781ba
          const gchar *operation;
Packit Service 2781ba
          collect_attribute (operation, "node");
Packit Service 2781ba
          new = gegl_node_new_child (pd->gegl, "operation", operation, NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else if (!strcmp (element_name, "filter"))
Packit Service 2781ba
        {
Packit Service 2781ba
          const gchar *type;
Packit Service 2781ba
          collect_attribute (type, "filter");
Packit Service 2781ba
          new = gegl_node_new_child (pd->gegl, "operation", type, NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          new = gegl_node_new_child (pd->gegl,
Packit Service 2781ba
                                     "operation", element_name,
Packit Service 2781ba
                                     NULL);
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      /* Could not instance an appropriate node */
Packit Service 2781ba
      if (!new)
Packit Service 2781ba
        {
Packit Service 2781ba
          *error = g_error_new (G_MARKUP_ERROR,
Packit Service 2781ba
                                G_MARKUP_ERROR_UNKNOWN_ELEMENT,
Packit Service 2781ba
                                "Could not instantiate operation '%s'",
Packit Service 2781ba
                                element_name);
Packit Service 2781ba
          return;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      while (*a)
Packit Service 2781ba
        {
Packit Service 2781ba
          param_set (pd, new, *a, *v);
Packit Service 2781ba
          a++;
Packit Service 2781ba
          v++;
Packit Service 2781ba
        }
Packit Service 2781ba
Packit Service 2781ba
      if (pd->state == STATE_TREE_FIRST_CHILD)
Packit Service 2781ba
        {
Packit Service 2781ba
          gegl_node_connect_from (pd->iter, "aux", new, "output");
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          if (pd->iter)
Packit Service 2781ba
            gegl_node_connect_from (pd->iter, "input", new, "output");
Packit Service 2781ba
        }
Packit Service 2781ba
      pd->parent = g_list_prepend (pd->parent, new);
Packit Service 2781ba
      pd->state  = STATE_TREE_FIRST_CHILD;
Packit Service 2781ba
      pd->iter   = new;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void text (GMarkupParseContext *context,
Packit Service 2781ba
                  const gchar         *text,
Packit Service 2781ba
                  gsize                text_len,
Packit Service 2781ba
                  gpointer             user_data,
Packit Service 2781ba
                  GError             **error)
Packit Service 2781ba
{
Packit Service 2781ba
  ParseData *pd = user_data;
Packit Service 2781ba
Packit Service 2781ba
  if (pd->param && pd->iter && !pd->curve)
Packit Service 2781ba
    {
Packit Service 2781ba
      param_set (pd, pd->iter, pd->param, text);
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/* Called for close tags </foo> */
Packit Service 2781ba
static void end_element (GMarkupParseContext *context,
Packit Service 2781ba
                         const gchar         *element_name,
Packit Service 2781ba
                         gpointer             user_data,
Packit Service 2781ba
                         GError             **error)
Packit Service 2781ba
{
Packit Service 2781ba
  ParseData *pd = user_data;
Packit Service 2781ba
Packit Service 2781ba
  if (!strcmp (element_name, "gegl") ||
Packit Service 2781ba
      !strcmp (element_name, "image"))
Packit Service 2781ba
    {
Packit Service 2781ba
      /*ignored*/
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "tree") ||
Packit Service 2781ba
           !strcmp (element_name, "layers"))
Packit Service 2781ba
    {
Packit Service 2781ba
      if (gegl_node_get_pad (pd->iter, "input"))
Packit Service 2781ba
        {
Packit Service 2781ba
          gegl_node_connect_from (pd->iter, "input",
Packit Service 2781ba
                                  gegl_node_get_input_proxy (GEGL_NODE (pd->parent->data), "input"),
Packit Service 2781ba
                                  "output");
Packit Service 2781ba
          pd->iter = gegl_node_get_input_proxy (GEGL_NODE (pd->parent->data),
Packit Service 2781ba
                                                "input");
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          pd->iter = NULL;
Packit Service 2781ba
        }
Packit Service 2781ba
      pd->parent = g_list_delete_link (pd->parent, pd->parent);
Packit Service 2781ba
      pd->state  = STATE_TREE_NORMAL;
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "graph"))
Packit Service 2781ba
    {
Packit Service 2781ba
      /*NYI*/
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "param"))
Packit Service 2781ba
    {
Packit Service 2781ba
      g_free (pd->param);
Packit Service 2781ba
      pd->param = NULL;
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "curve"))
Packit Service 2781ba
    {
Packit Service 2781ba
      g_assert (pd->param && pd->iter);
Packit Service 2781ba
      param_set (pd, pd->iter, pd->param, NULL);
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (!strcmp (element_name, "link") ||
Packit Service 2781ba
           !strcmp (element_name, "links") ||
Packit Service 2781ba
           !strcmp (element_name, "launcher") ||
Packit Service 2781ba
           !strcmp (element_name, "launchers") ||
Packit Service 2781ba
           !strcmp (element_name, "source") ||
Packit Service 2781ba
           !strcmp (element_name, "destination") ||
Packit Service 2781ba
           !strcmp (element_name, "stack") ||
Packit Service 2781ba
           !strcmp (element_name, "params") ||
Packit Service 2781ba
           !strcmp (element_name, "curve-point"))
Packit Service 2781ba
    {
Packit Service 2781ba
      /* ignore */
Packit Service 2781ba
    }
Packit Service 2781ba
  else if (1 ||
Packit Service 2781ba
           !strcmp (element_name, "node") ||
Packit Service 2781ba
           !strcmp (element_name, "filter"))
Packit Service 2781ba
    {
Packit Service 2781ba
      pd->iter   = pd->parent->data;
Packit Service 2781ba
      pd->parent = g_list_delete_link (pd->parent, pd->parent);
Packit Service 2781ba
      pd->state  = STATE_TREE_NORMAL;
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/* Called on error, including one set by other
Packit Service 2781ba
 * methods in the vtable. The GError should not be freed.
Packit Service 2781ba
 */
Packit Service 2781ba
static void error (GMarkupParseContext *context,
Packit Service 2781ba
                   GError              *error,
Packit Service 2781ba
                   gpointer             user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  gint  line_number;
Packit Service 2781ba
  gint  char_number;
Packit Service 2781ba
Packit Service 2781ba
  g_markup_parse_context_get_position (context, &line_number, &char_number);
Packit Service 2781ba
  g_warning ("XML Parse error %i:%i: %s",
Packit Service 2781ba
             line_number, char_number, error->message);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static GMarkupParser parser = {
Packit Service 2781ba
  start_element,
Packit Service 2781ba
  end_element,
Packit Service 2781ba
  text,
Packit Service 2781ba
  NULL,
Packit Service 2781ba
  error
Packit Service 2781ba
};
Packit Service 2781ba
Packit Service 2781ba
static void each_ref (gpointer value,
Packit Service 2781ba
                      gpointer user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  ParseData *pd        = user_data;
Packit Service 2781ba
  GeglNode  *dest_node = value;
Packit Service 2781ba
  gchar     *ref;
Packit Service 2781ba
  GeglNode  *source_node;
Packit Service 2781ba
Packit Service 2781ba
  gegl_node_get (dest_node, "ref", &ref, NULL);
Packit Service 2781ba
  source_node = g_hash_table_lookup (pd->ids, ref);
Packit Service 2781ba
  g_free (ref);
Packit Service 2781ba
  gegl_node_connect_from (dest_node, "input", source_node, "output");
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
GeglNode *gegl_node_new_from_xml (const gchar *xmldata,
Packit Service 2781ba
                                  const gchar *path_root)
Packit Service 2781ba
{
Packit Service 2781ba
  glong                time = gegl_ticks ();
Packit Service 2781ba
  ParseData            pd   = { 0, };
Packit Service 2781ba
  GMarkupParseContext *context;
Packit Service 2781ba
  gboolean             success = FALSE;
Packit Service 2781ba
Packit Service 2781ba
  g_return_val_if_fail (xmldata != NULL, NULL);
Packit Service 2781ba
Packit Service 2781ba
  pd.ids       = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
Packit Service 2781ba
  pd.refs      = NULL;
Packit Service 2781ba
  pd.path_root = path_root;
Packit Service 2781ba
Packit Service 2781ba
  g_list_free (pd.refs);
Packit Service 2781ba
  context = g_markup_parse_context_new   (&parser, 0, &pd, NULL);
Packit Service 2781ba
  success = g_markup_parse_context_parse (context,
Packit Service 2781ba
                                          xmldata,
Packit Service 2781ba
                                          strlen (xmldata),
Packit Service 2781ba
                                          NULL);
Packit Service 2781ba
  if (success)
Packit Service 2781ba
    {
Packit Service 2781ba
      /* connect clones */
Packit Service 2781ba
      g_list_foreach (pd.refs, each_ref, &pd;;
Packit Service 2781ba
    }
Packit Service 2781ba
  else
Packit Service 2781ba
    {
Packit Service 2781ba
      if (pd.gegl)
Packit Service 2781ba
        {
Packit Service 2781ba
          g_object_unref (pd.gegl);
Packit Service 2781ba
          pd.gegl = NULL;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  g_list_free (pd.refs);
Packit Service 2781ba
  g_list_free (pd.parent);
Packit Service 2781ba
  g_markup_parse_context_free (context);
Packit Service 2781ba
  g_hash_table_destroy (pd.ids);
Packit Service 2781ba
Packit Service 2781ba
  time = gegl_ticks () - time;
Packit Service 2781ba
  gegl_instrument ("gegl", "gegl_parse_xml", time);
Packit Service 2781ba
Packit Service 2781ba
  return success ? GEGL_NODE (pd.gegl) : NULL;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
GeglNode *
Packit Service 2781ba
gegl_node_new_from_file (const gchar   *path)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglNode *node = NULL;
Packit Service 2781ba
  GError   *err  = NULL;
Packit Service 2781ba
  gchar    *script;
Packit Service 2781ba
  gchar    *path_root;
Packit Service 2781ba
  gchar    *dirname;
Packit Service 2781ba
Packit Service 2781ba
  g_assert (path);
Packit Service 2781ba
Packit Service 2781ba
  dirname = g_path_get_dirname (path);
Packit Service 2781ba
  path_root = realpath (dirname, NULL);
Packit Service 2781ba
  if (!path_root)
Packit Service 2781ba
    {
Packit Service 2781ba
      goto cleanup;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  g_file_get_contents (path, &script, NULL, &err;;
Packit Service 2781ba
  if (err != NULL)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_warning ("Unable to read file: %s", err->message);
Packit Service 2781ba
      g_error_free (err);
Packit Service 2781ba
      goto cleanup;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  node = gegl_node_new_from_xml (script, path_root);
Packit Service 2781ba
Packit Service 2781ba
cleanup:
Packit Service 2781ba
  g_free (path_root);
Packit Service 2781ba
  g_free (dirname);
Packit Service 2781ba
  return node;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/****/
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
#define ind    do { gint i; for (i = 0; i < indent; i++) g_string_append (ss->buf, " "); } while (0)
Packit Service 2781ba
Packit Service 2781ba
typedef struct _SerializeState SerializeState;
Packit Service 2781ba
struct _SerializeState
Packit Service 2781ba
{
Packit Service 2781ba
  GString     *buf;
Packit Service 2781ba
  const gchar *path_root;
Packit Service 2781ba
  gint         clone_count;
Packit Service 2781ba
  GHashTable  *clones;
Packit Service 2781ba
  gboolean     terse;
Packit Service 2781ba
};
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
free_clone_id (gpointer key,
Packit Service 2781ba
               gpointer value,
Packit Service 2781ba
               gpointer user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  g_free (value);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_attr (GString     *buf,
Packit Service 2781ba
          const gchar *key,
Packit Service 2781ba
          const gchar *value)
Packit Service 2781ba
{
Packit Service 2781ba
  g_assert (key);
Packit Service 2781ba
Packit Service 2781ba
  if (value)
Packit Service 2781ba
    {
Packit Service 2781ba
      gchar *text = g_markup_escape_text (value, -1);
Packit Service 2781ba
      gchar *p;
Packit Service 2781ba
Packit Service 2781ba
      g_string_append_c (buf, ' ');
Packit Service 2781ba
      g_string_append (buf, key);
Packit Service 2781ba
      g_string_append_c (buf, '=');
Packit Service 2781ba
      g_string_append_c (buf, '\'');
Packit Service 2781ba
      for (p = text; *p; p++)
Packit Service 2781ba
        {
Packit Service 2781ba
          if (*p == '\n')
Packit Service 2781ba
            g_string_append (buf, "
");
Packit Service 2781ba
          else
Packit Service 2781ba
            g_string_append_c (buf, *p);
Packit Service 2781ba
        }
Packit Service 2781ba
      g_string_append_c (buf, '\'');
Packit Service 2781ba
Packit Service 2781ba
      g_free (text);
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_param_start (SerializeState *ss,
Packit Service 2781ba
                 gint            indent,
Packit Service 2781ba
                 const gchar    *key)
Packit Service 2781ba
{
Packit Service 2781ba
  g_assert (key);
Packit Service 2781ba
  ind; g_string_append (ss->buf, "
Packit Service 2781ba
  g_string_append (ss->buf, key);
Packit Service 2781ba
  g_string_append (ss->buf, "'>");
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_param_text (SerializeState *ss,
Packit Service 2781ba
                const gchar    *value)
Packit Service 2781ba
{
Packit Service 2781ba
  gchar *text;
Packit Service 2781ba
  /*gchar *p;*/
Packit Service 2781ba
Packit Service 2781ba
  g_assert (value);
Packit Service 2781ba
Packit Service 2781ba
  /* Why isn't this used here??? */
Packit Service 2781ba
  text = g_markup_escape_text (value, -1);
Packit Service 2781ba
Packit Service 2781ba
  g_string_append (ss->buf, value);
Packit Service 2781ba
  /*for (p=text;*p;p++)
Packit Service 2781ba
    {
Packit Service 2781ba
    if (*p=='\n')
Packit Service 2781ba
    g_string_append (ss->buf, "
");
Packit Service 2781ba
    else
Packit Service 2781ba
    g_string_append_c (ss->buf, *p);
Packit Service 2781ba
Packit Service 2781ba
    }*/
Packit Service 2781ba
Packit Service 2781ba
  g_free (text);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_param_end (SerializeState *ss)
Packit Service 2781ba
{
Packit Service 2781ba
  g_string_append (ss->buf, "</param>\n");
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_param (SerializeState *ss,
Packit Service 2781ba
           gint            indent,
Packit Service 2781ba
           const gchar    *key,
Packit Service 2781ba
           const gchar    *value)
Packit Service 2781ba
{
Packit Service 2781ba
  g_assert (key);
Packit Service 2781ba
Packit Service 2781ba
  if (value)
Packit Service 2781ba
  {
Packit Service 2781ba
    xml_param_start (ss, indent, key);
Packit Service 2781ba
    xml_param_text (ss, value);
Packit Service 2781ba
    xml_param_end (ss);
Packit Service 2781ba
  }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_curve_point (SerializeState *ss,
Packit Service 2781ba
                 gint            indent,
Packit Service 2781ba
                 gfloat          x,
Packit Service 2781ba
                 gfloat          y)
Packit Service 2781ba
{
Packit Service 2781ba
  gchar str[64];
Packit Service 2781ba
  ind; g_string_append (ss->buf, "
Packit Service 2781ba
  g_ascii_dtostr (str, sizeof(str), x);
Packit Service 2781ba
  g_string_append (ss->buf, str);
Packit Service 2781ba
  g_string_append (ss->buf, "' y='");
Packit Service 2781ba
  g_ascii_dtostr (str, sizeof(str), y);
Packit Service 2781ba
  g_string_append (ss->buf, str);
Packit Service 2781ba
  g_string_append (ss->buf, "'/>\n");
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
xml_curve (SerializeState *ss,
Packit Service 2781ba
           gint            indent,
Packit Service 2781ba
           GeglCurve      *curve)
Packit Service 2781ba
{
Packit Service 2781ba
  gchar str[G_ASCII_DTOSTR_BUF_SIZE];
Packit Service 2781ba
  gdouble min_y, max_y;
Packit Service 2781ba
  guint num_points = gegl_curve_num_points (curve);
Packit Service 2781ba
  guint i;
Packit Service 2781ba
Packit Service 2781ba
  gegl_curve_get_y_bounds (curve, &min_y, &max_y);
Packit Service 2781ba
Packit Service 2781ba
  ind; g_string_append (ss->buf, "
Packit Service 2781ba
  g_ascii_dtostr (str, sizeof(str), min_y);
Packit Service 2781ba
  g_string_append (ss->buf, str);
Packit Service 2781ba
  g_string_append (ss->buf, "' ymax='");
Packit Service 2781ba
  g_ascii_dtostr (str, sizeof(str), max_y);
Packit Service 2781ba
  g_string_append (ss->buf, str);
Packit Service 2781ba
  g_string_append (ss->buf, "'>\n");
Packit Service 2781ba
  for (i = 0; i < num_points; ++i)
Packit Service 2781ba
    {
Packit Service 2781ba
      gdouble x, y;
Packit Service 2781ba
      gegl_curve_get_point (curve, i, &x, &y);
Packit Service 2781ba
      xml_curve_point (ss, indent + 2, x, y);
Packit Service 2781ba
    }
Packit Service 2781ba
  ind; g_string_append (ss->buf, "</curve>\n");
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
serialize_properties (SerializeState *ss,
Packit Service 2781ba
                      gint            indent,
Packit Service 2781ba
                      GeglNode       *node)
Packit Service 2781ba
{
Packit Service 2781ba
  GParamSpec **properties;
Packit Service 2781ba
  guint        n_properties;
Packit Service 2781ba
  gboolean     got_a_param = FALSE;
Packit Service 2781ba
  gint         i;
Packit Service 2781ba
Packit Service 2781ba
  properties = gegl_operation_list_properties (gegl_node_get_operation (node),
Packit Service 2781ba
                                     &n_properties);
Packit Service 2781ba
Packit Service 2781ba
  for (i = 0; i < n_properties; i++)
Packit Service 2781ba
    {
Packit Service 2781ba
      if (strcmp (properties[i]->name, "input") &&
Packit Service 2781ba
          strcmp (properties[i]->name, "output") &&
Packit Service 2781ba
          strcmp (properties[i]->name, "aux"))
Packit Service 2781ba
        {
Packit Service 2781ba
          if (!got_a_param)
Packit Service 2781ba
            {
Packit Service 2781ba
              ind; g_string_append (ss->buf, "<params>\n");
Packit Service 2781ba
              got_a_param = TRUE;
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          if (g_type_is_a (G_PARAM_SPEC_TYPE (properties[i]),
Packit Service 2781ba
                           GEGL_TYPE_PARAM_FILE_PATH))
Packit Service 2781ba
            {
Packit Service 2781ba
              gchar *value;
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
Packit Service 2781ba
              if (value)
Packit Service 2781ba
                {
Packit Service 2781ba
                  if (ss->path_root &&
Packit Service 2781ba
                      !strncmp (ss->path_root, value, strlen (ss->path_root)))
Packit Service 2781ba
                    {
Packit Service 2781ba
                      xml_param (ss, indent + 2, properties[i]->name, &value[strlen (ss->path_root) + 1]);
Packit Service 2781ba
                    }
Packit Service 2781ba
                  else
Packit Service 2781ba
                    {
Packit Service 2781ba
                      xml_param (ss, indent + 2, properties[i]->name, value);
Packit Service 2781ba
                    }
Packit Service 2781ba
                }
Packit Service 2781ba
Packit Service 2781ba
              g_free (value);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == G_TYPE_FLOAT)
Packit Service 2781ba
            {
Packit Service 2781ba
              gfloat value;
Packit Service 2781ba
              gchar  str[G_ASCII_DTOSTR_BUF_SIZE];
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
              g_ascii_dtostr (str, sizeof(str), value);
Packit Service 2781ba
              xml_param (ss, indent + 2, properties[i]->name, str);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == G_TYPE_DOUBLE)
Packit Service 2781ba
            {
Packit Service 2781ba
              gdouble value;
Packit Service 2781ba
              gchar   str[G_ASCII_DTOSTR_BUF_SIZE];
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
              g_ascii_dtostr (str, sizeof(str), value);
Packit Service 2781ba
              xml_param (ss, indent + 2, properties[i]->name, str);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == G_TYPE_INT)
Packit Service 2781ba
            {
Packit Service 2781ba
              gint  value;
Packit Service 2781ba
              gchar str[64];
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
              g_snprintf (str, sizeof (str), "%i", value);
Packit Service 2781ba
              xml_param (ss, indent + 2, properties[i]->name, str);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == G_TYPE_BOOLEAN)
Packit Service 2781ba
            {
Packit Service 2781ba
              gboolean value;
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
              if (value)
Packit Service 2781ba
                {
Packit Service 2781ba
                  xml_param (ss, indent + 2, properties[i]->name, "true");
Packit Service 2781ba
                }
Packit Service 2781ba
              else
Packit Service 2781ba
                {
Packit Service 2781ba
                  xml_param (ss, indent + 2, properties[i]->name, "false");
Packit Service 2781ba
                }
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == G_TYPE_STRING)
Packit Service 2781ba
            {
Packit Service 2781ba
              gchar *value;
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
              xml_param (ss, indent + 2, properties[i]->name, value);
Packit Service 2781ba
              g_free (value);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (g_type_is_a (properties[i]->value_type, G_TYPE_ENUM))
Packit Service 2781ba
            {
Packit Service 2781ba
              GEnumClass *eclass = g_type_class_peek (properties[i]->value_type);
Packit Service 2781ba
              GEnumValue *evalue;
Packit Service 2781ba
              gint value;
Packit Service 2781ba
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &value, NULL);
Packit Service 2781ba
              evalue = g_enum_get_value (eclass, value);
Packit Service 2781ba
Packit Service 2781ba
              xml_param (ss, indent + 2, properties[i]->name, evalue->value_nick);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == GEGL_TYPE_COLOR)
Packit Service 2781ba
            {
Packit Service 2781ba
              GeglColor *color;
Packit Service 2781ba
              gchar     *value;
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &color, NULL);
Packit Service 2781ba
              g_object_get (color, "string", &value, NULL);
Packit Service 2781ba
              g_object_unref (color);
Packit Service 2781ba
              xml_param (ss, indent + 2, properties[i]->name, value);
Packit Service 2781ba
              g_free (value);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == GEGL_TYPE_CURVE)
Packit Service 2781ba
            {
Packit Service 2781ba
              GeglCurve *curve;
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &curve, NULL);
Packit Service 2781ba
              xml_param_start (ss, indent + 2, properties[i]->name);
Packit Service 2781ba
              g_string_append (ss->buf, "\n");
Packit Service 2781ba
              xml_curve (ss, indent + 4, curve);
Packit Service 2781ba
              indent += 2; ind; indent -= 2; xml_param_end (ss);
Packit Service 2781ba
              g_object_unref (curve);
Packit Service 2781ba
            }
Packit Service 2781ba
          else if (properties[i]->value_type == GEGL_TYPE_PATH)
Packit Service 2781ba
            {
Packit Service 2781ba
              gchar *svg_path;
Packit Service 2781ba
              GeglPath *path;
Packit Service 2781ba
              gegl_node_get (node, properties[i]->name, &path, NULL);
Packit Service 2781ba
              xml_param_start (ss, indent + 2, properties[i]->name);
Packit Service 2781ba
              svg_path = gegl_path_to_string (path);
Packit Service 2781ba
              g_string_append (ss->buf, svg_path);
Packit Service 2781ba
              xml_param_end (ss);
Packit Service 2781ba
Packit Service 2781ba
              g_object_unref (path);
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              g_warning ("%s: serialization of %s properties not implemented",
Packit Service 2781ba
                         properties[i]->name, g_type_name (properties[i]->value_type));
Packit Service 2781ba
            }
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (got_a_param)
Packit Service 2781ba
    {
Packit Service 2781ba
      ind; g_string_append (ss->buf, "</params>\n");
Packit Service 2781ba
    }
Packit Service 2781ba
  g_free (properties);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
serialize_layer (SerializeState *ss,
Packit Service 2781ba
                 gint            indent,
Packit Service 2781ba
                 GeglNode       *layer)
Packit Service 2781ba
{
Packit Service 2781ba
  gchar  *name;
Packit Service 2781ba
  gchar  *src;
Packit Service 2781ba
  gchar  *composite_op;
Packit Service 2781ba
  gdouble x;
Packit Service 2781ba
  gdouble y;
Packit Service 2781ba
  gdouble opacity;
Packit Service 2781ba
Packit Service 2781ba
  gegl_node_get (layer, "name", &name,
Packit Service 2781ba
                 "src", &src,
Packit Service 2781ba
                 "x", &x,
Packit Service 2781ba
                 "y", &y,
Packit Service 2781ba
                 "opacity", &opacity,
Packit Service 2781ba
                 "composite_op", &composite_op,
Packit Service 2781ba
                 NULL);
Packit Service 2781ba
  ind; g_string_append (ss->buf, "
Packit Service 2781ba
  if (name[0])
Packit Service 2781ba
    g_string_append_printf (ss->buf, " name='%s'", name);
Packit Service 2781ba
  if (x != 0.0)
Packit Service 2781ba
    {
Packit Service 2781ba
      gchar str[G_ASCII_DTOSTR_BUF_SIZE];
Packit Service 2781ba
      g_ascii_dtostr (str, sizeof(str), x);
Packit Service 2781ba
      g_string_append_printf (ss->buf, " x='%s'", str);
Packit Service 2781ba
    }
Packit Service 2781ba
  if (y != 0.0)
Packit Service 2781ba
    {
Packit Service 2781ba
      gchar str[G_ASCII_DTOSTR_BUF_SIZE];
Packit Service 2781ba
      g_ascii_dtostr (str, sizeof(str), y);
Packit Service 2781ba
      g_string_append_printf (ss->buf, " y='%s'", str);
Packit Service 2781ba
    }
Packit Service 2781ba
  if (opacity != 1.0)
Packit Service 2781ba
    {
Packit Service 2781ba
      gchar str[G_ASCII_DTOSTR_BUF_SIZE];
Packit Service 2781ba
      g_ascii_dtostr (str, sizeof(str), opacity);
Packit Service 2781ba
      g_string_append_printf (ss->buf, " opacity='%s'", str);
Packit Service 2781ba
    }
Packit Service 2781ba
  if (src[0])
Packit Service 2781ba
    {
Packit Service 2781ba
      if (ss->path_root &&
Packit Service 2781ba
          !strncmp (ss->path_root, src, strlen (ss->path_root)))
Packit Service 2781ba
        {
Packit Service 2781ba
          g_string_append_printf (ss->buf, " src='%s'", &src[strlen (ss->path_root) + 1]);
Packit Service 2781ba
        }
Packit Service 2781ba
      else
Packit Service 2781ba
        {
Packit Service 2781ba
          g_string_append_printf (ss->buf, " src='%s'", src);
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
  g_string_append (ss->buf, "/>\n");
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
add_stack (SerializeState *ss,
Packit Service 2781ba
           gint            indent,
Packit Service 2781ba
           GeglNode       *head)
Packit Service 2781ba
{
Packit Service 2781ba
  /*ind; g_string_append (ss->buf, "<stack>\n");
Packit Service 2781ba
     indent+=2;*/
Packit Service 2781ba
Packit Service 2781ba
  if (GEGL_IS_NODE (head))
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglNode *iter = head;
Packit Service 2781ba
Packit Service 2781ba
      while (iter)
Packit Service 2781ba
        {
Packit Service 2781ba
          GeglPad     *input, *aux;
Packit Service 2781ba
          const gchar *id = NULL;
Packit Service 2781ba
          gchar       *class;
Packit Service 2781ba
          gegl_node_get (iter, "operation", &class, NULL);
Packit Service 2781ba
Packit Service 2781ba
          input = gegl_node_get_pad (iter, "input");
Packit Service 2781ba
          aux   = gegl_node_get_pad (iter, "aux");
Packit Service 2781ba
Packit Service 2781ba
          if (gegl_node_get_num_sinks (iter) > 1)
Packit Service 2781ba
            {
Packit Service 2781ba
              const gchar *new_id = g_hash_table_lookup (ss->clones, iter);
Packit Service 2781ba
              if (new_id)
Packit Service 2781ba
                {
Packit Service 2781ba
                  ind; g_string_append (ss->buf, "
Packit Service 2781ba
                  g_string_append (ss->buf, new_id);
Packit Service 2781ba
                  g_string_append (ss->buf, "'/>\n");
Packit Service 2781ba
                  return; /* terminate the stack, the cloned part is already
Packit Service 2781ba
                             serialized */
Packit Service 2781ba
                }
Packit Service 2781ba
              else
Packit Service 2781ba
                {
Packit Service 2781ba
                  gchar temp_id[64];
Packit Service 2781ba
                  g_snprintf (temp_id, sizeof (temp_id),
Packit Service 2781ba
                              "clone%i", ss->clone_count++);
Packit Service 2781ba
                  id = g_strdup (temp_id);
Packit Service 2781ba
                  g_hash_table_insert (ss->clones, iter, (gchar *) id);
Packit Service 2781ba
                  /* the allocation is freed by the hash table */
Packit Service 2781ba
                }
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          if (class)
Packit Service 2781ba
            {
Packit Service 2781ba
              if (!strcmp (class, "layer"))
Packit Service 2781ba
                {
Packit Service 2781ba
                  serialize_layer (ss, indent, iter);
Packit Service 2781ba
                }
Packit Service 2781ba
              else
Packit Service 2781ba
                {
Packit Service 2781ba
                  if (aux &&
Packit Service 2781ba
                      gegl_pad_get_connected_to (aux))
Packit Service 2781ba
                    {
Packit Service 2781ba
                      GeglPad  *source_pad;
Packit Service 2781ba
                      GeglNode *source_node;
Packit Service 2781ba
                      source_pad  = gegl_pad_get_connected_to (aux);
Packit Service 2781ba
                      source_node = gegl_pad_get_node (source_pad);
Packit Service 2781ba
                      {
Packit Service 2781ba
                        GeglNode *graph = g_object_get_data (G_OBJECT (source_node),
Packit Service 2781ba
                                                             "graph");
Packit Service 2781ba
                        if (graph)
Packit Service 2781ba
                          source_node = graph;
Packit Service 2781ba
                      }
Packit Service 2781ba
                      ind; g_string_append (ss->buf, "
Packit Service 2781ba
Packit Service 2781ba
                      {
Packit Service 2781ba
                        gchar *class;
Packit Service 2781ba
                        gchar *name;
Packit Service 2781ba
                        gegl_node_get (iter, "operation", &class,
Packit Service 2781ba
                                       "name", &name,
Packit Service 2781ba
                                       NULL);
Packit Service 2781ba
                        if (name[0])
Packit Service 2781ba
                          {
Packit Service 2781ba
                            xml_attr (ss->buf, "name", name);
Packit Service 2781ba
                          }
Packit Service 2781ba
                        xml_attr (ss->buf, "operation", class);
Packit Service 2781ba
                        if (id != NULL)
Packit Service 2781ba
                          xml_attr (ss->buf, "id", id);
Packit Service 2781ba
                        g_free (name);
Packit Service 2781ba
                        g_free (class);
Packit Service 2781ba
                      }
Packit Service 2781ba
Packit Service 2781ba
                      g_string_append (ss->buf, ">\n");
Packit Service 2781ba
                      serialize_properties (ss, indent + 4, iter);
Packit Service 2781ba
                      add_stack (ss, indent + 4, source_node);
Packit Service 2781ba
Packit Service 2781ba
                      ind; g_string_append (ss->buf, "</node>\n");
Packit Service 2781ba
                    }
Packit Service 2781ba
                  else
Packit Service 2781ba
                    {
Packit Service 2781ba
                      if (strcmp (class, "gegl:nop") &&
Packit Service 2781ba
                          strcmp (class, "gegl:clone"))
Packit Service 2781ba
                        {
Packit Service 2781ba
                          ind; g_string_append (ss->buf, "
Packit Service 2781ba
Packit Service 2781ba
                          {
Packit Service 2781ba
                            gchar *class;
Packit Service 2781ba
                            gchar *name;
Packit Service 2781ba
                            gegl_node_get (iter, "operation", &class,
Packit Service 2781ba
                                           "name", &name,
Packit Service 2781ba
                                           NULL);
Packit Service 2781ba
                            if (name[0])
Packit Service 2781ba
                              {
Packit Service 2781ba
                                xml_attr (ss->buf, "name", name);
Packit Service 2781ba
                              }
Packit Service 2781ba
                            xml_attr (ss->buf, "operation", class);
Packit Service 2781ba
                            if (id != NULL)
Packit Service 2781ba
                              xml_attr (ss->buf, "id", id);
Packit Service 2781ba
                            g_free (name);
Packit Service 2781ba
                            g_free (class);
Packit Service 2781ba
                          }
Packit Service 2781ba
Packit Service 2781ba
                          g_string_append (ss->buf, ">\n");
Packit Service 2781ba
                          serialize_properties (ss, indent + 4, iter);
Packit Service 2781ba
                          ind; g_string_append (ss->buf, "</node>\n");
Packit Service 2781ba
                        }
Packit Service 2781ba
                    }
Packit Service 2781ba
                }
Packit Service 2781ba
            }
Packit Service 2781ba
          id = NULL;
Packit Service 2781ba
          if (input)
Packit Service 2781ba
            {
Packit Service 2781ba
              GeglPad *source_pad;
Packit Service 2781ba
              source_pad = gegl_pad_get_connected_to (input);
Packit Service 2781ba
              if (source_pad)
Packit Service 2781ba
                {
Packit Service 2781ba
                  GeglNode *source_node = gegl_pad_get_node (source_pad);
Packit Service 2781ba
                  GeglNode *graph       = g_object_get_data (G_OBJECT (source_node),
Packit Service 2781ba
                                                             "graph");
Packit Service 2781ba
                  if (graph)
Packit Service 2781ba
                    source_node = graph;
Packit Service 2781ba
                  iter = source_node;
Packit Service 2781ba
                }
Packit Service 2781ba
              else
Packit Service 2781ba
                iter = NULL;
Packit Service 2781ba
            }
Packit Service 2781ba
          else
Packit Service 2781ba
            {
Packit Service 2781ba
              iter = NULL;
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          g_free (class);
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
  /*indent-=2;
Packit Service 2781ba
     ind; g_string_append (ss->buf, "<stack>\n");*/
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
gchar *
Packit Service 2781ba
gegl_node_to_xml (GeglNode    *gegl,
Packit Service 2781ba
                  const gchar *path_root)
Packit Service 2781ba
{
Packit Service 2781ba
  SerializeState  ss;
Packit Service 2781ba
Packit Service 2781ba
  ss.buf         = g_string_new ("");
Packit Service 2781ba
  ss.path_root   = path_root;
Packit Service 2781ba
  ss.clone_count = 0;
Packit Service 2781ba
  ss.clones      = g_hash_table_new (NULL, NULL);
Packit Service 2781ba
  ss.terse       = FALSE;
Packit Service 2781ba
Packit Service 2781ba
  gegl = gegl_node_get_output_proxy (gegl, "output");
Packit Service 2781ba
Packit Service 2781ba
  g_string_append (ss.buf, "\n");
Packit Service 2781ba
  g_string_append (ss.buf, "<gegl>\n");
Packit Service 2781ba
Packit Service 2781ba
  add_stack (&ss, 2, gegl);
Packit Service 2781ba
Packit Service 2781ba
  g_string_append (ss.buf, "</gegl>\n");
Packit Service 2781ba
Packit Service 2781ba
  g_hash_table_foreach (ss.clones, free_clone_id, NULL);
Packit Service 2781ba
  g_hash_table_destroy (ss.clones);
Packit Service 2781ba
Packit Service 2781ba
  return g_string_free (ss.buf, FALSE);
Packit Service 2781ba
}