Changed include paths to be explicitly specified in the #include directive.
[pspp-builds.git] / src / data / por-file-reader.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4    Code for parsing floating-point numbers adapted from GNU C
5    library.
6
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License as
9    published by the Free Software Foundation; either version 2 of the
10    License, or (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA. */
21
22 #include <config.h>
23 #include "por-file-reader.h"
24 #include <libpspp/message.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <math.h>
31 #include <setjmp.h>
32 #include <libpspp/alloc.h>
33 #include <stdbool.h>
34 #include "case.h"
35 #include <libpspp/compiler.h>
36 #include "dictionary.h"
37 #include "file-handle-def.h"
38 #include "format.h"
39 #include <libpspp/hash.h>
40 #include <libpspp/magic.h>
41 #include <libpspp/misc.h>
42 #include <libpspp/pool.h>
43 #include <libpspp/str.h>
44 #include "value-labels.h"
45 #include "variable.h"
46
47 #include "gettext.h"
48 #define _(msgid) gettext (msgid)
49
50 #include <libpspp/debug-print.h>
51
52 /* portable_to_local[PORTABLE] translates the given portable
53    character into the local character set. */
54 static const char portable_to_local[256] =
55   {
56     "                                                                "
57     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
58     "<(+|&[]!$*);^-/|,%_>?`:$@'=\"      ~-   0123456789   -() {}\\     "
59     "                                                                "
60   };
61
62 /* Portable file reader. */
63 struct pfm_reader
64   {
65     struct pool *pool;          /* All the portable file state. */
66
67     jmp_buf bail_out;           /* longjmp() target for error handling. */
68
69     struct file_handle *fh;     /* File handle. */
70     FILE *file;                 /* File stream. */
71     char cc;                    /* Current character. */
72     char *trans;                /* 256-byte character set translation table. */
73     int var_cnt;                /* Number of variables. */
74     int weight_index;           /* 0-based index of weight variable, or -1. */
75     int *widths;                /* Variable widths, 0 for numeric. */
76     int value_cnt;              /* Number of `value's per case. */
77     bool ok;                    /* Set false on I/O error. */
78   };
79
80 static void
81 error (struct pfm_reader *r, const char *msg,...)
82      PRINTF_FORMAT (2, 3);
83
84 /* Displays MSG as an error message and aborts reading the
85    portable file via longjmp(). */
86 static void
87 error (struct pfm_reader *r, const char *msg, ...)
88 {
89   struct error e;
90   const char *filename;
91   char *title;
92   va_list args;
93
94   e.class = ME;
95   e.where.filename = NULL;
96   e.where.line_number = 0;
97   filename = fh_get_filename (r->fh);
98   e.title = title = pool_alloc (r->pool, strlen (filename) + 80);
99   sprintf (title, _("portable file %s corrupt at offset %ld: "),
100            filename, ftell (r->file));
101
102   va_start (args, msg);
103   err_vmsg (&e, msg, args);
104   va_end (args);
105
106   r->ok = false;
107
108   longjmp (r->bail_out, 1);
109 }
110
111 /* Closes portable file reader R, after we're done with it. */
112 void
113 pfm_close_reader (struct pfm_reader *r)
114 {
115   if (r != NULL)
116     pool_destroy (r->pool);
117 }
118
119 /* Read a single character into cur_char.  */
120 static void
121 advance (struct pfm_reader *r)
122 {
123   int c;
124
125   while ((c = getc (r->file)) == '\r' || c == '\n')
126     continue;
127   if (c == EOF)
128     error (r, _("unexpected end of file")); 
129
130   if (r->trans != NULL)
131     c = r->trans[c]; 
132   r->cc = c;
133 }
134
135 /* Skip a single character if present, and return whether it was
136    skipped. */
137 static inline bool
138 match (struct pfm_reader *r, int c)
139 {
140   if (r->cc == c)
141     {
142       advance (r);
143       return true;
144     }
145   else
146     return false;
147 }
148
149 static void read_header (struct pfm_reader *);
150 static void read_version_data (struct pfm_reader *, struct pfm_read_info *);
151 static void read_variables (struct pfm_reader *, struct dictionary *);
152 static void read_value_label (struct pfm_reader *, struct dictionary *);
153 void dump_dictionary (struct dictionary *);
154
155 /* Reads the dictionary from file with handle H, and returns it in a
156    dictionary structure.  This dictionary may be modified in order to
157    rename, reorder, and delete variables, etc. */
158 struct pfm_reader *
159 pfm_open_reader (struct file_handle *fh, struct dictionary **dict,
160                  struct pfm_read_info *info)
161 {
162   struct pool *volatile pool = NULL;
163   struct pfm_reader *volatile r = NULL;
164
165   *dict = dict_create ();
166   if (!fh_open (fh, FH_REF_FILE, "portable file", "rs"))
167     goto error;
168
169   /* Create and initialize reader. */
170   pool = pool_create ();
171   r = pool_alloc (pool, sizeof *r);
172   r->pool = pool;
173   if (setjmp (r->bail_out))
174     goto error;
175   r->fh = fh;
176   r->file = pool_fopen (r->pool, fh_get_filename (r->fh), "rb");
177   r->weight_index = -1;
178   r->trans = NULL;
179   r->var_cnt = 0;
180   r->widths = NULL;
181   r->value_cnt = 0;
182   r->ok = true;
183
184   /* Check that file open succeeded, prime reading. */
185   if (r->file == NULL)
186     {
187       msg (ME, _("An error occurred while opening \"%s\" for reading "
188                  "as a portable file: %s."),
189            fh_get_filename (r->fh), strerror (errno));
190       goto error;
191     }
192   
193   /* Read header, version, date info, product id, variables. */
194   read_header (r);
195   read_version_data (r, info);
196   read_variables (r, *dict);
197
198   /* Read value labels. */
199   while (match (r, 'D'))
200     read_value_label (r, *dict);
201
202   /* Check that we've made it to the data. */
203   if (!match (r, 'F'))
204     error (r, _("Data record expected."));
205
206   return r;
207
208  error:
209   pfm_close_reader (r);
210   dict_destroy (*dict);
211   *dict = NULL;
212   return NULL;
213 }
214 \f
215 /* Returns the value of base-30 digit C,
216    or -1 if C is not a base-30 digit. */
217 static int
218 base_30_value (unsigned char c) 
219 {
220   static const char base_30_digits[] = "0123456789ABCDEFGHIJKLMNOPQRST";
221   const char *p = strchr (base_30_digits, c);
222   return p != NULL ? p - base_30_digits : -1;
223 }
224
225 /* Read a floating point value and return its value. */
226 static double
227 read_float (struct pfm_reader *r)
228 {
229   double num = 0.;
230   int exponent = 0;
231   bool got_dot = false;         /* Seen a decimal point? */
232   bool got_digit = false;       /* Seen any digits? */
233   bool negative = false;        /* Number is negative? */
234
235   /* Skip leading spaces. */
236   while (match (r, ' '))
237     continue;
238
239   /* `*' indicates system-missing. */
240   if (match (r, '*'))
241     {
242       advance (r);      /* Probably a dot (.) but doesn't appear to matter. */
243       return SYSMIS;
244     }
245
246   negative = match (r, '-');
247   for (;;)
248     {
249       int digit = base_30_value (r->cc);
250       if (digit != -1)
251         {
252           got_digit = true;
253
254           /* Make sure that multiplication by 30 will not overflow.  */
255           if (num > DBL_MAX * (1. / 30.))
256             /* The value of the digit doesn't matter, since we have already
257                gotten as many digits as can be represented in a `double'.
258                This doesn't necessarily mean the result will overflow.
259                The exponent may reduce it to within range.
260
261                We just need to record that there was another
262                digit so that we can multiply by 10 later.  */
263             ++exponent;
264           else
265             num = (num * 30.0) + digit;
266
267           /* Keep track of the number of digits after the decimal point.
268              If we just divided by 30 here, we would lose precision.  */
269           if (got_dot)
270             --exponent;
271         }
272       else if (!got_dot && r->cc == '.')
273         /* Record that we have found the decimal point.  */
274         got_dot = 1;
275       else
276         /* Any other character terminates the number.  */
277         break;
278
279       advance (r);
280     }
281
282   /* Check that we had some digits. */
283   if (!got_digit)
284     error (r, "Number expected.");
285
286   /* Get exponent if any. */
287   if (r->cc == '+' || r->cc == '-')
288     {
289       long int exp = 0;
290       bool negative_exponent = r->cc == '-';
291       int digit;
292
293       for (advance (r); (digit = base_30_value (r->cc)) != -1; advance (r))
294         {
295           if (exp > LONG_MAX / 30)
296             {
297               exp = LONG_MAX;
298               break;
299             }
300           exp = exp * 30 + digit;
301         }
302
303       /* We don't check whether there were actually any digits, but we
304          probably should. */
305       if (negative_exponent)
306         exp = -exp;
307       exponent += exp;
308     }
309
310   /* Numbers must end with `/'. */
311   if (!match (r, '/'))
312     error (r, _("Missing numeric terminator."));
313
314   /* Multiply `num' by 30 to the `exponent' power, checking for
315      overflow.  */
316   if (exponent < 0)
317     num *= pow (30.0, (double) exponent);
318   else if (exponent > 0)
319     {
320       if (num > DBL_MAX * pow (30.0, (double) -exponent))
321         num = DBL_MAX;
322       else
323         num *= pow (30.0, (double) exponent);
324     }
325
326   return negative ? -num : num;
327 }
328   
329 /* Read an integer and return its value. */
330 static int
331 read_int (struct pfm_reader *r)
332 {
333   double f = read_float (r);
334   if (floor (f) != f || f >= INT_MAX || f <= INT_MIN)
335     error (r, _("Invalid integer."));
336   return f;
337 }
338
339 /* Reads a string into BUF, which must have room for 256
340    characters. */
341 static void
342 read_string (struct pfm_reader *r, char *buf)
343 {
344   int n = read_int (r);
345   if (n < 0 || n > 255)
346     error (r, _("Bad string length %d."), n);
347   
348   while (n-- > 0)
349     {
350       *buf++ = r->cc;
351       advance (r);
352     }
353   *buf = '\0';
354 }
355
356 /* Reads a string and returns a copy of it allocated from R's
357    pool. */
358 static char *
359 read_pool_string (struct pfm_reader *r) 
360 {
361   char string[256];
362   read_string (r, string);
363   return pool_strdup (r->pool, string);
364 }
365 \f
366 /* Reads the 464-byte file header. */
367 static void
368 read_header (struct pfm_reader *r)
369 {
370   char *trans;
371   int i;
372
373   /* Read and ignore vanity splash strings. */
374   for (i = 0; i < 200; i++)
375     advance (r);
376   
377   /* Skip the first 64 characters of the translation table.
378      We don't care about these.  They are probably all set to
379      '0', marking them as untranslatable, and that would screw
380      up our actual translation of the real '0'. */
381   for (i = 0; i < 64; i++)
382     advance (r);
383
384   /* Read the rest of the translation table. */
385   trans = pool_malloc (r->pool, 256);
386   memset (trans, 0, 256);
387   for (; i < 256; i++) 
388     {
389       unsigned char c;
390
391       advance (r);
392
393       c = r->cc;
394       if (trans[c] == 0)
395         trans[c] = portable_to_local[i];
396     }
397
398   /* Set up the translation table, then read the first
399      translated character. */
400   r->trans = trans;
401   advance (r); 
402
403   /* Skip and verify signature. */
404   for (i = 0; i < 8; i++) 
405     if (!match (r, "SPSSPORT"[i])) 
406       {
407         msg (SE, _("%s: Not a portable file."), fh_get_filename (r->fh));
408         longjmp (r->bail_out, 1);
409       }
410 }
411
412 /* Reads the version and date info record, as well as product and
413    subproduct identification records if present. */
414 static void
415 read_version_data (struct pfm_reader *r, struct pfm_read_info *info)
416 {
417   static char empty_string[] = "";
418   char *date, *time, *product, *author, *subproduct;
419   int i;
420
421   /* Read file. */
422   if (!match (r, 'A'))
423     error (r, "Unrecognized version code `%c'.", r->cc);
424   date = read_pool_string (r);
425   time = read_pool_string (r);
426   product = match (r, '1') ? read_pool_string (r) : empty_string;
427   author = match (r, '2') ? read_pool_string (r) : empty_string;
428   subproduct = match (r, '3') ? read_pool_string (r) : empty_string;
429
430   /* Validate file. */
431   if (strlen (date) != 8)
432     error (r, _("Bad date string length %d."), strlen (date));
433   if (strlen (time) != 6)
434     error (r, _("Bad time string length %d."), strlen (time));
435
436   /* Save file info. */
437   if (info != NULL) 
438     {
439       /* Date. */
440       for (i = 0; i < 8; i++) 
441         {
442           static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1};
443           info->creation_date[map[i]] = date[i]; 
444         }
445       info->creation_date[2] = info->creation_date[5] = ' ';
446       info->creation_date[10] = 0;
447
448       /* Time. */
449       for (i = 0; i < 6; i++)
450         {
451           static const int map[] = {0, 1, 3, 4, 6, 7};
452           info->creation_time[map[i]] = time[i];
453         }
454       info->creation_time[2] = info->creation_time[5] = ' ';
455       info->creation_time[8] = 0;
456
457       /* Product. */
458       str_copy_trunc (info->product, sizeof info->product, product);
459       str_copy_trunc (info->subproduct, sizeof info->subproduct, subproduct);
460     }
461 }
462
463 /* Translates a format specification read from portable file R as
464    the three integers INTS into a normal format specifier FORMAT,
465    checking that the format is appropriate for variable V. */
466 static void
467 convert_format (struct pfm_reader *r, const int portable_format[3],
468                 struct fmt_spec *format, struct variable *v)
469 {
470   format->type = translate_fmt (portable_format[0]);
471   if (format->type == -1)
472     error (r, _("%s: Bad format specifier byte (%d)."),
473            v->name, portable_format[0]);
474   format->w = portable_format[1];
475   format->d = portable_format[2];
476
477   if (!check_output_specifier (format, false)
478       || !check_specifier_width (format, v->width, false))
479     error (r, _("%s variable %s has invalid format specifier %s."),
480            v->type == NUMERIC ? _("Numeric") : _("String"),
481            v->name, fmt_to_string (format));
482 }
483
484 static union value parse_value (struct pfm_reader *, struct variable *);
485
486 /* Read information on all the variables.  */
487 static void
488 read_variables (struct pfm_reader *r, struct dictionary *dict)
489 {
490   char *weight_name = NULL;
491   int i;
492   
493   if (!match (r, '4'))
494     error (r, _("Expected variable count record."));
495   
496   r->var_cnt = read_int (r);
497   if (r->var_cnt <= 0 || r->var_cnt == NOT_INT)
498     error (r, _("Invalid number of variables %d."), r->var_cnt);
499   r->widths = pool_nalloc (r->pool, r->var_cnt, sizeof *r->widths);
500
501   /* Purpose of this value is unknown.  It is typically 161. */
502   read_int (r);
503
504   if (match (r, '6'))
505     {
506       weight_name = read_pool_string (r);
507       if (strlen (weight_name) > SHORT_NAME_LEN) 
508         error (r, _("Weight variable name (%s) truncated."), weight_name);
509     }
510   
511   for (i = 0; i < r->var_cnt; i++)
512     {
513       int width;
514       char name[256];
515       int fmt[6];
516       struct variable *v;
517       int j;
518
519       if (!match (r, '7'))
520         error (r, _("Expected variable record."));
521
522       width = read_int (r);
523       if (width < 0)
524         error (r, _("Invalid variable width %d."), width);
525       r->widths[i] = width;
526
527       read_string (r, name);
528       for (j = 0; j < 6; j++)
529         fmt[j] = read_int (r);
530
531       if (!var_is_valid_name (name, false) || *name == '#' || *name == '$')
532         error (r, _("position %d: Invalid variable name `%s'."), i, name);
533       str_uppercase (name);
534
535       if (width < 0 || width > 255)
536         error (r, "Bad width %d for variable %s.", width, name);
537
538       v = dict_create_var (dict, name, width);
539       if (v == NULL)
540         error (r, _("Duplicate variable name %s."), name);
541
542       convert_format (r, &fmt[0], &v->print, v);
543       convert_format (r, &fmt[3], &v->write, v);
544
545       /* Range missing values. */
546       if (match (r, 'B')) 
547         {
548           double x = read_float (r);
549           double y = read_float (r);
550           mv_add_num_range (&v->miss, x, y);
551         }
552       else if (match (r, 'A'))
553         mv_add_num_range (&v->miss, read_float (r), HIGHEST);
554       else if (match (r, '9'))
555         mv_add_num_range (&v->miss, LOWEST, read_float (r));
556
557       /* Single missing values. */
558       while (match (r, '8')) 
559         {
560           union value value = parse_value (r, v);
561           mv_add_value (&v->miss, &value); 
562         }
563
564       if (match (r, 'C')) 
565         {
566           char label[256];
567           read_string (r, label);
568           v->label = xstrdup (label); 
569         }
570     }
571
572   if (weight_name != NULL) 
573     {
574       struct variable *weight_var = dict_lookup_var (dict, weight_name);
575       if (weight_var == NULL)
576         error (r, _("Weighting variable %s not present in dictionary."),
577                weight_name);
578
579       dict_set_weight (dict, weight_var);
580     }
581 }
582
583 /* Parse a value for variable VV into value V. */
584 static union value
585 parse_value (struct pfm_reader *r, struct variable *vv)
586 {
587   union value v;
588   
589   if (vv->type == ALPHA) 
590     {
591       char string[256];
592       read_string (r, string);
593       buf_copy_str_rpad (v.s, 8, string); 
594     }
595   else
596     v.f = read_float (r);
597
598   return v;
599 }
600
601 /* Parse a value label record and return success. */
602 static void
603 read_value_label (struct pfm_reader *r, struct dictionary *dict)
604 {
605   /* Variables. */
606   int nv;
607   struct variable **v;
608
609   /* Labels. */
610   int n_labels;
611
612   int i;
613
614   nv = read_int (r);
615   v = pool_nalloc (r->pool, nv, sizeof *v);
616   for (i = 0; i < nv; i++)
617     {
618       char name[256];
619       read_string (r, name);
620
621       v[i] = dict_lookup_var (dict, name);
622       if (v[i] == NULL)
623         error (r, _("Unknown variable %s while parsing value labels."), name);
624
625       if (v[0]->width != v[i]->width)
626         error (r, _("Cannot assign value labels to %s and %s, which "
627                     "have different variable types or widths."),
628                v[0]->name, v[i]->name);
629     }
630
631   n_labels = read_int (r);
632   for (i = 0; i < n_labels; i++)
633     {
634       union value val;
635       char label[256];
636       int j;
637
638       val = parse_value (r, v[0]);
639       read_string (r, label);
640
641       /* Assign the value_label's to each variable. */
642       for (j = 0; j < nv; j++)
643         {
644           struct variable *var = v[j];
645
646           if (!val_labs_replace (var->val_labs, val, label))
647             continue;
648
649           if (var->type == NUMERIC)
650             error (r, _("Duplicate label for value %g for variable %s."),
651                    val.f, var->name);
652           else
653             error (r, _("Duplicate label for value `%.*s' for variable %s."),
654                    var->width, val.s, var->name);
655         }
656     }
657 }
658
659 /* Reads one case from portable file R into C. */
660 bool
661 pfm_read_case (struct pfm_reader *r, struct ccase *c)
662 {
663   size_t i;
664   size_t idx;
665
666   setjmp (r->bail_out);
667   if (!r->ok)
668     return false;
669   
670   /* Check for end of file. */
671   if (r->cc == 'Z')
672     return false;
673
674   idx = 0;
675   for (i = 0; i < r->var_cnt; i++) 
676     {
677       int width = r->widths[i];
678       
679       if (width == 0)
680         {
681           case_data_rw (c, idx)->f = read_float (r);
682           idx++;
683         }
684       else
685         {
686           char string[256];
687           read_string (r, string);
688           buf_copy_str_rpad (case_data_rw (c, idx)->s, width, string);
689           idx += DIV_RND_UP (width, MAX_SHORT_STRING);
690         }
691     }
692   
693   return true;
694 }
695
696 /* Returns true if an I/O error has occurred on READER, false
697    otherwise. */
698 bool
699 pfm_read_error (const struct pfm_reader *reader) 
700 {
701   return !reader->ok;
702 }
703
704 /* Returns true if FILE is an SPSS portable file,
705    false otherwise. */
706 bool
707 pfm_detect (FILE *file) 
708 {
709   unsigned char header[464];
710   char trans[256];
711   int cooked_cnt, raw_cnt;
712   int i;
713
714   cooked_cnt = raw_cnt = 0;
715   while (cooked_cnt < sizeof header)
716     {
717       int c = getc (file);
718       if (c == EOF || raw_cnt++ > 512)
719         return false;
720       else if (c != '\n' && c != '\r') 
721         header[cooked_cnt++] = c;
722     }
723
724   memset (trans, 0, 256);
725   for (i = 64; i < 256; i++) 
726     {
727       unsigned char c = header[i + 200];
728       if (trans[c] == 0)
729         trans[c] = portable_to_local[i];
730     }
731
732   for (i = 0; i < 8; i++) 
733     if (trans[header[i + 456]] != "SPSSPORT"[i]) 
734       return false; 
735
736   return true;
737 }