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