Started polymorphism of ODS
authorJohn Darrington <john@darrington.wattle.id.au>
Sun, 13 Jan 2013 15:01:45 +0000 (16:01 +0100)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 16 Feb 2013 14:03:10 +0000 (15:03 +0100)
src/data/ods-reader.c
src/data/ods-reader.h
src/data/spreadsheet-reader.h
src/language/data-io/get-data.c
src/ui/gui/page-assistant.c
src/ui/gui/page-file.c
src/ui/gui/page-sheet-spec.c
src/ui/gui/text-data-import-dialog.c
src/ui/gui/text-data-import-dialog.h

index 85d3bc7dc10b47133ffe943fb0e408b5f419bfb7..2ce4e7eb9ba268d188564b94a9d4dc24df0b0d42 100644 (file)
@@ -336,55 +336,104 @@ convert_xml_to_value (struct ccase *c, const struct variable *var,
 }
 
 
-struct casereader *
-ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_read_options *opts,
-                struct dictionary **dict)
+/* Try to find out how many sheets there are in the "workbook" */
+static int
+get_sheet_count (struct zip_reader *zreader)
 {
-  int ret = 0;
-  xmlChar *type = NULL;
-  unsigned long int vstart = 0;
-  casenumber n_cases = CASENUMBER_MAX;
-  int i;
-  struct var_spec *var_spec = NULL;
-  int n_var_specs = 0;
+  xmlTextReaderPtr mxtr;
+  struct zip_member *meta = NULL;
+  meta = zip_member_open (zreader, "meta.xml");
+
+  if ( meta == NULL)
+    return -1;
+
+  mxtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
+                        (xmlInputCloseCallback) zip_member_finish,
+                        meta,   NULL, NULL, XML_PARSE_RECOVER);
+
+  while (1 == xmlTextReaderRead (mxtr))
+    {
+      xmlChar *name = xmlTextReaderName (mxtr);
+      if ( 0 == xmlStrcmp (name, _xml("meta:document-statistic")))
+       {
+         xmlChar *attr = xmlTextReaderGetAttribute (mxtr, _xml ("meta:table-count"));
+           
+         if ( attr != NULL)
+           {
+             int s = _xmlchar_to_int (attr);
+             return s;
+           }
+       }
+    }
+  return -1;
+}
 
-  struct ods_reader *r = xzalloc (sizeof *r);
+struct spreadsheet *ods_probe (const char *filename)
+{
+  struct ods_reader *r;
+  struct string errs;
+  xmlTextReaderPtr xtr ;
+  int sheet_count;
   struct zip_member *content = NULL;
-  struct zip_reader *zreader ;
-  xmlChar *val_string = NULL;
 
-  r->read_names = gri->read_names;
-  ds_init_empty (&r->ods_errs);
+  struct zip_reader *zreader = NULL;
 
-  zreader = zip_reader_create (gri->file_name, &r->ods_errs);
+  ds_init_empty (&errs);
 
-  if ( NULL == zreader)
-    {
-      msg (ME, _("Error opening `%s' for reading as a OpenDocument spreadsheet file: %s."),
-           gri->file_name, ds_cstr (&r->ods_errs));
+  zreader = zip_reader_create (filename, &errs);
 
-      goto error;
-    }
+  if (zreader == NULL)
+    return NULL;
 
   content = zip_member_open (zreader, "content.xml");
-  if ( NULL == content)
-    {
-      msg (ME, _("Could not extract OpenDocument spreadsheet from file `%s': %s."),
-           gri->file_name, ds_cstr (&r->ods_errs));
 
-      goto error;
-    }
+  if ( content == NULL)
+    goto error;
 
   zip_member_ref (content);
 
-  r->xtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
+  sheet_count = get_sheet_count (zreader);
+
+  xtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
                           (xmlInputCloseCallback) zip_member_finish,
                           content,   NULL, NULL, XML_PARSE_RECOVER);
 
