New function reading_target_sheet
[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   int row;
110   int col;
111   int node_type;
112   int current_sheet;
113   xmlChar *current_sheet_name;
114
115   const xmlChar *target_sheet_name;
116   int target_sheet_index;
117
118
119   int wanted_row_start;
120   int wanted_col_start;
121
122 #if 0
123   int start_row;
124   int start_col;
125   int stop_row;
126   int stop_col;
127 #endif
128
129   int col_span;
130
131   struct sheet_detail *sheets;
132   int n_allocated_sheets;
133
134   struct caseproto *proto;
135   struct dictionary *dict;
136   struct ccase *first_case;
137   bool used_first_case;
138   bool read_names;
139
140   struct string ods_errs;
141 };
142
143
144 static bool
145 reading_target_sheet (const struct ods_reader *r)
146 {
147   if (r->target_sheet_name != NULL)
148     {
149       if ( 0 == xmlStrcmp (r->target_sheet_name, r->current_sheet_name))
150         return true;
151     }
152   
153   if (r->target_sheet_index == r->current_sheet + 1)
154     return true;
155
156   return false;
157 }
158
159
160 static void process_node (struct ods_reader *r);
161
162
163 const char *
164 ods_get_sheet_name (struct spreadsheet *s, int n)
165 {
166   int ret;
167   struct ods_reader *or = (struct ods_reader *) s;
168   
169   assert (n < s->n_sheets);
170
171   while ( 
172          (or->n_allocated_sheets <= n)
173          && 
174          (1 == (ret = xmlTextReaderRead (or->xtr)))
175           )
176     {
177       process_node (or);
178     }
179
180   return or->sheets[n].name;
181 }
182
183 char *
184 ods_get_sheet_range (struct spreadsheet *s, int n)
185 {
186   int ret = -1;
187   struct ods_reader *or = (struct ods_reader *) s;
188   
189   assert (n < s->n_sheets);
190
191   while ( 
192          (
193           (or->n_allocated_sheets <= n)
194           || (or->sheets[n].stop_row == -1) )
195          && 
196          (1 == (ret = xmlTextReaderRead (or->xtr)))
197           )
198     {
199       process_node (or);
200     }
201
202
203   return create_cell_ref (
204                           or->sheets[n].start_col,
205                           or->sheets[n].start_row,
206                           or->sheets[n].stop_col,
207                           or->sheets[n].stop_row);
208 }
209
210
211 static void
212 ods_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
213 {
214   struct ods_reader *r = r_;
215   if ( r == NULL)
216     return ;
217
218   if (r->xtr)
219     xmlFreeTextReader (r->xtr);
220   r->xtr = NULL;
221
222   if ( ! ds_is_empty (&r->ods_errs))
223     msg (ME, "%s", ds_cstr (&r->ods_errs));
224
225   ds_destroy (&r->ods_errs);
226
227   if ( ! r->used_first_case )
228     case_unref (r->first_case);
229
230   caseproto_unref (r->proto);
231
232   //  free (r);
233 }
234
235 static void
236 process_node (struct ods_reader *r)
237 {
238   xmlChar *name = xmlTextReaderName (r->xtr);
239   if (name == NULL)
240     name = xmlStrdup (_xml ("--"));
241
242
243   r->node_type = xmlTextReaderNodeType (r->xtr);
244
245   switch (r->state)
246     {
247     case STATE_INIT:
248       if (0 == xmlStrcasecmp (name, _xml("office:spreadsheet")) &&
249           XML_READER_TYPE_ELEMENT  == r->node_type)
250         {
251           r->state = STATE_SPREADSHEET;
252           r->current_sheet = -1;
253           r->current_sheet_name = NULL;
254         }
255       break;
256     case STATE_SPREADSHEET:
257       if (0 == xmlStrcasecmp (name, _xml("table:table"))
258           && 
259           (XML_READER_TYPE_ELEMENT == r->node_type))
260         {
261           xmlFree (r->current_sheet_name);
262           r->current_sheet_name = xmlTextReaderGetAttribute (r->xtr, _xml ("table:name"));
263
264           ++r->current_sheet;
265
266           if (r->current_sheet >= r->n_allocated_sheets)
267             {
268               r->sheets = xrealloc (r->sheets, sizeof (*r->sheets) * ++r->n_allocated_sheets);
269               r->sheets[r->n_allocated_sheets - 1].start_col = -1;
270               r->sheets[r->n_allocated_sheets - 1].stop_col = -1;
271               r->sheets[r->n_allocated_sheets - 1].start_row = -1;
272               r->sheets[r->n_allocated_sheets - 1].stop_row = -1;
273               r->sheets[r->n_allocated_sheets - 1].name = xmlStrdup (r->current_sheet_name);
274             }
275
276           r->col = 0;
277           r->row = 0;
278
279           r->state = STATE_TABLE;
280         }
281       else if (0 == xmlStrcasecmp (name, _xml("office:spreadsheet")) &&
282                XML_READER_TYPE_ELEMENT  == r->node_type)
283         {
284           r->state = STATE_INIT;
285         }
286       break;
287     case STATE_TABLE:
288       if (0 == xmlStrcasecmp (name, _xml("table:table-row")) && 
289           (XML_READER_TYPE_ELEMENT  == r->node_type))
290         {
291           xmlChar *value =
292             xmlTextReaderGetAttribute (r->xtr,
293                                        _xml ("table:number-rows-repeated"));
294           
295           int row_span = value ? _xmlchar_to_int (value) : 1;
296
297           r->row += row_span;
298           r->col = 0;
299           
300           if (! xmlTextReaderIsEmptyElement (r->xtr))
301             r->state = STATE_ROW;
302         }
303       else if (0 == xmlStrcasecmp (name, _xml("table:table")) && 
304                (XML_READER_TYPE_END_ELEMENT  == r->node_type))
305         {
306           r->state = STATE_SPREADSHEET;
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           r->col_span = value ? _xmlchar_to_int (value) : 1;
319           r->col += r->col_span;
320
321           if (! xmlTextReaderIsEmptyElement (r->xtr))
322             r->state = STATE_CELL;
323         }
324       else if ( (0 == xmlStrcasecmp (name, _xml ("table:table-row")))
325                 &&
326                 (XML_READER_TYPE_END_ELEMENT  == r->node_type))
327         {
328           r->state = STATE_TABLE;
329         }
330       break;
331     case STATE_CELL:
332       if ( (0 == xmlStrcasecmp (name, _xml("text:p")))
333             &&
334            ( XML_READER_TYPE_ELEMENT  == r->node_type))
335         {
336           if (! xmlTextReaderIsEmptyElement (r->xtr))
337             r->state = STATE_CELL_CONTENT;
338         }
339       else if
340         ( (0 == xmlStrcasecmp (name, _xml("table:table-cell")))
341           &&
342           (XML_READER_TYPE_END_ELEMENT  == r->node_type)
343           )
344         {
345           r->state = STATE_ROW;
346         }
347       break;
348     case STATE_CELL_CONTENT:
349       assert (r->current_sheet >= 0);
350       assert (r->current_sheet < r->n_allocated_sheets);
351
352       if (r->sheets[r->current_sheet].start_row == -1)
353         r->sheets[r->current_sheet].start_row = r->row - 1;
354
355       if ( 
356           (r->sheets[r->current_sheet].start_col == -1)
357           ||
358           (r->sheets[r->current_sheet].start_col >= r->col - 1)
359            )
360         r->sheets[r->current_sheet].start_col = r->col - 1;
361
362       r->sheets[r->current_sheet].stop_row = r->row - 1;
363
364       if ( r->sheets[r->current_sheet].stop_col <  r->col - 1)
365         r->sheets[r->current_sheet].stop_col = r->col - 1;
366
367       if (XML_READER_TYPE_END_ELEMENT  == r->node_type)
368         r->state = STATE_CELL;
369       break;
370     default:
371       NOT_REACHED ();
372       break;
373     };
374
375   xmlFree (name);
376 }
377
378 /* 
379    A struct containing the parameters of a cell's value 
380    parsed from the xml
381 */
382 struct xml_value
383 {
384   xmlChar *type;
385   xmlChar *value;
386   xmlChar *text;
387 };
388
389 struct var_spec
390 {
391   char *name;
392   struct xml_value firstval;
393 };
394
395
396 /* Determine the width that a xmv should probably have */
397 static int
398 xmv_to_width (const struct xml_value *xmv, int fallback)
399 {
400   int width = SPREADSHEET_DEFAULT_WIDTH;
401
402   /* Non-strings always have zero width */
403   if (xmv->type != NULL && 0 != xmlStrcmp (xmv->type, _xml("string")))
404     return 0;
405
406   if ( fallback != -1)
407     return fallback;
408
409   if ( xmv->value )
410     width = ROUND_UP (xmlStrlen (xmv->value),
411                       SPREADSHEET_DEFAULT_WIDTH);
412   else if ( xmv->text)
413     width = ROUND_UP (xmlStrlen (xmv->text),
414                       SPREADSHEET_DEFAULT_WIDTH);
415
416   return width;
417 }
418
419 /*
420    Sets the VAR of case C, to the value corresponding to the xml data
421  */
422 static void
423 convert_xml_to_value (struct ccase *c, const struct variable *var,
424                       const struct xml_value *xmv)
425 {
426   union value *v = case_data_rw (c, var);
427
428   if (xmv->value == NULL && xmv->text == NULL)
429     value_set_missing (v, var_get_width (var));
430   else if ( var_is_alpha (var))
431     /* Use the text field, because it seems that there is no
432        value field for strings */
433     value_copy_str_rpad (v, var_get_width (var), xmv->text, ' ');
434   else
435     {
436       const char *text ;
437       const struct fmt_spec *fmt = var_get_write_format (var);
438       enum fmt_category fc  = fmt_get_category (fmt->type);
439
440       assert ( fc != FMT_CAT_STRING);
441
442       text =
443         xmv->value ? CHAR_CAST (const char *, xmv->value) : CHAR_CAST (const char *, xmv->text);
444
445       free (data_in (ss_cstr (text), "UTF-8",
446                      fmt->type,
447                      v,
448                      var_get_width (var),
449                      "UTF-8"));
450     }
451 }
452
453
454 /* Try to find out how many sheets there are in the "workbook" */
455 static int
456 get_sheet_count (struct zip_reader *zreader)
457 {
458   xmlTextReaderPtr mxtr;
459   struct zip_member *meta = NULL;
460   meta = zip_member_open (zreader, "meta.xml");
461
462   if ( meta == NULL)
463     return -1;
464
465   mxtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
466                          (xmlInputCloseCallback) zip_member_finish,
467                          meta,   NULL, NULL, 0);
468
469   while (1 == xmlTextReaderRead (mxtr))
470     {
471       xmlChar *name = xmlTextReaderName (mxtr);
472       if ( 0 == xmlStrcmp (name, _xml("meta:document-statistic")))
473         {
474           xmlChar *attr = xmlTextReaderGetAttribute (mxtr, _xml ("meta:table-count"));
475             
476           if ( attr != NULL)
477             {
478               int s = _xmlchar_to_int (attr);
479               return s;
480             }
481         }
482     }
483   return -1;
484 }
485
486 static void
487 ods_error_handler (void *ctx, const char *mesg,
488                         UNUSED xmlParserSeverities sev, xmlTextReaderLocatorPtr loc)
489 {
490   struct ods_reader *r = ctx;
491        
492   msg (MW, _("There was a problem whilst reading the %s file `%s' (near line %d): `%s'"),
493        "ODF",
494        r->spreadsheet.file_name,
495        xmlTextReaderLocatorLineNumber (loc),
496        mesg);
497 }
498
499
500 static bool
501 init_reader (struct ods_reader *r, bool report_errors)
502 {
503   struct zip_member *content = zip_member_open (r->zreader, "content.xml");
504   xmlTextReaderPtr xtr;
505
506   if ( content == NULL)
507     return false;
508
509   zip_member_ref (content);
510
511
512   xtr = xmlReaderForIO ((xmlInputReadCallback) zip_member_read,
513                         (xmlInputCloseCallback) zip_member_finish,
514                         content,   NULL, NULL,
515                         report_errors ? 0 : (XML_PARSE_NOERROR | XML_PARSE_NOWARNING) );
516
517   if ( xtr == NULL)
518     return false;
519
520   r->xtr = xtr;
521   r->spreadsheet.type = SPREADSHEET_ODS;
522
523   if (report_errors) 
524     xmlTextReaderSetErrorHandler (xtr, ods_error_handler, r);
525
526   return true;
527 }
528
529
530 struct spreadsheet *
531 ods_probe (const char *filename, bool report_errors)
532 {
533   struct ods_reader *r;
534   struct string errs = DS_EMPTY_INITIALIZER;
535   int sheet_count;
536   struct zip_reader *zr = zip_reader_create (filename, &errs);
537
538   if (zr == NULL)
539     return NULL;
540
541   sheet_count = get_sheet_count (zr);
542
543   r = xzalloc (sizeof *r);
544   r->zreader = zr;
545
546   if (! init_reader (r, report_errors))
547     {
548       goto error;
549     }
550
551   r->spreadsheet.n_sheets = sheet_count;
552   r->n_allocated_sheets = 0;
553   r->sheets = NULL;
554
555   ds_destroy (&errs);
556
557   r->spreadsheet.file_name = filename;
558   return &r->spreadsheet;
559
560  error:
561   zip_reader_destroy (r->zreader);
562   ds_destroy (&errs);
563   free (r);
564   return NULL;
565 }
566
567 struct casereader *
568 ods_make_reader (struct spreadsheet *spreadsheet, 
569                  const struct spreadsheet_read_options *opts)
570 {
571   intf ret = 0;
572   xmlChar *type = NULL;
573   unsigned long int vstart = 0;
574   casenumber n_cases = CASENUMBER_MAX;
575   int i;
576   struct var_spec *var_spec = NULL;
577   int n_var_specs = 0;
578
579   struct ods_reader *r = (struct ods_reader *) spreadsheet;
580   xmlChar *val_string = NULL;
581
582   assert (r);
583   r->read_names = opts->read_names;
584   ds_init_empty (&r->ods_errs);
585
586
587   if ( !init_reader (r, true))
588     goto error;
589
590 #if 0
591   if ( opts->cell_range )
592     {
593       if ( ! convert_cell_ref (opts->cell_range,
594                                &r->start_col, &r->start_row,
595                                &r->stop_col, &r->stop_row))
596         {
597           msg (SE, _("Invalid cell range `%s'"),
598                opts->cell_range);
599           goto error;
600         }
601     }
602   else
603     {
604       r->start_col = 0;
605       r->start_row = 0;
606       r->stop_col = -1;
607       r->stop_row = -1;
608     }
609 #endif
610
611   r->state = STATE_INIT;
612   r->target_sheet_name = BAD_CAST opts->sheet_name;
613   r->target_sheet_index = opts->sheet_index;
614   r->row = r->col = 0;
615
616 #if 0
617   /* If CELLRANGE was given, then we know how many variables should be read */
618   if ( r->stop_col != -1 )
619     {
620       assert (var_spec == NULL);
621       n_var_specs =  r->stop_col - r->start_col + 1;
622       var_spec = xrealloc (var_spec, sizeof (*var_spec) * n_var_specs);
623       memset (var_spec, '\0', sizeof (*var_spec) * n_var_specs);
624     }
625 #endif
626
627   /* Advance to the start of the cells for the target sheet */
628   while ( ! reading_target_sheet (r)  || r->state != STATE_ROW  )
629     {
630       if (1 != (ret = xmlTextReaderRead (r->xtr)))
631            break;
632
633       process_node (r);
634     }
635
636
637   if (ret < 1)
638     {
639       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
640            spreadsheet->file_name);
641       goto error;
642     }
643
644   if ( opts->read_names)
645     {
646       while (1 == (ret = xmlTextReaderRead (r->xtr)))
647         {
648           int idx;
649
650           process_node (r);
651
652           /* If the row is finished then stop for now */
653           if (r->state == STATE_TABLE && r->row > r->wanted_row_start)
654             break;
655
656           idx = r->col - r->wanted_col_start - 1;
657
658           if (r->state == STATE_CELL_CONTENT 
659               &&
660               XML_READER_TYPE_TEXT  == r->node_type)
661             {
662               xmlChar *value = xmlTextReaderValue (r->xtr);
663
664               if ( idx >= n_var_specs)
665                 {
666                   var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
667
668                   /* xrealloc (unlike realloc) doesn't initialise its memory to 0 */
669                   memset (var_spec + n_var_specs,
670                           0, 
671                           (n_var_specs - idx + 1) * sizeof (*var_spec));
672                   n_var_specs = idx + 1;
673                 }
674               var_spec[idx].firstval.text = 0;
675               var_spec[idx].firstval.value = 0;
676               var_spec[idx].firstval.type = 0;
677
678               var_spec [idx].name = strdup (CHAR_CAST (const char *, value));
679               xmlFree (value);
680             }
681         }
682     }
683
684   /* Read in the first row of data */
685   while (1 == xmlTextReaderRead (r->xtr))
686     {
687       int idx;
688       process_node (r);
689
690       /* If the row is finished then stop for now */
691       if (r->state == STATE_TABLE && r->row > r->wanted_row_start + (opts->read_names ? 1 : 0))
692         break;
693
694       idx = r->col - r->wanted_col_start - 1;
695
696       if ( r->state == STATE_CELL &&
697            XML_READER_TYPE_ELEMENT  == r->node_type)
698         {
699           type = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value-type"));
700           val_string = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value"));
701         }
702
703       if ( r->state == STATE_CELL_CONTENT &&
704            XML_READER_TYPE_TEXT  == r->node_type)
705         {
706           if ( idx >= n_var_specs) 
707             {
708               var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
709               var_spec [idx].name = NULL;
710               n_var_specs = idx + 1;
711             }
712             
713           var_spec [idx].firstval.type = type;
714           var_spec [idx].firstval.text = xmlTextReaderValue (r->xtr);
715           var_spec [idx].firstval.value = val_string;
716
717           val_string = NULL;
718           type = NULL;
719         }
720     }
721
722
723   /* Create the dictionary and populate it */
724   r->spreadsheet.dict = r->dict = dict_create (
725     CHAR_CAST (const char *, xmlTextReaderConstEncoding (r->xtr)));
726
727   for (i = 0; i < n_var_specs ; ++i )
728     {
729       struct fmt_spec fmt;
730       struct variable *var = NULL;
731       char *name = dict_make_unique_var_name (r->dict, var_spec[i].name, &vstart);
732       int width  = xmv_to_width (&var_spec[i].firstval, opts->asw);
733       dict_create_var (r->dict, name, width);
734       free (name);
735
736       var = dict_get_var (r->dict, i);
737
738       if ( 0 == xmlStrcmp (var_spec[i].firstval.type, _xml("date")))
739         {
740           fmt.type = FMT_DATE;
741           fmt.d = 0;
742           fmt.w = 20;
743         }
744       else
745         fmt = fmt_default_for_width (width);
746
747       var_set_both_formats (var, &fmt);
748     }
749
750   /* Create the first case, and cache it */
751   r->used_first_case = false;
752
753   if ( n_var_specs ==  0 )
754     {
755       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
756            spreadsheet->file_name);
757       goto error;
758     }
759
760   r->proto = caseproto_ref (dict_get_proto (r->dict));
761   r->first_case = case_create (r->proto);
762   case_set_missing (r->first_case);
763
764   for (i = 0 ; i < n_var_specs; ++i)
765     {
766       const struct variable *var = dict_get_var (r->dict, i);
767
768       convert_xml_to_value (r->first_case, var,  &var_spec[i].firstval);
769     }
770
771   /* Read in the first row of data */
772   while (1 == xmlTextReaderRead (r->xtr))
773     {
774       process_node (r);
775
776       if (r->state == STATE_ROW)
777         break;
778     }
779
780   //  zip_reader_destroy (zreader);
781
782 #if 0
783   for ( i = 0 ; i < n_var_specs ; ++i )
784     {
785       free (var_spec[i].firstval.type);
786       free (var_spec[i].firstval.value);
787       free (var_spec[i].firstval.text);
788       free (var_spec[i].name);
789     }
790
791   free (var_spec);
792 #endif
793
794   return casereader_create_sequential
795     (NULL,
796      r->proto,
797      n_cases,
798      &ods_file_casereader_class, r);
799
800  error:
801   
802   // zip_reader_destroy (zreader);
803
804   for ( i = 0 ; i < n_var_specs ; ++i )
805     {
806       free (var_spec[i].firstval.type);
807       free (var_spec[i].firstval.value);
808       free (var_spec[i].firstval.text);
809       free (var_spec[i].name);
810     }
811
812   free (var_spec);
813
814   dict_destroy (r->spreadsheet.dict);
815   r->spreadsheet.dict = NULL;
816   ods_file_casereader_destroy (NULL, r);
817
818
819   return NULL;
820 }
821
822
823 /* Reads and returns one case from READER's file.  Returns a null
824    pointer on failure. */
825 static struct ccase *
826 ods_file_casereader_read (struct casereader *reader UNUSED, void *r_)
827 {
828   struct ccase *c = NULL;
829   xmlChar *val_string = NULL;
830   struct ods_reader *r = r_;
831   int current_row = r->row;
832
833   if (!r->used_first_case)
834     {
835       r->used_first_case = true;
836       return r->first_case;
837     }
838
839   if (reading_target_sheet (r)  && r->state != STATE_TABLE)
840     {
841       c = case_create (r->proto);
842       case_set_missing (c);
843     }
844   
845   while (1 == xmlTextReaderRead (r->xtr))
846     {
847       process_node (r);
848 #if 0
849       if (r->row > current_row && r->state == STATE_ROW)
850         break;
851 #endif
852
853       if ( r->state == STATE_CELL &&
854            r->node_type == XML_READER_TYPE_ELEMENT )
855         {
856           val_string = xmlTextReaderGetAttribute (r->xtr, _xml ("office:value"));
857         }
858
859       if ( r->state == STATE_CELL_CONTENT && 
860            r->node_type == XML_READER_TYPE_TEXT )
861         {
862           int col;
863           struct xml_value *xmv = xzalloc (sizeof *xmv);
864           xmv->text = xmlTextReaderValue (r->xtr);
865           xmv->value = val_string;
866           val_string = NULL;
867
868           for (col = 0; col < r->col_span; ++col)
869             {
870               const int idx = r->col + col - r->wanted_col_start - 1;
871               const struct variable *var = dict_get_var (r->dict, idx);
872               convert_xml_to_value (c, var, xmv);
873             }
874
875           free (xmv->text);
876           free (xmv->value);
877           free (xmv);
878         }
879
880       if ( r->state == STATE_TABLE)
881         break;
882     }
883
884   if (NULL == c)
885     {
886       case_unref (c);
887       return NULL;
888     }
889   else
890     {
891       return c;
892     }
893 }
894 #endif