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