-  if ( r->xtr == NULL)
-    {
-      goto error;
-    }
+  if ( xtr == NULL)
+    goto error;
+
+  r = xzalloc (sizeof *r);
+  r->xtr = xtr;
+  r->spreadsheet.type = SPREADSHEET_ODS;
+  r->spreadsheet.sheets = sheet_count;
+
+  ds_destroy (&errs);
+
+  return &r->spreadsheet;
+
+ error:
+  zip_reader_destroy (zreader);
+  ds_destroy (&errs);
+  return NULL;
+}
+
+struct casereader *
+ods_make_reader (struct spreadsheet *spreadsheet, 
+                const struct spreadsheet_read_info *gri, struct spreadsheet_read_options *opts)
+{
+  intf ret = 0;
+  xmlChar *type = NULL;
+  unsigned long int vstart = 0;
+  casenumber n_cases = CASENUMBER_MAX;
+  int i;
+  struct var_spec *var_spec = NULL;
+  int n_var_specs = 0;
+
+  struct ods_reader *r = (struct ods_reader *) spreadsheet;
+  xmlChar *val_string = NULL;
+
+  assert (r);
+  r->read_names = gri->read_names;
+  ds_init_empty (&r->ods_errs);
 
   if ( opts->cell_range )
     {
@@ -517,7 +566,7 @@ ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_rea
     }
 
   /* Create the dictionary and populate it */
-  *dict = r->dict = dict_create (
+  r->spreadsheet.dict = r->dict = dict_create (
     CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->xtr)));
 
   for (i = 0 ; i < n_var_specs ; ++i )
@@ -564,7 +613,7 @@ ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_rea
       convert_xml_to_value (r->first_case, var,  &var_spec[i].firstval);
     }
 
