sys-file-reader: Improve diagnostics for unexpected special values.
[pspp] / src / data / sys-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-2000, 2006-2007, 2009-2013 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 "data/attributes.h"
29 #include "data/case.h"
30 #include "data/casereader-provider.h"
31 #include "data/casereader.h"
32 #include "data/dictionary.h"
33 #include "data/file-handle-def.h"
34 #include "data/file-name.h"
35 #include "data/format.h"
36 #include "data/identifier.h"
37 #include "data/missing-values.h"
38 #include "data/mrset.h"
39 #include "data/short-names.h"
40 #include "data/value-labels.h"
41 #include "data/value.h"
42 #include "data/variable.h"
43 #include "libpspp/array.h"
44 #include "libpspp/assertion.h"
45 #include "libpspp/compiler.h"
46 #include "libpspp/i18n.h"
47 #include "libpspp/message.h"
48 #include "libpspp/misc.h"
49 #include "libpspp/pool.h"
50 #include "libpspp/str.h"
51 #include "libpspp/stringi-set.h"
52
53 #include "gl/c-strtod.h"
54 #include "gl/c-ctype.h"
55 #include "gl/inttostr.h"
56 #include "gl/localcharset.h"
57 #include "gl/minmax.h"
58 #include "gl/unlocked-io.h"
59 #include "gl/xalloc.h"
60 #include "gl/xsize.h"
61
62 #include "gettext.h"
63 #define _(msgid) gettext (msgid)
64 #define N_(msgid) (msgid)
65
66 enum
67   {
68     /* subtypes 0-2 unknown */
69     EXT_INTEGER       = 3,      /* Machine integer info. */
70     EXT_FLOAT         = 4,      /* Machine floating-point info. */
71     EXT_VAR_SETS      = 5,      /* Variable sets. */
72     EXT_DATE          = 6,      /* DATE. */
73     EXT_MRSETS        = 7,      /* Multiple response sets. */
74     EXT_DATA_ENTRY    = 8,      /* SPSS Data Entry. */
75     /* subtypes 9-10 unknown */
76     EXT_DISPLAY       = 11,     /* Variable display parameters. */
77     /* subtype 12 unknown */
78     EXT_LONG_NAMES    = 13,     /* Long variable names. */
79     EXT_LONG_STRINGS  = 14,     /* Long strings. */
80     /* subtype 15 unknown */
81     EXT_NCASES        = 16,     /* Extended number of cases. */
82     EXT_FILE_ATTRS    = 17,     /* Data file attributes. */
83     EXT_VAR_ATTRS     = 18,     /* Variable attributes. */
84     EXT_MRSETS2       = 19,     /* Multiple response sets (extended). */
85     EXT_ENCODING      = 20,     /* Character encoding. */
86     EXT_LONG_LABELS   = 21      /* Value labels for long strings. */
87   };
88
89 /* Fields from the top-level header record. */
90 struct sfm_header_record
91   {
92     char magic[5];              /* First 4 bytes of file, then null. */
93     int weight_idx;             /* 0 if unweighted, otherwise a var index. */
94     int nominal_case_size;      /* Number of var positions. */
95
96     /* These correspond to the members of struct sfm_file_info or a dictionary
97        but in the system file's encoding rather than ASCII. */
98     char creation_date[10];     /* "dd mmm yy". */
99     char creation_time[9];      /* "hh:mm:ss". */
100     char eye_catcher[61];       /* Eye-catcher string, then product name. */
101     char file_label[65];        /* File label. */
102   };
103
104 struct sfm_var_record
105   {
106     off_t pos;
107     int width;
108     char name[8];
109     int print_format;
110     int write_format;
111     int missing_value_code;
112     uint8_t missing[24];
113     char *label;
114     struct variable *var;
115   };
116
117 struct sfm_value_label
118   {
119     uint8_t value[8];
120     char *label;
121   };
122
123 struct sfm_value_label_record
124   {
125     off_t pos;
126     struct sfm_value_label *labels;
127     size_t n_labels;
128
129     int *vars;
130     size_t n_vars;
131   };
132
133 struct sfm_document_record
134   {
135     off_t pos;
136     char *documents;
137     size_t n_lines;
138   };
139
140 struct sfm_extension_record
141   {
142     off_t pos;                  /* Starting offset in file. */
143     size_t size;                /* Size of data elements. */
144     size_t count;               /* Number of data elements. */
145     void *data;                 /* Contents. */
146   };
147
148 /* System file reader. */
149 struct sfm_reader
150   {
151     /* Resource tracking. */
152     struct pool *pool;          /* All system file state. */
153     jmp_buf bail_out;           /* longjmp() target for error handling. */
154
155     /* File state. */
156     struct file_handle *fh;     /* File handle. */
157     struct fh_lock *lock;       /* Mutual exclusion for file handle. */
158     FILE *file;                 /* File stream. */
159     off_t pos;                  /* Position in file. */
160     bool error;                 /* I/O or corruption error? */
161     struct caseproto *proto;    /* Format of output cases. */
162
163     /* File format. */
164     enum integer_format integer_format; /* On-disk integer format. */
165     enum float_format float_format; /* On-disk floating point format. */
166     struct sfm_var *sfm_vars;   /* Variables. */
167     size_t sfm_var_cnt;         /* Number of variables. */
168     casenumber case_cnt;        /* Number of cases */
169     const char *encoding;       /* String encoding. */
170
171     /* Decompression. */
172     bool compressed;            /* File is compressed? */
173     double bias;                /* Compression bias, usually 100.0. */
174     uint8_t opcodes[8];         /* Current block of opcodes. */
175     size_t opcode_idx;          /* Next opcode to interpret, 8 if none left. */
176     bool corruption_warning;    /* Warned about possible corruption? */
177   };
178
179 static const struct casereader_class sys_file_casereader_class;
180
181 static bool close_reader (struct sfm_reader *);
182
183 static struct variable *lookup_var_by_index (struct sfm_reader *, off_t,
184                                              const struct sfm_var_record *,
185                                              size_t n, int idx);
186
187 static void sys_msg (struct sfm_reader *r, off_t, int class,
188                      const char *format, va_list args)
189      PRINTF_FORMAT (4, 0);
190 static void sys_warn (struct sfm_reader *, off_t, const char *, ...)
191      PRINTF_FORMAT (3, 4);
192 static void sys_error (struct sfm_reader *, off_t, const char *, ...)
193      PRINTF_FORMAT (3, 4)
194      NO_RETURN;
195
196 static void read_bytes (struct sfm_reader *, void *, size_t);
197 static bool try_read_bytes (struct sfm_reader *, void *, size_t);
198 static int read_int (struct sfm_reader *);
199 static double read_float (struct sfm_reader *);
200 static void read_string (struct sfm_reader *, char *, size_t);
201 static void skip_bytes (struct sfm_reader *, size_t);
202
203 static int parse_int (struct sfm_reader *, const void *data, size_t ofs);
204 static double parse_float (struct sfm_reader *, const void *data, size_t ofs);
205
206 static void read_variable_record (struct sfm_reader *,
207                                   struct sfm_var_record *);
208 static void read_value_label_record (struct sfm_reader *,
209                                      struct sfm_value_label_record *,
210                                      size_t n_vars);
211 static struct sfm_document_record *read_document_record (struct sfm_reader *);
212 static struct sfm_extension_record *read_extension_record (
213   struct sfm_reader *, int subtype);
214 static void skip_extension_record (struct sfm_reader *, int subtype);
215
216 static const char *choose_encoding (
217   struct sfm_reader *,
218   const struct sfm_header_record *,
219   const struct sfm_extension_record *ext_integer,
220   const struct sfm_extension_record *ext_encoding);
221
222 static struct text_record *open_text_record (
223   struct sfm_reader *, const struct sfm_extension_record *,
224   bool recode_to_utf8);
225 static void close_text_record (struct sfm_reader *,
226                                struct text_record *);
227 static bool read_variable_to_value_pair (struct sfm_reader *,
228                                          struct dictionary *,
229                                          struct text_record *,
230                                          struct variable **var, char **value);
231 static void text_warn (struct sfm_reader *r, struct text_record *text,
232                        const char *format, ...)
233   PRINTF_FORMAT (3, 4);
234 static char *text_get_token (struct text_record *,
235                              struct substring delimiters, char *delimiter);
236 static bool text_match (struct text_record *, char c);
237 static bool text_read_variable_name (struct sfm_reader *, struct dictionary *,
238                                      struct text_record *,
239                                      struct substring delimiters,
240                                      struct variable **);
241 static bool text_read_short_name (struct sfm_reader *, struct dictionary *,
242                                   struct text_record *,
243                                   struct substring delimiters,
244                                   struct variable **);
245 static const char *text_parse_counted_string (struct sfm_reader *,
246                                               struct text_record *);
247 static size_t text_pos (const struct text_record *);
248
249 static bool close_reader (struct sfm_reader *r);
250 \f
251 /* Dictionary reader. */
252
253 enum which_format
254   {
255     PRINT_FORMAT,
256     WRITE_FORMAT
257   };
258
259 static void read_header (struct sfm_reader *, struct sfm_read_info *,
260                          struct sfm_header_record *);
261 static void parse_header (struct sfm_reader *,
262                           const struct sfm_header_record *,
263                           struct sfm_read_info *, struct dictionary *);
264 static void parse_variable_records (struct sfm_reader *, struct dictionary *,
265                                     struct sfm_var_record *, size_t n);
266 static void parse_format_spec (struct sfm_reader *, off_t pos,
267                                unsigned int format, enum which_format,
268                                struct variable *, int *format_warning_cnt);
269 static void parse_document (struct dictionary *, struct sfm_document_record *);
270 static void parse_display_parameters (struct sfm_reader *,
271                                       const struct sfm_extension_record *,
272                                       struct dictionary *);
273 static void parse_machine_integer_info (struct sfm_reader *,
274                                         const struct sfm_extension_record *,
275                                         struct sfm_read_info *);
276 static void parse_machine_float_info (struct sfm_reader *,
277                                       const struct sfm_extension_record *);
278 static void parse_mrsets (struct sfm_reader *,
279                           const struct sfm_extension_record *,
280                           struct dictionary *);
281 static void parse_long_var_name_map (struct sfm_reader *,
282                                      const struct sfm_extension_record *,
283                                      struct dictionary *);
284 static void parse_long_string_map (struct sfm_reader *,
285                                    const struct sfm_extension_record *,
286                                    struct dictionary *);
287 static void parse_value_labels (struct sfm_reader *, struct dictionary *,
288                                 const struct sfm_var_record *,
289                                 size_t n_var_recs,
290                                 const struct sfm_value_label_record *);
291 static void parse_data_file_attributes (struct sfm_reader *,
292                                         const struct sfm_extension_record *,
293                                         struct dictionary *);
294 static void parse_variable_attributes (struct sfm_reader *,
295                                        const struct sfm_extension_record *,
296                                        struct dictionary *);
297 static void parse_long_string_value_labels (struct sfm_reader *,
298                                             const struct sfm_extension_record *,
299                                             struct dictionary *);
300
301 /* Frees the strings inside INFO. */
302 void
303 sfm_read_info_destroy (struct sfm_read_info *info)
304 {
305   if (info)
306     {
307       free (info->creation_date);
308       free (info->creation_time);
309       free (info->product);
310     }
311 }
312
313 /* Opens the system file designated by file handle FH for reading.  Reads the
314    system file's dictionary into *DICT.
315
316    Ordinarily the reader attempts to automatically detect the character
317    encoding based on the file's contents.  This isn't always possible,
318    especially for files written by old versions of SPSS or PSPP, so specifying
319    a nonnull ENCODING overrides the choice of character encoding.
320
321    If INFO is non-null, then it receives additional info about the system file,
322    which the caller must eventually free with sfm_read_info_destroy() when it
323    is no longer needed. */
324 struct casereader *
325 sfm_open_reader (struct file_handle *fh, const char *volatile encoding,
326                  struct dictionary **dictp, struct sfm_read_info *infop)
327 {
328   struct sfm_reader *volatile r = NULL;
329   struct sfm_read_info *volatile info;
330
331   struct sfm_header_record header;
332
333   struct sfm_var_record *vars;
334   size_t n_vars, allocated_vars;
335
336   struct sfm_value_label_record *labels;
337   size_t n_labels, allocated_labels;
338
339   struct sfm_document_record *document;
340
341   struct sfm_extension_record *extensions[32];
342
343   struct dictionary *volatile dict = NULL;
344   size_t i;
345
346   /* Create and initialize reader. */
347   r = pool_create_container (struct sfm_reader, pool);
348   r->fh = fh_ref (fh);
349   r->lock = NULL;
350   r->file = NULL;
351   r->pos = 0;
352   r->error = false;
353   r->opcode_idx = sizeof r->opcodes;
354   r->corruption_warning = false;
355
356   info = infop ? infop : xmalloc (sizeof *info);
357   memset (info, 0, sizeof *info);
358
359   /* TRANSLATORS: this fragment will be interpolated into
360      messages in fh_lock() that identify types of files. */
361   r->lock = fh_lock (fh, FH_REF_FILE, N_("system file"), FH_ACC_READ, false);
362   if (r->lock == NULL)
363     goto error;
364
365   r->file = fn_open (fh_get_file_name (fh), "rb");
366   if (r->file == NULL)
367     {
368       msg (ME, _("Error opening `%s' for reading as a system file: %s."),
369            fh_get_file_name (r->fh), strerror (errno));
370       goto error;
371     }
372
373   if (setjmp (r->bail_out))
374     goto error;
375
376   /* Read header. */
377   read_header (r, info, &header);
378
379   vars = NULL;
380   n_vars = allocated_vars = 0;
381
382   labels = NULL;
383   n_labels = allocated_labels = 0;
384
385   document = NULL;
386
387   memset (extensions, 0, sizeof extensions);
388
389   for (;;)
390     {
391       int subtype;
392       int type;
393
394       type = read_int (r);
395       if (type == 999)
396         {
397           read_int (r);         /* Skip filler. */
398           break;
399         }
400
401       switch (type)
402         {
403         case 2:
404           if (n_vars >= allocated_vars)
405             vars = pool_2nrealloc (r->pool, vars, &allocated_vars,
406                                    sizeof *vars);
407           read_variable_record (r, &vars[n_vars++]);
408           break;
409
410         case 3:
411           if (n_labels >= allocated_labels)
412             labels = pool_2nrealloc (r->pool, labels, &allocated_labels,
413                                      sizeof *labels);
414           read_value_label_record (r, &labels[n_labels++], n_vars);
415           break;
416
417         case 4:
418           /* A Type 4 record is always immediately after a type 3 record,
419              so the code for type 3 records reads the type 4 record too. */
420           sys_error (r, r->pos, _("Misplaced type 4 record."));
421
422         case 6:
423           if (document != NULL)
424             sys_error (r, r->pos, _("Duplicate type 6 (document) record."));
425           document = read_document_record (r);
426           break;
427
428         case 7:
429           subtype = read_int (r);
430           if (subtype < 0 || subtype >= sizeof extensions / sizeof *extensions)
431             {
432               sys_warn (r, r->pos,
433                         _("Unrecognized record type 7, subtype %d.  Please "
434                           "send a copy of this file, and the syntax which "
435                           "created it to %s."),
436                         subtype, PACKAGE_BUGREPORT);
437               skip_extension_record (r, subtype);
438             }
439           else if (extensions[subtype] != NULL)
440             {
441               sys_warn (r, r->pos,
442                         _("Record type 7, subtype %d found here has the same "
443                           "type as the record found near offset 0x%llx.  "
444                           "Please send a copy of this file, and the syntax "
445                           "which created it to %s."),
446                         subtype, (long long int) extensions[subtype]->pos,
447                         PACKAGE_BUGREPORT);
448               skip_extension_record (r, subtype);
449             }
450           else
451             extensions[subtype] = read_extension_record (r, subtype);
452           break;
453
454         default:
455           sys_error (r, r->pos, _("Unrecognized record type %d."), type);
456           goto error;
457         }
458     }
459
460   /* Now actually parse what we read.
461
462      First, figure out the correct character encoding, because this determines
463      how the rest of the header data is to be interpreted. */
464   dict = dict_create (encoding
465                       ? encoding
466                       : choose_encoding (r, &header, extensions[EXT_INTEGER],
467                                          extensions[EXT_ENCODING]));
468   r->encoding = dict_get_encoding (dict);
469
470   /* These records don't use variables at all. */
471   if (document != NULL)
472     parse_document (dict, document);
473
474   if (extensions[EXT_INTEGER] != NULL)
475     parse_machine_integer_info (r, extensions[EXT_INTEGER], info);
476
477   if (extensions[EXT_FLOAT] != NULL)
478     parse_machine_float_info (r, extensions[EXT_FLOAT]);
479
480   if (extensions[EXT_FILE_ATTRS] != NULL)
481     parse_data_file_attributes (r, extensions[EXT_FILE_ATTRS], dict);
482
483   parse_header (r, &header, info, dict);
484
485   /* Parse the variable records, the basis of almost everything else. */
486   parse_variable_records (r, dict, vars, n_vars);
487
488   /* Parse value labels and the weight variable immediately after the variable
489      records.  These records use indexes into var_recs[], so we must parse them
490      before those indexes become invalidated by very long string variables. */
491   for (i = 0; i < n_labels; i++)
492     parse_value_labels (r, dict, vars, n_vars, &labels[i]);
493   if (header.weight_idx != 0)
494     {
495       struct variable *weight_var;
496
497       weight_var = lookup_var_by_index (r, 76, vars, n_vars,
498                                         header.weight_idx);
499       if (var_is_numeric (weight_var))
500         dict_set_weight (dict, weight_var);
501       else
502         sys_error (r, -1, _("Weighting variable must be numeric "
503                             "(not string variable `%s')."),
504                    var_get_name (weight_var));
505     }
506
507   if (extensions[EXT_DISPLAY] != NULL)
508     parse_display_parameters (r, extensions[EXT_DISPLAY], dict);
509
510   /* The following records use short names, so they need to be parsed before
511      parse_long_var_name_map() changes short names to long names. */
512   if (extensions[EXT_MRSETS] != NULL)
513     parse_mrsets (r, extensions[EXT_MRSETS], dict);
514
515   if (extensions[EXT_MRSETS2] != NULL)
516     parse_mrsets (r, extensions[EXT_MRSETS2], dict);
517
518   if (extensions[EXT_LONG_STRINGS] != NULL)
519     parse_long_string_map (r, extensions[EXT_LONG_STRINGS], dict);
520
521   /* Now rename variables to their long names. */
522   parse_long_var_name_map (r, extensions[EXT_LONG_NAMES], dict);
523
524   /* The following records use long names, so they need to follow renaming. */
525   if (extensions[EXT_VAR_ATTRS] != NULL)
526     parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
527
528   if (extensions[EXT_LONG_LABELS] != NULL)
529     parse_long_string_value_labels (r, extensions[EXT_LONG_LABELS], dict);
530
531   /* Warn if the actual amount of data per case differs from the
532      amount that the header claims.  SPSS version 13 gets this
533      wrong when very long strings are involved, so don't warn in
534      that case. */
535   if (header.nominal_case_size != -1 && header.nominal_case_size != n_vars
536       && info->version_major != 13)
537     sys_warn (r, -1, _("File header claims %d variable positions but "
538                        "%zu were read from file."),
539               header.nominal_case_size, n_vars);
540
541   /* Create an index of dictionary variable widths for
542      sfm_read_case to use.  We cannot use the `struct variable's
543      from the dictionary we created, because the caller owns the
544      dictionary and may destroy or modify its variables. */
545   sfm_dictionary_to_sfm_vars (dict, &r->sfm_vars, &r->sfm_var_cnt);
546   pool_register (r->pool, free, r->sfm_vars);
547   r->proto = caseproto_ref_pool (dict_get_proto (dict), r->pool);
548
549   *dictp = dict;
550   if (infop != info)
551     {
552       sfm_read_info_destroy (info);
553       free (info);
554     }
555
556   return casereader_create_sequential
557     (NULL, r->proto,
558      r->case_cnt == -1 ? CASENUMBER_MAX: r->case_cnt,
559                                        &sys_file_casereader_class, r);
560
561 error:
562   if (infop != info)
563     {
564       sfm_read_info_destroy (info);
565       free (info);
566     }
567
568   close_reader (r);
569   dict_destroy (dict);
570   *dictp = NULL;
571   return NULL;
572 }
573
574 /* Closes a system file after we're done with it.
575    Returns true if an I/O error has occurred on READER, false
576    otherwise. */
577 static bool
578 close_reader (struct sfm_reader *r)
579 {
580   bool error;
581
582   if (r == NULL)
583     return true;
584
585   if (r->file)
586     {
587       if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
588         {
589           msg (ME, _("Error closing system file `%s': %s."),
590                fh_get_file_name (r->fh), strerror (errno));
591           r->error = true;
592         }
593       r->file = NULL;
594     }
595
596   fh_unlock (r->lock);
597   fh_unref (r->fh);
598
599   error = r->error;
600   pool_destroy (r->pool);
601
602   return !error;
603 }
604
605 /* Destroys READER. */
606 static void
607 sys_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
608 {
609   struct sfm_reader *r = r_;
610   close_reader (r);
611 }
612
613 /* Returns true if FILE is an SPSS system file,
614    false otherwise. */
615 bool
616 sfm_detect (FILE *file)
617 {
618   char magic[5];
619
620   if (fread (magic, 4, 1, file) != 1)
621     return false;
622   magic[4] = '\0';
623
624   return !strcmp (ASCII_MAGIC, magic) || !strcmp (EBCDIC_MAGIC, magic);
625 }
626 \f
627 /* Reads the global header of the system file.  Initializes *HEADER and *INFO,
628    except for the string fields in *INFO, which parse_header() will initialize
629    later once the file's encoding is known. */
630 static void
631 read_header (struct sfm_reader *r, struct sfm_read_info *info,
632              struct sfm_header_record *header)
633 {
634   uint8_t raw_layout_code[4];
635   uint8_t raw_bias[8];
636
637   read_string (r, header->magic, sizeof header->magic);
638   read_string (r, header->eye_catcher, sizeof header->eye_catcher);
639
640   if (strcmp (ASCII_MAGIC, header->magic)
641       && strcmp (EBCDIC_MAGIC, header->magic))
642     sys_error (r, 0, _("This is not an SPSS system file."));
643
644   /* Identify integer format. */
645   read_bytes (r, raw_layout_code, sizeof raw_layout_code);
646   if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
647                           &r->integer_format)
648        && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
649                              &r->integer_format))
650       || (r->integer_format != INTEGER_MSB_FIRST
651           && r->integer_format != INTEGER_LSB_FIRST))
652     sys_error (r, 64, _("This is not an SPSS system file."));
653
654   header->nominal_case_size = read_int (r);
655   if (header->nominal_case_size < 0
656       || header->nominal_case_size > INT_MAX / 16)
657     header->nominal_case_size = -1;
658
659   r->compressed = read_int (r) != 0;
660
661   header->weight_idx = read_int (r);
662
663   r->case_cnt = read_int (r);
664   if ( r->case_cnt > INT_MAX / 2)
665     r->case_cnt = -1;
666
667   /* Identify floating-point format and obtain compression bias. */
668   read_bytes (r, raw_bias, sizeof raw_bias);
669   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
670     {
671       uint8_t zero_bias[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
672
673       if (memcmp (raw_bias, zero_bias, 8))
674         sys_warn (r, r->pos - 8,
675                   _("Compression bias is not the usual "
676                     "value of 100, or system file uses unrecognized "
677                     "floating-point format."));
678       else
679         {
680           /* Some software is known to write all-zeros to this
681              field.  Such software also writes floating-point
682              numbers in the format that we expect by default
683              (it seems that all software most likely does, in
684              reality), so don't warn in this case. */
685         }
686
687       if (r->integer_format == INTEGER_MSB_FIRST)
688         r->float_format = FLOAT_IEEE_DOUBLE_BE;
689       else
690         r->float_format = FLOAT_IEEE_DOUBLE_LE;
691     }
692   float_convert (r->float_format, raw_bias, FLOAT_NATIVE_DOUBLE, &r->bias);
693
694   read_string (r, header->creation_date, sizeof header->creation_date);
695   read_string (r, header->creation_time, sizeof header->creation_time);
696   read_string (r, header->file_label, sizeof header->file_label);
697   skip_bytes (r, 3);
698
699   info->integer_format = r->integer_format;
700   info->float_format = r->float_format;
701   info->compressed = r->compressed;
702   info->case_cnt = r->case_cnt;
703 }
704
705 /* Reads a variable (type 2) record from R into RECORD. */
706 static void
707 read_variable_record (struct sfm_reader *r, struct sfm_var_record *record)
708 {
709   int has_variable_label;
710
711   memset (record, 0, sizeof *record);
712
713   record->pos = r->pos;
714   record->width = read_int (r);
715   has_variable_label = read_int (r);
716   record->missing_value_code = read_int (r);
717   record->print_format = read_int (r);
718   record->write_format = read_int (r);
719   read_bytes (r, record->name, sizeof record->name);
720
721   if (has_variable_label == 1)
722     {
723       enum { MAX_LABEL_LEN = 255 };
724       size_t len, read_len;
725
726       len = read_int (r);
727
728       /* Read up to MAX_LABEL_LEN bytes of label. */
729       read_len = MIN (MAX_LABEL_LEN, len);
730       record->label = pool_malloc (r->pool, read_len + 1);
731       read_string (r, record->label, read_len + 1);
732
733       /* Skip unread label bytes. */
734       skip_bytes (r, len - read_len);
735
736       /* Skip label padding up to multiple of 4 bytes. */
737       skip_bytes (r, ROUND_UP (len, 4) - len);
738     }
739   else if (has_variable_label != 0)
740     sys_error (r, record->pos,
741                _("Variable label indicator field is not 0 or 1."));
742
743   /* Set missing values. */
744   if (record->missing_value_code != 0)
745     {
746       int code = record->missing_value_code;
747       if (record->width == 0)
748         {
749           if (code < -3 || code > 3 || code == -1)
750             sys_error (r, record->pos,
751                        _("Numeric missing value indicator field is not "
752                          "-3, -2, 0, 1, 2, or 3."));
753         }
754       else
755         {
756           if (code < 1 || code > 3)
757             sys_error (r, record->pos,
758                        _("String missing value indicator field is not "
759                          "0, 1, 2, or 3."));
760         }
761
762       read_bytes (r, record->missing, 8 * abs (code));
763     }
764 }
765
766 /* Reads value labels from R into RECORD. */
767 static void
768 read_value_label_record (struct sfm_reader *r,
769                          struct sfm_value_label_record *record,
770                          size_t n_vars)
771 {
772   size_t i;
773
774   /* Read type 3 record. */
775   record->pos = r->pos;
776   record->n_labels = read_int (r);
777   if (record->n_labels > SIZE_MAX / sizeof *record->labels)
778     sys_error (r, r->pos - 4, _("Invalid number of labels %zu."),
779                record->n_labels);
780   record->labels = pool_nmalloc (r->pool, record->n_labels,
781                                  sizeof *record->labels);
782   for (i = 0; i < record->n_labels; i++)
783     {
784       struct sfm_value_label *label = &record->labels[i];
785       unsigned char label_len;
786       size_t padded_len;
787
788       read_bytes (r, label->value, sizeof label->value);
789
790       /* Read label length. */
791       read_bytes (r, &label_len, sizeof label_len);
792       padded_len = ROUND_UP (label_len + 1, 8);
793
794       /* Read label, padding. */
795       label->label = pool_malloc (r->pool, padded_len + 1);
796       read_bytes (r, label->label, padded_len - 1);
797       label->label[label_len] = '\0';
798     }
799
800   /* Read record type of type 4 record. */
801   if (read_int (r) != 4)
802     sys_error (r, r->pos - 4,
803                _("Variable index record (type 4) does not immediately "
804                  "follow value label record (type 3) as it should."));
805
806   /* Read number of variables associated with value label from type 4
807      record. */
808   record->n_vars = read_int (r);
809   if (record->n_vars < 1 || record->n_vars > n_vars)
810     sys_error (r, r->pos - 4,
811                _("Number of variables associated with a value label (%zu) "
812                  "is not between 1 and the number of variables (%zu)."),
813                record->n_vars, n_vars);
814   record->vars = pool_nmalloc (r->pool, record->n_vars, sizeof *record->vars);
815   for (i = 0; i < record->n_vars; i++)
816     record->vars[i] = read_int (r);
817 }
818
819 /* Reads a document record from R and returns it. */
820 static struct sfm_document_record *
821 read_document_record (struct sfm_reader *r)
822 {
823   struct sfm_document_record *record;
824   int n_lines;
825
826   record = pool_malloc (r->pool, sizeof *record);
827   record->pos = r->pos;
828
829   n_lines = read_int (r);
830   if (n_lines <= 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH)
831     sys_error (r, record->pos,
832                _("Number of document lines (%d) "
833                  "must be greater than 0 and less than %d."),
834                n_lines, INT_MAX / DOC_LINE_LENGTH);
835
836   record->n_lines = n_lines;
837   record->documents = pool_malloc (r->pool, DOC_LINE_LENGTH * n_lines);
838   read_bytes (r, record->documents, DOC_LINE_LENGTH * n_lines);
839
840   return record;
841 }
842
843 static void
844 read_extension_record_header (struct sfm_reader *r, int subtype,
845                               struct sfm_extension_record *record)
846 {
847   record->pos = r->pos;
848   record->size = read_int (r);
849   record->count = read_int (r);
850
851   /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
852      allows an extra byte for a null terminator, used by some
853      extension processing routines. */
854   if (record->size != 0
855       && size_overflow_p (xsum (1, xtimes (record->count, record->size))))
856     sys_error (r, record->pos, "Record type 7 subtype %d too large.", subtype);
857 }
858
859 /* Reads an extension record from R into RECORD. */
860 static struct sfm_extension_record *
861 read_extension_record (struct sfm_reader *r, int subtype)
862 {
863   struct extension_record_type
864     {
865       int subtype;
866       int size;
867       int count;
868     };
869
870   static const struct extension_record_type types[] =
871     {
872       /* Implemented record types. */
873       { EXT_INTEGER,      4, 8 },
874       { EXT_FLOAT,        8, 3 },
875       { EXT_MRSETS,       1, 0 },
876       { EXT_DISPLAY,      4, 0 },
877       { EXT_LONG_NAMES,   1, 0 },
878       { EXT_LONG_STRINGS, 1, 0 },
879       { EXT_NCASES,       8, 2 },
880       { EXT_FILE_ATTRS,   1, 0 },
881       { EXT_VAR_ATTRS,    1, 0 },
882       { EXT_MRSETS2,      1, 0 },
883       { EXT_ENCODING,     1, 0 },
884       { EXT_LONG_LABELS,  1, 0 },
885
886       /* Ignored record types. */
887       { EXT_VAR_SETS,     0, 0 },
888       { EXT_DATE,         0, 0 },
889       { EXT_DATA_ENTRY,   0, 0 },
890     };
891
892   const struct extension_record_type *type;
893   struct sfm_extension_record *record;
894   size_t n_bytes;
895
896   record = pool_malloc (r->pool, sizeof *record);
897   read_extension_record_header (r, subtype, record);
898   n_bytes = record->count * record->size;
899
900   for (type = types; type < &types[sizeof types / sizeof *types]; type++)
901     if (subtype == type->subtype)
902       {
903         if (type->size > 0 && record->size != type->size)
904           sys_warn (r, record->pos,
905                     _("Record type 7, subtype %d has bad size %zu "
906                       "(expected %d)."), subtype, record->size, type->size);
907         else if (type->count > 0 && record->count != type->count)
908           sys_warn (r, record->pos,
909                     _("Record type 7, subtype %d has bad count %zu "
910                       "(expected %d)."), subtype, record->count, type->count);
911         else if (type->count == 0 && type->size == 0)
912           {
913             /* Ignore this record. */
914           }
915         else
916           {
917             char *data = pool_malloc (r->pool, n_bytes + 1);
918             data[n_bytes] = '\0';
919
920             record->data = data;
921             read_bytes (r, record->data, n_bytes);
922             return record;
923           }
924
925         goto skip;
926       }
927
928   sys_warn (r, record->pos,
929             _("Unrecognized record type 7, subtype %d.  Please send a "
930               "copy of this file, and the syntax which created it to %s."),
931             subtype, PACKAGE_BUGREPORT);
932
933 skip:
934   skip_bytes (r, n_bytes);
935   return NULL;
936 }
937
938 static void
939 skip_extension_record (struct sfm_reader *r, int subtype)
940 {
941   struct sfm_extension_record record;
942
943   read_extension_record_header (r, subtype, &record);
944   skip_bytes (r, record.count * record.size);
945 }
946
947 static void
948 parse_header (struct sfm_reader *r, const struct sfm_header_record *header,
949               struct sfm_read_info *info, struct dictionary *dict)
950 {
951   const char *dict_encoding = dict_get_encoding (dict);
952   struct substring product;
953   struct substring label;
954
955   /* Convert file label to UTF-8 and put it into DICT. */
956   label = recode_substring_pool ("UTF-8", dict_encoding,
957                                  ss_cstr (header->file_label), r->pool);
958   ss_trim (&label, ss_cstr (" "));
959   label.string[label.length] = '\0';
960   dict_set_label (dict, label.string);
961
962   /* Put creation date and time in UTF-8 into INFO. */
963   info->creation_date = recode_string ("UTF-8", dict_encoding,
964                                        header->creation_date, -1);
965   info->creation_time = recode_string ("UTF-8", dict_encoding,
966                                        header->creation_time, -1);
967
968   /* Put product name into INFO, dropping eye-catcher string if present. */
969   product = recode_substring_pool ("UTF-8", dict_encoding,
970                                    ss_cstr (header->eye_catcher), r->pool);
971   ss_match_string (&product, ss_cstr ("@(#) SPSS DATA FILE"));
972   ss_trim (&product, ss_cstr (" "));
973   info->product = ss_xstrdup (product);
974 }
975
976 /* Reads a variable (type 2) record from R and adds the
977    corresponding variable to DICT.
978    Also skips past additional variable records for long string
979    variables. */
980 static void
981 parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
982                         struct sfm_var_record *var_recs, size_t n_var_recs)
983 {
984   const char *dict_encoding = dict_get_encoding (dict);
985   struct sfm_var_record *rec;
986   int n_warnings = 0;
987
988   for (rec = var_recs; rec < &var_recs[n_var_recs]; )
989     {
990       struct variable *var;
991       size_t n_values;
992       char *name;
993       size_t i;
994
995       name = recode_string_pool ("UTF-8", dict_encoding,
996                                  rec->name, 8, r->pool);
997       name[strcspn (name, " ")] = '\0';
998
999       if (!dict_id_is_valid (dict, name, false)
1000           || name[0] == '$' || name[0] == '#')
1001         sys_error (r, rec->pos, _("Invalid variable name `%s'."), name);
1002
1003       if (rec->width < 0 || rec->width > 255)
1004         sys_error (r, rec->pos,
1005                    _("Bad width %d for variable %s."), rec->width, name);
1006
1007       var = rec->var = dict_create_var (dict, name, rec->width);
1008       if (var == NULL)
1009         sys_error (r, rec->pos, _("Duplicate variable name `%s'."), name);
1010
1011       /* Set the short name the same as the long name. */
1012       var_set_short_name (var, 0, name);
1013
1014       /* Get variable label, if any. */
1015       if (rec->label)
1016         {
1017           char *utf8_label;
1018
1019           utf8_label = recode_string_pool ("UTF-8", dict_encoding,
1020                                            rec->label, -1, r->pool);
1021           var_set_label (var, utf8_label, false);
1022         }
1023
1024       /* Set missing values. */
1025       if (rec->missing_value_code != 0)
1026         {
1027           int width = var_get_width (var);
1028           struct missing_values mv;
1029
1030           mv_init_pool (r->pool, &mv, width);
1031           if (var_is_numeric (var))
1032             {
1033               bool has_range = rec->missing_value_code < 0;
1034               int n_discrete = (has_range
1035                                 ? rec->missing_value_code == -3
1036                                 : rec->missing_value_code);
1037               int ofs = 0;
1038
1039               if (has_range)
1040                 {
1041                   double low = parse_float (r, rec->missing, 0);
1042                   double high = parse_float (r, rec->missing, 8);
1043                   mv_add_range (&mv, low, high);
1044                   ofs += 16;
1045                 }
1046
1047               for (i = 0; i < n_discrete; i++)
1048                 {
1049                   mv_add_num (&mv, parse_float (r, rec->missing, ofs));
1050                   ofs += 8;
1051                 }
1052             }
1053           else
1054             {
1055               union value value;
1056
1057               value_init_pool (r->pool, &value, width);
1058               value_set_missing (&value, width);
1059               for (i = 0; i < rec->missing_value_code; i++)
1060                 {
1061                   uint8_t *s = value_str_rw (&value, width);
1062                   memcpy (s, rec->missing + 8 * i, MIN (width, 8));
1063                   mv_add_str (&mv, s);
1064                 }
1065             }
1066           var_set_missing_values (var, &mv);
1067         }
1068
1069       /* Set formats. */
1070       parse_format_spec (r, rec->pos + 12, rec->print_format,
1071                          PRINT_FORMAT, var, &n_warnings);
1072       parse_format_spec (r, rec->pos + 16, rec->write_format,
1073                          WRITE_FORMAT, var, &n_warnings);
1074
1075       /* Account for values.
1076          Skip long string continuation records, if any. */
1077       n_values = rec->width == 0 ? 1 : DIV_RND_UP (rec->width, 8);
1078       for (i = 1; i < n_values; i++)
1079         if (i + (rec - var_recs) >= n_var_recs || rec[i].width != -1)
1080           sys_error (r, rec->pos, _("Missing string continuation record."));
1081       rec += n_values;
1082     }
1083 }
1084
1085 /* Translates the format spec from sysfile format to internal
1086    format. */
1087 static void
1088 parse_format_spec (struct sfm_reader *r, off_t pos, unsigned int format,
1089                    enum which_format which, struct variable *v,
1090                    int *n_warnings)
1091 {
1092   const int max_warnings = 8;
1093   uint8_t raw_type = format >> 16;
1094   uint8_t w = format >> 8;
1095   uint8_t d = format;
1096   struct fmt_spec f;
1097   bool ok;
1098
1099   f.w = w;
1100   f.d = d;
1101
1102   msg_disable ();
1103   ok = (fmt_from_io (raw_type, &f.type)
1104         && fmt_check_output (&f)
1105         && fmt_check_width_compat (&f, var_get_width (v)));
1106   msg_enable ();
1107
1108   if (ok)
1109     {
1110       if (which == PRINT_FORMAT)
1111         var_set_print_format (v, &f);
1112       else
1113         var_set_write_format (v, &f);
1114     }
1115   else if (format == 0)
1116     {
1117       /* Actually observed in the wild.  No point in warning about it. */
1118     }
1119   else if (++*n_warnings <= max_warnings)
1120     {
1121       if (which == PRINT_FORMAT)
1122         sys_warn (r, pos, _("Variable %s with width %d has invalid print "
1123                             "format 0x%x."),
1124                   var_get_name (v), var_get_width (v), format);
1125       else
1126         sys_warn (r, pos, _("Variable %s with width %d has invalid write "
1127                             "format 0x%x."),
1128                   var_get_name (v), var_get_width (v), format);
1129
1130       if (*n_warnings == max_warnings)
1131         sys_warn (r, -1, _("Suppressing further invalid format warnings."));
1132     }
1133 }
1134
1135 static void
1136 parse_document (struct dictionary *dict, struct sfm_document_record *record)
1137 {
1138   const char *p;
1139
1140   for (p = record->documents;
1141        p < record->documents + DOC_LINE_LENGTH * record->n_lines;
1142        p += DOC_LINE_LENGTH)
1143     {
1144       struct substring line;
1145
1146       line = recode_substring_pool ("UTF-8", dict_get_encoding (dict),
1147                                     ss_buffer (p, DOC_LINE_LENGTH), NULL);
1148       ss_rtrim (&line, ss_cstr (" "));
1149       line.string[line.length] = '\0';
1150
1151       dict_add_document_line (dict, line.string, false);
1152
1153       ss_dealloc (&line);
1154     }
1155 }
1156
1157 /* Parses record type 7, subtype 3. */
1158 static void
1159 parse_machine_integer_info (struct sfm_reader *r,
1160                             const struct sfm_extension_record *record,
1161                             struct sfm_read_info *info)
1162 {
1163   int float_representation, expected_float_format;
1164   int integer_representation, expected_integer_format;
1165
1166   /* Save version info. */
1167   info->version_major = parse_int (r, record->data, 0);
1168   info->version_minor = parse_int (r, record->data, 4);
1169   info->version_revision = parse_int (r, record->data, 8);
1170
1171   /* Check floating point format. */
1172   float_representation = parse_int (r, record->data, 16);
1173   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
1174       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
1175     expected_float_format = 1;
1176   else if (r->float_format == FLOAT_Z_LONG)
1177     expected_float_format = 2;
1178   else if (r->float_format == FLOAT_VAX_G || r->float_format == FLOAT_VAX_D)
1179     expected_float_format = 3;
1180   else
1181     NOT_REACHED ();
1182   if (float_representation != expected_float_format)
1183     sys_error (r, record->pos, _("Floating-point representation indicated by "
1184                  "system file (%d) differs from expected (%d)."),
1185                float_representation, expected_float_format);
1186
1187   /* Check integer format. */
1188   integer_representation = parse_int (r, record->data, 24);
1189   if (r->integer_format == INTEGER_MSB_FIRST)
1190     expected_integer_format = 1;
1191   else if (r->integer_format == INTEGER_LSB_FIRST)
1192     expected_integer_format = 2;
1193   else
1194     NOT_REACHED ();
1195   if (integer_representation != expected_integer_format)
1196     sys_warn (r, record->pos,
1197               _("Integer format indicated by system file (%d) "
1198                 "differs from expected (%d)."),
1199               integer_representation, expected_integer_format);
1200
1201 }
1202
1203 static const char *
1204 choose_encoding (struct sfm_reader *r,
1205                  const struct sfm_header_record *header,
1206                  const struct sfm_extension_record *ext_integer,
1207                  const struct sfm_extension_record *ext_encoding)
1208 {
1209   /* The EXT_ENCODING record is a more reliable way to determine dictionary
1210      encoding. */
1211   if (ext_encoding)
1212     return ext_encoding->data;
1213
1214   /* But EXT_INTEGER is better than nothing as a fallback. */
1215   if (ext_integer)
1216     {
1217       int codepage = parse_int (r, ext_integer->data, 7 * 4);
1218       const char *encoding;
1219
1220       switch (codepage)
1221         {
1222         case 1:
1223           return "EBCDIC-US";
1224
1225         case 2:
1226         case 3:
1227           /* These ostensibly mean "7-bit ASCII" and "8-bit ASCII"[sic]
1228              respectively.  However, there are known to be many files in the wild
1229              with character code 2, yet have data which are clearly not ASCII.
1230              Therefore we ignore these values. */
1231           break;
1232
1233         case 4:
1234           return "MS_KANJI";
1235
1236         default:
1237           encoding = sys_get_encoding_from_codepage (codepage);
1238           if (encoding != NULL)
1239             return encoding;
1240           break;
1241         }
1242     }
1243
1244   /* If the file magic number is EBCDIC then its character data is too. */
1245   if (!strcmp (header->magic, EBCDIC_MAGIC))
1246     return "EBCDIC-US";
1247
1248   return locale_charset ();
1249 }
1250
1251 /* Parses record type 7, subtype 4. */
1252 static void
1253 parse_machine_float_info (struct sfm_reader *r,
1254                           const struct sfm_extension_record *record)
1255 {
1256   double sysmis = parse_float (r, record->data, 0);
1257   double highest = parse_float (r, record->data, 8);
1258   double lowest = parse_float (r, record->data, 16);
1259
1260   if (sysmis != SYSMIS)
1261     sys_warn (r, record->pos,
1262               _("File specifies unexpected value %g (%a) as %s, "
1263                 "instead of %g (%a)."),
1264               sysmis, sysmis, "SYSMIS", SYSMIS, SYSMIS);
1265
1266   if (highest != HIGHEST)
1267     sys_warn (r, record->pos,
1268               _("File specifies unexpected value %g (%a) as %s, "
1269                 "instead of %g (%a)."),
1270               highest, highest, "HIGHEST", HIGHEST, HIGHEST);
1271
1272   if (lowest != LOWEST)
1273     sys_warn (r, record->pos,
1274               _("File specifies unexpected value %g (%a) as %s, "
1275                 "instead of %g (%a)."),
1276               lowest, lowest, "LOWEST", LOWEST, LOWEST);
1277 }
1278
1279 /* Parses record type 7, subtype 7 or 19. */
1280 static void
1281 parse_mrsets (struct sfm_reader *r, const struct sfm_extension_record *record,
1282               struct dictionary *dict)
1283 {
1284   struct text_record *text;
1285   struct mrset *mrset;
1286
1287   text = open_text_record (r, record, false);
1288   for (;;)
1289     {
1290       const char *counted = NULL;
1291       const char *name;
1292       const char *label;
1293       struct stringi_set var_names;
1294       size_t allocated_vars;
1295       char delimiter;
1296       int width;
1297
1298       mrset = xzalloc (sizeof *mrset);
1299
1300       name = text_get_token (text, ss_cstr ("="), NULL);
1301       if (name == NULL)
1302         break;
1303       mrset->name = recode_string ("UTF-8", r->encoding, name, -1);
1304
1305       if (mrset->name[0] != '$')
1306         {
1307           sys_warn (r, record->pos,
1308                     _("`%s' does not begin with `$' at offset %zu "
1309                       "in MRSETS record."), mrset->name, text_pos (text));
1310           break;
1311         }
1312
1313       if (text_match (text, 'C'))
1314         {
1315           mrset->type = MRSET_MC;
1316           if (!text_match (text, ' '))
1317             {
1318               sys_warn (r, record->pos,
1319                         _("Missing space following `%c' at offset %zu "
1320                           "in MRSETS record."), 'C', text_pos (text));
1321               break;
1322             }
1323         }
1324       else if (text_match (text, 'D'))
1325         {
1326           mrset->type = MRSET_MD;
1327           mrset->cat_source = MRSET_VARLABELS;
1328         }
1329       else if (text_match (text, 'E'))
1330         {
1331           char *number;
1332
1333           mrset->type = MRSET_MD;
1334           mrset->cat_source = MRSET_COUNTEDVALUES;
1335           if (!text_match (text, ' '))
1336             {
1337               sys_warn (r, record->pos,
1338                         _("Missing space following `%c' at offset %zu "
1339                           "in MRSETS record."), 'E',  text_pos (text));
1340               break;
1341             }
1342
1343           number = text_get_token (text, ss_cstr (" "), NULL);
1344           if (!strcmp (number, "11"))
1345             mrset->label_from_var_label = true;
1346           else if (strcmp (number, "1"))
1347             sys_warn (r, record->pos,
1348                       _("Unexpected label source value `%s' following `E' "
1349                         "at offset %zu in MRSETS record."),
1350                       number, text_pos (text));
1351         }
1352       else
1353         {
1354           sys_warn (r, record->pos,
1355                     _("Missing `C', `D', or `E' at offset %zu "
1356                       "in MRSETS record."),
1357                     text_pos (text));
1358           break;
1359         }
1360
1361       if (mrset->type == MRSET_MD)
1362         {
1363           counted = text_parse_counted_string (r, text);
1364           if (counted == NULL)
1365             break;
1366         }
1367
1368       label = text_parse_counted_string (r, text);
1369       if (label == NULL)
1370         break;
1371       if (label[0] != '\0')
1372         mrset->label = recode_string ("UTF-8", r->encoding, label, -1);
1373
1374       stringi_set_init (&var_names);
1375       allocated_vars = 0;
1376       width = INT_MAX;
1377       do
1378         {
1379           const char *raw_var_name;
1380           struct variable *var;
1381           char *var_name;
1382
1383           raw_var_name = text_get_token (text, ss_cstr (" \n"), &delimiter);
1384           if (raw_var_name == NULL)
1385             {
1386               sys_warn (r, record->pos,
1387                         _("Missing new-line parsing variable names "
1388                           "at offset %zu in MRSETS record."),
1389                         text_pos (text));
1390               break;
1391             }
1392           var_name = recode_string ("UTF-8", r->encoding, raw_var_name, -1);
1393
1394           var = dict_lookup_var (dict, var_name);
1395           if (var == NULL)
1396             {
1397               free (var_name);
1398               continue;
1399             }
1400           if (!stringi_set_insert (&var_names, var_name))
1401             {
1402               sys_warn (r, record->pos,
1403                         _("Duplicate variable name %s "
1404                           "at offset %zu in MRSETS record."),
1405                         var_name, text_pos (text));
1406               free (var_name);
1407               continue;
1408             }
1409           free (var_name);
1410
1411           if (mrset->label == NULL && mrset->label_from_var_label
1412               && var_has_label (var))
1413             mrset->label = xstrdup (var_get_label (var));
1414
1415           if (mrset->n_vars
1416               && var_get_type (var) != var_get_type (mrset->vars[0]))
1417             {
1418               sys_warn (r, record->pos,
1419                         _("MRSET %s contains both string and "
1420                           "numeric variables."), name);
1421               continue;
1422             }
1423           width = MIN (width, var_get_width (var));
1424
1425           if (mrset->n_vars >= allocated_vars)
1426             mrset->vars = x2nrealloc (mrset->vars, &allocated_vars,
1427                                       sizeof *mrset->vars);
1428           mrset->vars[mrset->n_vars++] = var;
1429         }
1430       while (delimiter != '\n');
1431
1432       if (mrset->n_vars < 2)
1433         {
1434           sys_warn (r, record->pos,
1435                     _("MRSET %s has only %zu variables."), mrset->name,
1436                     mrset->n_vars);
1437           mrset_destroy (mrset);
1438           stringi_set_destroy (&var_names);
1439           continue;
1440         }
1441
1442       if (mrset->type == MRSET_MD)
1443         {
1444           mrset->width = width;
1445           value_init (&mrset->counted, width);
1446           if (width == 0)
1447             mrset->counted.f = c_strtod (counted, NULL);
1448           else
1449             value_copy_str_rpad (&mrset->counted, width,
1450                                  (const uint8_t *) counted, ' ');
1451         }
1452
1453       dict_add_mrset (dict, mrset);
1454       mrset = NULL;
1455       stringi_set_destroy (&var_names);
1456     }
1457   mrset_destroy (mrset);
1458   close_text_record (r, text);
1459 }
1460
1461 /* Read record type 7, subtype 11, which specifies how variables
1462    should be displayed in GUI environments. */
1463 static void
1464 parse_display_parameters (struct sfm_reader *r,
1465                          const struct sfm_extension_record *record,
1466                          struct dictionary *dict)
1467 {
1468   bool includes_width;
1469   bool warned = false;
1470   size_t n_vars;
1471   size_t ofs;
1472   size_t i;
1473
1474   n_vars = dict_get_var_cnt (dict);
1475   if (record->count == 3 * n_vars)
1476     includes_width = true;
1477   else if (record->count == 2 * n_vars)
1478     includes_width = false;
1479   else
1480     {
1481       sys_warn (r, record->pos,
1482                 _("Extension 11 has bad count %zu (for %zu variables)."),
1483                 record->count, n_vars);
1484       return;
1485     }
1486
1487   ofs = 0;
1488   for (i = 0; i < n_vars; ++i)
1489     {
1490       struct variable *v = dict_get_var (dict, i);
1491       int measure, width, align;
1492
1493       measure = parse_int (r, record->data, ofs);
1494       ofs += 4;
1495
1496       if (includes_width)
1497         {
1498           width = parse_int (r, record->data, ofs);
1499           ofs += 4;
1500         }
1501       else
1502         width = 0;
1503
1504       align = parse_int (r, record->data, ofs);
1505       ofs += 4;
1506
1507       /* SPSS 14 sometimes seems to set string variables' measure
1508          to zero. */
1509       if (0 == measure && var_is_alpha (v))
1510         measure = 1;
1511
1512       if (measure < 1 || measure > 3 || align < 0 || align > 2)
1513         {
1514           if (!warned)
1515             sys_warn (r, record->pos,
1516                       _("Invalid variable display parameters for variable "
1517                         "%zu (%s).  Default parameters substituted."),
1518                       i, var_get_name (v));
1519           warned = true;
1520           continue;
1521         }
1522
1523       var_set_measure (v, (measure == 1 ? MEASURE_NOMINAL
1524                            : measure == 2 ? MEASURE_ORDINAL
1525                            : MEASURE_SCALE));
1526       var_set_alignment (v, (align == 0 ? ALIGN_LEFT
1527                              : align == 1 ? ALIGN_RIGHT
1528                              : ALIGN_CENTRE));
1529
1530       /* Older versions (SPSS 9.0) sometimes set the display
1531          width to zero.  This causes confusion in the GUI, so
1532          only set the width if it is nonzero. */
1533       if (width > 0)
1534         var_set_display_width (v, width);
1535     }
1536 }
1537
1538 static void
1539 rename_var_and_save_short_names (struct dictionary *dict, struct variable *var,
1540                                  const char *new_name)
1541 {
1542   size_t n_short_names;
1543   char **short_names;
1544   size_t i;
1545
1546   /* Renaming a variable may clear its short names, but we
1547      want to retain them, so we save them and re-set them
1548      afterward. */
1549   n_short_names = var_get_short_name_cnt (var);
1550   short_names = xnmalloc (n_short_names, sizeof *short_names);
1551   for (i = 0; i < n_short_names; i++)
1552     {
1553       const char *s = var_get_short_name (var, i);
1554       short_names[i] = s != NULL ? xstrdup (s) : NULL;
1555     }
1556
1557   /* Set long name. */
1558   dict_rename_var (dict, var, new_name);
1559
1560   /* Restore short names. */
1561   for (i = 0; i < n_short_names; i++)
1562     {
1563       var_set_short_name (var, i, short_names[i]);
1564       free (short_names[i]);
1565     }
1566   free (short_names);
1567 }
1568
1569 /* Parses record type 7, subtype 13, which gives the long name that corresponds
1570    to each short name.  Modifies variable names in DICT accordingly.  */
1571 static void
1572 parse_long_var_name_map (struct sfm_reader *r,
1573                          const struct sfm_extension_record *record,
1574                          struct dictionary *dict)
1575 {
1576   struct text_record *text;
1577   struct variable *var;
1578   char *long_name;
1579
1580   if (record == NULL)
1581     {
1582       /* There are no long variable names.  Use the short variable names,
1583          converted to lowercase, as the long variable names. */
1584       size_t i;
1585
1586       for (i = 0; i < dict_get_var_cnt (dict); i++)
1587         {
1588           struct variable *var = dict_get_var (dict, i);
1589           char *new_name;
1590
1591           new_name = utf8_to_lower (var_get_name (var));
1592           rename_var_and_save_short_names (dict, var, new_name);
1593           free (new_name);
1594         }
1595
1596       return;
1597     }
1598
1599   /* Rename each of the variables, one by one.  (In a correctly constructed
1600      system file, this cannot create any intermediate duplicate variable names,
1601      because all of the new variable names are longer than any of the old
1602      variable names and thus there cannot be any overlaps.) */
1603   text = open_text_record (r, record, true);
1604   while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
1605     {
1606       /* Validate long name. */
1607       if (!dict_id_is_valid (dict, long_name, false))
1608         {
1609           sys_warn (r, record->pos,
1610                     _("Long variable mapping from %s to invalid "
1611                       "variable name `%s'."),
1612                     var_get_name (var), long_name);
1613           continue;
1614         }
1615
1616       /* Identify any duplicates. */
1617       if (utf8_strcasecmp (var_get_short_name (var, 0), long_name)
1618           && dict_lookup_var (dict, long_name) != NULL)
1619         {
1620           sys_warn (r, record->pos,
1621                     _("Duplicate long variable name `%s'."), long_name);
1622           continue;
1623         }
1624
1625       rename_var_and_save_short_names (dict, var, long_name);
1626     }
1627   close_text_record (r, text);
1628 }
1629
1630 /* Reads record type 7, subtype 14, which gives the real length
1631    of each very long string.  Rearranges DICT accordingly. */
1632 static void
1633 parse_long_string_map (struct sfm_reader *r,
1634                        const struct sfm_extension_record *record,
1635                        struct dictionary *dict)
1636 {
1637   struct text_record *text;
1638   struct variable *var;
1639   char *length_s;
1640
1641   text = open_text_record (r, record, true);
1642   while (read_variable_to_value_pair (r, dict, text, &var, &length_s))
1643     {
1644       size_t idx = var_get_dict_index (var);
1645       long int length;
1646       int segment_cnt;
1647       int i;
1648
1649       /* Get length. */
1650       length = strtol (length_s, NULL, 10);
1651       if (length < 1 || length > MAX_STRING)
1652         {
1653           sys_warn (r, record->pos,
1654                     _("%s listed as string of invalid length %s "
1655                       "in very long string record."),
1656                     var_get_name (var), length_s);
1657           continue;
1658         }
1659
1660       /* Check segments. */
1661       segment_cnt = sfm_width_to_segments (length);
1662       if (segment_cnt == 1)
1663         {
1664           sys_warn (r, record->pos,
1665                     _("%s listed in very long string record with width %s, "
1666                       "which requires only one segment."),
1667                     var_get_name (var), length_s);
1668           continue;
1669         }
1670       if (idx + segment_cnt > dict_get_var_cnt (dict))
1671         sys_error (r, record->pos,
1672                    _("Very long string %s overflows dictionary."),
1673                    var_get_name (var));
1674
1675       /* Get the short names from the segments and check their
1676          lengths. */
1677       for (i = 0; i < segment_cnt; i++)
1678         {
1679           struct variable *seg = dict_get_var (dict, idx + i);
1680           int alloc_width = sfm_segment_alloc_width (length, i);
1681           int width = var_get_width (seg);
1682
1683           if (i > 0)
1684             var_set_short_name (var, i, var_get_short_name (seg, 0));
1685           if (ROUND_UP (width, 8) != ROUND_UP (alloc_width, 8))
1686             sys_error (r, record->pos,
1687                        _("Very long string with width %ld has segment %d "
1688                          "of width %d (expected %d)."),
1689                        length, i, width, alloc_width);
1690         }
1691       dict_delete_consecutive_vars (dict, idx + 1, segment_cnt - 1);
1692       var_set_width (var, length);
1693     }
1694   close_text_record (r, text);
1695   dict_compact_values (dict);
1696 }
1697
1698 static void
1699 parse_value_labels (struct sfm_reader *r, struct dictionary *dict,
1700                     const struct sfm_var_record *var_recs, size_t n_var_recs,
1701                     const struct sfm_value_label_record *record)
1702 {
1703   struct variable **vars;
1704   char **utf8_labels;
1705   size_t i;
1706
1707   utf8_labels = pool_nmalloc (r->pool, sizeof *utf8_labels, record->n_labels);
1708   for (i = 0; i < record->n_labels; i++)
1709     utf8_labels[i] = recode_string_pool ("UTF-8", dict_get_encoding (dict),
1710                                          record->labels[i].label, -1,
1711                                          r->pool);
1712
1713   vars = pool_nmalloc (r->pool, record->n_vars, sizeof *vars);
1714   for (i = 0; i < record->n_vars; i++)
1715     vars[i] = lookup_var_by_index (r, record->pos,
1716                                    var_recs, n_var_recs, record->vars[i]);
1717
1718   for (i = 1; i < record->n_vars; i++)
1719     if (var_get_type (vars[i]) != var_get_type (vars[0]))
1720       sys_error (r, record->pos,
1721                  _("Variables associated with value label are not all of "
1722                    "identical type.  Variable %s is %s, but variable "
1723                    "%s is %s."),
1724                  var_get_name (vars[0]),
1725                  var_is_numeric (vars[0]) ? _("numeric") : _("string"),
1726                  var_get_name (vars[i]),
1727                  var_is_numeric (vars[i]) ? _("numeric") : _("string"));
1728
1729   for (i = 0; i < record->n_vars; i++)
1730     {
1731       struct variable *var = vars[i];
1732       int width;
1733       size_t j;
1734
1735       width = var_get_width (var);
1736       if (width > 8)
1737         sys_error (r, record->pos,
1738                    _("Value labels may not be added to long string "
1739                      "variables (e.g. %s) using records types 3 and 4."),
1740                    var_get_name (var));
1741
1742       for (j = 0; j < record->n_labels; j++)
1743         {
1744           struct sfm_value_label *label = &record->labels[j];
1745           union value value;
1746
1747           value_init (&value, width);
1748           if (width == 0)
1749             value.f = parse_float (r, label->value, 0);
1750           else
1751             memcpy (value_str_rw (&value, width), label->value, width);
1752
1753           if (!var_add_value_label (var, &value, utf8_labels[j]))
1754             {
1755               if (var_is_numeric (var))
1756                 sys_warn (r, record->pos,
1757                           _("Duplicate value label for %g on %s."),
1758                           value.f, var_get_name (var));
1759               else
1760                 sys_warn (r, record->pos,
1761                           _("Duplicate value label for `%.*s' on %s."),
1762                           width, value_str (&value, width),
1763                           var_get_name (var));
1764             }
1765
1766           value_destroy (&value, width);
1767         }
1768     }
1769
1770   pool_free (r->pool, vars);
1771   for (i = 0; i < record->n_labels; i++)
1772     pool_free (r->pool, utf8_labels[i]);
1773   pool_free (r->pool, utf8_labels);
1774 }
1775
1776 static struct variable *
1777 lookup_var_by_index (struct sfm_reader *r, off_t offset,
1778                      const struct sfm_var_record *var_recs, size_t n_var_recs,
1779                      int idx)
1780 {
1781   const struct sfm_var_record *rec;
1782
1783   if (idx < 1 || idx > n_var_recs)
1784     {
1785       sys_error (r, offset,
1786                  _("Variable index %d not in valid range 1...%zu."),
1787                  idx, n_var_recs);
1788       return NULL;
1789     }
1790
1791   rec = &var_recs[idx - 1];
1792   if (rec->var == NULL)
1793     {
1794       sys_error (r, offset,
1795                  _("Variable index %d refers to long string continuation."),
1796                  idx);
1797       return NULL;
1798     }
1799
1800   return rec->var;
1801 }
1802
1803 /* Parses a set of custom attributes from TEXT into ATTRS.
1804    ATTRS may be a null pointer, in which case the attributes are
1805    read but discarded. */
1806 static void
1807 parse_attributes (struct sfm_reader *r, struct text_record *text,
1808                   struct attrset *attrs)
1809 {
1810   do
1811     {
1812       struct attribute *attr;
1813       char *key;
1814       int index;
1815
1816       /* Parse the key. */
1817       key = text_get_token (text, ss_cstr ("("), NULL);
1818       if (key == NULL)
1819         return;
1820
1821       attr = attribute_create (key);
1822       for (index = 1; ; index++)
1823         {
1824           /* Parse the value. */
1825           char *value;
1826           size_t length;
1827
1828           value = text_get_token (text, ss_cstr ("\n"), NULL);
1829           if (value == NULL)
1830             {
1831               text_warn (r, text, _("Error parsing attribute value %s[%d]."),
1832                          key, index);
1833               break;
1834             }              
1835
1836           length = strlen (value);
1837           if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') 
1838             {
1839               value[length - 1] = '\0';
1840               attribute_add_value (attr, value + 1); 
1841             }
1842           else 
1843             {
1844               text_warn (r, text,
1845                          _("Attribute value %s[%d] is not quoted: %s."),
1846                          key, index, value);
1847               attribute_add_value (attr, value); 
1848             }
1849
1850           /* Was this the last value for this attribute? */
1851           if (text_match (text, ')'))
1852             break;
1853         }
1854       if (attrs != NULL)
1855         attrset_add (attrs, attr);
1856       else
1857         attribute_destroy (attr);
1858     }
1859   while (!text_match (text, '/'));
1860 }
1861
1862 /* Reads record type 7, subtype 17, which lists custom
1863    attributes on the data file.  */
1864 static void
1865 parse_data_file_attributes (struct sfm_reader *r,
1866                             const struct sfm_extension_record *record,
1867                             struct dictionary *dict)
1868 {
1869   struct text_record *text = open_text_record (r, record, true);
1870   parse_attributes (r, text, dict_get_attributes (dict));
1871   close_text_record (r, text);
1872 }
1873
1874 /* Parses record type 7, subtype 18, which lists custom
1875    attributes on individual variables.  */
1876 static void
1877 parse_variable_attributes (struct sfm_reader *r,
1878                            const struct sfm_extension_record *record,
1879                            struct dictionary *dict)
1880 {
1881   struct text_record *text;
1882   struct variable *var;
1883
1884   text = open_text_record (r, record, true);
1885   while (text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
1886     parse_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
1887   close_text_record (r, text);
1888 }
1889
1890 static void
1891 check_overflow (struct sfm_reader *r,
1892                 const struct sfm_extension_record *record,
1893                 size_t ofs, size_t length)
1894 {
1895   size_t end = record->size * record->count;
1896   if (length >= end || ofs + length > end)
1897     sys_error (r, record->pos + end,
1898                _("Long string value label record ends unexpectedly."));
1899 }
1900
1901 static void
1902 parse_long_string_value_labels (struct sfm_reader *r,
1903                                 const struct sfm_extension_record *record,
1904                                 struct dictionary *dict)
1905 {
1906   const char *dict_encoding = dict_get_encoding (dict);
1907   size_t end = record->size * record->count;
1908   size_t ofs = 0;
1909
1910   while (ofs < end)
1911     {
1912       char *var_name;
1913       size_t n_labels, i;
1914       struct variable *var;
1915       union value value;
1916       int var_name_len;
1917       int width;
1918
1919       /* Parse variable name length. */
1920       check_overflow (r, record, ofs, 4);
1921       var_name_len = parse_int (r, record->data, ofs);
1922       ofs += 4;
1923
1924       /* Parse variable name, width, and number of labels. */
1925       check_overflow (r, record, ofs, var_name_len + 8);
1926       var_name = recode_string_pool ("UTF-8", dict_encoding,
1927                                      (const char *) record->data + ofs,
1928                                      var_name_len, r->pool);
1929       width = parse_int (r, record->data, ofs + var_name_len);
1930       n_labels = parse_int (r, record->data, ofs + var_name_len + 4);
1931       ofs += var_name_len + 8;
1932
1933       /* Look up 'var' and validate. */
1934       var = dict_lookup_var (dict, var_name);
1935       if (var == NULL)
1936         sys_warn (r, record->pos + ofs,
1937                   _("Ignoring long string value record for "
1938                     "unknown variable %s."), var_name);
1939       else if (var_is_numeric (var))
1940         {
1941           sys_warn (r, record->pos + ofs,
1942                     _("Ignoring long string value record for "
1943                       "numeric variable %s."), var_name);
1944           var = NULL;
1945         }
1946       else if (width != var_get_width (var))
1947         {
1948           sys_warn (r, record->pos + ofs,
1949                     _("Ignoring long string value record for variable %s "
1950                       "because the record's width (%d) does not match the "
1951                       "variable's width (%d)."),
1952                     var_name, width, var_get_width (var));
1953           var = NULL;
1954         }
1955
1956       /* Parse values. */
1957       value_init_pool (r->pool, &value, width);
1958       for (i = 0; i < n_labels; i++)
1959         {
1960           size_t value_length, label_length;
1961           bool skip = var == NULL;
1962
1963           /* Parse value length. */
1964           check_overflow (r, record, ofs, 4);
1965           value_length = parse_int (r, record->data, ofs);
1966           ofs += 4;
1967
1968           /* Parse value. */
1969           check_overflow (r, record, ofs, value_length);
1970           if (!skip)
1971             {
1972               if (value_length == width)
1973                 memcpy (value_str_rw (&value, width),
1974                         (const uint8_t *) record->data + ofs, width);
1975               else
1976                 {
1977                   sys_warn (r, record->pos + ofs,
1978                             _("Ignoring long string value %zu for variable "
1979                               "%s, with width %d, that has bad value "
1980                               "width %zu."),
1981                             i, var_get_name (var), width, value_length);
1982                   skip = true;
1983                 }
1984             }
1985           ofs += value_length;
1986
1987           /* Parse label length. */
1988           check_overflow (r, record, ofs, 4);
1989           label_length = parse_int (r, record->data, ofs);
1990           ofs += 4;
1991
1992           /* Parse label. */
1993           check_overflow (r, record, ofs, label_length);
1994           if (!skip)
1995             {
1996               char *label;
1997
1998               label = recode_string_pool ("UTF-8", dict_encoding,
1999                                           (const char *) record->data + ofs,
2000                                           label_length, r->pool);
2001               if (!var_add_value_label (var, &value, label))
2002                 sys_warn (r, record->pos + ofs,
2003                           _("Duplicate value label for `%.*s' on %s."),
2004                           width, value_str (&value, width),
2005                           var_get_name (var));
2006               pool_free (r->pool, label);
2007             }
2008           ofs += label_length;
2009         }
2010     }
2011 }
2012 \f
2013 /* Case reader. */
2014
2015 static void partial_record (struct sfm_reader *r)
2016      NO_RETURN;
2017
2018 static void read_error (struct casereader *, const struct sfm_reader *);
2019
2020 static bool read_case_number (struct sfm_reader *, double *);
2021 static bool read_case_string (struct sfm_reader *, uint8_t *, size_t);
2022 static int read_opcode (struct sfm_reader *);
2023 static bool read_compressed_number (struct sfm_reader *, double *);
2024 static bool read_compressed_string (struct sfm_reader *, uint8_t *);
2025 static bool read_whole_strings (struct sfm_reader *, uint8_t *, size_t);
2026 static bool skip_whole_strings (struct sfm_reader *, size_t);
2027
2028 /* Reads and returns one case from READER's file.  Returns a null
2029    pointer if not successful. */
2030 static struct ccase *
2031 sys_file_casereader_read (struct casereader *reader, void *r_)
2032 {
2033   struct sfm_reader *r = r_;
2034   struct ccase *volatile c;
2035   int i;
2036
2037   if (r->error)
2038     return NULL;
2039
2040   c = case_create (r->proto);
2041   if (setjmp (r->bail_out))
2042     {
2043       casereader_force_error (reader);
2044       case_unref (c);
2045       return NULL;
2046     }
2047
2048   for (i = 0; i < r->sfm_var_cnt; i++)
2049     {
2050       struct sfm_var *sv = &r->sfm_vars[i];
2051       union value *v = case_data_rw_idx (c, sv->case_index);
2052
2053       if (sv->var_width == 0)
2054         {
2055           if (!read_case_number (r, &v->f))
2056             goto eof;
2057         }
2058       else
2059         {
2060           uint8_t *s = value_str_rw (v, sv->var_width);
2061           if (!read_case_string (r, s + sv->offset, sv->segment_width))
2062             goto eof;
2063           if (!skip_whole_strings (r, ROUND_DOWN (sv->padding, 8)))
2064             partial_record (r);
2065         }
2066     }
2067   return c;
2068
2069 eof:
2070   if (i != 0)
2071     partial_record (r);
2072   if (r->case_cnt != -1)
2073     read_error (reader, r);
2074   case_unref (c);
2075   return NULL;
2076 }
2077
2078 /* Issues an error that R ends in a partial record. */
2079 static void
2080 partial_record (struct sfm_reader *r)
2081 {
2082   sys_error (r, r->pos, _("File ends in partial case."));
2083 }
2084
2085 /* Issues an error that an unspecified error occurred SFM, and
2086    marks R tainted. */
2087 static void
2088 read_error (struct casereader *r, const struct sfm_reader *sfm)
2089 {
2090   msg (ME, _("Error reading case from file %s."), fh_get_name (sfm->fh));
2091   casereader_force_error (r);
2092 }
2093
2094 /* Reads a number from R and stores its value in *D.
2095    If R is compressed, reads a compressed number;
2096    otherwise, reads a number in the regular way.
2097    Returns true if successful, false if end of file is
2098    reached immediately. */
2099 static bool
2100 read_case_number (struct sfm_reader *r, double *d)
2101 {
2102   if (!r->compressed)
2103     {
2104       uint8_t number[8];
2105       if (!try_read_bytes (r, number, sizeof number))
2106         return false;
2107       float_convert (r->float_format, number, FLOAT_NATIVE_DOUBLE, d);
2108       return true;
2109     }
2110   else
2111     return read_compressed_number (r, d);
2112 }
2113
2114 /* Reads LENGTH string bytes from R into S.
2115    Always reads a multiple of 8 bytes; if LENGTH is not a
2116    multiple of 8, then extra bytes are read and discarded without
2117    being written to S.
2118    Reads compressed strings if S is compressed.
2119    Returns true if successful, false if end of file is
2120    reached immediately. */
2121 static bool
2122 read_case_string (struct sfm_reader *r, uint8_t *s, size_t length)
2123 {
2124   size_t whole = ROUND_DOWN (length, 8);
2125   size_t partial = length % 8;
2126
2127   if (whole)
2128     {
2129       if (!read_whole_strings (r, s, whole))
2130         return false;
2131     }
2132
2133   if (partial)
2134     {
2135       uint8_t bounce[8];
2136       if (!read_whole_strings (r, bounce, sizeof bounce))
2137         {
2138           if (whole)
2139             partial_record (r);
2140           return false;
2141         }
2142       memcpy (s + whole, bounce, partial);
2143     }
2144
2145   return true;
2146 }
2147
2148 /* Reads and returns the next compression opcode from R. */
2149 static int
2150 read_opcode (struct sfm_reader *r)
2151 {
2152   assert (r->compressed);
2153   for (;;)
2154     {
2155       int opcode;
2156       if (r->opcode_idx >= sizeof r->opcodes)
2157         {
2158           if (!try_read_bytes (r, r->opcodes, sizeof r->opcodes))
2159             return -1;
2160           r->opcode_idx = 0;
2161         }
2162       opcode = r->opcodes[r->opcode_idx++];
2163
2164       if (opcode != 0)
2165         return opcode;
2166     }
2167 }
2168
2169 /* Reads a compressed number from R and stores its value in D.
2170    Returns true if successful, false if end of file is
2171    reached immediately. */
2172 static bool
2173 read_compressed_number (struct sfm_reader *r, double *d)
2174 {
2175   int opcode = read_opcode (r);
2176   switch (opcode)
2177     {
2178     case -1:
2179     case 252:
2180       return false;
2181
2182     case 253:
2183       *d = read_float (r);
2184       break;
2185
2186     case 254:
2187       float_convert (r->float_format, "        ", FLOAT_NATIVE_DOUBLE, d);
2188       if (!r->corruption_warning)
2189         {
2190           r->corruption_warning = true;
2191           sys_warn (r, r->pos,
2192                     _("Possible compressed data corruption: "
2193                       "compressed spaces appear in numeric field."));
2194         }
2195       break;
2196
2197     case 255:
2198       *d = SYSMIS;
2199       break;
2200
2201     default:
2202       *d = opcode - r->bias;
2203       break;
2204     }
2205
2206   return true;
2207 }
2208
2209 /* Reads a compressed 8-byte string segment from R and stores it
2210    in DST.
2211    Returns true if successful, false if end of file is
2212    reached immediately. */
2213 static bool
2214 read_compressed_string (struct sfm_reader *r, uint8_t *dst)
2215 {
2216   int opcode = read_opcode (r);
2217   switch (opcode)
2218     {
2219     case -1:
2220     case 252:
2221       return false;
2222
2223     case 253:
2224       read_bytes (r, dst, 8);
2225       break;
2226
2227     case 254:
2228       memset (dst, ' ', 8);
2229       break;
2230
2231     default:
2232       {
2233         double value = opcode - r->bias;
2234         float_convert (FLOAT_NATIVE_DOUBLE, &value, r->float_format, dst);
2235         if (value == 0.0)
2236           {
2237             /* This has actually been seen "in the wild".  The submitter of the
2238                file that showed that the contents decoded as spaces, but they
2239                were at the end of the field so it's possible that the null
2240                bytes just acted as null terminators. */
2241           }
2242         else if (!r->corruption_warning)
2243           {
2244             r->corruption_warning = true;
2245             sys_warn (r, r->pos,
2246                       _("Possible compressed data corruption: "
2247                         "string contains compressed integer (opcode %d)."),
2248                       opcode);
2249           }
2250       }
2251       break;
2252     }
2253
2254   return true;
2255 }
2256
2257 /* Reads LENGTH string bytes from R into S.
2258    LENGTH must be a multiple of 8.
2259    Reads compressed strings if S is compressed.
2260    Returns true if successful, false if end of file is
2261    reached immediately. */
2262 static bool
2263 read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length)
2264 {
2265   assert (length % 8 == 0);
2266   if (!r->compressed)
2267     return try_read_bytes (r, s, length);
2268   else
2269     {
2270       size_t ofs;
2271       for (ofs = 0; ofs < length; ofs += 8)
2272         if (!read_compressed_string (r, s + ofs))
2273           {
2274             if (ofs != 0)
2275               partial_record (r);
2276             return false;
2277           }
2278       return true;
2279     }
2280 }
2281
2282 /* Skips LENGTH string bytes from R.
2283    LENGTH must be a multiple of 8.
2284    (LENGTH is also limited to 1024, but that's only because the
2285    current caller never needs more than that many bytes.)
2286    Returns true if successful, false if end of file is
2287    reached immediately. */
2288 static bool
2289 skip_whole_strings (struct sfm_reader *r, size_t length)
2290 {
2291   uint8_t buffer[1024];
2292   assert (length < sizeof buffer);
2293   return read_whole_strings (r, buffer, length);
2294 }
2295 \f
2296 /* Helpers for reading records that contain structured text
2297    strings. */
2298
2299 /* Maximum number of warnings to issue for a single text
2300    record. */
2301 #define MAX_TEXT_WARNINGS 5
2302
2303 /* State. */
2304 struct text_record
2305   {
2306     struct substring buffer;    /* Record contents. */
2307     off_t start;                /* Starting offset in file. */
2308     size_t pos;                 /* Current position in buffer. */
2309     int n_warnings;             /* Number of warnings issued or suppressed. */
2310     bool recoded;               /* Recoded into UTF-8? */
2311   };
2312
2313 static struct text_record *
2314 open_text_record (struct sfm_reader *r,
2315                   const struct sfm_extension_record *record,
2316                   bool recode_to_utf8)
2317 {
2318   struct text_record *text;
2319   struct substring raw;
2320
2321   text = pool_alloc (r->pool, sizeof *text);
2322   raw = ss_buffer (record->data, record->size * record->count);
2323   text->start = record->pos;
2324   text->buffer = (recode_to_utf8
2325                   ? recode_substring_pool ("UTF-8", r->encoding, raw, r->pool)
2326                   : raw);
2327   text->pos = 0;
2328   text->n_warnings = 0;
2329   text->recoded = recode_to_utf8;
2330
2331   return text;
2332 }
2333
2334 /* Closes TEXT, frees its storage, and issues a final warning
2335    about suppressed warnings if necesary. */
2336 static void
2337 close_text_record (struct sfm_reader *r, struct text_record *text)
2338 {
2339   if (text->n_warnings > MAX_TEXT_WARNINGS)
2340     sys_warn (r, -1, _("Suppressed %d additional related warnings."),
2341               text->n_warnings - MAX_TEXT_WARNINGS);
2342   if (text->recoded)
2343     pool_free (r->pool, ss_data (text->buffer));
2344 }
2345
2346 /* Reads a variable=value pair from TEXT.
2347    Looks up the variable in DICT and stores it into *VAR.
2348    Stores a null-terminated value into *VALUE. */
2349 static bool
2350 read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict,
2351                              struct text_record *text,
2352                              struct variable **var, char **value)
2353 {
2354   for (;;)
2355     {
2356       if (!text_read_short_name (r, dict, text, ss_cstr ("="), var))
2357         return false;
2358       
2359       *value = text_get_token (text, ss_buffer ("\t\0", 2), NULL);
2360       if (*value == NULL)
2361         return false;
2362
2363       text->pos += ss_span (ss_substr (text->buffer, text->pos, SIZE_MAX),
2364                             ss_buffer ("\t\0", 2));
2365
2366       if (*var != NULL)
2367         return true;
2368     }
2369 }
2370
2371 static bool
2372 text_read_variable_name (struct sfm_reader *r, struct dictionary *dict,
2373                          struct text_record *text, struct substring delimiters,
2374                          struct variable **var)
2375 {
2376   char *name;
2377
2378   name = text_get_token (text, delimiters, NULL);
2379   if (name == NULL)
2380     return false;
2381
2382   *var = dict_lookup_var (dict, name);
2383   if (*var != NULL)
2384     return true;
2385
2386   text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
2387              name);
2388   return false;
2389 }
2390
2391
2392 static bool
2393 text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
2394                       struct text_record *text, struct substring delimiters,
2395                       struct variable **var)
2396 {
2397   char *short_name = text_get_token (text, delimiters, NULL);
2398   if (short_name == NULL)
2399     return false;
2400
2401   *var = dict_lookup_var (dict, short_name);
2402   if (*var == NULL)
2403     text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
2404                short_name);
2405   return true;
2406 }
2407
2408 /* Displays a warning for the current file position, limiting the
2409    number to MAX_TEXT_WARNINGS for TEXT. */
2410 static void
2411 text_warn (struct sfm_reader *r, struct text_record *text,
2412            const char *format, ...)
2413 {
2414   if (text->n_warnings++ < MAX_TEXT_WARNINGS) 
2415     {
2416       va_list args;
2417
2418       va_start (args, format);
2419       sys_msg (r, text->start + text->pos, MW, format, args);
2420       va_end (args);
2421     }
2422 }
2423
2424 static char *
2425 text_get_token (struct text_record *text, struct substring delimiters,
2426                 char *delimiter)
2427 {
2428   struct substring token;
2429   char *end;
2430
2431   if (!ss_tokenize (text->buffer, delimiters, &text->pos, &token))
2432     return NULL;
2433
2434   end = &ss_data (token)[ss_length (token)];
2435   if (delimiter != NULL)
2436     *delimiter = *end;
2437   *end = '\0';
2438   return ss_data (token);
2439 }
2440
2441 /* Reads a integer value expressed in decimal, then a space, then a string that
2442    consists of exactly as many bytes as specified by the integer, then a space,
2443    from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
2444    buffer (so the caller should not free the string). */
2445 static const char *
2446 text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
2447 {
2448   size_t start;
2449   size_t n;
2450   char *s;
2451
2452   start = text->pos;
2453   n = 0;
2454   while (text->pos < text->buffer.length)
2455     {
2456       int c = text->buffer.string[text->pos];
2457       if (c < '0' || c > '9')
2458         break;
2459       n = (n * 10) + (c - '0');
2460       text->pos++;
2461     }
2462   if (text->pos >= text->buffer.length || start == text->pos)
2463     {
2464       sys_warn (r, text->start,
2465                 _("Expecting digit at offset %zu in MRSETS record."),
2466                 text->pos);
2467       return NULL;
2468     }
2469
2470   if (!text_match (text, ' '))
2471     {
2472       sys_warn (r, text->start,
2473                 _("Expecting space at offset %zu in MRSETS record."),
2474                 text->pos);
2475       return NULL;
2476     }
2477
2478   if (text->pos + n > text->buffer.length)
2479     {
2480       sys_warn (r, text->start,
2481                 _("%zu-byte string starting at offset %zu "
2482                   "exceeds record length %zu."),
2483                 n, text->pos, text->buffer.length);
2484       return NULL;
2485     }
2486
2487   s = &text->buffer.string[text->pos];
2488   if (s[n] != ' ')
2489     {
2490       sys_warn (r, text->start,
2491                 _("Expecting space at offset %zu following %zu-byte string."),
2492                 text->pos + n, n);
2493       return NULL;
2494     }
2495   s[n] = '\0';
2496   text->pos += n + 1;
2497   return s;
2498 }
2499
2500 static bool
2501 text_match (struct text_record *text, char c)
2502 {
2503   if (text->buffer.string[text->pos] == c) 
2504     {
2505       text->pos++;
2506       return true;
2507     }
2508   else
2509     return false;
2510 }
2511
2512 /* Returns the current byte offset (as converted to UTF-8, if it was converted)
2513    inside the TEXT's string. */
2514 static size_t
2515 text_pos (const struct text_record *text)
2516 {
2517   return text->pos;
2518 }
2519 \f
2520 /* Messages. */
2521
2522 /* Displays a corruption message. */
2523 static void
2524 sys_msg (struct sfm_reader *r, off_t offset,
2525          int class, const char *format, va_list args)
2526 {
2527   struct msg m;
2528   struct string text;
2529
2530   ds_init_empty (&text);
2531   if (offset >= 0)
2532     ds_put_format (&text, _("`%s' near offset 0x%llx: "),
2533                    fh_get_file_name (r->fh), (long long int) offset);
2534   else
2535     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
2536   ds_put_vformat (&text, format, args);
2537
2538   m.category = msg_class_to_category (class);
2539   m.severity = msg_class_to_severity (class);
2540   m.file_name = NULL;
2541   m.first_line = 0;
2542   m.last_line = 0;
2543   m.first_column = 0;
2544   m.last_column = 0;
2545   m.text = ds_cstr (&text);
2546
2547   msg_emit (&m);
2548 }
2549
2550 /* Displays a warning for offset OFFSET in the file. */
2551 static void
2552 sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...)
2553 {
2554   va_list args;
2555
2556   va_start (args, format);
2557   sys_msg (r, offset, MW, format, args);
2558   va_end (args);
2559 }
2560
2561 /* Displays an error for the current file position,
2562    marks it as in an error state,
2563    and aborts reading it using longjmp. */
2564 static void
2565 sys_error (struct sfm_reader *r, off_t offset, const char *format, ...)
2566 {
2567   va_list args;
2568
2569   va_start (args, format);
2570   sys_msg (r, offset, ME, format, args);
2571   va_end (args);
2572
2573   r->error = true;
2574   longjmp (r->bail_out, 1);
2575 }
2576 \f
2577 /* Reads BYTE_CNT bytes into BUF.
2578    Returns true if exactly BYTE_CNT bytes are successfully read.
2579    Aborts if an I/O error or a partial read occurs.
2580    If EOF_IS_OK, then an immediate end-of-file causes false to be
2581    returned; otherwise, immediate end-of-file causes an abort
2582    too. */
2583 static inline bool
2584 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
2585                    void *buf, size_t byte_cnt)
2586 {
2587   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
2588   r->pos += bytes_read;
2589   if (bytes_read == byte_cnt)
2590     return true;
2591   else if (ferror (r->file))
2592     sys_error (r, r->pos, _("System error: %s."), strerror (errno));
2593   else if (!eof_is_ok || bytes_read != 0)
2594     sys_error (r, r->pos, _("Unexpected end of file."));
2595   else
2596     return false;
2597 }
2598
2599 /* Reads BYTE_CNT into BUF.
2600    Aborts upon I/O error or if end-of-file is encountered. */
2601 static void
2602 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
2603 {
2604   read_bytes_internal (r, false, buf, byte_cnt);
2605 }
2606
2607 /* Reads BYTE_CNT bytes into BUF.
2608    Returns true if exactly BYTE_CNT bytes are successfully read.
2609    Returns false if an immediate end-of-file is encountered.
2610    Aborts if an I/O error or a partial read occurs. */
2611 static bool
2612 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
2613 {
2614   return read_bytes_internal (r, true, buf, byte_cnt);
2615 }
2616
2617 /* Reads a 32-bit signed integer from R and returns its value in
2618    host format. */
2619 static int
2620 read_int (struct sfm_reader *r)
2621 {
2622   uint8_t integer[4];
2623   read_bytes (r, integer, sizeof integer);
2624   return integer_get (r->integer_format, integer, sizeof integer);
2625 }
2626
2627 /* Reads a 64-bit floating-point number from R and returns its
2628    value in host format. */
2629 static double
2630 read_float (struct sfm_reader *r)
2631 {
2632   uint8_t number[8];
2633   read_bytes (r, number, sizeof number);
2634   return float_get_double (r->float_format, number);
2635 }
2636
2637 static int
2638 parse_int (struct sfm_reader *r, const void *data, size_t ofs)
2639 {
2640   return integer_get (r->integer_format, (const uint8_t *) data + ofs, 4);
2641 }
2642
2643 static double
2644 parse_float (struct sfm_reader *r, const void *data, size_t ofs)
2645 {
2646   return float_get_double (r->float_format, (const uint8_t *) data + ofs);
2647 }
2648
2649 /* Reads exactly SIZE - 1 bytes into BUFFER
2650    and stores a null byte into BUFFER[SIZE - 1]. */
2651 static void
2652 read_string (struct sfm_reader *r, char *buffer, size_t size)
2653 {
2654   assert (size > 0);
2655   read_bytes (r, buffer, size - 1);
2656   buffer[size - 1] = '\0';
2657 }
2658
2659 /* Skips BYTES bytes forward in R. */
2660 static void
2661 skip_bytes (struct sfm_reader *r, size_t bytes)
2662 {
2663   while (bytes > 0)
2664     {
2665       char buffer[1024];
2666       size_t chunk = MIN (sizeof buffer, bytes);
2667       read_bytes (r, buffer, chunk);
2668       bytes -= chunk;
2669     }
2670 }
2671 \f
2672 static const struct casereader_class sys_file_casereader_class =
2673   {
2674     sys_file_casereader_read,
2675     sys_file_casereader_destroy,
2676     NULL,
2677     NULL,
2678   };