Test both compressed and uncompressed system files with very long
[pspp] / src / data / sys-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007 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 <data/sys-file-reader.h>
20 #include <data/sys-file-private.h>
21
22 #include <errno.h>
23 #include <float.h>
24 #include <inttypes.h>
25 #include <setjmp.h>
26 #include <stdlib.h>
27
28 #include <libpspp/alloc.h>
29 #include <libpspp/assertion.h>
30 #include <libpspp/message.h>
31 #include <libpspp/compiler.h>
32 #include <libpspp/magic.h>
33 #include <libpspp/misc.h>
34 #include <libpspp/pool.h>
35 #include <libpspp/str.h>
36 #include <libpspp/hash.h>
37 #include <libpspp/array.h>
38
39 #include <data/case.h>
40 #include <data/casereader-provider.h>
41 #include <data/casereader.h>
42 #include <data/dictionary.h>
43 #include <data/file-handle-def.h>
44 #include <data/file-name.h>
45 #include <data/format.h>
46 #include <data/missing-values.h>
47 #include <data/value-labels.h>
48 #include <data/variable.h>
49 #include <data/value.h>
50
51 #include "c-ctype.h"
52 #include "inttostr.h"
53 #include "minmax.h"
54 #include "unlocked-io.h"
55 #include "xsize.h"
56
57 #include "gettext.h"
58 #define _(msgid) gettext (msgid)
59 #define N_(msgid) (msgid)
60
61 /* System file reader. */
62 struct sfm_reader
63   {
64     /* Resource tracking. */
65     struct pool *pool;          /* All system file state. */
66     jmp_buf bail_out;           /* longjmp() target for error handling. */
67
68     /* File state. */
69     struct file_handle *fh;     /* File handle. */
70     FILE *file;                 /* File stream. */
71     bool error;                 /* I/O or corruption error? */
72     size_t value_cnt;           /* Number of "union value"s in struct case. */
73
74     /* File format. */
75     enum integer_format integer_format; /* On-disk integer format. */
76     enum float_format float_format; /* On-disk floating point format. */
77     int flt64_cnt;              /* Number of 8-byte units per case. */
78     struct sfm_var *vars;       /* Variables. */
79     size_t var_cnt;             /* Number of variables. */
80     int32_t case_cnt;           /* Number of cases */
81     bool has_long_var_names;    /* File has a long variable name map */
82     bool has_vls;               /* File has one or more very long strings? */
83
84     /* Decompression. */
85     bool compressed;            /* File is compressed? */
86     double bias;                /* Compression bias, usually 100.0. */
87     uint8_t opcodes[8];         /* Current block of opcodes. */
88     size_t opcode_idx;          /* Next opcode to interpret, 8 if none left. */
89   };
90
91 /* A variable in a system file. */
92 struct sfm_var
93   {
94     int width;                  /* 0=numeric, otherwise string width. */
95     int case_index;             /* Index into case. */
96   };
97
98 static struct casereader_class sys_file_casereader_class;
99
100 static bool close_reader (struct sfm_reader *);
101
102 static struct variable **make_var_by_value_idx (struct sfm_reader *,
103                                                 struct dictionary *);
104 static struct variable *lookup_var_by_value_idx (struct sfm_reader *,
105                                                  struct variable **,
106                                                  int value_idx);
107
108 static void sys_warn (struct sfm_reader *, const char *, ...)
109      PRINTF_FORMAT (2, 3);
110
111 static void sys_error (struct sfm_reader *, const char *, ...)
112      PRINTF_FORMAT (2, 3)
113      NO_RETURN;
114
115 static void read_bytes (struct sfm_reader *, void *, size_t);
116 static bool try_read_bytes (struct sfm_reader *, void *, size_t);
117 static int32_t read_int32 (struct sfm_reader *);
118 static double read_flt64 (struct sfm_reader *);
119 static void read_string (struct sfm_reader *, char *, size_t);
120 static void skip_bytes (struct sfm_reader *, size_t);
121
122 static int32_t int32_to_native (const struct sfm_reader *, const uint8_t[4]);
123 static double flt64_to_double (const struct sfm_reader *, const uint8_t[8]);
124
125 static struct variable_to_value_map *open_variable_to_value_map (
126   struct sfm_reader *, size_t size);
127 static void close_variable_to_value_map (struct sfm_reader *r,
128                                          struct variable_to_value_map *);
129 static bool read_variable_to_value_map (struct sfm_reader *,
130                                         struct dictionary *,
131                                         struct variable_to_value_map *,
132                                         struct variable **var, char **value,
133                                         int *warning_cnt);
134
135 static bool close_reader (struct sfm_reader *r);
136 \f
137 /* Dictionary reader. */
138
139 enum which_format
140   {
141     PRINT_FORMAT,
142     WRITE_FORMAT
143   };
144
145 static void read_header (struct sfm_reader *, struct dictionary *,
146                          int *weight_idx, int *claimed_flt64_cnt,
147                          struct sfm_read_info *);
148 static void read_variable_record (struct sfm_reader *, struct dictionary *,
149                                   int *format_warning_cnt);
150 static void parse_format_spec (struct sfm_reader *, uint32_t,
151                                enum which_format, struct variable *,
152                                int *format_warning_cnt);
153 static void setup_weight (struct sfm_reader *, int weight_idx,
154                           struct variable **var_by_value_idx,
155                           struct dictionary *);
156 static void read_documents (struct sfm_reader *, struct dictionary *);
157 static void read_value_labels (struct sfm_reader *, struct dictionary *,
158                                struct variable **var_by_value_idx);
159
160 static void read_extension_record (struct sfm_reader *, struct dictionary *);
161 static void read_machine_int32_info (struct sfm_reader *,
162                                      size_t size, size_t count);
163 static void read_machine_flt64_info (struct sfm_reader *,
164                                      size_t size, size_t count);
165 static void read_display_parameters (struct sfm_reader *,
166                                      size_t size, size_t count,
167                                      struct dictionary *);
168 static void read_long_var_name_map (struct sfm_reader *,
169                                     size_t size, size_t count,
170                                     struct dictionary *);
171 static void read_long_string_map (struct sfm_reader *,
172                                   size_t size, size_t count,
173                                   struct dictionary *);
174
175
176 /* Opens the system file designated by file handle FH for
177    reading.  Reads the system file's dictionary into *DICT.
178    If INFO is non-null, then it receives additional info about the
179    system file. */
180 struct casereader *
181 sfm_open_reader (struct file_handle *fh, struct dictionary **dict,
182                  struct sfm_read_info *info)
183 {
184   struct sfm_reader *volatile r = NULL;
185   struct variable **var_by_value_idx;
186   int format_warning_cnt = 0;
187   int weight_idx;
188   int claimed_flt64_cnt;
189   int rec_type;
190   size_t i;
191
192   if (!fh_open (fh, FH_REF_FILE, "system file", "rs"))
193     return NULL;
194
195   *dict = dict_create ();
196
197   /* Create and initialize reader. */
198   r = pool_create_container (struct sfm_reader, pool);
199   r->fh = fh;
200   r->file = fn_open (fh_get_file_name (fh), "rb");
201   r->error = false;
202   r->flt64_cnt = 0;
203   r->has_vls = false;
204   r->has_long_var_names = false;
205   r->opcode_idx = sizeof r->opcodes;
206
207   if (setjmp (r->bail_out))
208     {
209       close_reader (r);
210       dict_destroy (*dict);
211       *dict = NULL;
212       return NULL;
213     }
214
215   if (r->file == NULL)
216     {
217       msg (ME, _("Error opening \"%s\" for reading as a system file: %s."),
218            fh_get_file_name (r->fh), strerror (errno));
219       longjmp (r->bail_out, 1);
220     }
221
222   /* Read header. */
223   read_header (r, *dict, &weight_idx, &claimed_flt64_cnt, info);
224
225   /* Read all the variable definition records. */
226   rec_type = read_int32 (r);
227   while (rec_type == 2)
228     {
229       read_variable_record (r, *dict, &format_warning_cnt);
230       rec_type = read_int32 (r);
231     }
232
233   /* Figure out the case format. */
234   var_by_value_idx = make_var_by_value_idx (r, *dict);
235   setup_weight (r, weight_idx, var_by_value_idx, *dict);
236
237   /* Read all the rest of the dictionary records. */
238   while (rec_type != 999)
239     {
240       switch (rec_type)
241         {
242         case 3:
243           read_value_labels (r, *dict, var_by_value_idx);
244           break;
245
246         case 4:
247           sys_error (r, _("Misplaced type 4 record."));
248
249         case 6:
250           read_documents (r, *dict);
251           break;
252
253         case 7:
254           read_extension_record (r, *dict);
255           break;
256
257         default:
258           sys_error (r, _("Unrecognized record type %d."), rec_type);
259         }
260       rec_type = read_int32 (r);
261     }
262
263
264   if ( ! r->has_long_var_names )
265     {
266       int i;
267       for (i = 0; i < dict_get_var_cnt (*dict); i++)
268         {
269           struct variable *var = dict_get_var (*dict, i);
270           char short_name [SHORT_NAME_LEN + 1];
271           char long_name [SHORT_NAME_LEN + 1];
272
273           strcpy (short_name, var_get_name (var));
274
275           strcpy (long_name, short_name);
276           str_lowercase (long_name);
277
278           /* Set long name.  Renaming a variable may clear the short
279              name, but we want to retain it, so re-set it
280              explicitly. */
281           dict_rename_var (*dict, var, long_name);
282           var_set_short_name (var, short_name);
283         }
284
285       r->has_long_var_names = true;
286     }
287
288   /* Read record 999 data, which is just filler. */
289   read_int32 (r);
290
291   if (claimed_flt64_cnt != -1 && claimed_flt64_cnt != r->flt64_cnt)
292     sys_warn (r, _("File header claims %d variable positions but "
293                    "%d were read from file."),
294               claimed_flt64_cnt, r->flt64_cnt);
295
296   /* Create an index of dictionary variable widths for
297      sfm_read_case to use.  We cannot use the `struct variable's
298      from the dictionary we created, because the caller owns the
299      dictionary and may destroy or modify its variables. */
300   r->var_cnt = dict_get_var_cnt (*dict);
301   r->vars = pool_nalloc (r->pool, r->var_cnt, sizeof *r->vars);
302   for (i = 0; i < r->var_cnt; i++)
303     {
304       struct variable *v = dict_get_var (*dict, i);
305       struct sfm_var *sv = &r->vars[i];
306       sv->width = var_get_width (v);
307       sv->case_index = var_get_case_index (v);
308     }
309
310   pool_free (r->pool, var_by_value_idx);
311   r->value_cnt = dict_get_next_value_idx (*dict);
312   return casereader_create_sequential
313     (NULL, r->value_cnt,
314      r->case_cnt == -1 ? CASENUMBER_MAX: r->case_cnt,
315                                        &sys_file_casereader_class, r);
316 }
317
318 /* Closes a system file after we're done with it.
319    Returns true if an I/O error has occurred on READER, false
320    otherwise. */
321 static bool
322 close_reader (struct sfm_reader *r)
323 {
324   bool error;
325
326   if (r == NULL)
327     return true;
328
329   if (r->file)
330     {
331       if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
332         {
333           msg (ME, _("Error closing system file \"%s\": %s."),
334                fh_get_file_name (r->fh), strerror (errno));
335           r->error = true;
336         }
337       r->file = NULL;
338     }
339
340   if (r->fh != NULL)
341     fh_close (r->fh, "system file", "rs");
342
343   error = r->error;
344   pool_destroy (r->pool);
345
346   return !error;
347 }
348
349 /* Destroys READER. */
350 static void
351 sys_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
352 {
353   struct sfm_reader *r = r_;
354   close_reader (r);
355 }
356
357 /* Returns true if FILE is an SPSS system file,
358    false otherwise. */
359 bool
360 sfm_detect (FILE *file)
361 {
362   char rec_type[5];
363
364   if (fread (rec_type, 4, 1, file) != 1)
365     return false;
366   rec_type[4] = '\0';
367
368   return !strcmp ("$FL2", rec_type);
369 }
370 \f
371 /* Reads the global header of the system file.
372    Sets DICT's file label to the system file's label.
373    Sets *WEIGHT_IDX to 0 if the system file is unweighted,
374    or to the value index of the weight variable otherwise.
375    Sets *CLAIMED_FLT64_CNT to the number of values that the file
376    claims to have (although it is not always correct).
377    If INFO is non-null, initializes *INFO with header
378    information. */
379 static void
380 read_header (struct sfm_reader *r, struct dictionary *dict,
381              int *weight_idx, int *claimed_flt64_cnt,
382              struct sfm_read_info *info)
383 {
384   char rec_type[5];
385   char eye_catcher[61];
386   uint8_t raw_layout_code[4];
387   uint8_t raw_bias[8];
388   char creation_date[10];
389   char creation_time[9];
390   char file_label[65];
391   struct substring file_label_ss;
392
393   read_string (r, rec_type, sizeof rec_type);
394   read_string (r, eye_catcher, sizeof eye_catcher);
395
396   if (strcmp ("$FL2", rec_type) != 0)
397     sys_error (r, _("This is not an SPSS system file."));
398
399   /* Identify integer format. */
400   read_bytes (r, raw_layout_code, sizeof raw_layout_code);
401   if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
402                           &r->integer_format)
403        && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
404                              &r->integer_format))
405       || (r->integer_format != INTEGER_MSB_FIRST
406           && r->integer_format != INTEGER_LSB_FIRST))
407     sys_error (r, _("This is not an SPSS system file."));
408
409   *claimed_flt64_cnt = read_int32 (r);
410   if (*claimed_flt64_cnt < 0 || *claimed_flt64_cnt > INT_MAX / 16)
411     *claimed_flt64_cnt = -1;
412
413   r->compressed = read_int32 (r) != 0;
414
415   *weight_idx = read_int32 (r);
416
417   r->case_cnt = read_int32 (r);
418   if ( r->case_cnt > INT_MAX / 2)
419     r->case_cnt = -1;
420
421
422   /* Identify floating-point format and obtain compression bias. */
423   read_bytes (r, raw_bias, sizeof raw_bias);
424   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
425     {
426       sys_warn (r, _("Compression bias (%g) is not the usual "
427                      "value of 100, or system file uses unrecognized "
428                      "floating-point format."),
429                 r->bias);
430       if (r->integer_format == INTEGER_MSB_FIRST)
431         r->float_format = FLOAT_IEEE_DOUBLE_BE;
432       else
433         r->float_format = FLOAT_IEEE_DOUBLE_LE;
434     }
435   float_convert (r->float_format, raw_bias, FLOAT_NATIVE_DOUBLE, &r->bias);
436
437   read_string (r, creation_date, sizeof creation_date);
438   read_string (r, creation_time, sizeof creation_time);
439   read_string (r, file_label, sizeof file_label);
440   skip_bytes (r, 3);
441
442   file_label_ss = ss_cstr (file_label);
443   ss_trim (&file_label_ss, ss_cstr (" "));
444   if (!ss_is_empty (file_label_ss))
445     {
446       ss_data (file_label_ss)[ss_length (file_label_ss)] = '\0';
447       dict_set_label (dict, ss_data (file_label_ss));
448     }
449
450   if (info)
451     {
452       struct substring product;
453
454       strcpy (info->creation_date, creation_date);
455       strcpy (info->creation_time, creation_time);
456       info->integer_format = r->integer_format;
457       info->float_format = r->float_format;
458       info->compressed = r->compressed;
459       info->case_cnt = r->case_cnt;
460
461       product = ss_cstr (eye_catcher);
462       ss_match_string (&product, ss_cstr ("@(#) SPSS DATA FILE"));
463       ss_trim (&product, ss_cstr (" "));
464       str_copy_buf_trunc (info->product, sizeof info->product,
465                           ss_data (product), ss_length (product));
466     }
467 }
468
469 /* Reads a variable (type 2) record from R and adds the
470    corresponding variable to DICT.
471    Also skips past additional variable records for long string
472    variables. */
473 static void
474 read_variable_record (struct sfm_reader *r, struct dictionary *dict,
475                       int *format_warning_cnt)
476 {
477   int width;
478   int has_variable_label;
479   int missing_value_code;
480   int print_format;
481   int write_format;
482   char name[9];
483
484   struct variable *var;
485   int nv;
486
487   width = read_int32 (r);
488   has_variable_label = read_int32 (r);
489   missing_value_code = read_int32 (r);
490   print_format = read_int32 (r);
491   write_format = read_int32 (r);
492   read_string (r, name, sizeof name);
493   name[strcspn (name, " ")] = '\0';
494
495   /* Check variable name. */
496   if (name[0] == '$' || name[0] == '#')
497     sys_error (r, "Variable name begins with invalid character `%c'.",
498                name[0]);
499   if (!var_is_plausible_name (name, false))
500     sys_error (r, _("Invalid variable name `%s'."), name);
501
502   /* Create variable. */
503   if (width < 0 || width > 255)
504     sys_error (r, _("Bad variable width %d."), width);
505   var = dict_create_var (dict, name, width);
506   if (var == NULL)
507     sys_error (r,
508                _("Duplicate variable name `%s' within system file."),
509                name);
510
511   /* Set the short name the same as the long name */
512   var_set_short_name (var, var_get_name (var));
513
514   /* Get variable label, if any. */
515   if (has_variable_label != 0 && has_variable_label != 1)
516     sys_error (r, _("Variable label indicator field is not 0 or 1."));
517   if (has_variable_label == 1)
518     {
519       size_t len;
520       char label[255 + 1];
521
522       len = read_int32 (r);
523       if (len >= sizeof label)
524         sys_error (r, _("Variable %s has label of invalid length %u."),
525                    name, (unsigned int) len);
526       read_string (r, label, len + 1);
527       var_set_label (var, label);
528
529       skip_bytes (r, ROUND_UP (len, 4) - len);
530     }
531
532   /* Set missing values. */
533   if (missing_value_code < -3 || missing_value_code > 3
534       || missing_value_code == -1)
535     sys_error (r, _("Missing value indicator field is not "
536                     "-3, -2, 0, 1, 2, or 3."));
537   if (missing_value_code != 0)
538     {
539       struct missing_values mv;
540       mv_init (&mv, var_get_width (var));
541       if (var_is_numeric (var))
542         {
543           if (missing_value_code > 0)
544             {
545               int i;
546               for (i = 0; i < missing_value_code; i++)
547                 mv_add_num (&mv, read_flt64 (r));
548             }
549           else
550             {
551               double low = read_flt64 (r);
552               double high = read_flt64 (r);
553               mv_add_num_range (&mv, low, high);
554               if (missing_value_code == -3)
555                 mv_add_num (&mv, read_flt64 (r));
556             }
557         }
558       else if (var_get_width (var) <= MAX_SHORT_STRING)
559         {
560           if (missing_value_code > 0)
561             {
562               int i;
563               for (i = 0; i < missing_value_code; i++)
564                 {
565                   char string[9];
566                   read_string (r, string, sizeof string);
567                   mv_add_str (&mv, string);
568                 }
569             }
570           else
571             sys_error (r, _("String variable %s may not have missing "
572                             "values specified as a range."),
573                        name);
574         }
575       else /* var->width > MAX_SHORT_STRING */
576         sys_error (r, _("Long string variable %s may not have missing "
577                         "values."),
578                    name);
579       var_set_missing_values (var, &mv);
580     }
581
582   /* Set formats. */
583   parse_format_spec (r, print_format, PRINT_FORMAT, var, format_warning_cnt);
584   parse_format_spec (r, write_format, WRITE_FORMAT, var, format_warning_cnt);
585
586   /* Account for values.
587      Skip long string continuation records, if any. */
588   nv = width == 0 ? 1 : DIV_RND_UP (width, 8);
589   r->flt64_cnt += nv;
590   if (width > 8)
591     {
592       int i;
593
594       for (i = 1; i < nv; i++)
595         {
596           /* Check for record type 2 and width -1. */
597           if (read_int32 (r) != 2 || read_int32 (r) != -1)
598             sys_error (r, _("Missing string continuation record."));
599
600           /* Skip and ignore remaining continuation data. */
601           has_variable_label = read_int32 (r);
602           missing_value_code = read_int32 (r);
603           print_format = read_int32 (r);
604           write_format = read_int32 (r);
605           read_string (r, name, sizeof name);
606
607           /* Variable label fields on continuation records have
608              been spotted in system files created by "SPSS Power
609              Macintosh Release 6.1". */
610           if (has_variable_label)
611             skip_bytes (r, ROUND_UP (read_int32 (r), 4));
612         }
613     }
614 }
615
616 /* Translates the format spec from sysfile format to internal
617    format. */
618 static void
619 parse_format_spec (struct sfm_reader *r, uint32_t s,
620                    enum which_format which, struct variable *v,
621                    int *format_warning_cnt)
622 {
623   const int max_format_warnings = 8;
624   struct fmt_spec f;
625   uint8_t raw_type = s >> 16;
626   uint8_t w = s >> 8;
627   uint8_t d = s;
628
629   bool ok;
630
631   if (!fmt_from_io (raw_type, &f.type))
632     sys_error (r, _("Unknown variable format %d."), (int) raw_type);
633   f.w = w;
634   f.d = d;
635
636   msg_disable ();
637   ok = fmt_check_output (&f) && fmt_check_width_compat (&f, var_get_width (v));
638   msg_enable ();
639
640   if (ok)
641     {
642       if (which == PRINT_FORMAT)
643         var_set_print_format (v, &f);
644       else
645         var_set_write_format (v, &f);
646     }
647   else if (*++format_warning_cnt <= max_format_warnings)
648     {
649       char fmt_string[FMT_STRING_LEN_MAX + 1];
650       sys_warn (r, _("%s variable %s has invalid %s format %s."),
651                 var_is_numeric (v) ? _("Numeric") : _("String"),
652                 var_get_name (v),
653                 which == PRINT_FORMAT ? _("print") : _("write"),
654                 fmt_to_string (&f, fmt_string));
655
656       if (*format_warning_cnt == max_format_warnings)
657         sys_warn (r, _("Suppressing further invalid format warnings."));
658     }
659 }
660
661 /* Sets the weighting variable in DICT to the variable
662    corresponding to the given 1-based VALUE_IDX, if VALUE_IDX is
663    nonzero. */
664 static void
665 setup_weight (struct sfm_reader *r, int weight_idx,
666               struct variable **var_by_value_idx, struct dictionary *dict)
667 {
668   if (weight_idx != 0)
669     {
670       struct variable *weight_var
671         = lookup_var_by_value_idx (r, var_by_value_idx, weight_idx);
672       if (var_is_numeric (weight_var))
673         dict_set_weight (dict, weight_var);
674       else
675         sys_error (r, _("Weighting variable must be numeric."));
676     }
677 }
678
679 /* Reads a document record, type 6, from system file R, and sets up
680    the documents and n_documents fields in the associated
681    dictionary. */
682 static void
683 read_documents (struct sfm_reader *r, struct dictionary *dict)
684 {
685   int line_cnt;
686   char *documents;
687
688   if (dict_get_documents (dict) != NULL)
689     sys_error (r, _("Multiple type 6 (document) records."));
690
691   line_cnt = read_int32 (r);
692   if (line_cnt <= 0)
693     sys_error (r, _("Number of document lines (%d) "
694                     "must be greater than 0."), line_cnt);
695
696   documents = pool_nmalloc (r->pool, line_cnt + 1, DOC_LINE_LENGTH);
697   read_string (r, documents, DOC_LINE_LENGTH * line_cnt + 1);
698   if (strlen (documents) == DOC_LINE_LENGTH * line_cnt)
699     dict_set_documents (dict, documents);
700   else
701     sys_error (r, _("Document line contains null byte."));
702   pool_free (r->pool, documents);
703 }
704
705 /* Read a type 7 extension record. */
706 static void
707 read_extension_record (struct sfm_reader *r, struct dictionary *dict)
708 {
709   int subtype = read_int32 (r);
710   size_t size = read_int32 (r);
711   size_t count = read_int32 (r);
712   size_t bytes = size * count;
713
714   /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
715      allows an extra byte for a null terminator, used by some
716      extension processing routines. */
717   if (size != 0 && size_overflow_p (xsum (1, xtimes (count, size))))
718     sys_error (r, "Record type 7 subtype %d too large.", subtype);
719
720   switch (subtype)
721     {
722     case 3:
723       read_machine_int32_info (r, size, count);
724       return;
725
726     case 4:
727       read_machine_flt64_info (r, size, count);
728       return;
729
730     case 5:
731       /* Variable sets information.  We don't use these yet.
732          They only apply to GUIs; see VARSETS on the APPLY
733          DICTIONARY command in SPSS documentation. */
734       break;
735
736     case 6:
737       /* DATE variable information.  We don't use it yet, but we
738          should. */
739       break;
740
741     case 7:
742       /* Unknown purpose. */
743       break;
744
745     case 11:
746       read_display_parameters (r, size, count, dict);
747       return;
748
749     case 13:
750       read_long_var_name_map (r, size, count, dict);
751       return;
752
753     case 14:
754       read_long_string_map (r, size, count, dict);
755       return;
756
757     case 16:
758       /* New in SPSS v14?  Unknown purpose.  */
759       break;
760
761     case 17:
762       /* Text field that defines variable attributes.  New in
763          SPSS 14. */
764       break;
765
766     default:
767       sys_warn (r, _("Unrecognized record type 7, subtype %d."), subtype);
768       break;
769     }
770
771   skip_bytes (r, bytes);
772 }
773
774 /* Read record type 7, subtype 3. */
775 static void
776 read_machine_int32_info (struct sfm_reader *r, size_t size, size_t count)
777 {
778   int version_major UNUSED = read_int32 (r);
779   int version_minor UNUSED = read_int32 (r);
780   int version_revision UNUSED = read_int32 (r);
781   int machine_code UNUSED = read_int32 (r);
782   int float_representation = read_int32 (r);
783   int compression_code UNUSED = read_int32 (r);
784   int integer_representation = read_int32 (r);
785   int character_code UNUSED = read_int32 (r);
786
787   int expected_float_format;
788   int expected_integer_format;
789
790   if (size != 4 || count != 8)
791     sys_error (r, _("Bad size (%u) or count (%u) field on record type 7, "
792                     "subtype 3."),
793                (unsigned int) size, (unsigned int) count);
794
795   /* Check floating point format. */
796   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
797       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
798     expected_float_format = 1;
799   else if (r->float_format == FLOAT_Z_LONG)
800     expected_float_format = 2;
801   else if (r->float_format == FLOAT_VAX_G || r->float_format == FLOAT_VAX_D)
802     expected_float_format = 3;
803   else
804     NOT_REACHED ();
805   if (float_representation != expected_float_format)
806     sys_error (r, _("Floating-point representation indicated by "
807                     "system file (%d) differs from expected (%d)."),
808                r->float_format, expected_float_format);
809
810   /* Check integer format. */
811   if (r->integer_format == INTEGER_MSB_FIRST)
812     expected_integer_format = 1;
813   else if (r->integer_format == INTEGER_LSB_FIRST)
814     expected_integer_format = 2;
815   else
816     NOT_REACHED ();
817   if (integer_representation != expected_integer_format)
818     {
819       static const char *endian[] = {N_("little-endian"), N_("big-endian")};
820       sys_warn (r, _("Integer format indicated by system file (%s) "
821                      "differs from expected (%s)."),
822                 gettext (endian[integer_representation == 1]),
823                 gettext (endian[expected_integer_format == 1]));
824     }
825 }
826
827 /* Read record type 7, subtype 4. */
828 static void
829 read_machine_flt64_info (struct sfm_reader *r, size_t size, size_t count)
830 {
831   double sysmis = read_flt64 (r);
832   double highest = read_flt64 (r);
833   double lowest = read_flt64 (r);
834
835   if (size != 8 || count != 3)
836     sys_error (r, _("Bad size (%u) or count (%u) on extension 4."),
837                (unsigned int) size, (unsigned int) count);
838
839   if (sysmis != SYSMIS)
840     sys_warn (r, _("File specifies unexpected value %g as SYSMIS."), sysmis);
841   if (highest != HIGHEST)
842     sys_warn (r, _("File specifies unexpected value %g as HIGHEST."), highest);
843   if (lowest != LOWEST)
844     sys_warn (r, _("File specifies unexpected value %g as LOWEST."), lowest);
845 }
846
847 /* Read record type 7, subtype 11, which specifies how variables
848    should be displayed in GUI environments. */
849 static void
850 read_display_parameters (struct sfm_reader *r, size_t size, size_t count,
851                          struct dictionary *dict)
852 {
853   const size_t n_vars = count / 3 ;
854   bool warned = false;
855   int i;
856
857   if (count % 3 || n_vars != dict_get_var_cnt (dict))
858     sys_error (r, _("Bad size (%u) or count (%u) on extension 11."),
859                (unsigned int) size, (unsigned int) count);
860
861   for (i = 0; i < n_vars; ++i)
862     {
863       int measure = read_int32 (r);
864       int width = read_int32 (r);
865       int align = read_int32 (r);
866       struct variable *v = dict_get_var (dict, i);
867
868       /* spss v14 sometimes seems to set string variables' measure to zero */
869       if ( 0 == measure && var_is_alpha (v) ) measure = 1;
870
871
872       if (measure < 1 || measure > 3 || align < 0 || align > 2)
873         {
874           if (!warned)
875             sys_warn (r, _("Invalid variable display parameters.  "
876                            "Default parameters substituted."));
877           warned = true;
878           continue;
879         }
880
881       var_set_measure (v, (measure == 1 ? MEASURE_NOMINAL
882                            : measure == 2 ? MEASURE_ORDINAL
883                            : MEASURE_SCALE));
884       var_set_display_width (v, width);
885       var_set_alignment (v, (align == 0 ? ALIGN_LEFT
886                              : align == 1 ? ALIGN_RIGHT
887                              : ALIGN_CENTRE));
888     }
889 }
890
891 /* Reads record type 7, subtype 13, which gives the long name
892    that corresponds to each short name.  Modifies variable names
893    in DICT accordingly.  */
894 static void
895 read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count,
896                         struct dictionary *dict)
897 {
898   struct variable_to_value_map *map;
899   struct variable *var;
900   char *long_name;
901   int warning_cnt = 0;
902
903   map = open_variable_to_value_map (r, size * count);
904   while (read_variable_to_value_map (r, dict, map, &var, &long_name,
905                                      &warning_cnt))
906     {
907       char short_name[SHORT_NAME_LEN + 1];
908       strcpy (short_name, var_get_short_name (var));
909
910       /* Validate long name. */
911       if (!var_is_valid_name (long_name, false))
912         {
913           sys_warn (r, _("Long variable mapping from %s to invalid "
914                          "variable name `%s'."),
915                     var_get_name (var), long_name);
916           continue;
917         }
918
919       /* Identify any duplicates. */
920       if (strcasecmp (short_name, long_name)
921           && dict_lookup_var (dict, long_name) != NULL)
922         {
923           sys_warn (r, _("Duplicate long variable name `%s' "
924                          "within system file."), long_name);
925           continue;
926         }
927
928       /* Set long name.  Renaming a variable may clear the short
929          name, but we want to retain it, so re-set it
930          explicitly. */
931       dict_rename_var (dict, var, long_name);
932       var_set_short_name (var, short_name);
933     }
934   close_variable_to_value_map (r, map);
935   r->has_long_var_names = true;
936 }
937
938 /* Reads record type 7, subtype 14, which gives the real length
939    of each very long string.  Rearranges DICT accordingly. */
940 static void
941 read_long_string_map (struct sfm_reader *r, size_t size, size_t count,
942                       struct dictionary *dict)
943 {
944   struct variable_to_value_map *map;
945   struct variable *var;
946   char *length_s;
947   int warning_cnt = 0;
948
949   r->has_vls = true;
950
951   map = open_variable_to_value_map (r, size * count);
952   while (read_variable_to_value_map (r, dict, map, &var, &length_s,
953                                      &warning_cnt))
954     {
955       long length, remaining_length;
956       size_t idx;
957
958       /* Get length. */
959       length = strtol (length_s, NULL, 10);
960       if (length < MIN_VERY_LONG_STRING || length == LONG_MAX)
961         {
962           sys_warn (r, _("%s listed as string of length %s "
963                          "in length table."),
964                     var_get_name (var), length_s);
965           continue;
966         }
967
968       /* Group multiple variables into single variable
969          and delete all but the first. */
970       remaining_length = length;
971       for (idx = var_get_dict_index (var); remaining_length > 0; idx++)
972         if (idx < dict_get_var_cnt (dict))
973           remaining_length -= MIN (var_get_width (dict_get_var (dict, idx)),
974                                    EFFECTIVE_LONG_STRING_LENGTH);
975         else
976           sys_error (r, _("Very long string %s overflows dictionary."),
977                      var_get_name (var));
978       dict_delete_consecutive_vars (dict,
979                                     var_get_dict_index (var) + 1,
980                                     idx - var_get_dict_index (var) - 1);
981
982       /* Assign all the length to the first variable. */
983       var_set_width (var, length);
984     }
985   close_variable_to_value_map (r, map);
986   dict_compact_values (dict);
987 }
988
989 /* Reads value labels from sysfile H and inserts them into the
990    associated dictionary. */
991 static void
992 read_value_labels (struct sfm_reader *r,
993                    struct dictionary *dict, struct variable **var_by_value_idx)
994 {
995   struct pool *subpool;
996
997   struct label
998     {
999       char raw_value[8];        /* Value as uninterpreted bytes. */
1000       union value value;        /* Value. */
1001       char *label;              /* Null-terminated label string. */
1002     };
1003
1004   struct label *labels = NULL;
1005   int label_cnt;                /* Number of labels. */
1006
1007   struct variable **var = NULL; /* Associated variables. */
1008   int var_cnt;                  /* Number of associated variables. */
1009
1010   int i;
1011
1012   subpool = pool_create_subpool (r->pool);
1013
1014   /* Read the type 3 record and record its contents.  We can't do
1015      much with the data yet because we don't know whether it is
1016      of numeric or string type. */
1017
1018   /* Read number of labels. */
1019   label_cnt = read_int32 (r);
1020
1021   if (label_cnt >= INT32_MAX / sizeof *labels)
1022     {
1023       sys_warn (r, _("Invalid number of labels: %d.  Ignoring labels."),
1024                 label_cnt);
1025       label_cnt = 0;
1026     }
1027
1028   /* Read each value/label tuple into labels[]. */
1029   labels = pool_nalloc (subpool, label_cnt, sizeof *labels);
1030   for (i = 0; i < label_cnt; i++)
1031     {
1032       struct label *label = labels + i;
1033       unsigned char label_len;
1034       size_t padded_len;
1035
1036       /* Read value. */
1037       read_bytes (r, label->raw_value, sizeof label->raw_value);
1038
1039       /* Read label length. */
1040       read_bytes (r, &label_len, sizeof label_len);
1041       padded_len = ROUND_UP (label_len + 1, 8);
1042
1043       /* Read label, padding. */
1044       label->label = pool_alloc (subpool, padded_len + 1);
1045       read_bytes (r, label->label, padded_len - 1);
1046       label->label[label_len] = 0;
1047     }
1048
1049   /* Now, read the type 4 record that has the list of variables
1050      to which the value labels are to be applied. */
1051
1052   /* Read record type of type 4 record. */
1053   if (read_int32 (r) != 4)
1054     sys_error (r, _("Variable index record (type 4) does not immediately "
1055                     "follow value label record (type 3) as it should."));
1056
1057   /* Read number of variables associated with value label from type 4
1058      record. */
1059   var_cnt = read_int32 (r);
1060   if (var_cnt < 1 || var_cnt > dict_get_var_cnt (dict))
1061     sys_error (r, _("Number of variables associated with a value label (%d) "
1062                     "is not between 1 and the number of variables (%u)."),
1063                var_cnt, (unsigned int) dict_get_var_cnt (dict));
1064
1065   /* Read the list of variables. */
1066   var = pool_nalloc (subpool, var_cnt, sizeof *var);
1067   for (i = 0; i < var_cnt; i++)
1068     {
1069       var[i] = lookup_var_by_value_idx (r, var_by_value_idx, read_int32 (r));
1070       if (var_is_long_string (var[i]))
1071         sys_error (r, _("Value labels are not allowed on long string "
1072                         "variables (%s)."), var_get_name (var[i]));
1073     }
1074
1075   /* Type check the variables. */
1076   for (i = 1; i < var_cnt; i++)
1077     if (var_get_type (var[i]) != var_get_type (var[0]))
1078       sys_error (r, _("Variables associated with value label are not all of "
1079                       "identical type.  Variable %s is %s, but variable "
1080                       "%s is %s."),
1081                  var_get_name (var[0]),
1082                  var_is_numeric (var[0]) ? _("numeric") : _("string"),
1083                  var_get_name (var[i]),
1084                  var_is_numeric (var[i]) ? _("numeric") : _("string"));
1085
1086   /* Fill in labels[].value, now that we know the desired type. */
1087   for (i = 0; i < label_cnt; i++)
1088     {
1089       struct label *label = labels + i;
1090
1091       if (var_is_alpha (var[0]))
1092         buf_copy_rpad (label->value.s, sizeof label->value.s,
1093                        label->raw_value, sizeof label->raw_value);
1094       else
1095         label->value.f = flt64_to_double (r, (uint8_t *) label->raw_value);
1096     }
1097
1098   /* Assign the `value_label's to each variable. */
1099   for (i = 0; i < var_cnt; i++)
1100     {
1101       struct variable *v = var[i];
1102       int j;
1103
1104       /* Add each label to the variable. */
1105       for (j = 0; j < label_cnt; j++)
1106         {
1107           struct label *label = &labels[j];
1108           if (!var_add_value_label (v, &label->value, label->label))
1109             {
1110               if (var_is_numeric (var[0]))
1111                 sys_warn (r, _("Duplicate value label for %g on %s."),
1112                           label->value.f, var_get_name (v));
1113               else
1114                 sys_warn (r, _("Duplicate value label for \"%.*s\" on %s."),
1115                           var_get_width (v), label->value.s,
1116                           var_get_name (v));
1117             }
1118         }
1119     }
1120
1121   pool_destroy (subpool);
1122 }
1123 \f
1124 /* Case reader. */
1125
1126 static void partial_record (struct sfm_reader *r)
1127      NO_RETURN;
1128
1129 static void read_error (struct casereader *, const struct sfm_reader *);
1130
1131
1132 static bool read_case_number (struct sfm_reader *, double *);
1133 static bool read_case_string (struct sfm_reader *, char *, size_t);
1134 static int read_opcode (struct sfm_reader *);
1135 static bool read_compressed_number (struct sfm_reader *, double *);
1136 static bool read_compressed_string (struct sfm_reader *, char *);
1137 static bool read_whole_strings (struct sfm_reader *, char *, size_t);
1138
1139 /* Reads one case from READER's file into C.  Returns true only
1140    if successful. */
1141 static bool
1142 sys_file_casereader_read (struct casereader *reader, void *r_,
1143                           struct ccase *c)
1144 {
1145   struct sfm_reader *r = r_;
1146   if (r->error)
1147     return false;
1148
1149   case_create (c, r->value_cnt);
1150   if (setjmp (r->bail_out))
1151     {
1152       casereader_force_error (reader);
1153       case_destroy (c);
1154       return false;
1155     }
1156
1157   if (!r->compressed && sizeof (double) == 8 && !r->has_vls)
1158     {
1159       /* Fast path.  Read the whole case directly. */
1160       if (!try_read_bytes (r, case_data_all_rw (c),
1161                            sizeof (union value) * r->flt64_cnt))
1162         {
1163           case_destroy (c);
1164           if ( r->case_cnt != -1 )
1165             read_error (reader, r);
1166           return false;
1167         }
1168
1169       /* Convert floating point numbers to native format if needed. */
1170       if (r->float_format != FLOAT_NATIVE_DOUBLE)
1171         {
1172           int i;
1173
1174           for (i = 0; i < r->var_cnt; i++)
1175             if (r->vars[i].width == 0)
1176               {
1177                 double *d = &case_data_rw_idx (c, r->vars[i].case_index)->f;
1178                 float_convert (r->float_format, d, FLOAT_NATIVE_DOUBLE, d);
1179               }
1180         }
1181       return true;
1182     }
1183   else
1184     {
1185       /* Slow path.  Convert from external to internal format. */
1186       int i;
1187
1188       for (i = 0; i < r->var_cnt; i++)
1189         {
1190           struct sfm_var *sv = &r->vars[i];
1191           union value *v = case_data_rw_idx (c, sv->case_index);
1192
1193           if (sv->width == 0)
1194             {
1195               if (!read_case_number (r, &v->f))
1196                 goto eof;
1197             }
1198           else
1199             {
1200               /* Read the string data in segments up to 255 bytes
1201                  at a time, packed into 8-byte units. */
1202               const int max_chunk = MIN_VERY_LONG_STRING - 1;
1203               int ofs, chunk_size;
1204               for (ofs = 0; ofs < sv->width; ofs += chunk_size)
1205                 {
1206                   chunk_size = MIN (max_chunk, sv->width - ofs);
1207                   if (!read_case_string (r, v->s + ofs, chunk_size))
1208                     {
1209                       if (ofs)
1210                         partial_record (r);
1211                       goto eof;
1212                     }
1213                 }
1214
1215               /* Very long strings have trailing wasted space
1216                  that we must skip. */
1217               if (sv->width >= MIN_VERY_LONG_STRING)
1218                 {
1219                   int bytes_read = (sv->width / max_chunk * 256
1220                                     + ROUND_UP (sv->width % max_chunk, 8));
1221                   int total_bytes = sfm_width_to_bytes (sv->width);
1222                   int excess_bytes = total_bytes - bytes_read;
1223
1224                   while (excess_bytes > 0)
1225                     {
1226                       char buffer[1024];
1227                       size_t chunk = MIN (sizeof buffer, excess_bytes);
1228                       if (!read_whole_strings (r, buffer, chunk))
1229                         partial_record (r);
1230                       excess_bytes -= chunk;
1231                     }
1232                 }
1233             }
1234         }
1235       return true;
1236
1237     eof:
1238       case_destroy (c);
1239       if (i != 0)
1240         partial_record (r);
1241       if ( r->case_cnt != -1 )
1242         read_error (reader, r);
1243       return false;
1244     }
1245 }
1246
1247 /* Issues an error that R ends in a partial record. */
1248 static void
1249 partial_record (struct sfm_reader *r)
1250 {
1251   sys_error (r, _("File ends in partial case."));
1252 }
1253
1254 static void
1255 read_error (struct casereader *r, const struct sfm_reader *sfm)
1256 {
1257   msg (ME, _("Error reading case from file %s"), fh_get_name (sfm->fh));
1258   casereader_force_error (r);
1259 }
1260
1261 /* Reads a number from R and stores its value in *D.
1262    If R is compressed, reads a compressed number;
1263    otherwise, reads a number in the regular way.
1264    Returns true if successful, false if end of file is
1265    reached immediately. */
1266 static bool
1267 read_case_number (struct sfm_reader *r, double *d)
1268 {
1269   if (!r->compressed)
1270     {
1271       uint8_t flt64[8];
1272       if (!try_read_bytes (r, flt64, sizeof flt64))
1273         return false;
1274       *d = flt64_to_double (r, flt64);
1275       return true;
1276     }
1277   else
1278     return read_compressed_number (r, d);
1279 }
1280
1281 /* Reads LENGTH string bytes from R into S.
1282    Always reads a multiple of 8 bytes; if LENGTH is not a
1283    multiple of 8, then extra bytes are read and discarded without
1284    being written to S.
1285    Reads compressed strings if S is compressed.
1286    Returns true if successful, false if end of file is
1287    reached immediately. */
1288 static bool
1289 read_case_string (struct sfm_reader *r, char *s, size_t length)
1290 {
1291   size_t whole = ROUND_DOWN (length, 8);
1292   size_t partial = length % 8;
1293
1294   if (whole)
1295     {
1296       if (!read_whole_strings (r, s, whole))
1297         return false;
1298     }
1299
1300   if (partial)
1301     {
1302       char bounce[8];
1303       if (!read_whole_strings (r, bounce, sizeof bounce))
1304         {
1305           if (whole)
1306             partial_record (r);
1307           return false;
1308         }
1309       memcpy (s + whole, bounce, partial);
1310     }
1311
1312   return true;
1313 }
1314
1315 /* Reads and returns the next compression opcode from R. */
1316 static int
1317 read_opcode (struct sfm_reader *r)
1318 {
1319   assert (r->compressed);
1320   for (;;)
1321     {
1322       int opcode;
1323       if (r->opcode_idx >= sizeof r->opcodes)
1324         {
1325           if (!try_read_bytes (r, r->opcodes, sizeof r->opcodes))
1326             return -1;
1327           r->opcode_idx = 0;
1328         }
1329       opcode = r->opcodes[r->opcode_idx++];
1330
1331       if (opcode != 0)
1332         return opcode;
1333     }
1334 }
1335
1336 /* Reads a compressed number from R and stores its value in D.
1337    Returns true if successful, false if end of file is
1338    reached immediately. */
1339 static bool
1340 read_compressed_number (struct sfm_reader *r, double *d)
1341 {
1342   int opcode = read_opcode (r);
1343   switch (opcode)
1344     {
1345     case -1:
1346     case 252:
1347       return false;
1348
1349     case 253:
1350       *d = read_flt64 (r);
1351       break;
1352
1353     case 254:
1354       sys_error (r, _("Compressed data is corrupt."));
1355
1356     case 255:
1357       *d = SYSMIS;
1358       break;
1359
1360     default:
1361       *d = opcode - r->bias;
1362       break;
1363     }
1364
1365   return true;
1366 }
1367
1368 /* Reads a compressed 8-byte string segment from R and stores it
1369    in DST.
1370    Returns true if successful, false if end of file is
1371    reached immediately. */
1372 static bool
1373 read_compressed_string (struct sfm_reader *r, char *dst)
1374 {
1375   switch (read_opcode (r))
1376     {
1377     case -1:
1378     case 252:
1379       return false;
1380
1381     case 253:
1382       read_bytes (r, dst, 8);
1383       break;
1384
1385     case 254:
1386       memset (dst, ' ', 8);
1387       break;
1388
1389     default:
1390       sys_error (r, _("Compressed data is corrupt."));
1391     }
1392
1393   return true;
1394 }
1395
1396 /* Reads LENGTH string bytes from R into S.
1397    LENGTH must be a multiple of 8.
1398    Reads compressed strings if S is compressed.
1399    Returns true if successful, false if end of file is
1400    reached immediately. */
1401 static bool
1402 read_whole_strings (struct sfm_reader *r, char *s, size_t length)
1403 {
1404   assert (length % 8 == 0);
1405   if (!r->compressed)
1406     return try_read_bytes (r, s, length);
1407   else
1408     {
1409       size_t ofs;
1410       for (ofs = 0; ofs < length; ofs += 8)
1411         if (!read_compressed_string (r, s + ofs))
1412           {
1413             if (ofs != 0)
1414               partial_record (r);
1415             return false;
1416           }
1417       return true;
1418     }
1419 }
1420 \f
1421 /* Creates and returns a table that can be used for translating a value
1422    index into a case to a "struct variable *" for DICT.  Multiple
1423    system file fields reference variables this way.
1424
1425    This table must be created before processing the very long
1426    string extension record, because that record causes some
1427    values to be deleted from the case and the dictionary to be
1428    compacted. */
1429 static struct variable **
1430 make_var_by_value_idx (struct sfm_reader *r, struct dictionary *dict)
1431 {
1432   struct variable **var_by_value_idx;
1433   int value_idx = 0;
1434   int i;
1435
1436   var_by_value_idx = pool_nmalloc (r->pool,
1437                                    r->flt64_cnt, sizeof *var_by_value_idx);
1438   for (i = 0; i < dict_get_var_cnt (dict); i++)
1439     {
1440       struct variable *v = dict_get_var (dict, i);
1441       int nv = var_is_numeric (v) ? 1 : DIV_RND_UP (var_get_width (v), 8);
1442       int j;
1443
1444       var_by_value_idx[value_idx++] = v;
1445       for (j = 1; j < nv; j++)
1446         var_by_value_idx[value_idx++] = NULL;
1447     }
1448   assert (value_idx == r->flt64_cnt);
1449
1450   return var_by_value_idx;
1451 }
1452
1453 /* Returns the "struct variable" corresponding to the given
1454    1-basd VALUE_IDX in VAR_BY_VALUE_IDX.  Verifies that the index
1455    is valid. */
1456 static struct variable *
1457 lookup_var_by_value_idx (struct sfm_reader *r,
1458                          struct variable **var_by_value_idx, int value_idx)
1459 {
1460   struct variable *var;
1461
1462   if (value_idx < 1 || value_idx > r->flt64_cnt)
1463     sys_error (r, _("Variable index %d not in valid range 1...%d."),
1464                value_idx, r->flt64_cnt);
1465
1466   var = var_by_value_idx[value_idx - 1];
1467   if (var == NULL)
1468     sys_error (r, _("Variable index %d refers to long string "
1469                     "continuation."),
1470                value_idx);
1471
1472   return var;
1473 }
1474
1475 /* Returns the variable in D with the given SHORT_NAME,
1476    or a null pointer if there is none. */
1477 static struct variable *
1478 lookup_var_by_short_name (struct dictionary *d, const char *short_name)
1479 {
1480   struct variable *var;
1481   size_t var_cnt;
1482   size_t i;
1483
1484   /* First try looking up by full name.  This often succeeds. */
1485   var = dict_lookup_var (d, short_name);
1486   if (var != NULL && !strcasecmp (var_get_short_name (var), short_name))
1487     return var;
1488
1489   /* Iterate through the whole dictionary as a fallback. */
1490   var_cnt = dict_get_var_cnt (d);
1491   for (i = 0; i < var_cnt; i++)
1492     {
1493       var = dict_get_var (d, i);
1494       if (!strcasecmp (var_get_short_name (var), short_name))
1495         return var;
1496     }
1497
1498   return NULL;
1499 }
1500 \f
1501 /* Helpers for reading records that contain "variable=value"
1502    pairs. */
1503
1504 /* State. */
1505 struct variable_to_value_map
1506   {
1507     struct substring buffer;    /* Record contents. */
1508     size_t pos;                 /* Current position in buffer. */
1509   };
1510
1511 /* Reads SIZE bytes into a "variable=value" map for R,
1512    and returns the map. */
1513 static struct variable_to_value_map *
1514 open_variable_to_value_map (struct sfm_reader *r, size_t size)
1515 {
1516   struct variable_to_value_map *map = pool_alloc (r->pool, sizeof *map);
1517   char *buffer = pool_malloc (r->pool, size + 1);
1518   read_bytes (r, buffer, size);
1519   map->buffer = ss_buffer (buffer, size);
1520   map->pos = 0;
1521   return map;
1522 }
1523
1524 /* Closes MAP and frees its storage.
1525    Not really needed, because the pool will free the map anyway,
1526    but can be used to free it earlier. */
1527 static void
1528 close_variable_to_value_map (struct sfm_reader *r,
1529                              struct variable_to_value_map *map)
1530 {
1531   pool_free (r->pool, ss_data (map->buffer));
1532 }
1533
1534 /* Reads the next variable=value pair from MAP.
1535    Looks up the variable in DICT and stores it into *VAR.
1536    Stores a null-terminated value into *VALUE. */
1537 static bool
1538 read_variable_to_value_map (struct sfm_reader *r, struct dictionary *dict,
1539                             struct variable_to_value_map *map,
1540                             struct variable **var, char **value,
1541                             int *warning_cnt)
1542 {
1543   int max_warnings = 5;
1544
1545   for (;;)
1546     {
1547       struct substring short_name_ss, value_ss;
1548
1549       if (!ss_tokenize (map->buffer, ss_cstr ("="), &map->pos, &short_name_ss)
1550           || !ss_tokenize (map->buffer, ss_buffer ("\t\0", 2), &map->pos,
1551                            &value_ss))
1552         {
1553           if (*warning_cnt > max_warnings)
1554             sys_warn (r, _("Suppressed %d additional variable map warnings."),
1555                       *warning_cnt - max_warnings);
1556           return false;
1557         }
1558
1559       map->pos += ss_span (ss_substr (map->buffer, map->pos, SIZE_MAX),
1560                            ss_buffer ("\t\0", 2));
1561
1562       ss_data (short_name_ss)[ss_length (short_name_ss)] = '\0';
1563       *var = lookup_var_by_short_name (dict, ss_data (short_name_ss));
1564       if (*var == NULL)
1565         {
1566           if (++*warning_cnt <= 5)
1567             sys_warn (r, _("Variable map refers to unknown variable %s."),
1568                       ss_data (short_name_ss));
1569           continue;
1570         }
1571
1572       ss_data (value_ss)[ss_length (value_ss)] = '\0';
1573       *value = ss_data (value_ss);
1574
1575       return true;
1576     }
1577 }
1578 \f
1579 /* Messages. */
1580
1581 /* Displays a corruption message. */
1582 static void
1583 sys_msg (struct sfm_reader *r, int class, const char *format, va_list args)
1584 {
1585   struct msg m;
1586   struct string text;
1587
1588   ds_init_empty (&text);
1589   ds_put_format (&text, "\"%s\" near offset 0x%lx: ",
1590                  fh_get_file_name (r->fh), (unsigned long) ftell (r->file));
1591   ds_put_vformat (&text, format, args);
1592
1593   m.category = msg_class_to_category (class);
1594   m.severity = msg_class_to_severity (class);
1595   m.where.file_name = NULL;
1596   m.where.line_number = 0;
1597   m.text = ds_cstr (&text);
1598
1599   msg_emit (&m);
1600 }
1601
1602 /* Displays a warning for the current file position. */
1603 static void
1604 sys_warn (struct sfm_reader *r, const char *format, ...)
1605 {
1606   va_list args;
1607
1608   va_start (args, format);
1609   sys_msg (r, MW, format, args);
1610   va_end (args);
1611 }
1612
1613 /* Displays an error for the current file position,
1614    marks it as in an error state,
1615    and aborts reading it using longjmp. */
1616 static void
1617 sys_error (struct sfm_reader *r, const char *format, ...)
1618 {
1619   va_list args;
1620
1621   va_start (args, format);
1622   sys_msg (r, ME, format, args);
1623   va_end (args);
1624
1625   r->error = true;
1626   longjmp (r->bail_out, 1);
1627 }
1628 \f
1629 /* Reads BYTE_CNT bytes into BUF.
1630    Returns true if exactly BYTE_CNT bytes are successfully read.
1631    Aborts if an I/O error or a partial read occurs.
1632    If EOF_IS_OK, then an immediate end-of-file causes false to be
1633    returned; otherwise, immediate end-of-file causes an abort
1634    too. */
1635 static inline bool
1636 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
1637                    void *buf, size_t byte_cnt)
1638 {
1639   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
1640   if (bytes_read == byte_cnt)
1641     return true;
1642   else if (ferror (r->file))
1643     sys_error (r, _("System error: %s."), strerror (errno));
1644   else if (!eof_is_ok || bytes_read != 0)
1645     sys_error (r, _("Unexpected end of file."));
1646   else
1647     return false;
1648 }
1649
1650 /* Reads BYTE_CNT into BUF.
1651    Aborts upon I/O error or if end-of-file is encountered. */
1652 static void
1653 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
1654 {
1655   read_bytes_internal (r, false, buf, byte_cnt);
1656 }
1657
1658 /* Reads BYTE_CNT bytes into BUF.
1659    Returns true if exactly BYTE_CNT bytes are successfully read.
1660    Returns false if an immediate end-of-file is encountered.
1661    Aborts if an I/O error or a partial read occurs. */
1662 static bool
1663 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
1664 {
1665   return read_bytes_internal (r, true, buf, byte_cnt);
1666 }
1667
1668 /* Reads a 32-bit signed integer from R and returns its value in
1669    host format. */
1670 static int32_t
1671 read_int32 (struct sfm_reader *r)
1672 {
1673   uint8_t int32[4];
1674   read_bytes (r, int32, sizeof int32);
1675   return int32_to_native (r, int32);
1676 }
1677
1678 /* Reads a 64-bit floating-point number from R and returns its
1679    value in host format. */
1680 static double
1681 read_flt64 (struct sfm_reader *r)
1682 {
1683   uint8_t flt64[8];
1684   read_bytes (r, flt64, sizeof flt64);
1685   return flt64_to_double (r, flt64);
1686 }
1687
1688 /* Reads exactly SIZE - 1 bytes into BUFFER
1689    and stores a null byte into BUFFER[SIZE - 1]. */
1690 static void
1691 read_string (struct sfm_reader *r, char *buffer, size_t size)
1692 {
1693   assert (size > 0);
1694   read_bytes (r, buffer, size - 1);
1695   buffer[size - 1] = '\0';
1696 }
1697
1698 /* Skips BYTES bytes forward in R. */
1699 static void
1700 skip_bytes (struct sfm_reader *r, size_t bytes)
1701 {
1702   while (bytes > 0)
1703     {
1704       char buffer[1024];
1705       size_t chunk = MIN (sizeof buffer, bytes);
1706       read_bytes (r, buffer, chunk);
1707       bytes -= chunk;
1708     }
1709 }
1710 \f
1711 /* Returns the value of the 32-bit signed integer at INT32,
1712    converted from the format used by R to the host format. */
1713 static int32_t
1714 int32_to_native (const struct sfm_reader *r, const uint8_t int32[4])
1715 {
1716   int32_t x;
1717   if (r->integer_format == INTEGER_NATIVE)
1718     memcpy (&x, int32, sizeof x);
1719   else
1720     x = integer_get (r->integer_format, int32, sizeof x);
1721   return x;
1722 }
1723
1724 /* Returns the value of the 64-bit floating point number at
1725    FLT64, converted from the format used by R to the host
1726    format. */
1727 static double
1728 flt64_to_double (const struct sfm_reader *r, const uint8_t flt64[8])
1729 {
1730   double x;
1731   if (r->float_format == FLOAT_NATIVE_DOUBLE)
1732     memcpy (&x, flt64, sizeof x);
1733   else
1734     float_convert (r->float_format, flt64, FLOAT_NATIVE_DOUBLE, &x);
1735   return x;
1736 }
1737 \f
1738 static struct casereader_class sys_file_casereader_class =
1739   {
1740     sys_file_casereader_read,
1741     sys_file_casereader_destroy,
1742     NULL,
1743     NULL,
1744   };