c1bf389d262c6ee0368d324d224732d9568fb157
[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",
641                          fmt->type,
642                          v,
643                          var_get_width (var),
644                          "UTF-8");
645
646       if (m)
647         {
648           char buf [FMT_STRING_LEN_MAX + 1];
649           char *cell = create_cell_ref (col, row);
650
651           msg (MW, _("Cannot convert the value in the spreadsheet cell %s to format (%s): %s"),
652                cell, fmt_to_string (fmt, buf), m);
653           free (cell);
654         }
655       free (m);
656     }
657 }
658
659 struct var_spec
660 {
661   char *name;
662   int width;
663   xmlChar *first_value;
664   int first_type;
665 };
666
667
668 static void
669 gnumeric_error_handler (void *ctx, const char *mesg,
670                         xmlParserSeverities sev UNUSED,
671                         xmlTextReaderLocatorPtr loc)
672 {
673   struct gnumeric_reader *r = ctx;
674
675   msg (MW, _("There was a problem whilst reading the %s file `%s' (near line %d): `%s'"),
676        "Gnumeric",
677        r->spreadsheet.file_name,
678        xmlTextReaderLocatorLineNumber (loc),
679        mesg);
680 }
681
682 static struct casereader *
683 gnumeric_make_reader (struct spreadsheet *spreadsheet,
684                       const struct spreadsheet_read_options *opts)
685 {
686   int type = 0;
687   int x = 0;
688   struct gnumeric_reader *r = NULL;
689   unsigned long int vstart = 0;
690   int ret;
691   casenumber n_cases = CASENUMBER_MAX;
692   int i;
693   struct var_spec *var_spec = NULL;
694   int n_var_specs = 0;
695
696   r = (struct gnumeric_reader *) (spreadsheet);
697
698   r = gnumeric_reopen (r, NULL, true);
699
700   if (opts->cell_range)
701     {
702       if (! convert_cell_ref (opts->cell_range,
703                                &r->spreadsheet.start_col, &r->spreadsheet.start_row,
704                                &r->spreadsheet.stop_col, &r->spreadsheet.stop_row))
705         {
706           msg (SE, _("Invalid cell range `%s'"),
707                opts->cell_range);
708           goto error;
709         }
710     }
711   else
712     {
713       r->spreadsheet.start_col = -1;
714       r->spreadsheet.start_row = 0;
715       r->spreadsheet.stop_col = -1;
716       r->spreadsheet.stop_row = -1;
717     }
718
719   r->target_sheet_name = BAD_CAST opts->sheet_name;
720   r->target_sheet_index = opts->sheet_index;
721   r->rsd.row = r->rsd.col = -1;
722   r->rsd.current_sheet = -1;
723   r->spreadsheet.first_case = NULL;
724   r->spreadsheet.proto = NULL;
725
726   /* Advance to the start of the cells for the target sheet */
727   while ((r->rsd.state != STATE_CELL || r->rsd.row < r->spreadsheet.start_row)
728           && 1 == (ret = xmlTextReaderRead (r->rsd.xtr)))
729     {
730       xmlChar *value ;
731       process_node (r, &r->rsd);
732       value = xmlTextReaderValue (r->rsd.xtr);
733
734       if (r->rsd.state == STATE_MAXROW  && r->rsd.node_type == XML_READER_TYPE_TEXT)
735         {
736           n_cases = 1 + _xmlchar_to_int (value) ;
737         }
738       free (value);
739     }
740
741   /* If a range has been given, then  use that to calculate the number
742      of cases */
743   if (opts->cell_range)
744     {
745       n_cases = MIN (n_cases, r->spreadsheet.stop_row - r->spreadsheet.start_row + 1);
746     }
747
748   if (opts->read_names)
749     {
750       r->spreadsheet.start_row++;
751       n_cases --;
752     }
753
754
755   /* Read in the first row of cells,
756      including the headers if read_names was set */
757   while (
758          ((r->rsd.state == STATE_CELLS_START && r->rsd.row <= r->spreadsheet.start_row) || r->rsd.state == STATE_CELL)
759          && (ret = xmlTextReaderRead (r->rsd.xtr))
760         )
761     {
762       int idx;
763
764       if (r->rsd.state == STATE_CELL && r->rsd.node_type == XML_READER_TYPE_TEXT)
765         {
766           xmlChar *attr =
767             xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
768
769           type  =  _xmlchar_to_int (attr);
770
771           xmlFree (attr);
772         }
773
774       process_node (r, &r->rsd);
775
776       if (r->rsd.row > r->spreadsheet.start_row)
777         {
778           xmlChar *attr =
779             xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
780
781           r->vtype  =  _xmlchar_to_int (attr);
782
783           xmlFree (attr);
784           break;
785         }
786
787       if (r->rsd.col < r->spreadsheet.start_col ||
788            (r->spreadsheet.stop_col != -1 && r->rsd.col > r->spreadsheet.stop_col))
789         continue;
790
791       idx = r->rsd.col - r->spreadsheet.start_col;
792
793       if (idx  >= n_var_specs)
794         {
795           int i;
796           var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
797           for (i = n_var_specs; i <= idx; ++i)
798           {
799             var_spec [i].name = NULL;
800             var_spec [i].width = -1;
801             var_spec [i].first_value = NULL;
802             var_spec [i].first_type = -1;
803           }
804           n_var_specs =  idx + 1 ;
805         }
806
807       var_spec [idx].first_type = type;
808
809       if (r->rsd.node_type == XML_READER_TYPE_TEXT)
810         {
811           xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
812           const char *text  = CHAR_CAST (const char *, value);
813
814           if (r->rsd.row < r->spreadsheet.start_row)
815             {
816               if (opts->read_names)
817                 {
818                   var_spec [idx].name = xstrdup (text);
819                 }
820             }
821           else
822             {
823               var_spec [idx].first_value = xmlStrdup (value);
824
825               if (-1 ==  var_spec [idx].width)
826                 var_spec [idx].width = (opts->asw == -1) ?
827                   ROUND_UP (strlen(text), SPREADSHEET_DEFAULT_WIDTH) : opts->asw;
828             }
829
830           free (value);
831         }
832       else if (r->rsd.node_type == XML_READER_TYPE_ELEMENT
833                 && r->rsd.state == STATE_CELL)
834         {
835           if (r->rsd.row == r->spreadsheet.start_row)
836             {
837               xmlChar *attr =
838                 xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
839
840               if (NULL == attr || VALUE_STRING !=  _xmlchar_to_int (attr))
841                 var_spec [idx].width = 0;
842
843               free (attr);
844             }
845         }
846     }
847
848   {
849     const xmlChar *enc = xmlTextReaderConstEncoding (r->rsd.xtr);
850     if (enc == NULL)
851       goto error;
852     /* Create the dictionary and populate it */
853     spreadsheet->dict = dict_create (CHAR_CAST (const char *, enc));
854   }
855
856   for (i = 0 ; i < n_var_specs ; ++i)
857     {
858       char *name;
859
860       if ((var_spec[i].name == NULL) && (var_spec[i].first_value == NULL))
861         continue;
862
863       /* Probably no data exists for this variable, so allocate a
864          default width */
865       if (var_spec[i].width == -1)
866         var_spec[i].width = SPREADSHEET_DEFAULT_WIDTH;
867
868       name = dict_make_unique_var_name (r->spreadsheet.dict, var_spec[i].name, &vstart);
869       dict_create_var (r->spreadsheet.dict, name, var_spec[i].width);
870       free (name);
871     }
872
873   /* Create the first case, and cache it */
874   r->spreadsheet.used_first_case = false;
875
876   if (n_var_specs ==  0)
877     {
878       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
879            spreadsheet->file_name);
880       goto error;
881     }
882
883   r->spreadsheet.proto = caseproto_ref (dict_get_proto (r->spreadsheet.dict));
884   r->spreadsheet.first_case = case_create (r->spreadsheet.proto);
885   case_set_missing (r->spreadsheet.first_case);
886
887
888   for (i = 0 ; i < n_var_specs ; ++i)
889     {
890       const struct variable *var;
891
892       if ((var_spec[i].name == NULL) && (var_spec[i].first_value == NULL))
893         continue;
894
895       var = dict_get_var (r->spreadsheet.dict, x++);
896
897       convert_xml_string_to_value (r->spreadsheet.first_case, var,
898                                    var_spec[i].first_value,
899                                    var_spec[i].first_type,
900                                    r->rsd.col + i - 1,
901                                    r->rsd.row - 1);
902     }
903
904   for (i = 0 ; i < n_var_specs ; ++i)
905     {
906       free (var_spec[i].first_value);
907       free (var_spec[i].name);
908     }
909
910   free (var_spec);
911
912
913   return casereader_create_sequential
914     (NULL,
915      r->spreadsheet.proto,
916      n_cases,
917      &gnm_file_casereader_class, r);
918
919
920  error:
921   for (i = 0 ; i < n_var_specs ; ++i)
922     {
923       free (var_spec[i].first_value);
924       free (var_spec[i].name);
925     }
926
927   free (var_spec);
928
929   gnm_file_casereader_destroy (NULL, r);
930
931   return NULL;
932 };
933
934
935 /* Reads and returns one case from READER's file.  Returns a null
936    pointer on failure. */
937 static struct ccase *
938 gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_)
939 {
940   struct ccase *c;
941   int ret = 0;
942
943   struct gnumeric_reader *r = r_;
944   int current_row = r->rsd.row;
945
946   if (!r->spreadsheet.used_first_case)
947     {
948       r->spreadsheet.used_first_case = true;
949       return r->spreadsheet.first_case;
950     }
951
952   c = case_create (r->spreadsheet.proto);
953   case_set_missing (c);
954
955   if (r->spreadsheet.start_col == -1)
956     r->spreadsheet.start_col = r->rsd.min_col;
957
958
959   while ((r->rsd.state == STATE_CELL || r->rsd.state == STATE_CELLS_START)
960          && r->rsd.row == current_row && (ret = xmlTextReaderRead (r->rsd.xtr)))
961     {
962       process_node (r, &r->rsd);
963
964       if (r->rsd.state == STATE_CELL && r->rsd.node_type == XML_READER_TYPE_ELEMENT)
965         {
966           xmlChar *attr =
967             xmlTextReaderGetAttribute (r->rsd.xtr, _xml ("ValueType"));
968
969           r->vtype  = _xmlchar_to_int (attr);
970
971           xmlFree (attr);
972         }
973
974       if (r->rsd.col < r->spreadsheet.start_col || (r->spreadsheet.stop_col != -1 &&
975                                      r->rsd.col > r->spreadsheet.stop_col))
976         continue;
977
978       if (r->rsd.col - r->spreadsheet.start_col >= caseproto_get_n_widths (r->spreadsheet.proto))
979         continue;
980
981       if (r->spreadsheet.stop_row != -1 && r->rsd.row > r->spreadsheet.stop_row)
982         break;
983
984
985       if (r->rsd.node_type == XML_READER_TYPE_TEXT)
986         {
987           xmlChar *value = xmlTextReaderValue (r->rsd.xtr);
988           const int idx = r->rsd.col - r->spreadsheet.start_col;
989           const struct variable *var = dict_get_var (r->spreadsheet.dict, idx);
990
991           convert_xml_string_to_value (c, var, value, r->vtype,
992                                        r->rsd.col, r->rsd.row);
993
994           xmlFree (value);
995         }
996     }
997
998   if (ret == 1)
999     return c;
1000   else
1001     {
1002       case_unref (c);
1003       return NULL;
1004     }
1005 }
1006
1007 static struct gnumeric_reader *
1008 gnumeric_reopen (struct gnumeric_reader *r, const char *filename, bool show_errors)
1009 {
1010   int ret = -1;
1011   struct state_data *sd;
1012
1013   xmlTextReaderPtr xtr;
1014   gzFile gz;
1015
1016   assert (r == NULL || filename == NULL);
1017
1018   if (filename)
1019     {
1020       gz = gzopen (filename, "r");
1021     }
1022   else
1023     {
1024       gz = gzopen (r->spreadsheet.file_name, "r");
1025     }
1026
1027   if (NULL == gz)
1028     return NULL;
1029
1030   if (r == NULL)
1031     {
1032       r = xzalloc (sizeof *r);
1033       r->n_sheets = -1;
1034       r->spreadsheet.file_name = strdup (filename);
1035       struct spreadsheet *s = SPREADSHEET_CAST (r);
1036       strcpy (s->type, "GNM");
1037       s->destroy = gnumeric_destroy;
1038       s->make_reader = gnumeric_make_reader;
1039       s->get_sheet_name = gnumeric_get_sheet_name;
1040       s->get_sheet_range = gnumeric_get_sheet_range;
1041       s->get_sheet_n_sheets = gnumeric_get_sheet_n_sheets;
1042       s->get_sheet_n_rows = gnumeric_get_sheet_n_rows;
1043       s->get_sheet_n_columns = gnumeric_get_sheet_n_columns;
1044       s->get_sheet_cell = gnumeric_get_sheet_cell;
1045
1046       sd = &r->msd;
1047       hmap_init (&r->cache);
1048     }
1049   else
1050     {
1051       sd = &r->rsd;
1052     }
1053   sd->gz = gz;
1054
1055   r = (struct gnumeric_reader *) spreadsheet_ref (SPREADSHEET_CAST (r));
1056
1057   {
1058     xtr = xmlReaderForIO ((xmlInputReadCallback) gzread,
1059                           (xmlInputCloseCallback) gzclose, gz,
1060                           NULL, NULL,
1061                           show_errors ? 0 : (XML_PARSE_NOERROR | XML_PARSE_NOWARNING));
1062
1063     if (xtr == NULL)
1064       {
1065         gzclose (gz);
1066         free (r);
1067         return NULL;
1068       }
1069
1070     if (show_errors)
1071       xmlTextReaderSetErrorHandler (xtr, gnumeric_error_handler, r);
1072
1073     sd->row = sd->col = -1;
1074     sd->state = STATE_PRE_INIT;
1075     sd->xtr = xtr;
1076   }
1077
1078   r->target_sheet_name = NULL;
1079   r->target_sheet_index = -1;
1080
1081
1082   /* Advance to the start of the workbook.
1083      This gives us some confidence that we are actually dealing with a gnumeric
1084      spreadsheet.
1085    */
1086   while ((sd->state != STATE_INIT)
1087           && 1 == (ret = xmlTextReaderRead (sd->xtr)))
1088     {
1089       process_node (r, sd);
1090     }
1091
1092   if (ret != 1)
1093     {
1094       /* Does not seem to be a gnumeric file */
1095       spreadsheet_unref (&r->spreadsheet);
1096       return NULL;
1097     }
1098
1099   if (show_errors)
1100     {
1101       const xmlChar *enc = xmlTextReaderConstEncoding (sd->xtr);
1102       xmlCharEncoding xce = xmlParseCharEncoding (CHAR_CAST (const char *, enc));
1103
1104       if (XML_CHAR_ENCODING_UTF8 != xce)
1105         {
1106           /* I have been told that ALL gnumeric files are UTF8 encoded.  If that is correct, this
1107              can never happen. */
1108           msg (MW, _("The gnumeric file `%s' is encoded as %s instead of the usual UTF-8 encoding. "
1109                      "Any non-ascii characters will be incorrectly imported."),
1110                r->spreadsheet.file_name,
1111                enc);
1112         }
1113     }
1114
1115   return r;
1116 }
1117
1118
1119 struct spreadsheet *
1120 gnumeric_probe (const char *filename, bool report_errors)
1121 {
1122   struct gnumeric_reader *r = gnumeric_reopen (NULL, filename, report_errors);
1123
1124   return &r->spreadsheet;
1125 }