-  zip_reader_destroy (zreader);
+  //  zip_reader_destroy (zreader);
 
   for ( i = 0 ; i < n_var_specs ; ++i )
     {
@@ -584,7 +633,7 @@ ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_rea
 
  error:
   
-  zip_reader_destroy (zreader);
+  // zip_reader_destroy (zreader);
 
   for ( i = 0 ; i < n_var_specs ; ++i )
     {
@@ -596,7 +645,8 @@ ods_open_reader (const struct spreadsheet_read_info *gri, struct spreadsheet_rea
 
   free (var_spec);
 
-  dict_destroy (r->dict);
+  dict_destroy (r->spreadsheet.dict);
+  r->spreadsheet.dict = NULL;
   ods_file_casereader_destroy (NULL, r);
 
 
@@ -623,7 +673,6 @@ ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
       return r->first_case;
     }
 
-
   if ( r->state > STATE_INIT)
     {
       c = case_create (r->proto);
index b26997cfc1958ef5f1c156942eefbc6a7febe234..18eb65bc90f279ff0565bcd5c2f3dec447fe3d51 100644 (file)
@@ -23,9 +23,11 @@ struct spreadsheet_read_info;
 struct spreadsheet_read_options;
 
 
-struct casereader * ods_open_reader (const struct spreadsheet_read_info *,
-                                    struct spreadsheet_read_options *,
-                                    struct dictionary **);
+struct spreadsheet *ods_probe (const char *filename);
+
+struct casereader * ods_make_reader (struct spreadsheet *spreadsheet, 
+                                    const struct spreadsheet_read_info *gri,
+                                    struct spreadsheet_read_options *opts);
 
 
 #endif
index 3fbbde1d21f605242ad1117b64345a155764c7e5..77ed5ab9dbbe6551f59126ed21a6da2c3e53575f 100644 (file)
@@ -54,6 +54,7 @@ bool convert_cell_ref (const char *ref,
 
 enum spreadsheet_type
   {
+    SPREADSHEET_NONE,
     SPREADSHEET_GNUMERIC,
     SPREADSHEET_ODS
   };
index 723a16c8d1361cfe0d4fe832d2cc469a9b0b07c7..cca86a2bd838bf5b83f9f89f9e0530a83301a188 100644 (file)
@@ -93,7 +93,9 @@ cmd_get_data (struct lexer *lexer, struct dataset *ds)
        }
       else if (0 == strncasecmp (tok, "ODS", 3))
        {
-         reader = ods_open_reader (&sri, &opts, &dict);
+         struct spreadsheet *spreadsheet = ods_probe (sri.file_name);
+         reader = ods_make_reader (spreadsheet, &sri, &opts);
+         dict = spreadsheet->dict;
        }
 
       if (reader)
index 9ef5782a30f003fd0a1a84c707f2b37471e40e73..0d43248bac4682fc2db959e5822549671c83a2f0 100644 (file)
@@ -148,9 +148,11 @@ static void
 on_prepare (GtkAssistant *assistant, GtkWidget *page,
             struct import_assistant *ia)
 {
+  struct sheet_spec_page *ssp = &ia->sheet_spec;
+
   int pn = gtk_assistant_get_current_page (assistant);
 
-  if (pn == 1 && ia->file.type != FTYPE_TEXT)
+  if (pn == 1 && ssp->spreadsheet)
     post_sheet_spec_page (ia);
 
   if (gtk_assistant_get_page_type (assistant, page)
@@ -165,8 +167,10 @@ on_prepare (GtkAssistant *assistant, GtkWidget *page,
     prepare_separators_page (ia);
   else if (page == ia->formats.page)
     prepare_formats_page (ia);
-  else if (page == ia->sheet_spec.page)
-    prepare_sheet_spec_page (ia);
+  else if (page == ia->sheet_spec.page && ssp->spreadsheet)
+    {
+      prepare_sheet_spec_page (ia);
+    }
 
 
   
index ac751e8f97e7581a0846e470d4a8552329e050cd..9ac69e86856db98fe049a4824a1e76377b99086b 100644 (file)
@@ -86,6 +86,7 @@ update_assistant (struct import_assistant *ia)
       struct ccase *c;
       int col;
 
+
       sepp->column_cnt = dict_get_var_cnt (ssp->dict);
       sepp->columns = xcalloc (sepp->column_cnt, sizeof (*sepp->columns));
       for (col = 0; col < sepp->column_cnt ; ++col)
@@ -121,8 +122,6 @@ update_assistant (struct import_assistant *ia)
     }
   
   file->line_cnt = rows;
-  casereader_destroy (ssp->reader);
-  ssp->reader = NULL;
 }
 
 
@@ -154,37 +153,25 @@ init_file (struct import_assistant *ia, GtkWindow *parent_window)
   sri.read_names = true;
   sri.asw = -1;
 
-  ssp->spreadsheet = gnumeric_probe (sri.file_name);
+  if (ssp->spreadsheet == NULL)
+    ssp->spreadsheet = gnumeric_probe (sri.file_name);
+  
+  printf ("%s:%d %p %d\n", __FILE__, __LINE__, ssp->spreadsheet, ssp->spreadsheet->type);
+  
+  if (ssp->spreadsheet == NULL)
+    ssp->spreadsheet = ods_probe (sri.file_name);
+
+  printf ("%s:%d %p %d\n", __FILE__, __LINE__, ssp->spreadsheet, ssp->spreadsheet->type);
 
   if (ssp->spreadsheet)
     {
-      struct casereader *creader = NULL;
-      struct dictionary *dict = NULL;
-
-      if (ssp->spreadsheet->type == SPREADSHEET_GNUMERIC) 
-       {
-         ia->file.type = FTYPE_GNUMERIC;
-       }
-      else if (ssp->spreadsheet->type == SPREADSHEET_ODS) 
-       {
-         ia->file.type = FTYPE_ODS;
-       }
-      else
-       {
-         assert (0);
-       }
-    
-      {
-       struct sheet_spec_page *ssp = &ia->sheet_spec;
-       ssp->dict = dict;
-       ssp->reader = creader;
-       
-       update_assistant (ia);
-      }
-
+      
+      //      update_assistant (ia);
     }
   else
     {
+  printf ("%s:%d %p\n", __FILE__, __LINE__, ssp->spreadsheet);
+
     struct string input;
     struct line_reader *reader = line_reader_for_file (file->encoding, file->file_name, O_RDONLY);
     if (reader == NULL)
@@ -246,7 +233,6 @@ init_file (struct import_assistant *ia, GtkWindow *parent_window)
       }
 
     line_reader_close (reader);
-    ia->file.type = FTYPE_TEXT;
   }
 
   return true;
index f87bce21f6cb6afc8cc1546aba0451a404aba452..560a73dd4300ad30ec4643f5b6d4f6f50d9babf0 100644 (file)
@@ -145,12 +145,15 @@ post_sheet_spec_page (struct import_assistant *ia)
   ssp->sri.read_names = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (readnames_checkbox));
   ssp->sri.asw = -1;
 
-  switch (ia->file.type)
+  switch (ssp->spreadsheet->type)
     {
-    case FTYPE_ODS:
-      creader = ods_open_reader (&ssp->sri, &ssp->opts, &dict);
+    case SPREADSHEET_ODS:
+      {
+       creader = ods_make_reader (ssp->spreadsheet, &ssp->sri, &ssp->opts);
+       dict = ssp->spreadsheet->dict;
+      }
       break;
-    case FTYPE_GNUMERIC:
+    case SPREADSHEET_GNUMERIC:
       {
        creader = gnumeric_make_reader (ssp->spreadsheet, &ssp->sri, &ssp->opts);
        dict = ssp->spreadsheet->dict;
index df6e5ec995161be6708222bf31ad45b9383d8410..385af3e2bd4f3e437f0f9153183c279fcbb117aa 100644 (file)
@@ -72,6 +72,7 @@ text_data_import_assistant (PsppireDataWindow *dw)
 {
   GtkWindow *parent_window = GTK_WINDOW (dw);
   struct import_assistant *ia;
+  struct sheet_spec_page *ssp ;
 
   ia = xzalloc (sizeof *ia);
   if (!init_file (ia, parent_window))
@@ -81,7 +82,8 @@ text_data_import_assistant (PsppireDataWindow *dw)
     }
 
   init_assistant (ia, parent_window);
-  if ( ia->file.type == FTYPE_TEXT)
+  ssp = &ia->sheet_spec;
+  if (ssp->spreadsheet == NULL)
     {
       init_intro_page (ia);
       init_first_line_page (ia);
@@ -112,7 +114,7 @@ text_data_import_assistant (PsppireDataWindow *dw)
       break;
     }
 
-  if ( ia->file.type == FTYPE_TEXT)
+  if (ssp->spreadsheet == NULL)
     {
       destroy_formats_page (ia);
       destroy_separators_page (ia);
@@ -211,111 +213,104 @@ apply_dict (const struct dictionary *dict, struct string *s)
 static char *
 generate_syntax (const struct import_assistant *ia)
 {
+  struct sheet_spec_page *ssp = &ia->sheet_spec;
+
   struct string s = DS_EMPTY_INITIALIZER;
 
-  switch (ia->file.type)
+  if (ssp->spreadsheet == NULL)
     {
-    case FTYPE_TEXT:
-      {
-       size_t var_cnt;
-       size_t i;
-       syntax_gen_pspp (&s,
-                        "GET DATA"
-                        "\n  /TYPE=TXT"
-                        "\n  /FILE=%sq\n",
-                        ia->file.file_name);
-       if (ia->file.encoding && strcmp (ia->file.encoding, "Auto"))
-         syntax_gen_pspp (&s, "  /ENCODING=%sq\n", ia->file.encoding);
-       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
-                                                            ia->intro.n_cases_button)))
-         ds_put_format (&s, "  /IMPORTCASES=FIRST %d\n",
-                        gtk_spin_button_get_value_as_int (
-                                                          GTK_SPIN_BUTTON (ia->intro.n_cases_spin)));
-       else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
-                                                                 ia->intro.percent_button)))
-         ds_put_format (&s, "  /IMPORTCASES=PERCENT %d\n",
-                        gtk_spin_button_get_value_as_int (
-                                                          GTK_SPIN_BUTTON (ia->intro.percent_spin)));
-       else
-         ds_put_cstr (&s, "  /IMPORTCASES=ALL\n");
-       ds_put_cstr (&s,
-                    "  /ARRANGEMENT=DELIMITED\n"
-                    "  /DELCASE=LINE\n");
-       if (ia->first_line.skip_lines > 0)
-         ds_put_format (&s, "  /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
-       ds_put_cstr (&s, "  /DELIMITERS=\"");
-       if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
-         ds_put_cstr (&s, "\\t");
-       if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
-         ds_put_cstr (&s, "\\\\");
-       for (i = 0; i < ds_length (&ia->separators.separators); i++)
-         {
-           char c = ds_at (&ia->separators.separators, i);
-           if (c == '"')
-             ds_put_cstr (&s, "\"\"");
-           else if (c != '\t' && c != '\\')
-             ds_put_byte (&s, c);
-         }
-       ds_put_cstr (&s, "\"\n");
-       if (!ds_is_empty (&ia->separators.quotes))
-         syntax_gen_pspp (&s, "  /QUALIFIER=%sq\n", ds_cstr (&ia->separators.quotes));
-       if (!ds_is_empty (&ia->separators.quotes) && ia->separators.escape)
-         ds_put_cstr (&s, "  /ESCAPE\n");
-       ds_put_cstr (&s, "  /VARIABLES=\n");
-
-       var_cnt = dict_get_var_cnt (ia->formats.dict);
-       for (i = 0; i < var_cnt; i++)
-         {
-           struct variable *var = dict_get_var (ia->formats.dict, i);
-           char format_string[FMT_STRING_LEN_MAX + 1];
-           fmt_to_string (var_get_print_format (var), format_string);
-           ds_put_format (&s, "    %s %s%s\n",
-                          var_get_name (var), format_string,
-                          i == var_cnt - 1 ? "." : "");
-         }
-
-       apply_dict (ia->formats.dict, &s);
-      }
-      break;
-    case FTYPE_GNUMERIC:
-    case FTYPE_ODS:
-      {
-       const struct sheet_spec_page *ssp = &ia->sheet_spec;
-
-       syntax_gen_pspp (&s,
-                        "GET DATA"
-                        "\n  /TYPE=%ss"
-                        "\n  /FILE=%sq"
-                        "\n  /SHEET=index %d"
-                        "\n  /READNAMES=%ss",
-                        (ia->file.type == FTYPE_GNUMERIC) ? "GNM" : "ODS",
-                        ia->file.file_name,                     
-                        ssp->opts.sheet_index,
-                        ssp->sri.read_names ? "ON" : "OFF");
-
-
-       if ( ssp->opts.cell_range)
-         {
-           syntax_gen_pspp (&s,
-                            "\n  /CELLRANGE=RANGE %sq",
-                            ssp->opts.cell_range);
-         }
-       else
-         {
-           syntax_gen_pspp (&s,
-                            "\n  /CELLRANGE=FULL");
-         }
-
-
-       syntax_gen_pspp (&s, ".");
-
-      }
-      break;
-    
-    default:
-      g_assert_not_reached ();
+      size_t var_cnt;
+      size_t i;
+      syntax_gen_pspp (&s,
+                      "GET DATA"
+                      "\n  /TYPE=TXT"
+                      "\n  /FILE=%sq\n",
+                      ia->file.file_name);
+      if (ia->file.encoding && strcmp (ia->file.encoding, "Auto"))
+       syntax_gen_pspp (&s, "  /ENCODING=%sq\n", ia->file.encoding);
+      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
+                                                          ia->intro.n_cases_button)))
+       ds_put_format (&s, "  /IMPORTCASES=FIRST %d\n",
+                      gtk_spin_button_get_value_as_int (
+                                                        GTK_SPIN_BUTTON (ia->intro.n_cases_spin)));
+      else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (
+                                                               ia->intro.percent_button)))
+       ds_put_format (&s, "  /IMPORTCASES=PERCENT %d\n",
+                      gtk_spin_button_get_value_as_int (
+                                                        GTK_SPIN_BUTTON (ia->intro.percent_spin)));
+      else
+       ds_put_cstr (&s, "  /IMPORTCASES=ALL\n");
+      ds_put_cstr (&s,
+                  "  /ARRANGEMENT=DELIMITED\n"
+                  "  /DELCASE=LINE\n");
+      if (ia->first_line.skip_lines > 0)
+       ds_put_format (&s, "  /FIRSTCASE=%d\n", ia->first_line.skip_lines + 1);
+      ds_put_cstr (&s, "  /DELIMITERS=\"");
+      if (ds_find_byte (&ia->separators.separators, '\t') != SIZE_MAX)
+       ds_put_cstr (&s, "\\t");
+      if (ds_find_byte (&ia->separators.separators, '\\') != SIZE_MAX)
+       ds_put_cstr (&s, "\\\\");
+      for (i = 0; i < ds_length (&ia->separators.separators); i++)
+       {
+         char c = ds_at (&ia->separators.separators, i);
+         if (c == '"')
+           ds_put_cstr (&s, "\"\"");
+         else if (c != '\t' && c != '\\')
+           ds_put_byte (&s, c);
+       }
+      ds_put_cstr (&s, "\"\n");
+      if (!ds_is_empty (&ia->separators.quotes))
+       syntax_gen_pspp (&s, "  /QUALIFIER=%sq\n", ds_cstr (&ia->separators.quotes));
+      if (!ds_is_empty (&ia->separators.quotes) && ia->separators.escape)
+       ds_put_cstr (&s, "  /ESCAPE\n");
+      ds_put_cstr (&s, "  /VARIABLES=\n");
+
+      var_cnt = dict_get_var_cnt (ia->formats.dict);
+      for (i = 0; i < var_cnt; i++)
+       {
+         struct variable *var = dict_get_var (ia->formats.dict, i);
+         char format_string[FMT_STRING_LEN_MAX + 1];
+         fmt_to_string (var_get_print_format (var), format_string);
+         ds_put_format (&s, "    %s %s%s\n",
+                        var_get_name (var), format_string,
+                        i == var_cnt - 1 ? "." : "");
+       }
+
+      apply_dict (ia->formats.dict, &s);
+    }
+  else
+    {
+      const struct sheet_spec_page *ssp = &ia->sheet_spec;
+
+      printf ("%s:%d %p %d\n", __FILE__, __LINE__, ssp->spreadsheet, ssp->spreadsheet->type);
+
+      syntax_gen_pspp (&s,
+                      "GET DATA"
+                      "\n  /TYPE=%ss"
+                      "\n  /FILE=%sq"
+                      "\n  /SHEET=index %d"
+                      "\n  /READNAMES=%ss",
+                      (ssp->spreadsheet->type == SPREADSHEET_GNUMERIC) ? "GNM" : "ODS",
+                      ia->file.file_name,                       
+                      ssp->opts.sheet_index,
+                      ssp->sri.read_names ? "ON" : "OFF");
+
+
+      if ( ssp->opts.cell_range)
+       {
+         syntax_gen_pspp (&s,
+                          "\n  /CELLRANGE=RANGE %sq",
+                          ssp->opts.cell_range);
+       }
+      else
+       {
+         syntax_gen_pspp (&s,
+                          "\n  /CELLRANGE=FULL");
+       }
+
+
+      syntax_gen_pspp (&s, ".");
     }
-
 
   return ds_cstr (&s);
 }
index 55064574f1aa31a1c5f08fb6c17ef84529cc7164..561c0405bf1b23fd781cf3e20d811f82a0e9a613 100644 (file)
 
 #include "libpspp/str.h"
 
-enum file_type
-  {
-    FTYPE_TEXT,
-    FTYPE_GNUMERIC,
-    FTYPE_ODS
-  };
-
 /* The file to be imported. */
 struct file
   {
     char *file_name;        /* File name. */
 
-    enum file_type type;
-
     /* Relevant only for text files */
 
     gchar *encoding;        /* Encoding. */