vizml work
[pspp] / src / output / spv / spv.c
index f186e638e70c9f8944a31a826081bc36f3f5e296..ecb008c9911fd5027f6a7f363889c0a850ac19a6 100644 (file)
@@ -40,6 +40,7 @@
 #include "output/spv/spv-legacy-decoder.h"
 #include "output/spv/spv-light-decoder.h"
 #include "output/spv/structure-xml-parser.h"
+#include "output/spv/vizml-parser.h"
 
 #include "gl/c-ctype.h"
 #include "gl/intprops.h"
@@ -181,6 +182,12 @@ spv_item_is_table (const struct spv_item *item)
   return item->type == SPV_ITEM_TABLE;
 }
 
+bool
+spv_item_is_graph (const struct spv_item *item)
+{
+  return item->type == SPV_ITEM_GRAPH;
+}
+
 bool
 spv_item_is_text (const struct spv_item *item)
 {
@@ -572,6 +579,8 @@ spv_item_load (const struct spv_item *item)
 {
   if (spv_item_is_table (item))
     spv_item_get_table (item);
+  else if (spv_item_is_graph (item))
+    spv_item_get_graph (item);
 }
 
 bool
@@ -652,8 +661,11 @@ char * WARN_UNUSED_RESULT
 spv_item_get_raw_legacy_data (const struct spv_item *item,
                               void **data, size_t *size)
 {
-  if (!spv_item_is_legacy_table (item))
-    return xstrdup ("not a legacy table object");
+  if (!spv_item_is_legacy_table (item) && !spv_item_is_graph (item))
+    return xstrdup ("not a graph or legacy table object");
+
+  if (!item->bin_member)
+    return xstrdup ("graph or legacy table lacks legacy data");
 
   return zip_member_read_all (item->spv->zip, item->bin_member, data, size);
 }
@@ -873,6 +885,74 @@ spv_item_get_table (const struct spv_item *item_)
   return item->table;
 }
 
+static char * WARN_UNUSED_RESULT
+spv_open_graph (struct spv_item *item)
+{
+  assert (spv_item_is_graph (item));
+
+  struct spv_data data;
+  char *error = spv_item_get_legacy_data (item, &data);
+  if (error)
+    {
+      struct string s = DS_EMPTY_INITIALIZER;
+      spv_item_format_path (item, &s);
+      ds_put_format (&s, " (%s): %s", item->bin_member, error);
+
+      free (error);
+      return ds_steal_cstr (&s);
+    }
+
+  xmlDoc *doc;
+  error = spv_read_xml_member (item->spv, item->xml_member, false,
+                               "visualization", &doc);
+  if (error)
+    {
+      spv_data_uninit (&data);
+      return error;
+    }
+
+  struct spvxml_context ctx = SPVXML_CONTEXT_INIT (ctx);
+  struct vizml_visualization *v;
+  vizml_parse_visualization (&ctx, xmlDocGetRootElement (doc), &v);
+  error = spvxml_context_finish (&ctx, &v->node_);
+
+  if (error)
+    {
+      struct string s = DS_EMPTY_INITIALIZER;
+      spv_item_format_path (item, &s);
+      ds_put_format (&s, " (%s): %s", item->xml_member, error);
+
+      free (error);
+      error = ds_steal_cstr (&s);
+    }
+
+  spv_data_uninit (&data);
+  vizml_free_visualization (v);
+  if (doc)
+    xmlFreeDoc (doc);
+
+  return error;
+}
+
+void
+spv_item_get_graph (const struct spv_item *item_)
+{
+  struct spv_item *item = CONST_CAST (struct spv_item *, item_);
+
+  assert (spv_item_is_graph (item));
+  if (!item->graph)
+    {
+      item->graph = true;
+      char *error = spv_open_graph (item);
+      if (error)
+        {
+          item->error = true;
+          msg (ME, "%s", error);
+          free (error);
+        }
+    }
+}
+
 /* Constructs a new spv_item from XML and stores it in *ITEMP.  Returns NULL if
    successful, otherwise an error message for the caller to use and free (with
    free()).
@@ -904,7 +984,7 @@ spv_decode_container (const struct spvsx_container *c,
       item->subtype = xstrdup_if_nonempty (table->sub_type);
       if (ts->path)
         {
-          item->xml_member = ts->path ? xstrdup (ts->path->text) : NULL;
+          item->xml_member = xstrdup_if_nonempty (ts->path->text);
           char *error = decode_spvsx_legacy_properties (
             table->table_properties, &item->legacy_properties);
           if (error)
@@ -916,10 +996,12 @@ spv_decode_container (const struct spvsx_container *c,
     }
   else if (spvsx_is_graph (content))
     {
-      struct spvsx_graph *graph = spvsx_cast_graph (content);
       item->type = SPV_ITEM_GRAPH;
+
+      struct spvsx_graph *graph = spvsx_cast_graph (content);
+      item->bin_member = xstrdup_if_nonempty (graph->data_path->text);
       item->command_id = xstrdup_if_nonempty (graph->command_name);
-      /* XXX */
+      item->xml_member = xstrdup_if_nonempty (graph->path->text);
     }
   else if (spvsx_is_model (content))
     {