Made it crash a little less often
[pspp] / src / data / ods-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2011, 2012, 2013 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "libpspp/message.h"
20 #include "libpspp/misc.h"
21 #include "libpspp/assertion.h"
22
23 #include "data/data-in.h"
24
25 #include "gl/minmax.h"
26
27 #include "gettext.h"
28 #define _(msgid) gettext (msgid)
29 #define N_(msgid) (msgid)
30
31 #include "ods-reader.h"
32 #include "spreadsheet-reader.h"
33
34 #if !ODF_READ_SUPPORT
35
36 struct casereader *
37 ods_open_reader (const struct spreadsheet_read_options *opts, 
38                  struct dictionary **dict)
39 {
40   msg (ME, _("Support for %s files was not compiled into this installation of PSPP"), "OpenDocument");
41
42   return NULL;
43 }
44
45 #else
46
47 #include "libpspp/zip-reader.h"
48
49
50 #include <assert.h>
51 #include <stdbool.h>
52 #include <errno.h>
53 #include <libxml/xmlreader.h>
54 #include <zlib.h>
55
56 #include "data/format.h"
57 #include "data/case.h"
58 #include "data/casereader-provider.h"
59 #include "data/dictionary.h"
60 #include "data/identifier.h"
61 #include "data/value.h"
62 #include "data/variable.h"
63 #include "libpspp/i18n.h"
64 #include "libpspp/str.h"
65
66 #include "gl/xalloc.h"
67
68 static void ods_file_casereader_destroy (struct casereader *, void *);
69
70 static struct ccase *ods_file_casereader_read (struct casereader *, void *);
71
72 static const struct casereader_class ods_file_casereader_class =
73   {
74     ods_file_casereader_read,
75     ods_file_casereader_destroy,
76     NULL,
77     NULL,
78   };
79
80 struct sheet_detail
81 {
82   /* The name of the sheet (utf8 encoding) */
83   char *name;
84
85   int start_col;
86   int stop_col;
87   int start_row;
88   int stop_row;
89 };
90
91
92 enum reader_state
93   {
94     STATE_INIT = 0,        /* Initial state */
95     STATE_SPREADSHEET,     /* Found the start of the spreadsheet doc */
96     STATE_TABLE,           /* Found the sheet that we actually want */
97     STATE_ROW,             /* Found the start of the cell array */
98     STATE_CELL,            /* Found a cell */
99     STATE_CELL_CONTENT     /* Found a the text within a cell */
100   };
101
102 struct ods_reader
103 {
104   struct spreadsheet spreadsheet;
105   struct zip_reader *zreader;
106   xmlTextReaderPtr xtr;
107
108   enum reader_state state;
109   bool sheet_found;
110   int row;
111   int col;
112   int node_type;
113   int sheet_index;
114
115   const xmlChar *target_sheet;
116   int target_sheet_index;
117
118   int start_row;
119   int start_col;
120   int stop_row;
121   int stop_col;
122
123   struct sheet_detail *sheets;
124   int n_allocated_sheets;
125
126   struct caseproto *proto;
127   struct dictionary *dict;
128   struct ccase *first_case;
129   bool used_first_case;
130   bool read_names;
131
132   struct string ods_errs;
133 };
134
135
136 static void process_node (struct ods_reader *r);
137
138
139 const char *
140 ods_get_sheet_name (struct spreadsheet *s, int n)
141 {
142   int ret;
143   struct ods_reader *or = (struct ods_reader *) s;
144   
145   assert (n < s->n_sheets);
146
147   while ( 
148          (or->n_allocated_sheets <= n)
149          && 
150          (1 == (ret = xmlTextReaderRead (or->xtr)))
151           )
152     {
153       process_node (or);
154     }
155
156   return or->sheets[n].name;
157 }
158
159 char *
160 ods_get_sheet_range (struct spreadsheet *s, int n)
161 {
162   int ret = -1;
163   struct ods_reader *or = (struct ods_reader *) s;
164   
165   assert (n < s->n_sheets);
166
167   while ( 
168          (
169           (or->n_allocated_sheets <= n)
170           || (or->sheets[n].stop_row == -1) )
171          && 
172          (1 == (ret = xmlTextReaderRead (or->xtr)))
173           )
174     {
175       process_node (or);
176     }
177
178
179   return create_cell_ref (
180                           or->sheets[n].start_col,
181                           or->sheets[n].start_row,
182                           or->sheets[n].stop_col,
183                           or->sheets[n].stop_row);
184 }
185
186
187 static void
188 ods_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
189 {
190   struct ods_reader *r = r_;
191   if ( r == NULL)
192     return ;
193
194   if (r->xtr)
195     xmlFreeTextReader (r->xtr);
196   r->xtr = NULL;
197
198   if ( ! ds_is_empty (&r->ods_errs))
199     msg (ME, "%s", ds_cstr (&r->ods_errs));
200
201   ds_destroy (&r->ods_errs);
202
203   if ( ! r->used_first_case )
204     case_unref (r->first_case);
205
206   caseproto_unref (r->proto);
207
208   //  free (r);
209 }
210
211 static void
212 process_node (struct ods_reader *r)
213 {
214   xmlChar *name = xmlTextReaderName (r->xtr);
215   if (name == NULL)
216     name = xmlStrdup (_xml ("--"));
217
218
219   r->node_type = xmlTextReaderNodeType (r->xtr);
220
221   switch (r->state)
222     {
223     case STATE_INIT:
224       if (0 == xmlStrcasecmp (name, _xml("office:spreadsheet")) &&
225           XML_READER_TYPE_ELEMENT  == r->node_type)
226         {
227           printf ("%s:%d Start of Workbook %d: Rows %d\n", __FILE__, __LINE__,
228                   r->sheet_index,  r->row);
229
230           r->state = STATE_SPREADSHEET;
231           r->sheet_index = -1;
232         }
233       break;
234     case STATE_SPREADSHEET:
235       if (0 == xmlStrcasecmp (name, _xml("table:table"))
236           && 
237           (XML_READER_TYPE_ELEMENT == r->node_type))
238         {
239           xmlChar *value = xmlTextReaderGetAttribute (r->xtr, _xml ("table:name"));
240
241
242           ++r->sheet_index;
243
244           printf ("%s:%d Start of SHEET %d: Allocated Sheets %d\n", __FILE__, __LINE__,
245                   r->sheet_index,  r->n_allocated_sheets);
246
247           if (r->sheet_index >= r->n_allocated_sheets)
248             {
249               r->sheets = xrealloc (r->sheets, sizeof (*r->sheets) * ++r->n_allocated_sheets);
250               r->sheets[r->n_allocated_sheets - 1].start_col = -1;
251               r->sheets[r->n_allocated_sheets - 1].stop_col = -1;
252               r->sheets[r->n_allocated_sheets - 1].start_row = -1;
253               r->sheets[r->n_allocated_sheets - 1].stop_row = -1;
254               r->sheets[r->n_allocated_sheets - 1].name = value;
255             }
256
257
258
259           r->col = 0;
260           r->row = 0;
261
262
263           if ( r->target_sheet != NULL)
264             {
265               if ( 0 == xmlStrcmp (value, r->target_sheet))
266                 {
267                   r->sheet_found = true;
268                 }
269             }
270           else if (r->target_sheet_index == r->sheet_index)
271             {
272               r->sheet_found = true;
273             }
274           r->state = STATE_TABLE;
275         }
276       else if (0 == xmlStrcasecmp (name, _xml("office:spreadsheet")) &&
277                XML_READER_TYPE_ELEMENT  == r->node_type)
278         {
279           r->state = STATE_INIT;
280           printf ("%s:%d End of Workbook %d: Rows %d Cols %d\n", __FILE__, __LINE__,
281                   r->sheet_index,  r->row, r->col);
282         }
283       break;
284     case STATE_TABLE:
285       if (0 == xmlStrcasecmp (name, _xml("table:table-row")) && 
286           (XML_READER_TYPE_ELEMENT  == r->node_type))
287         {
288           xmlChar *value =
289             xmlTextReaderGetAttribute (r->xtr,
290                                        _xml ("table:number-rows-repeated"));
291           
292           int row_span = value ? _xmlchar_to_int (value) : 1;
293
294           printf ("%s:%d  Start of Row %d Span %d\n", __FILE__, __LINE__,  r->row, row_span);
295           r->row += row_span;
296           r->col = 0;
297           
298           if (! xmlTextReaderIsEmptyElement (r->xtr))
299             r->state = STATE_ROW;
300         }
301       else if (0 == xmlStrcasecmp (name, _xml("table:table")) && 
302                (XML_READER_TYPE_END_ELEMENT  == r->node_type))
303         {
304           printf ("%s:%d End of SHEET %d %d,%d\n", __FILE__, __LINE__,  r->sheet_index,  r->row, r->col);
305           r->state = STATE_SPREADSHEET;
306
307         }
308       break;
309     case STATE_ROW:
310       if ( (0 == xmlStrcasecmp (name, _xml ("table:table-cell")))
311            && 
312            (XML_READER_TYPE_ELEMENT  == r->node_type))
313         {
314           xmlChar *value =
315             xmlTextReaderGetAttribute (r->xtr,
316                                        _xml ("table:number-columns-repeated"));
317           
318           int col_span = value ? _xmlchar_to_int (value) : 1;
319
320           r->col += col_span;
321
322           printf ("%s:%d  (span %d) Start of Cell %d, %d\n", __FILE__, __LINE__,  
323                   col_span,
324                   r->row, r->col);
325           if (! xmlTextReaderIsEmptyElement (r->xtr))
326             r->state = STATE_CELL;
327         }
328       else if ( (0 == xmlStrcasecmp (name, _xml ("table:table-row")))
329                 &&
330                 (XML_READER_TYPE_END_ELEMENT  == r->node_type))
331         {
332           /* Set the span back to the default */
333           printf ("%s:%d  End of Cell:  %d, %d\n", __FILE__, __LINE__, r->row, r->col);
334           r->state = STATE_TABLE;
335         }
336       break;
337     case STATE_CELL:
338       if ( (0 == xmlStrcasecmp (name, _xml("text:p")))
339             &&
340            ( XML_READER_TYPE_ELEMENT  == r->node_type))
341         {
342           printf ("%s:%d  Start of Cell Contents %d\n", __FILE__, __LINE__,    r->row);
343           if (! xmlTextReaderIsEmptyElement (r->xtr))
344             r->state = STATE_CELL_CONTENT;
345         }
346       else if
347         ( (0 == xmlStrcasecmp (name, _xml("table:table-cell")))
348           &&
349           (XML_READER_TYPE_END_ELEMENT  == r->node_type)
350           )
351         {
352           printf ("%s:%d End of Cell contents: Rows %d\n", __FILE__, __LINE__, r->row);
353           r->state = STATE_ROW;
354         }
355       break;
356     case STATE_CELL_CONTENT:
357       assert (r->sheet_index >= 0);
358       assert (r->sheet_index < r->n_allocated_sheets);
359
360       if (r->sheets[r->sheet_index].start_row == -1)
361         r->sheets[r->sheet_index].start_row = r->row - 1;
362
363       if ( 
364           (r->sheets[r->sheet_index].start_col == -1)
365           ||
366           (r->sheets[r->sheet_index].start_col >= r->col - 1)
367            )
368         r->sheets[r->sheet_index].start_col = r->col - 1;
369
370       r->sheets[r->sheet_index].stop_row = r->row - 1;
371       printf ("Stop Row for  %d is %d\n", r->sheet_index, r->sheets[r->sheet_index].stop_row);
372
373       if ( r->sheets[r->sheet_index].stop_col <  r->col - 1)
374         r->sheets[r->sheet_index].stop_col = r->col - 1;
375
376       if (XML_READER_TYPE_END_ELEMENT  == r->node_type)
377         r->state = STATE_CELL;
378       break;
379     default:
380       NOT_REACHED ();
381       break;
382     };
383
384   xmlFree (name);
385 }
386
387 /* 
388    A struct containing the parameters of a cell's value 
389    parsed from the xml
390 */
391 struct xml_value
392 {
393   xmlChar *type;
394   xmlChar *value;
395   xmlChar *text;
396 };
397
398 struct var_spec
399 {
400   char *name;
401   struct xml_value firstval;
402 };
403
404
405 /* Determine the width that a xmv should probably have */
406 static int
407 xmv_to_width (const struct xml_value *xmv, int fallback)
408 {
409   int width = SPREADSHEET_DEFAULT_WIDTH;
410
411   /* Non-strings always have zero width */
412   if (xmv->type != NULL && 0 != xmlStrcmp (xmv->type, _xml("string")))
413     return 0;
414
415   if ( fallback != -1)
416     return fallback;
417
418   if ( xmv->value )
419     width = ROUND_UP (xmlStrlen (xmv->value),
420                       SPREADSHEET_DEFAULT_WIDTH);
421   else if ( xmv->text)
422     width = ROUND_UP (xmlStrlen (xmv->text),
423                       SPREADSHEET_DEFAULT_WIDTH);
424
425   return width;
426 }
427
428 /*
429    Sets the VAR of case C, to the value corresponding to the xml data
430  */
431 static void
432 convert_xml_to_value (struct ccase *c, const struct variable *var,
433                       const struct xml_value *xmv)
434 {
435   union value *v = case_data_rw (c, var);
436
437   if (xmv->value == NULL && xmv->text == NULL)
438     value_set_missing (v, var_get_width (var));
439   else if ( var_is_alpha (var))
440     /* Use the text field, because it seems that there is no
441        value field for strings */
442     value_copy_str_rpad (v, var_get_width (var), xmv->text, ' ');
443   else
444     {
445       const char *text ;
446       const struct fmt_spec *fmt = var_get_write_format (var);
447       enum fmt_category fc  = fmt_get_category (fmt->type);
448
449       assert ( fc != FMT_CAT_STRING);
450
451       text =
452         xmv->value ? CHAR_CAST (const char *, xmv->value) : CHAR_CAST (const char *, xmv->text);
453
454       free (data_in (ss_cstr (text), "UTF-8",
455                      fmt->type,
456                      v,
457                      var_get_width (var),
458                      "UTF-8"));
459     }
460 }
461
462
463 /* Try to find out how many sheets there are in the "workbook" */
464 static int
465 get_sheet_count (struct zip_reader *zreader)
466 {
467   xmlTextReaderPtr mxtr;
468   struct zip_member *meta = NULL;
469   meta = zip_member_open (zreader, "meta.xml");
470
471   if ( meta == NULL)
472     return -1;
473
474   mxtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
475                          (xmlInputCloseCallback) zip_member_finish,
476                          meta,   NULL, NULL, 0);
477
478   while (1 == xmlTextReaderRead (mxtr))
479     {
480       xmlChar *name = xmlTextReaderName (mxtr);
481       if ( 0 == xmlStrcmp (name, _xml("meta:document-statistic")))
482         {
483           xmlChar *attr = xmlTextReaderGetAttribute (mxtr, _xml ("meta:table-count"));
484             
485           if ( attr != NULL)
486             {
487               int s = _xmlchar_to_int (attr);
488               return s;
489             }
490         }
491     }
492   return -1;
493 }
494
495 static void
496 ods_error_handler (void *ctx, const char *mesg,
497                         UNUSED xmlParserSeverities sev, xmlTextReaderLocatorPtr loc)
498 {
499   struct ods_reader *r = ctx;
500        
501   msg (MW, _("There was a problem whilst reading the %s file `%s' (near line %d): `%s'"),
502        "ODF",
503        r->spreadsheet.file_name,
504        xmlTextReaderLocatorLineNumber (loc),
505        mesg);
506 }
507
508
509 static bool
510 init_reader (struct ods_reader *r, bool report_errors)
511 {
512   struct zip_member *content = zip_member_open (r->zreader, "content.xml");
513   xmlTextReaderPtr xtr;
514
515   if ( content == NULL)
516     return false;
517
518   zip_member_ref (content);
519
520
521   xtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
522                         (xmlInputCloseCallback) zip_member_finish,
523                         content,   NULL, NULL,
524                         report_errors ? 0 : (XML_PARSE_NOERROR | XML_PARSE_NOWARNING) );
525
526   if ( xtr == NULL)
527     return false;
528
529   r->xtr = xtr;
530   r->spreadsheet.type = SPREADSHEET_ODS;
531
532   if (report_errors) 
533     xmlTextReaderSetErrorHandler (xtr, ods_error_handler, r);
534
535   return true;
536 }
537
538
539 struct spreadsheet *
540 ods_probe (const char *filename, bool report_errors)
541 {
542   struct ods_reader *r;
543   struct string errs = DS_EMPTY_INITIALIZER;
544   int sheet_count;
545   struct zip_reader *zr = zip_reader_create (filename, &errs);
546
547   if (zr == NULL)
548     return NULL;
549
550   sheet_count = get_sheet_count (zr);
551
552   r = xzalloc (sizeof *r);
553   r->zreader = zr;
554
555   if (! init_reader (r, false))
556     {
557       goto error;
558     }
559
560   r->spreadsheet.n_sheets = sheet_count;
561   r->n_allocated_sheets = 0;
562   r->sheet_index = -1;
563   r->sheets = NULL;
564
565   ds_destroy (&errs);
566
567   printf ("%s:%d\n", __FILE__, __LINE__);
568
569   r->spreadsheet.file_name = filename;
570   return &r->spreadsheet;
571
572  error:
573   zip_reader_destroy (r->zreader);
574   ds_destroy (&errs);
575   free (r);
576   return NULL;
577 }
578
579 struct casereader *
580 ods_make_reader (struct spreadsheet *spreadsheet, 
581                  const struct spreadsheet_read_options *opts)
582 {
583   intf ret = 0;
584   xmlChar *type = NULL;
585   unsigned long int vstart = 0;
586   casenumber n_cases = CASENUMBER_MAX;
587   int i;
588   struct var_spec *var_spec = NULL;
589   int n_var_specs = 0;
590
591   struct ods_reader *r = (struct ods_reader *) spreadsheet;
592   xmlChar *val_string = NULL;
593
594   assert (r);
595   r->read_names = opts->read_names;
596   ds_init_empty (&r->ods_errs);
597
598
599   printf ("%s:%d\n", __FILE__, __LINE__);
600
601   if ( !init_reader (r, true))
602     goto error;
603
604   printf ("%s:%d\n", __FILE__, __LINE__);
605
606   if ( opts->cell_range )
607     {
608       if ( ! convert_cell_ref (opts->cell_range,
609                                &r->start_col, &r->start_row,
610                                &r->stop_col, &r->stop_row))
611         {
612           msg (SE, _("Invalid cell range `%s'"),
613                opts->cell_range);
614           goto error;
615         }
616     }
617   else
618     {
619       r->start_col = 0;
620       r->start_row = 0;
621       r->stop_col = -1;
622       r->stop_row = -1;
623     }
624
625   r->state = STATE_INIT;
626   r->target_sheet = BAD_CAST opts->sheet_name;
627   r->target_sheet_index = opts->sheet_index;
628   r->row = r->col = 0;
629   r->sheet_index = 0;
630
631   printf ("%s:%d\n", __FILE__, __LINE__);
632
633
634   /* If CELLRANGE was given, then we know how many variables should be read */
635   if ( r->stop_col != -1 )
636     {
637       assert (var_spec == NULL);
638       n_var_specs =  r->stop_col - r->start_col + 1;
639       var_spec = xrealloc (var_spec, sizeof (*var_spec) * n_var_specs);
640       memset (var_spec, '\0', sizeof (*var_spec) * n_var_specs);
641     }
642
643   printf ("%s:%d Number of var specs %d\n", __FILE__, __LINE__, n_var_specs);
644   printf ("%s:%d Target Sjheet %d\n", __FILE__, __LINE__, r->target_sheet_index);
645
646
647   /* Advance to the start of the cells for the target sheet */
648   while ( r->sheet_index < r->target_sheet_index - 1 ||
649           r->state != STATE_TABLE
650           )
651     {
652       if (1 != (ret = xmlTextReaderRead (r->xtr)))
653            break;
654
655       process_node (r);
656     }
657
658   printf ("%s:%d\n", __FILE__, __LINE__);
659
660   if (ret < 1)
661     {
662       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
663            spreadsheet->file_name);
664       goto error;
665     }
666
667   printf ("%s:%d\n", __FILE__, __LINE__);
668
669   if ( opts->read_names)
670     {
671       while (1 == (ret = xmlTextReaderRead (r->xtr)))
672         {
673           int idx;
674
675           process_node (r);
676
677           /* If the row is finished then stop for now */
678           if (r->state == STATE_TABLE && r->row > r->start_row)
679             break;
680           
681           idx = r->col - r->start_col - 1;
682
683           if (r->state == STATE_CELL_CONTENT 
684               &&
685               XML_READER_TYPE_TEXT  == r->node_type)
686             {
687               xmlChar *value = xmlTextReaderValue (r->xtr);
688
689               if ( idx >= n_var_specs)
690                 {
691                   var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
692
693                   /* xrealloc (unlike realloc) doesn't initialise its memory to 0 */
694                   memset (var_spec + n_var_specs,
695                           0, 
696                           (n_var_specs - idx + 1) * sizeof (*var_spec));
697                   n_var_specs = idx + 1;
698                 }
699               var_spec[idx].firstval.text = 0;
700               var_spec[idx].firstval.value = 0;
701               var_spec[idx].firstval.type = 0;
702
703               var_spec [idx].name = strdup (CHAR_CAST (const char *, value));
704               xmlFree (value);
705             }
706         }
707     }
708
709   printf ("%s:%d N varspecs %d\n", __FILE__, __LINE__, n_var_specs);
710
711   /* Read in the first row of data */
712   while (1 == xmlTextReaderRead (r->xtr))
713     {
714       int idx;
715       process_node (r);
716
717       /* If the row is finished then stop for now */
718       if (r->state == STATE_TABLE && r->row > r->start_row + 1)
719         break;
720
721       idx = r->col - r->start_col - 1;
722
723       if ( r->state == STATE_CELL &&
724            XML_READER_TYPE_ELEMENT  == r->node_type)
725         {
726           type = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value-type"));
727           val_string = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value"));
728         }
729
730       if ( r->state == STATE_CELL_CONTENT &&
731            XML_READER_TYPE_TEXT  == r->node_type)
732         {
733
734           if ( idx >= n_var_specs) 
735             {
736               var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
737               var_spec [idx].name = NULL;
738               n_var_specs = idx + 1;
739             }
740             
741           var_spec [idx].firstval.type = type;
742           var_spec [idx].firstval.text = xmlTextReaderValue (r->xtr);
743           var_spec [idx].firstval.value = val_string;
744
745           val_string = NULL;
746           type = NULL;
747         }
748     }
749
750   printf ("%s:%d N varspecs %d\n", __FILE__, __LINE__, n_var_specs);
751
752   /* Create the dictionary and populate it */
753   r->spreadsheet.dict = r->dict = dict_create (
754     CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->xtr)));
755
756   for (i = 0; i < n_var_specs ; ++i )
757     {
758       struct fmt_spec fmt;
759       struct variable *var = NULL;
760       char *name = dict_make_unique_var_name (r->dict, var_spec[i].name, &vstart);
761       int width  = xmv_to_width (&var_spec[i].firstval, opts->asw);
762       dict_create_var (r->dict, name, width);
763       free (name);
764
765       var = dict_get_var (r->dict, i);
766
767       if ( 0 == xmlStrcmp (var_spec[i].firstval.type, _xml("date")))
768         {
769           fmt.type = FMT_DATE;
770           fmt.d = 0;
771           fmt.w = 20;
772         }
773       else
774         fmt = fmt_default_for_width (width);
775
776       var_set_both_formats (var, &fmt);
777     }
778
779   /* Create the first case, and cache it */
780   r->used_first_case = false;
781
782   if ( n_var_specs ==  0 )
783     {
784       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
785            spreadsheet->file_name);
786       goto error;
787     }
788
789   r->proto = caseproto_ref (dict_get_proto (r->dict));
790   r->first_case = case_create (r->proto);
791   case_set_missing (r->first_case);
792
793   printf ("%s:%d Hello %d\n", __FILE__, __LINE__, n_var_specs);
794
795   for ( i = 0 ; i < n_var_specs ; ++i )
796     {
797       const struct variable *var = dict_get_var (r->dict, i);
798
799       convert_xml_to_value (r->first_case, var,  &var_spec[i].firstval);
800     }
801
802   printf ("%s:%d Hello %d\n", __FILE__, __LINE__, n_var_specs);
803
804   //  zip_reader_destroy (zreader);
805
806 #if 0
807   for ( i = 0 ; i < n_var_specs ; ++i )
808     {
809       free (var_spec[i].firstval.type);
810       free (var_spec[i].firstval.value);
811       free (var_spec[i].firstval.text);
812       free (var_spec[i].name);
813     }
814
815   free (var_spec);
816 #endif
817
818   printf ("%s:%d Creating reader\n", __FILE__, __LINE__);
819   return casereader_create_sequential
820     (NULL,
821      r->proto,
822      n_cases,
823      &ods_file_casereader_class, r);
824
825  error:
826   
827   // zip_reader_destroy (zreader);
828
829   for ( i = 0 ; i < n_var_specs ; ++i )
830     {
831       free (var_spec[i].firstval.type);
832       free (var_spec[i].firstval.value);
833       free (var_spec[i].firstval.text);
834       free (var_spec[i].name);
835     }
836
837   free (var_spec);
838
839   dict_destroy (r->spreadsheet.dict);
840   r->spreadsheet.dict = NULL;
841   ods_file_casereader_destroy (NULL, r);
842
843
844   return NULL;
845 }
846
847
848 /* Reads and returns one case from READER's file.  Returns a null
849    pointer on failure. */
850 static struct ccase *
851 ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
852 {
853   struct ccase *c = NULL;
854   xmlChar *val_string = NULL;
855   struct ods_reader *r = r_;
856   int current_row = r->row;
857
858   printf ("%s:%d Reading CASE\n", __FILE__, __LINE__);
859
860   if ( !r->used_first_case )
861     {
862       r->used_first_case = true;
863       return r->first_case;
864     }
865
866   printf ("%s:%d Reading CASE\n", __FILE__, __LINE__);
867
868   if ( r->state > STATE_INIT)
869     {
870       c = case_create (r->proto);
871       case_set_missing (c);
872     }
873
874   if (r->state == STATE_SPREADSHEET)
875     {
876       printf ("%s:%d CASES ARE ENDED\n", __FILE__, __LINE__);
877       return NULL;
878     }
879
880   while (1 == xmlTextReaderRead (r->xtr))
881     {
882       process_node (r);
883       if ( r->row > current_row)
884         {
885           break;
886         }
887       if ( r->col < r->start_col || (r->stop_col != -1 && r->col > r->stop_col))
888         {
889           continue;
890         }
891       if ( r->col - r->start_col >= caseproto_get_n_widths (r->proto))
892         {
893           continue;
894         }
895       if ( r->stop_row != -1 && r->row > r->stop_row)
896         {
897           continue;
898         }
899       if ( r->state == STATE_CELL &&
900            r->node_type == XML_READER_TYPE_ELEMENT )
901         {
902           val_string = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value"));
903         }
904
905       if ( r->state == STATE_CELL_CONTENT && r->node_type == XML_READER_TYPE_TEXT )
906         {
907           int col;
908           struct xml_value *xmv = xzalloc (sizeof *xmv);
909           xmv->text = xmlTextReaderValue (r->xtr);
910           xmv->value = val_string;
911           val_string = NULL;
912
913           /*
914           for (col = 0; col < r->span ; ++col)
915             {
916               const int idx = r->col + col - r->start_col;
917
918               const struct variable *var = dict_get_var (r->dict, idx);
919
920               convert_xml_to_value (c, var, xmv);
921             }
922           */
923           free (xmv->text);
924           free (xmv->value);
925           free (xmv);
926         }
927
928       if ( r->state < STATE_TABLE)
929         break;
930     }
931
932   if (NULL == c || (r->stop_row != -1 && r->row > r->stop_row + 1))
933     {
934       case_unref (c);
935       return NULL;
936     }
937   else
938     {
939       return c;
940     }
941 }
942 #endif