fbuf: New data structure for buffered file I/O.
[pspp] / src / data / gnumeric-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2009, 2010, 2011, 2012, 2013, 2016  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
22 #include "gl/minmax.h"
23 #include "gl/c-strtod.h"
24
25 #include "gettext.h"
26 #define _(msgid) gettext (msgid)
27 #define N_(msgid) (msgid)
28
29 #include "spreadsheet-reader.h"
30
31 #if !GNM_READ_SUPPORT
32
33 struct spreadsheet *
34 gnumeric_probe (const char *filename, bool report_errors)
35 {
36   if (report_errors)
37     msg (ME, _("Support for %s files was not compiled into this installation of PSPP"), "Gnumeric");
38
39   return NULL;
40 }
41
42 const char *
43 gnumeric_get_sheet_name (struct spreadsheet *s, int n)
44 {
45   return NULL;
46 }
47
48 char *
49 gnumeric_get_sheet_range (struct spreadsheet *s, int n)
50 {
51   return NULL;
52 }
53
54 struct casereader *
55 gnumeric_make_reader (struct spreadsheet *spreadsheet,
56                       const struct spreadsheet_read_options *opts)
57 {
58   return NULL;
59 }
60
61 void
62 gnumeric_unref (struct spreadsheet *r)
63 {
64 }
65
66
67 #else
68
69 #include "data/gnumeric-reader.h"
70
71 #include <assert.h>
72 #include <stdbool.h>
73 #include <errno.h>
74 #include <libxml/xmlreader.h>
75 #include <zlib.h>
76
77 #include "data/format.h"
78 #include "data/data-in.h"
79 #include "data/case.h"
80 #include "data/casereader-provider.h"
81 #include "data/dictionary.h"
82 #include "data/identifier.h"
83 #include "data/value.h"
84 #include "data/variable.h"
85 #include "libpspp/i18n.h"
86 #include "libpspp/str.h"
87
88 #include "gl/xalloc.h"
89
90
91 /* Shamelessly lifted from the Gnumeric sources:
92    https://git.gnome.org/browse/gnumeric/tree/src/value.h
93  */
94 enum gnm_value_type
95 {
96   VALUE_EMPTY   = 10,
97   VALUE_BOOLEAN = 20,
98   VALUE_INTEGER = 30, /* Note, this was removed from gnumeric in 2006 - old versions may of
99                          course still be around. New ones are supposed to use float.*/
100   VALUE_FLOAT   = 40,
101   VALUE_ERROR   = 50,
102   VALUE_STRING  = 60,
103   VALUE_CELLRANGE  = 70,
104   VALUE_ARRAY   = 80
105 };
106
107
108
109 static void gnm_file_casereader_destroy (struct casereader *, void *);
110
111 static struct ccase *gnm_file_casereader_read (struct casereader *, void *);
112
113
114 static const struct casereader_class gnm_file_casereader_class =
115   {
116     gnm_file_casereader_read,
117     gnm_file_casereader_destroy,
118     NULL,
119     NULL,
120   };
121
122 enum reader_state
123   {
124     STATE_PRE_INIT = 0,        /* Initial state */
125     STATE_SHEET_COUNT,      /* Found the sheet index */
126     STATE_INIT ,           /* Other Initial state */
127     STATE_SHEET_START,     /* Found the start of a sheet */
128     STATE_SHEET_NAME,      /* Found the sheet name */
129     STATE_MAXROW,
130     STATE_MAXCOL,
131     STATE_SHEET_FOUND,     /* Found the sheet that we actually want */
132     STATE_CELLS_START,     /* Found the start of the cell array */
133     STATE_CELL             /* Found a cell */
134   };
135
136 struct sheet_detail
137 {
138   /* The name of the sheet (utf8 encoding) */
139   char *name;
140
141   int start_col;
142   int stop_col;
143   int start_row;
144   int stop_row;
145
146   int maxcol;
147   int maxrow;
148 };
149
150 struct state_data
151 {
152   /* The libxml reader for this instance */
153   xmlTextReaderPtr xtr;
154
155   /* An internal state variable */
156   enum reader_state state;
157
158   int node_type;
159   int current_sheet;
160
161   int row;
162   int col;
163
164   int min_col;
165 };
166
167
168 static void
169 state_data_destroy (struct state_data *sd)
170 {
171   xmlFreeTextReader (sd->xtr);
172 }
173
174
175 struct gnumeric_reader
176 {
177   struct spreadsheet spreadsheet;
178
179   struct state_data rsd;
180   struct state_data msd;
181
182   int start_col;
183   int stop_col;
184   int start_row;
185   int stop_row;
186
187   struct sheet_detail *sheets;
188
189   const xmlChar *target_sheet;
190   int target_sheet_index;
191
192   struct caseproto *proto;
193   struct dictionary *dict;
194   struct ccase *first_case;
195   bool used_first_case;
196
197   enum gnm_value_type vtype;
198 };
199
200
201 void
202 gnumeric_unref (struct spreadsheet *s)
203 {
204   struct gnumeric_reader *r = (struct gnumeric_reader *) s;
205
206   if (0 == --s->ref_cnt)
207     {
208       int i;
209
210       for (i = 0; i < s->n_sheets; ++i)
211         {
212           xmlFree (r->sheets[i].name);
213         }
214
215
216       free (r->sheets);
217       state_data_destroy (&r->msd);
218
219       dict_destroy (r->dict);
220
221       free (s->file_name);
222
223       free (r);
224     }
225 }
226
227
228 const char *
229 gnumeric_get_sheet_name (struct spreadsheet *s, int n)
230 {
231   struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
232   assert (n < s->n_sheets);
233
234   return gr->sheets[n].name;
235 }
236
237
238 static void process_node (struct gnumeric_reader *r, struct state_data *sd);
239
240
241
242 char *
243 gnumeric_get_sheet_range (struct spreadsheet *s, int n)
244 {
245   int ret;
246   struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
247
248   assert (n < s->n_sheets);
249
250   while (
251          (gr->sheets[n].stop_col == -1)
252          &&
253          (1 == (ret = xmlTextReaderRead (gr->msd.xtr)))
254           )
255     {
256       process_node (gr, &gr->msd);
257     }
258
259   return create_cell_range (
260                           gr->sheets[n].start_col,
261                           gr->sheets[n].start_row,
262                           gr->sheets[n].stop_col,
263                           gr->sheets[n].stop_row);
264 }
265
266
267 static void
268 gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
269 {
270   struct gnumeric_reader *r = r_;
271
272   if ( r == NULL)
273         return ;
274
275   state_data_destroy (&r->rsd);
276
277   if (r->first_case &&  ! r->used_first_case )
278     case_unref (r->first_case);
279
280   if (r->proto)
281     caseproto_unref (r->proto);
282
283   gnumeric_unref (&r->spreadsheet);
284 }
285
286
287 static void
288 process_node (struct gnumeric_reader *r, struct state_data *sd)
289 {
290   xmlChar *name = xmlTextReaderName (sd->xtr);
291   if (name == NULL)
292     name = xmlStrdup (_xml ("--"));
293
294   sd->node_type = xmlTextReaderNodeType (sd->xtr);
295
296   switch (sd->state)
297     {
298     case STATE_PRE_INIT:
299       sd->current_sheet = -1;
300       if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) &&
301           XML_READER_TYPE_ELEMENT  == sd->node_type)
302         {
303           sd->state = STATE_SHEET_COUNT;
304         }
305       break;
306
307     case STATE_SHEET_COUNT:
308       if (0 == xmlStrcasecmp (name, _xml("gnm:SheetName")) &&
309           XML_READER_TYPE_ELEMENT  == sd->node_type)
310         {
311           ++sd->current_sheet;
312           if (sd->current_sheet + 1 > r->spreadsheet.n_sheets)
313             {
314               struct sheet_detail *detail ;
315               r->sheets = xrealloc (r->sheets, (sd->current_sheet + 1) * sizeof *r->sheets);
316               detail = &r->sheets[sd->current_sheet];
317               detail->start_col = detail->stop_col = detail->start_row = detail->stop_row = -1;
318               detail->name = NULL;
319               r->spreadsheet.n_sheets = sd->current_sheet + 1;
320             }
321         }
322       else if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) &&
323           XML_READER_TYPE_END_ELEMENT  == sd->node_type)
324         {
325           sd->state = STATE_INIT;
326           sd->current_sheet = -1;
327         }
328       else if (XML_READER_TYPE_TEXT == sd->node_type)
329         {
330           if ( r->sheets [r->spreadsheet.n_sheets - 1].name == NULL)
331             r->sheets [r->spreadsheet.n_sheets - 1].name = CHAR_CAST (char *, xmlTextReaderValue (sd->xtr));
332         }
333       break;
334
335     case STATE_INIT:
336       if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) &&
337           XML_READER_TYPE_ELEMENT  == sd->node_type)
338         {
339           ++sd->current_sheet;
340           sd->state = STATE_SHEET_START;
341         }
342       break;
343     case STATE_SHEET_START:
344       if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
345           XML_READER_TYPE_ELEMENT  == sd->node_type)
346         {
347           sd->state = STATE_SHEET_NAME;
348         }
349       break;
350     case STATE_SHEET_NAME:
351       if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
352           XML_READER_TYPE_END_ELEMENT  == sd->node_type)
353         {
354           sd->state = STATE_INIT;
355         }
356       else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet"))  &&
357           XML_READER_TYPE_END_ELEMENT  == sd->node_type)
358         {
359           sd->state = STATE_INIT;
360         }
361       else if (XML_READER_TYPE_TEXT == sd->node_type)
362         {
363           if ( r->target_sheet != NULL)
364             {
365               xmlChar *value = xmlTextReaderValue (sd->xtr);
366               if ( 0 == xmlStrcmp (value, r->target_sheet))
367                 sd->state = STATE_SHEET_FOUND;
368               free (value);
369             }
370           else if (r->target_sheet_index == sd->current_sheet + 1)
371             {
372               sd->state = STATE_SHEET_FOUND;
373             }
374           else if (r->target_sheet_index == -1)
375             {
376               sd->state = STATE_SHEET_FOUND;
377             }
378         }
379       break;
380     case STATE_SHEET_FOUND:
381       if (0 == xmlStrcasecmp (name, _xml("gnm:Cells"))  &&
382           XML_READER_TYPE_ELEMENT  == sd->node_type)
383         {
384           sd->min_col = INT_MAX;
385           if (! xmlTextReaderIsEmptyElement (sd->xtr))
386             sd->state = STATE_CELLS_START;
387         }
388       else if (0 == xmlStrcasecmp (name, _xml("gnm:MaxRow"))  &&
389           XML_READER_TYPE_ELEMENT  == sd->node_type)
390         {
391           sd->state = STATE_MAXROW;
392         }
393       else if (0 == xmlStrcasecmp (name, _xml("gnm:MaxCol"))  &&
394           XML_READER_TYPE_ELEMENT  == sd->node_type)
395         {
396           sd->state = STATE_MAXCOL;
397         }
398       else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet"))  &&
399           XML_READER_TYPE_END_ELEMENT  == sd->node_type)
400         {
401           sd->state = STATE_INIT;
402         }
403       break;
404     case STATE_MAXROW:
405       if (0 == xmlStrcasecmp (name, _xml("gnm:MaxRow"))  &&
406           XML_READER_TYPE_END_ELEMENT  == sd->node_type)
407         {
408           sd->state = STATE_SHEET_FOUND;
409         }
410       else if (sd->node_type == XML_READER_TYPE_TEXT)
411         {
412           xmlChar *value = xmlTextReaderValue (sd->xtr);
413           r->sheets[sd->current_sheet].maxrow = _xmlchar_to_int (value);
414           xmlFree (value);
415         }
416       break;
417     case STATE_MAXCOL:
418       if (0 == xmlStrcasecmp (name, _xml("gnm:MaxCol"))  &&
419           XML_READER_TYPE_END_ELEMENT  == sd->node_type)
420         {
421           sd->state = STATE_SHEET_FOUND;
422         }
423       else if (sd->node_type == XML_READER_TYPE_TEXT)
424         {
425           xmlChar *value = xmlTextReaderValue (sd->xtr);
426           r->sheets[sd->current_sheet].maxcol = _xmlchar_to_int (value);
427           xmlFree (value);
428         }
429       break;
430     case STATE_CELLS_START:
431       if (0 == xmlStrcasecmp (name, _xml ("gnm:Cell"))  &&
432           XML_READER_TYPE_ELEMENT  == sd->node_type)
433         {
434           xmlChar *attr = NULL;
435
436           attr = xmlTextReaderGetAttribute (sd->xtr, _xml ("Col"));
437           sd->col =  _xmlchar_to_int (attr);
438           free (attr);
439
440           if (sd->col < sd->min_col)
441             sd->min_col = sd->col;
442
443           attr = xmlTextReaderGetAttribute (sd->xtr, _xml ("Row"));
444           sd->row = _xmlchar_to_int (attr);
445           free (attr);
446
447           if (r->sheets[sd->current_sheet].start_row == -1)
448             {
449               r->sheets[sd->current_sheet].start_row = sd->row;
450             }
451
452           if (r->sheets[sd->current_sheet].start_col == -1)
453             {
454               r->sheets[sd->current_sheet].start_col = sd->col;
455             }
456           if (! xmlTextReaderIsEmptyElement (sd->xtr))
457             sd->state = STATE_CELL;
458         }
459       else if ( (0 == xmlStrcasecmp (name, _xml("gnm:Cells")))  &&  (XML_READER_TYPE_END_ELEMENT  == sd->node_type) )
460         {
461           r->sheets[sd->current_sheet].stop_col = sd->col;
462           r->sheets[sd->current_sheet].stop_row = sd->row;
463           sd->state = STATE_SHEET_NAME;
464         }
465       break;
466     case STATE_CELL:
467       if (0 == xmlStrcasecmp (name, _xml("gnm:Cell"))  && XML_READER_TYPE_END_ELEMENT  == sd->node_type)
468         {
469           sd->state = STATE_CELLS_START;
470         }
471       break;
472     default:
473       break;
474     };
475
476   xmlFree (name);
477 }
478
479
480 /*
481    Sets the VAR of case C, to the value corresponding to the xml string XV
482  */
483 static void
484 convert_xml_string_to_value (struct ccase *c, const struct variable *var,
485                              const xmlChar *xv, enum gnm_value_type type, int col, int row)
486 {
487   union value *v = case_data_rw (c, var);
488
489   if (xv == NULL)
490     value_set_missing (v, var_get_width (var));
491   else if ( var_is_alpha (var))
492     value_copy_str_rpad (v, var_get_width (var), xv, ' ');
493   else if (type == VALUE_FLOAT || type == VALUE_INTEGER)
494     {
495       const char *text = CHAR_CAST (const char *, xv);
496       char *endptr;
497
498       errno = 0;
499       v->f = c_strtod (text, &endptr);
500       if ( errno != 0 || endptr == text)
501         v->f = SYSMIS;
502     }
503   else
504     {
505       const char *text = CHAR_CAST (const char *, xv);
506
507       const struct fmt_spec *fmt = var_get_write_format (var);
508
509       char *m = data_in (ss_cstr (text), "UTF-8",
510                          fmt->type,
511                          v,
512                          var_get_width (var),
513                          "UTF-8");
514
515       if (m)
516         {
517           char buf [FMT_STRING_LEN_MAX + 1];
518           char *cell = create_cell_ref (col, row);
519
520           msg (MW, _("Cannot convert the value in the spreadsheet cell %s to format (%s): %s"),
521                cell, fmt_to_string (fmt, buf), m);
522           free (cell);
523         }
524       free (m);
525     }
526 }
527
528 struct var_spec
529 {
530   char *name;
531   int width;
532   xmlChar *first_value;
533   int first_type;
534 };
535
536
537 static void
538 gnumeric_error_handler (void *ctx, const char *mesg,
539                         UNUSED xmlParserSeverities sev, xmlTextReaderLocatorPtr loc)
540 {
541   struct gnumeric_reader *r = ctx;
542
543   msg (MW, _("There was a problem whilst reading the %s file `%s' (near line %d): `%s'"),
544        "Gnumeric",
545        r->spreadsheet.file_name,
546        xmlTextReaderLocatorLineNumber (loc),
547        mesg);
548 }
549
550 static struct gnumeric_reader *
551 gnumeric_reopen (struct gnumeric_reader *r, const char *filename, bool show_errors)
552 {
553   int ret = -1;
554   struct state_data *sd;
555
556   xmlTextReaderPtr xtr;
557   gzFile gz;
558
559   assert (r == NULL || filename == NULL);
560
561   if (filename)
562     {
563       gz = gzopen (filename, "r");
564     }
565   else
566     {
567       gz = gzopen (r->spreadsheet.file_name, "r");
568     }
569
570   if (NULL == gz)
571     return NULL;
572
573
574   xtr = xmlReaderForIO ((xmlInputReadCallback) gzread,
575                         (xmlInputCloseCallback) gzclose, gz,
576                         NULL, NULL,
577                         show_errors ? 0 : (XML_PARSE_NOERROR | XML_PARSE_NOWARNING) );
578
579   if (xtr == NULL)
580     {
581       gzclose (gz);
582       return NULL;
583     }
584
585   if (r == NULL)
586     {
587       r = xzalloc (sizeof *r);
588       r->spreadsheet.n_sheets = -1;
589       r->spreadsheet.file_name = strdup (filename);
590       sd = &r->msd;
591     }
592   else
593     {
594       sd = &r->rsd;
595     }
596
597   if (show_errors)
598     xmlTextReaderSetErrorHandler (xtr, gnumeric_error_handler, r);
599
600   r->target_sheet = NULL;
601   r->target_sheet_index = -1;
602
603   sd->row = sd->col = -1;
604   sd->state = STATE_PRE_INIT;
605   sd->xtr = xtr;
606   r->spreadsheet.ref_cnt++;
607
608
609   /* Advance to the start of the workbook.
610      This gives us some confidence that we are actually dealing with a gnumeric
611      spreadsheet.
612    */
613   while ( (sd->state != STATE_INIT )
614           && 1 == (ret = xmlTextReaderRead (sd->xtr)))
615     {
616       process_node (r, sd);
617     }
618
619
620   if ( ret != 1)
621     {
622       /* Does not seem to be a gnumeric file */
623       gnumeric_unref (&r->spreadsheet);
624       return NULL;
625     }
626
627   r->spreadsheet.type = SPREADSHEET_GNUMERIC;
628
629   if (show_errors)
630     {
631       const xmlChar *enc = xmlTextReaderConstEncoding (sd->xtr);
632       xmlCharEncoding xce = xmlParseCharEncoding (CHAR_CAST (const char *, enc));
633
634       if ( XML_CHAR_ENCODING_UTF8 != xce)
635         {
636           /* I have been told that ALL gnumeric files are UTF8 encoded.  If that is correct, this
637              can never happen. */
638           msg (MW, _("The gnumeric file `%s' is encoded as %s instead of the usual UTF-8 encoding. "
639                      "Any non-ascii characters will be incorrectly imported."),
640                r->spreadsheet.file_name,
641                enc);
642         }
643     }
644
645   return r;
646 }
647
648
649 struct spreadsheet *
650 gnumeric_probe (const char *filename, bool report_errors)
651 {
652   struct gnumeric_reader *r = gnumeric_reopen (NULL, filename, report_errors);
653
654   return &r->spreadsheet;
655 }
656
657
658 struct casereader *
659 gnumeric_make_reader (struct spreadsheet *spreadsheet,
660                       const struct spreadsheet_read_options *opts)
661 {
662   int type = 0;
663   int x = 0;
664   struct gnumeric_reader *r = NULL;
665   unsigned long int vstart = 0;
666   int ret;
667   casenumber n_cases = CASENUMBER_MAX;
668   int i;
669   struct var_spec *var_spec = NULL;
670   int n_var_specs = 0;
671
672   r = (struct gnumeric_reader *) (spreadsheet);
673
674   r = gnumeric_reopen (r, NULL, true);
675
676   if ( opts->cell_range )
677     {
678       if ( ! convert_cell_ref (opts->cell_range,
679                                &r->start_col, &r->start_row,
680                                &r->stop_col, &r->stop_row))
681         {
682           msg (SE, _("Invalid cell range `%s'"),
683                opts->cell_range);
684           goto error;
685         }
686     }
687   else
688     {
689       r->start_col = -1;
690       r->start_row = 0;
691       r->stop_col = -1;
692       r->stop_row = -1;
693     }
694
695   r->target_sheet = BAD_CAST opts->sheet_name;
696   r->target_sheet_index = opts->sheet_index;
697   r->rsd.row = r->rsd.col = -1;
698   r->rsd.current_sheet = -1;
699   r->first_case = NULL;
700   r->proto = NULL;
701
702   /* Advance to the start of the cells for the target sheet */
703   while ( (r->rsd.state != STATE_CELL || r->rsd.row < r->start_row )
704           && 1 == (ret = xmlTextReaderRead (r->rsd.xtr)))
705     {
706       xmlChar *value ;
707       process_node (r, &r->rsd);
708       value = xmlTextReaderValue (r->rsd.xtr);
709
710       if ( r->rsd.state == STATE_MAXROW  && r->rsd.node_type == XML_READER_TYPE_TEXT)
711         {
712           n_cases = 1 + _xmlchar_to_int (value) ;
713         }
714       free (value);
715     }
716
717   /* If a range has been given, then  use that to calculate the number
718      of cases */
719   if ( opts->cell_range)
720     {
721       n_cases = MIN (n_cases, r->stop_row - r->start_row + 1);
722     }
723
724   if ( opts->read_names )
725     {
726       r->start_row++;
727       n_cases --;
728     }
729
730
731   /* Read in the first row of cells,
732      including the headers if read_names was set */
733   while (
734          (( r->rsd.state == STATE_CELLS_START && r->rsd.row <= r->start_row) || r->rsd.state == STATE_CELL )
735          && (ret = xmlTextReaderRead (r->rsd.xtr))
736          )
737     {
738       int idx;
739
740       if (r->rsd.state == STATE_CELL && r->rsd.node_type == XML_READER_TYPE_TEXT)
741         {
742           xmlChar *attr =
743             xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
744
745           type  =  _xmlchar_to_int (attr);
746
747           xmlFree (attr);
748         }
749
750       process_node (r, &r->rsd);
751
752       if ( r->rsd.row > r->start_row )
753         {
754           xmlChar *attr =
755             xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
756
757           r->vtype  =  _xmlchar_to_int (attr);
758
759           xmlFree (attr);
760           break;
761         }
762
763       if ( r->rsd.col < r->start_col ||
764            (r->stop_col != -1 && r->rsd.col > r->stop_col))
765         continue;
766
767       idx = r->rsd.col - r->start_col;
768
769       if ( idx  >= n_var_specs )
770         {
771           int i;
772           var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
773           for (i = n_var_specs; i <= idx; ++i)
774           {
775             var_spec [i].name = NULL;
776             var_spec [i].width = -1;
777             var_spec [i].first_value = NULL;
778             var_spec [i].first_type = -1;
779           }
780           n_var_specs =  idx + 1 ;
781         }
782
783       var_spec [idx].first_type = type;
784
785       if ( r->rsd.node_type == XML_READER_TYPE_TEXT )
786         {
787           xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
788           const char *text  = CHAR_CAST (const char *, value);
789
790           if ( r->rsd.row < r->start_row)
791             {
792               if ( opts->read_names )
793                 {
794                   var_spec [idx].name = xstrdup (text);
795                 }
796             }
797           else
798             {
799               var_spec [idx].first_value = xmlStrdup (value);
800
801               if (-1 ==  var_spec [idx].width )
802                 var_spec [idx].width = (opts->asw == -1) ?
803                   ROUND_UP (strlen(text), SPREADSHEET_DEFAULT_WIDTH) : opts->asw;
804             }
805
806           free (value);
807         }
808       else if ( r->rsd.node_type == XML_READER_TYPE_ELEMENT
809                 && r->rsd.state == STATE_CELL)
810         {
811           if ( r->rsd.row == r->start_row )
812             {
813               xmlChar *attr =
814                 xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
815
816               if ( NULL == attr || VALUE_STRING !=  _xmlchar_to_int (attr))
817                 var_spec [idx].width = 0;
818
819               free (attr);
820             }
821         }
822     }
823
824   {
825     const xmlChar *enc = xmlTextReaderConstEncoding (r->rsd.xtr);
826     if ( enc == NULL)
827       goto error;
828     /* Create the dictionary and populate it */
829     spreadsheet->dict = r->dict = dict_create (CHAR_CAST (const char *, enc));
830   }
831
832   for (i = 0 ; i < n_var_specs ; ++i )
833     {
834       char *name;
835
836       if ( (var_spec[i].name == NULL) && (var_spec[i].first_value == NULL))
837         continue;
838
839       /* Probably no data exists for this variable, so allocate a
840          default width */
841       if ( var_spec[i].width == -1 )
842         var_spec[i].width = SPREADSHEET_DEFAULT_WIDTH;
843
844       name = dict_make_unique_var_name (r->dict, var_spec[i].name, &vstart);
845       dict_create_var (r->dict, name, var_spec[i].width);
846       free (name);
847     }
848
849   /* Create the first case, and cache it */
850   r->used_first_case = false;
851
852   if ( n_var_specs ==  0 )
853     {
854       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
855            spreadsheet->file_name);
856       goto error;
857     }
858
859   r->proto = caseproto_ref (dict_get_proto (r->dict));
860   r->first_case = case_create (r->proto);
861   case_set_missing (r->first_case);
862
863
864   for ( i = 0 ; i < n_var_specs ; ++i )
865     {
866       const struct variable *var;
867
868       if ( (var_spec[i].name == NULL) && (var_spec[i].first_value == NULL))
869         continue;
870
871       var = dict_get_var (r->dict, x++);
872
873       convert_xml_string_to_value (r->first_case, var,
874                                    var_spec[i].first_value,
875                                    var_spec[i].first_type,
876                                    r->rsd.col + i - 1,
877                                    r->rsd.row - 1);
878     }
879
880   for ( i = 0 ; i < n_var_specs ; ++i )
881     {
882       free (var_spec[i].first_value);
883       free (var_spec[i].name);
884     }
885
886   free (var_spec);
887
888
889   return casereader_create_sequential
890     (NULL,
891      r->proto,
892      n_cases,
893      &gnm_file_casereader_class, r);
894
895
896  error:
897   for ( i = 0 ; i < n_var_specs ; ++i )
898     {
899       free (var_spec[i].first_value);
900       free (var_spec[i].name);
901     }
902
903   free (var_spec);
904
905   gnm_file_casereader_destroy (NULL, r);
906
907   return NULL;
908 };
909
910
911 /* Reads and returns one case from READER's file.  Returns a null
912    pointer on failure. */
913 static struct ccase *
914 gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_)
915 {
916   struct ccase *c;
917   int ret = 0;
918
919   struct gnumeric_reader *r = r_;
920   int current_row = r->rsd.row;
921
922   if ( !r->used_first_case )
923     {
924       r->used_first_case = true;
925       return r->first_case;
926     }
927
928   c = case_create (r->proto);
929   case_set_missing (c);
930
931   if (r->start_col == -1)
932     r->start_col = r->rsd.min_col;
933
934
935   while ((r->rsd.state == STATE_CELL || r->rsd.state == STATE_CELLS_START )
936          && r->rsd.row == current_row && (ret = xmlTextReaderRead (r->rsd.xtr)))
937     {
938       process_node (r, &r->rsd);
939
940       if (r->rsd.state == STATE_CELL && r->rsd.node_type == XML_READER_TYPE_ELEMENT)
941         {
942           xmlChar *attr =
943             xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
944
945           r->vtype  = _xmlchar_to_int (attr);
946
947           xmlFree (attr);
948         }
949
950       if ( r->rsd.col < r->start_col || (r->stop_col != -1 &&
951                                      r->rsd.col > r->stop_col))
952         continue;
953
954       if ( r->rsd.col - r->start_col >= caseproto_get_n_widths (r->proto))
955         continue;
956
957       if ( r->stop_row != -1 && r->rsd.row > r->stop_row)
958         break;
959
960
961       if ( r->rsd.node_type == XML_READER_TYPE_TEXT )
962         {
963           xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
964           const int idx = r->rsd.col - r->start_col;
965           const struct variable *var = dict_get_var (r->dict, idx);
966
967           convert_xml_string_to_value (c, var, value, r->vtype,
968                                        r->rsd.col, r->rsd.row);
969
970           xmlFree (value);
971         }
972     }
973
974   if (ret == 1)
975     return c;
976   else
977     {
978       case_unref (c);
979       return NULL;
980     }
981 }
982
983
984 #endif /* GNM_READ_SUPPORT */