Make both work at the same time
[pspp] / src / data / gnumeric-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2007, 2009, 2010, 2011, 2012 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 #include "c-xvasprintf.h"
32
33 #if !GNM_SUPPORT
34
35 struct casereader *
36 gnumeric_open_reader (struct spreadsheet_read_info *gri, struct spreadsheet_read_options *opts, struct dictionary **dict)
37 {
38   msg (ME, _("Support for %s files was not compiled into this installation of PSPP"), "Gnumeric");
39
40   return NULL;
41 }
42
43 #else
44
45 #include "data/gnumeric-reader.h"
46
47 #include <assert.h>
48 #include <stdbool.h>
49 #include <errno.h>
50 #include <libxml/xmlreader.h>
51 #include <zlib.h>
52
53 #include "data/case.h"
54 #include "data/casereader-provider.h"
55 #include "data/dictionary.h"
56 #include "data/identifier.h"
57 #include "data/value.h"
58 #include "data/variable.h"
59 #include "libpspp/i18n.h"
60 #include "libpspp/str.h"
61
62 #include "gl/xalloc.h"
63
64 static void gnm_file_casereader_destroy (struct casereader *, void *);
65
66 static struct ccase *gnm_file_casereader_read (struct casereader *, void *);
67
68 static const struct casereader_class gnm_file_casereader_class =
69   {
70     gnm_file_casereader_read,
71     gnm_file_casereader_destroy,
72     NULL,
73     NULL,
74   };
75
76 enum reader_state
77   {
78     STATE_PRE_INIT = 0,        /* Initial state */
79     STATE_SHEET_COUNT,      /* Found the sheet index */
80     STATE_INIT ,           /* Other Initial state */
81     STATE_SHEET_START,     /* Found the start of a sheet */
82     STATE_SHEET_NAME,      /* Found the sheet name */
83     STATE_MAXROW,
84     STATE_MAXCOL,
85     STATE_SHEET_FOUND,     /* Found the sheet that we actually want */
86     STATE_CELLS_START,     /* Found the start of the cell array */
87     STATE_CELL             /* Found a cell */
88   };
89
90 struct sheet_detail
91 {
92   xmlChar *name;
93
94   int start_col;
95   int stop_col;
96   int start_row;
97   int stop_row;
98
99   int maxcol;
100   int maxrow;
101
102   z_off_t offset;
103 };
104
105
106 struct gnumeric_reader
107 {
108   struct spreadsheet spreadsheet;
109
110   xmlTextReaderPtr xtr;
111   gzFile gz;
112
113   enum reader_state state;
114
115   int row;
116   int col;
117   int min_col;
118   int node_type;
119   int sheet_index;
120
121   int start_col;
122   int stop_col;
123   int start_row;
124   int stop_row;
125   
126   struct sheet_detail *sheets;
127
128   const xmlChar *target_sheet;
129   int target_sheet_index;
130
131   struct caseproto *proto;
132   struct dictionary *dict;
133   struct ccase *first_case;
134   bool used_first_case;
135 };
136
137
138 const char *
139 gnumeric_get_sheet_name (struct spreadsheet *s, int n)
140 {
141   struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
142   assert (n < s->sheets);
143
144   return gr->sheets[n].name;
145 }
146
147
148 static void process_node (struct gnumeric_reader *r);
149
150
151 char *
152 gnumeric_get_sheet_range (struct spreadsheet *s, int n)
153 {
154   int ret;
155   struct gnumeric_reader *gr = (struct gnumeric_reader *) s;
156   
157   assert (n < s->sheets);
158
159   while ( 
160          (gr->sheets[n].stop_col == -1)
161          && 
162          (1 == (ret = xmlTextReaderRead (gr->xtr)))
163           )
164     {
165       process_node (gr);
166     }
167
168
169   return create_cell_ref (
170                           gr->sheets[n].start_col,
171                           gr->sheets[n].start_row,
172                           gr->sheets[n].stop_col,
173                           gr->sheets[n].stop_row);
174 }
175
176
177 static void
178 gnm_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
179 {
180   int i;
181   struct gnumeric_reader *r = r_;
182   if ( r == NULL)
183         return ;
184
185   if ( r->xtr)
186     xmlFreeTextReader (r->xtr);
187
188   if ( ! r->used_first_case )
189     case_unref (r->first_case);
190
191   caseproto_unref (r->proto);
192
193   for (i = 0; i < r->spreadsheet.sheets; ++i)
194     {
195       xmlFree (r->sheets[i].name);
196     }
197     
198   free (r->sheets);
199
200   free (r);
201 }
202
203 static void
204 process_node (struct gnumeric_reader *r)
205 {
206   xmlChar *name = xmlTextReaderName (r->xtr);
207   if (name == NULL)
208     name = xmlStrdup (_xml ("--"));
209
210
211   r->node_type = xmlTextReaderNodeType (r->xtr);
212
213   switch ( r->state)
214     {
215     case STATE_PRE_INIT:
216       r->sheet_index = -1;
217       if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) &&
218           XML_READER_TYPE_ELEMENT  == r->node_type)
219         {
220           r->state = STATE_SHEET_COUNT;
221           r->spreadsheet.sheets = 0;
222         }
223       break;
224
225     case STATE_SHEET_COUNT:
226       if (0 == xmlStrcasecmp (name, _xml("gnm:SheetName")) &&
227           XML_READER_TYPE_ELEMENT  == r->node_type)
228         {
229           struct sheet_detail *sd ;
230           r->spreadsheet.sheets++;
231           r->sheets = xrealloc (r->sheets, r->spreadsheet.sheets * sizeof *r->sheets);
232           sd = &r->sheets[r->spreadsheet.sheets - 1];
233           sd->start_col = sd->stop_col = sd->start_row = sd->stop_row = -1;
234           sd->offset = -1;
235         }
236       else if (0 == xmlStrcasecmp (name, _xml("gnm:SheetNameIndex")) &&
237           XML_READER_TYPE_END_ELEMENT  == r->node_type)
238         {
239           r->state = STATE_INIT;
240         }
241       else if (XML_READER_TYPE_TEXT == r->node_type)
242         {
243           r->sheets [r->spreadsheet.sheets - 1].name = xmlTextReaderValue (r->xtr);
244         }
245       break;
246
247     case STATE_INIT:
248       if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet")) &&
249           XML_READER_TYPE_ELEMENT  == r->node_type)
250         {
251           ++r->sheet_index;
252           r->state = STATE_SHEET_START;
253           r->sheets[r->sheet_index].offset = gztell (r->gz);
254         }
255       break;
256     case STATE_SHEET_START:
257       if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
258           XML_READER_TYPE_ELEMENT  == r->node_type)
259         {
260           r->state = STATE_SHEET_NAME;
261         }
262       break;
263     case STATE_SHEET_NAME:
264       if (0 == xmlStrcasecmp (name, _xml("gnm:Name"))  &&
265           XML_READER_TYPE_END_ELEMENT  == r->node_type)
266         {
267           r->state = STATE_INIT;
268         }
269       else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet"))  &&
270           XML_READER_TYPE_END_ELEMENT  == r->node_type)
271         {
272           r->state = STATE_INIT;
273         }
274       else if (XML_READER_TYPE_TEXT == r->node_type)
275         {
276           if ( r->target_sheet != NULL)
277             {
278               xmlChar *value = xmlTextReaderValue (r->xtr);
279               if ( 0 == xmlStrcmp (value, r->target_sheet))
280                 r->state = STATE_SHEET_FOUND;
281               free (value);
282             }
283           else if (r->target_sheet_index == r->sheet_index + 1)
284             {
285               r->state = STATE_SHEET_FOUND;
286             }
287           else if (r->target_sheet_index == -1)
288             {
289               r->state = STATE_SHEET_FOUND;
290             }
291         }
292       break;
293     case STATE_SHEET_FOUND:
294       if (0 == xmlStrcasecmp (name, _xml("gnm:Cells"))  &&
295           XML_READER_TYPE_ELEMENT  == r->node_type)
296         {
297           r->min_col = INT_MAX;
298           if (! xmlTextReaderIsEmptyElement (r->xtr))
299             r->state = STATE_CELLS_START;
300         }
301       else if (0 == xmlStrcasecmp (name, _xml("gnm:MaxRow"))  &&
302           XML_READER_TYPE_ELEMENT  == r->node_type)
303         {
304           r->state = STATE_MAXROW;
305         }
306       else if (0 == xmlStrcasecmp (name, _xml("gnm:MaxCol"))  &&
307           XML_READER_TYPE_ELEMENT  == r->node_type)
308         {
309           r->state = STATE_MAXCOL;
310         }
311       else if (0 == xmlStrcasecmp (name, _xml("gnm:Sheet"))  &&
312           XML_READER_TYPE_END_ELEMENT  == r->node_type)
313         {
314           r->state = STATE_INIT;
315         }
316       break;
317     case STATE_MAXROW:
318       if (0 == xmlStrcasecmp (name, _xml("gnm:MaxRow"))  &&
319           XML_READER_TYPE_END_ELEMENT  == r->node_type)
320         {
321           r->state = STATE_SHEET_FOUND;
322         }
323       else if (r->node_type == XML_READER_TYPE_TEXT)
324         {
325           xmlChar *value = xmlTextReaderValue (r->xtr);
326           r->sheets[r->sheet_index].maxrow = _xmlchar_to_int (value);
327           xmlFree (value);
328         }
329       break;
330     case STATE_MAXCOL:
331       if (0 == xmlStrcasecmp (name, _xml("gnm:MaxCol"))  &&
332           XML_READER_TYPE_END_ELEMENT  == r->node_type)
333         {
334           r->state = STATE_SHEET_FOUND;
335         }
336       else if (r->node_type == XML_READER_TYPE_TEXT)
337         {
338           xmlChar *value = xmlTextReaderValue (r->xtr);
339           r->sheets[r->sheet_index].maxcol = _xmlchar_to_int (value);
340           xmlFree (value);
341         }
342       break;
343     case STATE_CELLS_START:
344       if (0 == xmlStrcasecmp (name, _xml ("gnm:Cell"))  &&
345           XML_READER_TYPE_ELEMENT  == r->node_type)
346         {
347           xmlChar *attr = NULL;
348           r->state = STATE_CELL;
349
350           attr = xmlTextReaderGetAttribute (r->xtr, _xml ("Col"));
351           r->col =  _xmlchar_to_int (attr);
352           free (attr);
353
354           if (r->col < r->min_col)
355             r->min_col = r->col;
356
357           attr = xmlTextReaderGetAttribute (r->xtr, _xml ("Row"));
358           r->row = _xmlchar_to_int (attr);
359           free (attr);
360           if (r->sheets[r->sheet_index].start_row == -1)
361             {
362               r->sheets[r->sheet_index].start_row = r->row;
363             }
364
365           if (r->sheets[r->sheet_index].start_col == -1)
366             {
367               r->sheets[r->sheet_index].start_col = r->col;
368             }
369         }
370       else if (0 == xmlStrcasecmp (name, _xml("gnm:Cells"))  &&
371                XML_READER_TYPE_END_ELEMENT  == r->node_type)
372         {
373           r->sheets[r->sheet_index].stop_col = r->col;
374           r->sheets[r->sheet_index].stop_row = r->row;
375           r->state = STATE_SHEET_NAME;
376         }
377       break;
378     case STATE_CELL:
379       if (0 == xmlStrcasecmp (name, _xml("gnm:Cell"))  &&
380                               XML_READER_TYPE_END_ELEMENT  == r->node_type)
381         {
382           r->state = STATE_CELLS_START;
383         }
384       break;
385     default:
386       break;
387     };
388
389   xmlFree (name);
390 }
391
392
393 /*
394    Sets the VAR of case C, to the value corresponding to the xml string XV
395  */
396 static void
397 convert_xml_string_to_value (struct ccase *c, const struct variable *var,
398                              const xmlChar *xv)
399 {
400   union value *v = case_data_rw (c, var);
401
402   if (xv == NULL)
403     value_set_missing (v, var_get_width (var));
404   else if ( var_is_alpha (var))
405     value_copy_str_rpad (v, var_get_width (var), xv, ' ');
406   else
407     {
408       const char *text = CHAR_CAST (const char *, xv);
409       char *endptr;
410
411       errno = 0;
412       v->f = c_strtod (text, &endptr);
413       if ( errno != 0 || endptr == text)
414         v->f = SYSMIS;
415     }
416 }
417
418 struct var_spec
419 {
420   char *name;
421   int width;
422   xmlChar *first_value;
423 };
424
425
426 void 
427 gnumeric_destroy (struct spreadsheet *s)
428 {
429   struct gnumeric_reader *r = (struct gnumeric *) s;
430   gnm_file_casereader_destroy (NULL, s);
431 }
432
433 struct spreadsheet *
434 gnumeric_probe (const char *filename)
435 {
436   int ret;
437   struct gnumeric_reader *r = NULL;
438   xmlTextReaderPtr xtr;
439
440   gzFile gz;
441   gz = gzopen (filename, "r");
442
443   if (NULL == gz)
444     return NULL;
445
446   xtr = xmlReaderForIO ((xmlInputReadCallback) gzread,
447                            (xmlInputCloseCallback) gzclose, gz,
448                            NULL, NULL, 0);
449
450   if (xtr == NULL)
451     {
452       gzclose (gz);
453       return NULL;
454     }
455
456   r = xzalloc (sizeof *r);
457   
458   r->gz = gz;
459   r->xtr = xtr;
460   r->spreadsheet.sheets = -1;
461   r->state = STATE_PRE_INIT;
462
463   r->target_sheet = NULL;
464   r->target_sheet_index = -1;
465
466
467   /* Advance to the start of the workbook.
468      This gives us some confidence that we are actually dealing with a gnumeric
469      spreadsheet.
470    */
471   while ( (r->state != STATE_INIT )
472           && 1 == (ret = xmlTextReaderRead (r->xtr)))
473     {
474       process_node (r);
475     }
476
477   if (ret != 1)
478     {
479       /* Not a gnumeric spreadsheet */
480       xmlFreeTextReader (r->xtr);
481       free (r);
482       return NULL;
483     }
484     
485   r->spreadsheet.type = SPREADSHEET_GNUMERIC;
486   r->spreadsheet.file_name = filename;
487   
488   return &r->spreadsheet;
489 }
490
491
492 struct casereader *
493 gnumeric_make_reader (struct spreadsheet *spreadsheet,
494                       const struct spreadsheet_read_info *gri, 
495                       struct spreadsheet_read_options *opts)
496 {
497   struct gnumeric_reader *r = NULL;
498   unsigned long int vstart = 0;
499   int ret;
500   casenumber n_cases = CASENUMBER_MAX;
501   int i;
502   struct var_spec *var_spec = NULL;
503   int n_var_specs = 0;
504
505   r = (struct gnumeric_reader *) (spreadsheet);
506
507   if ( opts->cell_range )
508     {
509       if ( ! convert_cell_ref (opts->cell_range,
510                                &r->start_col, &r->start_row,
511                                &r->stop_col, &r->stop_row))
512         {
513           msg (SE, _("Invalid cell range `%s'"),
514                opts->cell_range);
515           goto error;
516         }
517     }
518   else
519     {
520       r->start_col = -1;
521       r->start_row = 0;
522       r->stop_col = -1;
523       r->stop_row = -1;
524     }
525
526   r->target_sheet = BAD_CAST opts->sheet_name;
527   r->target_sheet_index = opts->sheet_index;
528   r->row = r->col = -1;
529   r->sheet_index = -1;
530
531   /* Advance to the start of the cells for the target sheet */
532   while ( (r->state != STATE_CELL || r->row < r->start_row )
533           && 1 == (ret = xmlTextReaderRead (r->xtr)))
534     {
535       xmlChar *value ;
536       process_node (r);
537       value = xmlTextReaderValue (r->xtr);
538
539       if ( r->state == STATE_MAXROW  && r->node_type == XML_READER_TYPE_TEXT)
540         {
541           n_cases = 1 + _xmlchar_to_int (value) ;
542         }
543       free (value);
544     }
545
546   /* If a range has been given, then  use that to calculate the number
547      of cases */
548   if ( opts->cell_range)
549     {
550       n_cases = MIN (n_cases, r->stop_row - r->start_row + 1);
551     }
552
553   if ( gri->read_names )
554     {
555       r->start_row++;
556       n_cases --;
557     }
558
559   /* Read in the first row of cells,
560      including the headers if read_names was set */
561   while (
562          (( r->state == STATE_CELLS_START && r->row <= r->start_row) || r->state == STATE_CELL )
563          && (ret = xmlTextReaderRead (r->xtr))
564          )
565     {
566       int idx;
567       process_node (r);
568
569       if ( r->row > r->start_row ) break;
570
571       if ( r->col < r->start_col ||
572            (r->stop_col != -1 && r->col > r->stop_col))
573         continue;
574
575       idx = r->col - r->start_col;
576
577       if ( idx  >= n_var_specs )
578         {
579           int i;
580           var_spec = xrealloc (var_spec, sizeof (*var_spec) * (idx + 1));
581           for (i = n_var_specs; i <= idx; ++i)
582           {
583             var_spec [i].name = NULL;
584             var_spec [i].width = -1;
585             var_spec [i].first_value = NULL;
586           }
587           n_var_specs =  idx + 1 ;
588         }
589
590       if ( r->node_type == XML_READER_TYPE_TEXT )
591         {
592           xmlChar *value = xmlTextReaderValue (r->xtr);
593           const char *text  = CHAR_CAST (const char *, value);
594
595           if ( r->row < r->start_row)
596             {
597               if ( gri->read_names )
598                 {
599                   var_spec [idx].name = xstrdup (text);
600                 }
601             }
602           else
603             {
604               var_spec [idx].first_value = xmlStrdup (value);
605
606               if (-1 ==  var_spec [idx].width )
607                 var_spec [idx].width = (gri->asw == -1) ?
608                   ROUND_UP (strlen(text), SPREADSHEET_DEFAULT_WIDTH) : gri->asw;
609             }
610
611           free (value);
612         }
613       else if ( r->node_type == XML_READER_TYPE_ELEMENT
614                 && r->state == STATE_CELL)
615         {
616           if ( r->row == r->start_row )
617             {
618               xmlChar *attr =
619                 xmlTextReaderGetAttribute (r->xtr, _xml ("ValueType"));
620
621               if ( NULL == attr || 60 !=  _xmlchar_to_int (attr))
622                 var_spec [idx].width = 0;
623
624               free (attr);
625             }
626         }
627     }
628
629   {
630     const xmlChar *enc = xmlTextReaderConstEncoding (r->xtr);
631     if ( enc == NULL)
632       goto error;
633     /* Create the dictionary and populate it */
634     spreadsheet->dict = r->dict = dict_create (CHAR_CAST (const char *, enc));
635   }
636
637   for (i = 0 ; i < n_var_specs ; ++i )
638     {
639       char *name;
640
641       if ( (var_spec[i].name == NULL) && (var_spec[i].first_value == NULL))
642         continue;
643
644       /* Probably no data exists for this variable, so allocate a
645          default width */
646       if ( var_spec[i].width == -1 )
647         var_spec[i].width = SPREADSHEET_DEFAULT_WIDTH;
648
649       name = dict_make_unique_var_name (r->dict, var_spec[i].name, &vstart);
650       dict_create_var (r->dict, name, var_spec[i].width);
651       free (name);
652     }
653
654   /* Create the first case, and cache it */
655   r->used_first_case = false;
656
657   if ( n_var_specs ==  0 )
658     {
659       msg (MW, _("Selected sheet or range of spreadsheet `%s' is empty."),
660            spreadsheet->file_name);
661       goto error;
662     }
663
664   r->proto = caseproto_ref (dict_get_proto (r->dict));
665   r->first_case = case_create (r->proto);
666   case_set_missing (r->first_case);
667
668   int x = 0;
669   for ( i = 0 ; i < n_var_specs ; ++i )
670     {
671       if ( (var_spec[i].name == NULL) && (var_spec[i].first_value == NULL))
672         continue;
673
674       const struct variable *var = dict_get_var (r->dict, x++);
675
676       convert_xml_string_to_value (r->first_case, var,
677                                    var_spec[i].first_value);
678     }
679
680   for ( i = 0 ; i < n_var_specs ; ++i )
681     {
682       free (var_spec[i].first_value);
683       free (var_spec[i].name);
684     }
685
686   free (var_spec);
687   
688   
689   if (opts->cell_range == NULL)
690     {
691       opts->cell_range = c_xasprintf ("%c%d:%c%ld", 
692                                        r->start_col + 'A',
693                                        r->start_row,
694                                        r->stop_col + 'A' + caseproto_get_n_widths (r->proto),
695                                        r->start_row + n_cases);
696     }
697   
698   return casereader_create_sequential
699     (NULL,
700      r->proto,
701      n_cases,
702      &gnm_file_casereader_class, r);
703
704
705  error:
706   for ( i = 0 ; i < n_var_specs ; ++i )
707     {
708       free (var_spec[i].first_value);
709       free (var_spec[i].name);
710     }
711
712   free (var_spec);
713   dict_destroy (spreadsheet->dict);
714   spreadsheet->dict = NULL;
715
716   gnm_file_casereader_destroy (NULL, r);
717
718   return NULL;
719 };
720
721
722 /* Reads and returns one case from READER's file.  Returns a null
723    pointer on failure. */
724 static struct ccase *
725 gnm_file_casereader_read (struct casereader *reader UNUSED, void *r_)
726 {
727   struct ccase *c;
728   int ret = 0;
729
730   struct gnumeric_reader *r = r_;
731   int current_row = r->row;
732
733   if ( !r->used_first_case )
734     {
735       r->used_first_case = true;
736       return r->first_case;
737     }
738
739   c = case_create (r->proto);
740   case_set_missing (c);
741
742   if (r->start_col == -1)
743     r->start_col = r->min_col;
744
745   while ((r->state == STATE_CELL || r->state == STATE_CELLS_START )
746          && r->row == current_row && (ret = xmlTextReaderRead (r->xtr)))
747     {
748       process_node (r);
749
750       if ( r->col < r->start_col || (r->stop_col != -1 &&
751                                      r->col > r->stop_col))
752         continue;
753
754       if ( r->col - r->start_col >= caseproto_get_n_widths (r->proto))
755         continue;
756
757       if ( r->stop_row != -1 && r->row > r->stop_row)
758         break;
759
760       if ( r->node_type == XML_READER_TYPE_TEXT )
761         {
762           xmlChar *value = xmlTextReaderValue (r->xtr);
763
764           const int idx = r->col - r->start_col;
765
766           const struct variable *var = dict_get_var (r->dict, idx);
767
768           convert_xml_string_to_value (c, var, value);
769
770           free (value);
771         }
772
773     }
774
775   if (ret == 1)
776     return c;
777   else
778     {
779       case_unref (c);
780       return NULL;
781     }
782 }
783
784
785 #endif /* GNM_SUPPORT */