d1676564d8aa965f831465418a10ad22cfd13400
[pspp] / src / data / sys-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-2000, 2006-2007, 2009-2016 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-private.h"
20
21 #include <errno.h>
22 #include <float.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 #include <zlib.h>
27
28 #include "data/any-reader.h"
29 #include "data/attributes.h"
30 #include "data/case.h"
31 #include "data/casereader-provider.h"
32 #include "data/casereader.h"
33 #include "data/dictionary.h"
34 #include "data/file-handle-def.h"
35 #include "data/file-name.h"
36 #include "data/format.h"
37 #include "data/identifier.h"
38 #include "data/missing-values.h"
39 #include "data/mrset.h"
40 #include "data/short-names.h"
41 #include "data/value-labels.h"
42 #include "data/value.h"
43 #include "data/variable.h"
44 #include "libpspp/array.h"
45 #include "libpspp/assertion.h"
46 #include "libpspp/compiler.h"
47 #include "libpspp/i18n.h"
48 #include "libpspp/ll.h"
49 #include "libpspp/message.h"
50 #include "libpspp/misc.h"
51 #include "libpspp/pool.h"
52 #include "libpspp/str.h"
53 #include "libpspp/stringi-set.h"
54
55 #include "gl/c-strtod.h"
56 #include "gl/c-ctype.h"
57 #include "gl/inttostr.h"
58 #include "gl/localcharset.h"
59 #include "gl/minmax.h"
60 #include "gl/unlocked-io.h"
61 #include "gl/xalloc.h"
62 #include "gl/xalloc-oversized.h"
63 #include "gl/xsize.h"
64
65 #include "gettext.h"
66 #define _(msgid) gettext (msgid)
67 #define N_(msgid) (msgid)
68
69 enum
70   {
71     /* subtypes 0-2 unknown */
72     EXT_INTEGER       = 3,      /* Machine integer info. */
73     EXT_FLOAT         = 4,      /* Machine floating-point info. */
74     EXT_VAR_SETS      = 5,      /* Variable sets. */
75     EXT_DATE          = 6,      /* DATE. */
76     EXT_MRSETS        = 7,      /* Multiple response sets. */
77     EXT_DATA_ENTRY    = 8,      /* SPSS Data Entry. */
78     /* subtype 9 unknown */
79     EXT_PRODUCT_INFO  = 10,     /* Extra product info text. */
80     EXT_DISPLAY       = 11,     /* Variable display parameters. */
81     /* subtype 12 unknown */
82     EXT_LONG_NAMES    = 13,     /* Long variable names. */
83     EXT_LONG_STRINGS  = 14,     /* Long strings. */
84     /* subtype 15 unknown */
85     EXT_NCASES        = 16,     /* Extended number of cases. */
86     EXT_FILE_ATTRS    = 17,     /* Data file attributes. */
87     EXT_VAR_ATTRS     = 18,     /* Variable attributes. */
88     EXT_MRSETS2       = 19,     /* Multiple response sets (extended). */
89     EXT_ENCODING      = 20,     /* Character encoding. */
90     EXT_LONG_LABELS   = 21,     /* Value labels for long strings. */
91     EXT_LONG_MISSING  = 22,     /* Missing values for long strings. */
92     EXT_DATAVIEW      = 24      /* "Format properties in dataview table". */
93   };
94
95 /* Fields from the top-level header record. */
96 struct sfm_header_record
97   {
98     char magic[5];              /* First 4 bytes of file, then null. */
99     int weight_idx;             /* 0 if unweighted, otherwise a var index. */
100     int nominal_case_size;      /* Number of var positions. */
101
102     /* These correspond to the members of struct any_file_info or a dictionary
103        but in the system file's encoding rather than ASCII. */
104     char creation_date[10];     /* "dd mmm yy". */
105     char creation_time[9];      /* "hh:mm:ss". */
106     char eye_catcher[61];       /* Eye-catcher string, then product name. */
107     char file_label[65];        /* File label. */
108   };
109
110 struct sfm_var_record
111   {
112     off_t pos;
113     int width;
114     char name[9];
115     int print_format;
116     int write_format;
117     int missing_value_code;
118     uint8_t missing[24];
119     char *label;
120     struct variable *var;
121   };
122
123 struct sfm_value_label
124   {
125     uint8_t value[8];
126     char *label;
127   };
128
129 struct sfm_value_label_record
130   {
131     off_t pos;
132     struct sfm_value_label *labels;
133     unsigned int n_labels;
134
135     int *vars;
136     unsigned int n_vars;
137   };
138
139 struct sfm_document_record
140   {
141     off_t pos;
142     char *documents;
143     size_t n_lines;
144   };
145
146 struct sfm_mrset
147   {
148     const char *name;           /* Name. */
149     const char *label;          /* Human-readable label for group. */
150     enum mrset_type type;       /* Group type. */
151     const char **vars;          /* Constituent variables' names. */
152     size_t n_vars;              /* Number of constituent variables. */
153
154     /* MRSET_MD only. */
155     enum mrset_md_cat_source cat_source; /* Source of category labels. */
156     bool label_from_var_label;  /* 'label' taken from variable label? */
157     const char *counted;        /* Counted value, as string. */
158   };
159
160 struct sfm_extension_record
161   {
162     struct ll ll;               /* In struct sfm_reader 'var_attrs' list. */
163     int subtype;                /* Record subtype. */
164     off_t pos;                  /* Starting offset in file. */
165     unsigned int size;          /* Size of data elements. */
166     unsigned int count;         /* Number of data elements. */
167     void *data;                 /* Contents. */
168   };
169
170 /* System file reader. */
171 struct sfm_reader
172   {
173     struct any_reader any_reader;
174
175     /* Resource tracking. */
176     struct pool *pool;          /* All system file state. */
177
178     /* File data. */
179     struct any_read_info info;
180     struct sfm_header_record header;
181     struct sfm_var_record *vars;
182     size_t n_vars;
183     struct sfm_value_label_record *labels;
184     size_t n_labels;
185     struct sfm_document_record *document;
186     struct sfm_mrset *mrsets;
187     size_t n_mrsets;
188     struct sfm_extension_record *extensions[32];
189     struct ll_list var_attrs;   /* Contains "struct sfm_extension_record"s. */
190
191     /* File state. */
192     struct file_handle *fh;     /* File handle. */
193     struct fh_lock *lock;       /* Mutual exclusion for file handle. */
194     FILE *file;                 /* File stream. */
195     off_t pos;                  /* Position in file. */
196     bool error;                 /* I/O or corruption error? */
197     struct caseproto *proto;    /* Format of output cases. */
198
199     /* File format. */
200     enum integer_format integer_format; /* On-disk integer format. */
201     enum float_format float_format; /* On-disk floating point format. */
202     struct sfm_var *sfm_vars;   /* Variables. */
203     size_t sfm_var_cnt;         /* Number of variables. */
204     int case_cnt;               /* Number of cases */
205     const char *encoding;       /* String encoding. */
206
207     /* Decompression. */
208     enum any_compression compression;
209     double bias;                /* Compression bias, usually 100.0. */
210     uint8_t opcodes[8];         /* Current block of opcodes. */
211     size_t opcode_idx;          /* Next opcode to interpret, 8 if none left. */
212     bool corruption_warning;    /* Warned about possible corruption? */
213
214     /* ZLIB decompression. */
215     long long int ztrailer_ofs; /* Offset of ZLIB trailer at end of file. */
216 #define ZIN_BUF_SIZE  4096
217     uint8_t *zin_buf;           /* Inflation input buffer. */
218 #define ZOUT_BUF_SIZE 16384
219     uint8_t *zout_buf;          /* Inflation output buffer. */
220     unsigned int zout_end;      /* Number of bytes of data in zout_buf. */
221     unsigned int zout_pos;      /* First unconsumed byte in zout_buf. */
222     z_stream zstream;           /* ZLIB inflater. */
223   };
224
225 static const struct casereader_class sys_file_casereader_class;
226
227 static struct sfm_reader *
228 sfm_reader_cast (const struct any_reader *r_)
229 {
230   assert (r_->klass == &sys_file_reader_class);
231   return UP_CAST (r_, struct sfm_reader, any_reader);
232 }
233
234 static bool sfm_close (struct any_reader *);
235
236 static struct variable *lookup_var_by_index (struct sfm_reader *, off_t,
237                                              const struct sfm_var_record *,
238                                              size_t n, int idx);
239
240 static void sys_msg (struct sfm_reader *r, off_t, int class,
241                      const char *format, va_list args)
242      PRINTF_FORMAT (4, 0);
243 static void sys_warn (struct sfm_reader *, off_t, const char *, ...)
244      PRINTF_FORMAT (3, 4);
245 static void sys_error (struct sfm_reader *, off_t, const char *, ...)
246      PRINTF_FORMAT (3, 4);
247
248 static bool read_bytes (struct sfm_reader *, void *, size_t)
249   WARN_UNUSED_RESULT;
250 static int try_read_bytes (struct sfm_reader *, void *, size_t)
251   WARN_UNUSED_RESULT;
252 static bool read_int (struct sfm_reader *, int *) WARN_UNUSED_RESULT;
253 static bool read_uint (struct sfm_reader *, unsigned int *) WARN_UNUSED_RESULT;
254 static bool read_int64 (struct sfm_reader *, long long int *)
255   WARN_UNUSED_RESULT;
256 static bool read_uint64 (struct sfm_reader *, unsigned long long int *)
257   WARN_UNUSED_RESULT;
258 static bool read_string (struct sfm_reader *, char *, size_t)
259   WARN_UNUSED_RESULT;
260 static bool skip_bytes (struct sfm_reader *, size_t) WARN_UNUSED_RESULT;
261
262 /* ZLIB compressed data handling. */
263 static bool read_zheader (struct sfm_reader *) WARN_UNUSED_RESULT;
264 static bool open_zstream (struct sfm_reader *) WARN_UNUSED_RESULT;
265 static bool close_zstream (struct sfm_reader *) WARN_UNUSED_RESULT;
266 static int read_bytes_zlib (struct sfm_reader *, void *, size_t)
267   WARN_UNUSED_RESULT;
268 static int read_compressed_bytes (struct sfm_reader *, void *, size_t)
269   WARN_UNUSED_RESULT;
270 static int try_read_compressed_bytes (struct sfm_reader *, void *, size_t)
271   WARN_UNUSED_RESULT;
272 static bool read_compressed_float (struct sfm_reader *, double *)
273   WARN_UNUSED_RESULT;
274
275 static char *fix_line_ends (const char *);
276
277 static int parse_int (const struct sfm_reader *, const void *data, size_t ofs);
278 static double parse_float (const struct sfm_reader *,
279                            const void *data, size_t ofs);
280
281 static bool read_variable_record (struct sfm_reader *,
282                                   struct sfm_var_record *);
283 static bool read_value_label_record (struct sfm_reader *,
284                                      struct sfm_value_label_record *);
285 static struct sfm_document_record *read_document_record (struct sfm_reader *);
286 static bool read_extension_record (struct sfm_reader *, int subtype,
287                                    struct sfm_extension_record **);
288 static bool skip_extension_record (struct sfm_reader *, int subtype);
289
290 static struct text_record *open_text_record (
291   struct sfm_reader *, const struct sfm_extension_record *,
292   bool recode_to_utf8);
293 static void close_text_record (struct sfm_reader *,
294                                struct text_record *);
295 static bool read_variable_to_value_pair (struct sfm_reader *,
296                                          struct dictionary *,
297                                          struct text_record *,
298                                          struct variable **var, char **value);
299 static void text_warn (struct sfm_reader *r, struct text_record *text,
300                        const char *format, ...)  PRINTF_FORMAT (3, 4);
301 static char *text_get_token (struct text_record *,
302                              struct substring delimiters, char *delimiter);
303 static bool text_match (struct text_record *, char c);
304 static bool text_read_variable_name (struct sfm_reader *, struct dictionary *,
305                                      struct text_record *,
306                                      struct substring delimiters,
307                                      struct variable **);
308 static bool text_read_short_name (struct sfm_reader *, struct dictionary *,
309                                   struct text_record *,
310                                   struct substring delimiters,
311                                   struct variable **);
312 static const char *text_parse_counted_string (struct sfm_reader *,
313                                               struct text_record *);
314 static size_t text_pos (const struct text_record *);
315 static const char *text_get_all (const struct text_record *);
316 \f
317 /* Dictionary reader. */
318
319 enum which_format
320   {
321     PRINT_FORMAT,
322     WRITE_FORMAT
323   };
324
325 static bool read_dictionary (struct sfm_reader *);
326 static bool read_record (struct sfm_reader *, int type,
327                          size_t *allocated_vars, size_t *allocated_labels);
328 static bool read_header (struct sfm_reader *, struct any_read_info *,
329                          struct sfm_header_record *);
330 static void parse_header (struct sfm_reader *,
331                           const struct sfm_header_record *,
332                           struct any_read_info *, struct dictionary *);
333 static bool parse_variable_records (struct sfm_reader *, struct dictionary *,
334                                     struct sfm_var_record *, size_t n);
335 static void parse_format_spec (struct sfm_reader *, off_t pos,
336                                unsigned int format, enum which_format,
337                                struct variable *, int *format_warning_cnt);
338 static void parse_document (struct dictionary *, struct sfm_document_record *);
339 static void parse_display_parameters (struct sfm_reader *,
340                                       const struct sfm_extension_record *,
341                                       struct dictionary *);
342 static bool parse_machine_integer_info (struct sfm_reader *,
343                                         const struct sfm_extension_record *,
344                                         struct any_read_info *);
345 static void parse_machine_float_info (struct sfm_reader *,
346                                       const struct sfm_extension_record *);
347 static void parse_extra_product_info (struct sfm_reader *,
348                                       const struct sfm_extension_record *,
349                                       struct any_read_info *);
350 static void parse_mrsets (struct sfm_reader *,
351                           const struct sfm_extension_record *,
352                           size_t *allocated_mrsets);
353 static void decode_mrsets (struct sfm_reader *, struct dictionary *);
354 static void parse_long_var_name_map (struct sfm_reader *,
355                                      const struct sfm_extension_record *,
356                                      struct dictionary *);
357 static bool parse_long_string_map (struct sfm_reader *,
358                                    const struct sfm_extension_record *,
359                                    struct dictionary *);
360 static bool parse_value_labels (struct sfm_reader *, struct dictionary *,
361                                 const struct sfm_var_record *,
362                                 size_t n_var_recs,
363                                 const struct sfm_value_label_record *);
364 static void parse_data_file_attributes (struct sfm_reader *,
365                                         const struct sfm_extension_record *,
366                                         struct dictionary *);
367 static void parse_variable_attributes (struct sfm_reader *,
368                                        const struct sfm_extension_record *,
369                                        struct dictionary *);
370 static void assign_variable_roles (struct sfm_reader *, struct dictionary *);
371 static void parse_long_string_value_labels (struct sfm_reader *,
372                                             const struct sfm_extension_record *,
373                                             struct dictionary *);
374 static void parse_long_string_missing_values (
375   struct sfm_reader *, const struct sfm_extension_record *,
376   struct dictionary *);
377
378 /* Frees the strings inside INFO. */
379 void
380 any_read_info_destroy (struct any_read_info *info)
381 {
382   if (info)
383     {
384       free (info->creation_date);
385       free (info->creation_time);
386       free (info->product);
387       free (info->product_ext);
388     }
389 }
390
391 /* Tries to open FH for reading as a system file.  Returns an sfm_reader if
392    successful, otherwise NULL. */
393 static struct any_reader *
394 sfm_open (struct file_handle *fh)
395 {
396   size_t allocated_mrsets = 0;
397   struct sfm_reader *r;
398
399   /* Create and initialize reader. */
400   r = xzalloc (sizeof *r);
401   r->any_reader.klass = &sys_file_reader_class;
402   r->pool = pool_create ();
403   pool_register (r->pool, free, r);
404   r->fh = fh_ref (fh);
405   r->opcode_idx = sizeof r->opcodes;
406   ll_init (&r->var_attrs);
407
408   /* TRANSLATORS: this fragment will be interpolated into
409      messages in fh_lock() that identify types of files. */
410   r->lock = fh_lock (fh, FH_REF_FILE, N_("system file"), FH_ACC_READ, false);
411   if (r->lock == NULL)
412     goto error;
413
414   r->file = fn_open (fh, "rb");
415   if (r->file == NULL)
416     {
417       msg (ME, _("Error opening `%s' for reading as a system file: %s."),
418            fh_get_file_name (r->fh), strerror (errno));
419       goto error;
420     }
421
422   if (!read_dictionary (r))
423     goto error;
424
425   if (r->extensions[EXT_MRSETS] != NULL)
426     parse_mrsets (r, r->extensions[EXT_MRSETS], &allocated_mrsets);
427
428   if (r->extensions[EXT_MRSETS2] != NULL)
429     parse_mrsets (r, r->extensions[EXT_MRSETS2], &allocated_mrsets);
430
431   return &r->any_reader;
432
433 error:
434   if (r)
435     sfm_close (&r->any_reader);
436   return NULL;
437 }
438
439 static bool
440 read_dictionary (struct sfm_reader *r)
441 {
442   size_t allocated_vars;
443   size_t allocated_labels;
444
445   if (!read_header (r, &r->info, &r->header))
446     return false;
447
448   allocated_vars = 0;
449   allocated_labels = 0;
450   for (;;)
451     {
452       int type;
453
454       if (!read_int (r, &type))
455         return false;
456       if (type == 999)
457         break;
458       if (!read_record (r, type, &allocated_vars, &allocated_labels))
459         return false;
460     }
461
462   if (!skip_bytes (r, 4))
463     return false;
464
465   if (r->compression == ANY_COMP_ZLIB && !read_zheader (r))
466     return false;
467
468   return true;
469 }
470
471 static bool
472 read_record (struct sfm_reader *r, int type,
473              size_t *allocated_vars, size_t *allocated_labels)
474 {
475   int subtype;
476
477   switch (type)
478     {
479     case 2:
480       if (r->n_vars >= *allocated_vars)
481         r->vars = pool_2nrealloc (r->pool, r->vars, allocated_vars,
482                                   sizeof *r->vars);
483       return read_variable_record (r, &r->vars[r->n_vars++]);
484
485     case 3:
486       if (r->n_labels >= *allocated_labels)
487         r->labels = pool_2nrealloc (r->pool, r->labels, allocated_labels,
488                                     sizeof *r->labels);
489       return read_value_label_record (r, &r->labels[r->n_labels++]);
490
491     case 4:
492       /* A Type 4 record is always immediately after a type 3 record,
493          so the code for type 3 records reads the type 4 record too. */
494       sys_error (r, r->pos, _("Misplaced type 4 record."));
495       return false;
496
497     case 6:
498       if (r->document != NULL)
499         {
500           sys_error (r, r->pos, _("Duplicate type 6 (document) record."));
501           return false;
502         }
503       r->document = read_document_record (r);
504       return r->document != NULL;
505
506     case 7:
507       if (!read_int (r, &subtype))
508         return false;
509       else if (subtype < 0
510                || subtype >= sizeof r->extensions / sizeof *r->extensions)
511         {
512           sys_warn (r, r->pos,
513                     _("Unrecognized record type 7, subtype %d.  For help, "
514                       "please send this file to %s and mention that you were "
515                       "using %s."),
516                     subtype, PACKAGE_BUGREPORT, PACKAGE_STRING);
517           return skip_extension_record (r, subtype);
518         }
519       else if (subtype == 18)
520         {
521           /* System files written by "Stata 14.1/-savespss- 1.77 by S.Radyakin"
522              put each variable attribute into a separate record with subtype
523              18.  I'm surprised that SPSS puts up with this. */
524           struct sfm_extension_record *ext;
525           bool ok = read_extension_record (r, subtype, &ext);
526           if (ok && ext)
527             ll_push_tail (&r->var_attrs, &ext->ll);
528           return ok;
529         }
530       else if (r->extensions[subtype] != NULL)
531         {
532           sys_warn (r, r->pos,
533                     _("Record type 7, subtype %d found here has the same "
534                       "type as the record found near offset 0x%llx.  For "
535                       "help, please send this file to %s and mention that "
536                       "you were using %s."),
537                     subtype, (long long int) r->extensions[subtype]->pos,
538                     PACKAGE_BUGREPORT, PACKAGE_STRING);
539           return skip_extension_record (r, subtype);
540         }
541       else
542         return read_extension_record (r, subtype, &r->extensions[subtype]);
543
544     default:
545       sys_error (r, r->pos, _("Unrecognized record type %d."), type);
546       return false;
547     }
548
549   NOT_REACHED ();
550 }
551
552 /* Returns the character encoding obtained from R, or a null pointer if R
553    doesn't have an indication of its character encoding.  */
554 static const char *
555 sfm_get_encoding (const struct sfm_reader *r)
556 {
557   /* The EXT_ENCODING record is the best way to determine dictionary
558      encoding. */
559   if (r->extensions[EXT_ENCODING])
560     return r->extensions[EXT_ENCODING]->data;
561
562   /* But EXT_INTEGER is better than nothing as a fallback. */
563   if (r->extensions[EXT_INTEGER])
564     {
565       int codepage = parse_int (r, r->extensions[EXT_INTEGER]->data, 7 * 4);
566       const char *encoding;
567
568       switch (codepage)
569         {
570         case 1:
571           return "EBCDIC-US";
572
573         case 2:
574         case 3:
575           /* These ostensibly mean "7-bit ASCII" and "8-bit ASCII"[sic]
576              respectively.  However, many files have character code 2 but data
577              which are clearly not ASCII.  Therefore, ignore these values. */
578           break;
579
580         case 4:
581           return "MS_KANJI";
582
583         default:
584           encoding = sys_get_encoding_from_codepage (codepage);
585           if (encoding != NULL)
586             return encoding;
587           break;
588         }
589     }
590
591   /* If the file magic number is EBCDIC then its character data is too. */
592   if (!strcmp (r->header.magic, EBCDIC_MAGIC))
593     return "EBCDIC-US";
594
595   return NULL;
596 }
597
598 struct get_strings_aux
599   {
600     struct pool *pool;
601     char **titles;
602     char **strings;
603     bool *ids;
604     size_t allocated;
605     size_t n;
606   };
607
608 static void
609 add_string__ (struct get_strings_aux *aux,
610               const char *string, bool id, char *title)
611 {
612   if (aux->n >= aux->allocated)
613     {
614       aux->allocated = 2 * (aux->allocated + 1);
615       aux->titles = pool_realloc (aux->pool, aux->titles,
616                                   aux->allocated * sizeof *aux->titles);
617       aux->strings = pool_realloc (aux->pool, aux->strings,
618                                    aux->allocated * sizeof *aux->strings);
619       aux->ids = pool_realloc (aux->pool, aux->ids,
620                                aux->allocated * sizeof *aux->ids);
621     }
622
623   aux->titles[aux->n] = title;
624   aux->strings[aux->n] = pool_strdup (aux->pool, string);
625   aux->ids[aux->n] = id;
626   aux->n++;
627 }
628
629 static void PRINTF_FORMAT (3, 4)
630 add_string (struct get_strings_aux *aux,
631             const char *string, const char *title, ...)
632 {
633   va_list args;
634
635   va_start (args, title);
636   add_string__ (aux, string, false, pool_vasprintf (aux->pool, title, args));
637   va_end (args);
638 }
639
640 static void PRINTF_FORMAT (3, 4)
641 add_id (struct get_strings_aux *aux, const char *id, const char *title, ...)
642 {
643   va_list args;
644
645   va_start (args, title);
646   add_string__ (aux, id, true, pool_vasprintf (aux->pool, title, args));
647   va_end (args);
648 }
649
650 /* Retrieves significant string data from R in its raw format, to allow the
651    caller to try to detect the encoding in use.
652
653    Returns the number of strings retrieved N.  Sets each of *TITLESP, *IDSP,
654    and *STRINGSP to an array of N elements allocated from POOL.  For each I in
655    0...N-1, UTF-8 string *TITLESP[I] describes *STRINGSP[I], which is in
656    whatever encoding system file R uses.  *IDS[I] is true if *STRINGSP[I] must
657    be a valid PSPP language identifier, false if *STRINGSP[I] is free-form
658    text. */
659 static size_t
660 sfm_get_strings (const struct any_reader *r_, struct pool *pool,
661                  char ***titlesp, bool **idsp, char ***stringsp)
662 {
663   struct sfm_reader *r = sfm_reader_cast (r_);
664   const struct sfm_mrset *mrset;
665   struct get_strings_aux aux;
666   size_t var_idx;
667   size_t i, j, k;
668
669   aux.pool = pool;
670   aux.titles = NULL;
671   aux.strings = NULL;
672   aux.ids = NULL;
673   aux.allocated = 0;
674   aux.n = 0;
675
676   var_idx = 0;
677   for (i = 0; i < r->n_vars; i++)
678     if (r->vars[i].width != -1)
679       add_id (&aux, r->vars[i].name, _("Variable %zu"), ++var_idx);
680
681   var_idx = 0;
682   for (i = 0; i < r->n_vars; i++)
683     if (r->vars[i].width != -1)
684       {
685         var_idx++;
686         if (r->vars[i].label)
687           add_string (&aux, r->vars[i].label, _("Variable %zu Label"),
688                       var_idx);
689       }
690
691   k = 0;
692   for (i = 0; i < r->n_labels; i++)
693     for (j = 0; j < r->labels[i].n_labels; j++)
694       add_string (&aux, r->labels[i].labels[j].label,
695                   _("Value Label %zu"), k++);
696
697   add_string (&aux, r->header.creation_date, _("Creation Date"));
698   add_string (&aux, r->header.creation_time, _("Creation Time"));
699   add_string (&aux, r->header.eye_catcher, _("Product"));
700   add_string (&aux, r->header.file_label, _("File Label"));
701
702   if (r->extensions[EXT_PRODUCT_INFO])
703     add_string (&aux, r->extensions[EXT_PRODUCT_INFO]->data,
704                 _("Extra Product Info"));
705
706   if (r->document)
707     {
708       size_t i;
709
710       for (i = 0; i < r->document->n_lines; i++)
711         {
712           char line[81];
713
714           memcpy (line, r->document->documents + i * 80, 80);
715           line[80] = '\0';
716
717           add_string (&aux, line, _("Document Line %zu"), i + 1);
718         }
719     }
720
721   for (mrset = r->mrsets; mrset < &r->mrsets[r->n_mrsets]; mrset++)
722     {
723       size_t mrset_idx = mrset - r->mrsets + 1;
724
725       add_id (&aux, mrset->name, _("MRSET %zu"), mrset_idx);
726       if (mrset->label[0])
727         add_string (&aux, mrset->label, _("MRSET %zu Label"), mrset_idx);
728
729       /* Skip the variables because they ought to be duplicates. */
730
731       if (mrset->counted)
732         add_string (&aux, mrset->counted, _("MRSET %zu Counted Value"),
733                     mrset_idx);
734     }
735
736   /* data file attributes */
737   /* variable attributes */
738   /* long var map */
739   /* long string value labels */
740   /* long string missing values */
741
742   *titlesp = aux.titles;
743   *idsp = aux.ids;
744   *stringsp = aux.strings;
745   return aux.n;
746 }
747
748 /* Decodes the dictionary read from R, saving it into into *DICT.  Character
749    strings in R are decoded using ENCODING, or an encoding obtained from R if
750    ENCODING is null, or the locale encoding if R specifies no encoding.
751
752    If INFOP is non-null, then it receives additional info about the system
753    file, which the caller must eventually free with any_read_info_destroy()
754    when it is no longer needed.
755
756    This function consumes R.  The caller must use it again later, even to
757    destroy it with sfm_close(). */
758 static struct casereader *
759 sfm_decode (struct any_reader *r_, const char *encoding,
760             struct dictionary **dictp, struct any_read_info *infop)
761 {
762   struct sfm_reader *r = sfm_reader_cast (r_);
763   struct dictionary *dict;
764   size_t i;
765
766   if (encoding == NULL)
767     {
768       encoding = sfm_get_encoding (r);
769       if (encoding == NULL)
770         {
771           sys_warn (r, -1, _("This system file does not indicate its own "
772                              "character encoding.  Using default encoding "
773                              "%s.  For best results, specify an encoding "
774                              "explicitly.  Use SYSFILE INFO with "
775                              "ENCODING=\"DETECT\" to analyze the possible "
776                              "encodings."),
777                     locale_charset ());
778           encoding = locale_charset ();
779         }
780     }
781
782   dict = dict_create (encoding);
783   r->encoding = dict_get_encoding (dict);
784
785   /* These records don't use variables at all. */
786   if (r->document != NULL)
787     parse_document (dict, r->document);
788
789   if (r->extensions[EXT_INTEGER] != NULL
790       && !parse_machine_integer_info (r, r->extensions[EXT_INTEGER], &r->info))
791     goto error;
792
793   if (r->extensions[EXT_FLOAT] != NULL)
794     parse_machine_float_info (r, r->extensions[EXT_FLOAT]);
795
796   if (r->extensions[EXT_PRODUCT_INFO] != NULL)
797     parse_extra_product_info (r, r->extensions[EXT_PRODUCT_INFO], &r->info);
798
799   if (r->extensions[EXT_FILE_ATTRS] != NULL)
800     parse_data_file_attributes (r, r->extensions[EXT_FILE_ATTRS], dict);
801
802   parse_header (r, &r->header, &r->info, dict);
803
804   /* Parse the variable records, the basis of almost everything else. */
805   if (!parse_variable_records (r, dict, r->vars, r->n_vars))
806     goto error;
807
808   /* Parse value labels and the weight variable immediately after the variable
809      records.  These records use indexes into var_recs[], so we must parse them
810      before those indexes become invalidated by very long string variables. */
811   for (i = 0; i < r->n_labels; i++)
812     if (!parse_value_labels (r, dict, r->vars, r->n_vars, &r->labels[i]))
813       goto error;
814   if (r->header.weight_idx != 0)
815     {
816       struct variable *weight_var;
817
818       weight_var = lookup_var_by_index (r, 76, r->vars, r->n_vars,
819                                         r->header.weight_idx);
820       if (weight_var != NULL)
821         {
822           if (var_is_numeric (weight_var))
823             dict_set_weight (dict, weight_var);
824           else
825             sys_warn (r, -1, _("Ignoring string variable `%s' set "
826                                "as weighting variable."),
827                       var_get_name (weight_var));
828         }
829     }
830
831   if (r->extensions[EXT_DISPLAY] != NULL)
832     parse_display_parameters (r, r->extensions[EXT_DISPLAY], dict);
833
834   /* The following records use short names, so they need to be parsed before
835      parse_long_var_name_map() changes short names to long names. */
836   decode_mrsets (r, dict);
837
838   if (r->extensions[EXT_LONG_STRINGS] != NULL
839       && !parse_long_string_map (r, r->extensions[EXT_LONG_STRINGS], dict))
840     goto error;
841
842   /* Now rename variables to their long names. */
843   parse_long_var_name_map (r, r->extensions[EXT_LONG_NAMES], dict);
844
845   /* The following records use long names, so they need to follow renaming. */
846   if (!ll_is_empty (&r->var_attrs))
847     {
848       struct sfm_extension_record *ext;
849       ll_for_each (ext, struct sfm_extension_record, ll, &r->var_attrs)
850         parse_variable_attributes (r, ext, dict);
851
852       /* Roles use the $@Role attribute.  */
853       assign_variable_roles (r, dict);
854     }
855   if (r->extensions[EXT_LONG_LABELS] != NULL)
856     parse_long_string_value_labels (r, r->extensions[EXT_LONG_LABELS], dict);
857   if (r->extensions[EXT_LONG_MISSING] != NULL)
858     parse_long_string_missing_values (r, r->extensions[EXT_LONG_MISSING],
859                                       dict);
860
861   /* Warn if the actual amount of data per case differs from the
862      amount that the header claims.  SPSS version 13 gets this
863      wrong when very long strings are involved, so don't warn in
864      that case. */
865   if (r->header.nominal_case_size != -1
866       && r->header.nominal_case_size != r->n_vars
867       && r->info.version_major != 13)
868     sys_warn (r, -1, _("File header claims %d variable positions but "
869                        "%zu were read from file."),
870               r->header.nominal_case_size, r->n_vars);
871
872   /* Create an index of dictionary variable widths for
873      sfm_read_case to use.  We cannot use the `struct variable's
874      from the dictionary we created, because the caller owns the
875      dictionary and may destroy or modify its variables. */
876   sfm_dictionary_to_sfm_vars (dict, &r->sfm_vars, &r->sfm_var_cnt);
877   pool_register (r->pool, free, r->sfm_vars);
878   r->proto = caseproto_ref_pool (dict_get_proto (dict), r->pool);
879
880   *dictp = dict;
881   if (infop)
882     {
883       *infop = r->info;
884       memset (&r->info, 0, sizeof r->info);
885     }
886
887   return casereader_create_sequential
888     (NULL, r->proto,
889      r->case_cnt == -1 ? CASENUMBER_MAX: r->case_cnt,
890                                        &sys_file_casereader_class, r);
891
892 error:
893   sfm_close (r_);
894   dict_destroy (dict);
895   *dictp = NULL;
896   return NULL;
897 }
898
899 /* Closes R, which should have been returned by sfm_open() but not already
900    closed with sfm_decode() or this function.
901    Returns true if an I/O error has occurred on READER, false
902    otherwise. */
903 static bool
904 sfm_close (struct any_reader *r_)
905 {
906   struct sfm_reader *r = sfm_reader_cast (r_);
907   bool error;
908
909   if (r->file)
910     {
911       if (fn_close (r->fh, r->file) == EOF)
912         {
913           msg (ME, _("Error closing system file `%s': %s."),
914                fh_get_file_name (r->fh), strerror (errno));
915           r->error = true;
916         }
917       r->file = NULL;
918     }
919
920   any_read_info_destroy (&r->info);
921   fh_unlock (r->lock);
922   fh_unref (r->fh);
923
924   error = r->error;
925   pool_destroy (r->pool);
926
927   return !error;
928 }
929
930 /* Destroys READER. */
931 static void
932 sys_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
933 {
934   struct sfm_reader *r = r_;
935   sfm_close (&r->any_reader);
936 }
937
938 /* Detects whether FILE is an SPSS system file.  Returns 1 if so, 0 if not, and
939    a negative errno value if there is an error reading FILE. */
940 static int
941 sfm_detect (FILE *file)
942 {
943   char magic[5];
944
945   if (fseek (file, 0, SEEK_SET) != 0)
946     return -errno;
947   if (fread (magic, 4, 1, file) != 1)
948     return ferror (file) ? -errno : 0;
949   magic[4] = '\0';
950
951   return (!strcmp (ASCII_MAGIC, magic)
952           || !strcmp (ASCII_ZMAGIC, magic)
953           || !strcmp (EBCDIC_MAGIC, magic));
954 }
955 \f
956 /* Reads the global header of the system file.  Initializes *HEADER and *INFO,
957    except for the string fields in *INFO, which parse_header() will initialize
958    later once the file's encoding is known. */
959 static bool
960 read_header (struct sfm_reader *r, struct any_read_info *info,
961              struct sfm_header_record *header)
962 {
963   uint8_t raw_layout_code[4];
964   uint8_t raw_bias[8];
965   int compressed;
966   bool zmagic;
967
968   if (!read_string (r, header->magic, sizeof header->magic)
969       || !read_string (r, header->eye_catcher, sizeof header->eye_catcher))
970     return false;
971
972   if (!strcmp (ASCII_MAGIC, header->magic)
973       || !strcmp (EBCDIC_MAGIC, header->magic))
974     zmagic = false;
975   else if (!strcmp (ASCII_ZMAGIC, header->magic))
976     zmagic = true;
977   else
978     {
979       sys_error (r, 0, _("This is not an SPSS system file."));
980       return false;
981     }
982
983   /* Identify integer format. */
984   if (!read_bytes (r, raw_layout_code, sizeof raw_layout_code))
985     return false;
986   if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
987                           &r->integer_format)
988        && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
989                              &r->integer_format))
990       || (r->integer_format != INTEGER_MSB_FIRST
991           && r->integer_format != INTEGER_LSB_FIRST))
992     {
993       sys_error (r, 64, _("This is not an SPSS system file."));
994       return false;
995     }
996
997   if (!read_int (r, &header->nominal_case_size))
998     return false;
999
1000   if (header->nominal_case_size < 0
1001       || header->nominal_case_size > INT_MAX / 16)
1002     header->nominal_case_size = -1;
1003
1004   if (!read_int (r, &compressed))
1005     return false;
1006   if (!zmagic)
1007     {
1008       if (compressed == 0)
1009         r->compression = ANY_COMP_NONE;
1010       else if (compressed == 1)
1011         r->compression = ANY_COMP_SIMPLE;
1012       else if (compressed != 0)
1013         {
1014           sys_error (r, 0, "System file header has invalid compression "
1015                      "value %d.", compressed);
1016           return false;
1017         }
1018     }
1019   else
1020     {
1021       if (compressed == 2)
1022         r->compression = ANY_COMP_ZLIB;
1023       else
1024         {
1025           sys_error (r, 0, "ZLIB-compressed system file header has invalid "
1026                      "compression value %d.", compressed);
1027           return false;
1028         }
1029     }
1030
1031   if (!read_int (r, &header->weight_idx))
1032     return false;
1033
1034   if (!read_int (r, &r->case_cnt))
1035     return false;
1036   if ( r->case_cnt > INT_MAX / 2)
1037     r->case_cnt = -1;
1038
1039   /* Identify floating-point format and obtain compression bias. */
1040   if (!read_bytes (r, raw_bias, sizeof raw_bias))
1041     return false;
1042   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
1043     {
1044       uint8_t zero_bias[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1045
1046       if (memcmp (raw_bias, zero_bias, 8))
1047         sys_warn (r, r->pos - 8,
1048                   _("Compression bias is not the usual "
1049                     "value of 100, or system file uses unrecognized "
1050                     "floating-point format."));
1051       else
1052         {
1053           /* Some software is known to write all-zeros to this
1054              field.  Such software also writes floating-point
1055              numbers in the format that we expect by default
1056              (it seems that all software most likely does, in
1057              reality), so don't warn in this case. */
1058         }
1059
1060       if (r->integer_format == INTEGER_MSB_FIRST)
1061         r->float_format = FLOAT_IEEE_DOUBLE_BE;
1062       else
1063         r->float_format = FLOAT_IEEE_DOUBLE_LE;
1064     }
1065   float_convert (r->float_format, raw_bias, FLOAT_NATIVE_DOUBLE, &r->bias);
1066
1067   if (!read_string (r, header->creation_date, sizeof header->creation_date)
1068       || !read_string (r, header->creation_time, sizeof header->creation_time)
1069       || !read_string (r, header->file_label, sizeof header->file_label)
1070       || !skip_bytes (r, 3))
1071     return false;
1072
1073   info->integer_format = r->integer_format;
1074   info->float_format = r->float_format;
1075   info->compression = r->compression;
1076   info->case_cnt = r->case_cnt;
1077
1078   return true;
1079 }
1080
1081 /* Reads a variable (type 2) record from R into RECORD. */
1082 static bool
1083 read_variable_record (struct sfm_reader *r, struct sfm_var_record *record)
1084 {
1085   int has_variable_label;
1086
1087   memset (record, 0, sizeof *record);
1088
1089   record->pos = r->pos;
1090   if (!read_int (r, &record->width)
1091       || !read_int (r, &has_variable_label)
1092       || !read_int (r, &record->missing_value_code)
1093       || !read_int (r, &record->print_format)
1094       || !read_int (r, &record->write_format)
1095       || !read_string (r, record->name, sizeof record->name))
1096     return false;
1097
1098   if (has_variable_label == 1)
1099     {
1100       enum { MAX_LABEL_LEN = 65536 };
1101       unsigned int len, read_len;
1102
1103       if (!read_uint (r, &len))
1104         return false;
1105
1106       /* Read up to MAX_LABEL_LEN bytes of label. */
1107       read_len = MIN (MAX_LABEL_LEN, len);
1108       record->label = pool_malloc (r->pool, read_len + 1);
1109       if (!read_string (r, record->label, read_len + 1))
1110         return false;
1111
1112       /* Skip unread label bytes. */
1113       if (!skip_bytes (r, len - read_len))
1114         return false;
1115
1116       /* Skip label padding up to multiple of 4 bytes. */
1117       if (!skip_bytes (r, ROUND_UP (len, 4) - len))
1118         return false;
1119     }
1120   else if (has_variable_label != 0)
1121     {
1122       sys_error (r, record->pos,
1123                  _("Variable label indicator field is not 0 or 1."));
1124       return false;
1125     }
1126
1127   /* Set missing values. */
1128   if (record->missing_value_code != 0)
1129     {
1130       int code = record->missing_value_code;
1131       if (record->width == 0)
1132         {
1133           if (code < -3 || code > 3 || code == -1)
1134             {
1135               sys_error (r, record->pos,
1136                          _("Numeric missing value indicator field is not "
1137                            "-3, -2, 0, 1, 2, or 3."));
1138               return false;
1139             }
1140         }
1141       else
1142         {
1143           if (code < 1 || code > 3)
1144             {
1145               sys_error (r, record->pos,
1146                          _("String missing value indicator field is not "
1147                            "0, 1, 2, or 3."));
1148               return false;
1149             }
1150         }
1151
1152       if (!read_bytes (r, record->missing, 8 * abs (code)))
1153         return false;
1154     }
1155
1156   return true;
1157 }
1158
1159 /* Reads value labels from R into RECORD. */
1160 static bool
1161 read_value_label_record (struct sfm_reader *r,
1162                          struct sfm_value_label_record *record)
1163 {
1164   size_t i;
1165   int type;
1166
1167   /* Read type 3 record. */
1168   record->pos = r->pos;
1169   if (!read_uint (r, &record->n_labels))
1170     return false;
1171   if (record->n_labels > UINT_MAX / sizeof *record->labels)
1172     {
1173       sys_error (r, r->pos - 4, _("Invalid number of labels %u."),
1174                  record->n_labels);
1175       return false;
1176     }
1177   record->labels = pool_nmalloc (r->pool, record->n_labels,
1178                                  sizeof *record->labels);
1179   for (i = 0; i < record->n_labels; i++)
1180     {
1181       struct sfm_value_label *label = &record->labels[i];
1182       unsigned char label_len;
1183       size_t padded_len;
1184
1185       if (!read_bytes (r, label->value, sizeof label->value))
1186         return false;
1187
1188       /* Read label length. */
1189       if (!read_bytes (r, &label_len, sizeof label_len))
1190         return false;
1191       padded_len = ROUND_UP (label_len + 1, 8);
1192
1193       /* Read label, padding. */
1194       label->label = pool_malloc (r->pool, padded_len + 1);
1195       if (!read_bytes (r, label->label, padded_len - 1))
1196         return false;
1197       label->label[label_len] = '\0';
1198     }
1199
1200   /* Read record type of type 4 record. */
1201   if (!read_int (r, &type))
1202     return false;
1203   if (type != 4)
1204     {
1205       sys_error (r, r->pos - 4,
1206                  _("Variable index record (type 4) does not immediately "
1207                    "follow value label record (type 3) as it should."));
1208       return false;
1209     }
1210
1211   /* Read number of variables associated with value label from type 4
1212      record. */
1213   if (!read_uint (r, &record->n_vars))
1214     return false;
1215   if (record->n_vars < 1 || record->n_vars > r->n_vars)
1216     {
1217       sys_error (r, r->pos - 4,
1218                  _("Number of variables associated with a value label (%u) "
1219                    "is not between 1 and the number of variables (%zu)."),
1220                  record->n_vars, r->n_vars);
1221       return false;
1222     }
1223
1224   record->vars = pool_nmalloc (r->pool, record->n_vars, sizeof *record->vars);
1225   for (i = 0; i < record->n_vars; i++)
1226     if (!read_int (r, &record->vars[i]))
1227       return false;
1228
1229   return true;
1230 }
1231
1232 /* Reads a document record from R and returns it. */
1233 static struct sfm_document_record *
1234 read_document_record (struct sfm_reader *r)
1235 {
1236   struct sfm_document_record *record;
1237   int n_lines;
1238
1239   record = pool_malloc (r->pool, sizeof *record);
1240   record->pos = r->pos;
1241
1242   if (!read_int (r, &n_lines))
1243     return NULL;
1244   if (n_lines <= 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH)
1245     {
1246       sys_error (r, record->pos,
1247                  _("Number of document lines (%d) "
1248                    "must be greater than 0 and less than %d."),
1249                  n_lines, INT_MAX / DOC_LINE_LENGTH);
1250       return NULL;
1251     }
1252
1253   record->n_lines = n_lines;
1254   record->documents = pool_malloc (r->pool, DOC_LINE_LENGTH * n_lines);
1255   if (!read_bytes (r, record->documents, DOC_LINE_LENGTH * n_lines))
1256     return NULL;
1257
1258   return record;
1259 }
1260
1261 static bool
1262 read_extension_record_header (struct sfm_reader *r, int subtype,
1263                               struct sfm_extension_record *record)
1264 {
1265   record->subtype = subtype;
1266   record->pos = r->pos;
1267   if (!read_uint (r, &record->size) || !read_uint (r, &record->count))
1268     return false;
1269
1270   /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
1271      allows an extra byte for a null terminator, used by some
1272      extension processing routines. */
1273   if (record->size != 0
1274       && xsum (1, xtimes (record->count, record->size)) >= UINT_MAX)
1275     {
1276       sys_error (r, record->pos, "Record type 7 subtype %d too large.",
1277                  subtype);
1278       return false;
1279     }
1280
1281   return true;
1282 }
1283
1284 /* Reads an extension record from R into RECORD. */
1285 static bool
1286 read_extension_record (struct sfm_reader *r, int subtype,
1287                        struct sfm_extension_record **recordp)
1288 {
1289   struct extension_record_type
1290     {
1291       int subtype;
1292       int size;
1293       int count;
1294     };
1295
1296   static const struct extension_record_type types[] =
1297     {
1298       /* Implemented record types. */
1299       { EXT_INTEGER,      4, 8 },
1300       { EXT_FLOAT,        8, 3 },
1301       { EXT_MRSETS,       1, 0 },
1302       { EXT_PRODUCT_INFO, 1, 0 },
1303       { EXT_DISPLAY,      4, 0 },
1304       { EXT_LONG_NAMES,   1, 0 },
1305       { EXT_LONG_STRINGS, 1, 0 },
1306       { EXT_NCASES,       8, 2 },
1307       { EXT_FILE_ATTRS,   1, 0 },
1308       { EXT_VAR_ATTRS,    1, 0 },
1309       { EXT_MRSETS2,      1, 0 },
1310       { EXT_ENCODING,     1, 0 },
1311       { EXT_LONG_LABELS,  1, 0 },
1312       { EXT_LONG_MISSING, 1, 0 },
1313
1314       /* Ignored record types. */
1315       { EXT_VAR_SETS,     0, 0 },
1316       { EXT_DATE,         0, 0 },
1317       { EXT_DATA_ENTRY,   0, 0 },
1318       { EXT_DATAVIEW,     0, 0 },
1319     };
1320
1321   const struct extension_record_type *type;
1322   struct sfm_extension_record *record;
1323   size_t n_bytes;
1324
1325   *recordp = NULL;
1326   record = pool_malloc (r->pool, sizeof *record);
1327   if (!read_extension_record_header (r, subtype, record))
1328     return false;
1329   n_bytes = record->count * record->size;
1330
1331   for (type = types; type < &types[sizeof types / sizeof *types]; type++)
1332     if (subtype == type->subtype)
1333       {
1334         if (type->size > 0 && record->size != type->size)
1335           sys_warn (r, record->pos,
1336                     _("Record type 7, subtype %d has bad size %u "
1337                       "(expected %d)."), subtype, record->size, type->size);
1338         else if (type->count > 0 && record->count != type->count)
1339           sys_warn (r, record->pos,
1340                     _("Record type 7, subtype %d has bad count %u "
1341                       "(expected %d)."), subtype, record->count, type->count);
1342         else if (type->count == 0 && type->size == 0)
1343           {
1344             /* Ignore this record. */
1345           }
1346         else
1347           {
1348             char *data = pool_malloc (r->pool, n_bytes + 1);
1349             data[n_bytes] = '\0';
1350
1351             record->data = data;
1352             if (!read_bytes (r, record->data, n_bytes))
1353               return false;
1354             *recordp = record;
1355             return true;
1356           }
1357
1358         goto skip;
1359       }
1360
1361   sys_warn (r, record->pos,
1362             _("Unrecognized record type 7, subtype %d.  For help, please "
1363               "send this file to %s and mention that you were using %s."),
1364             subtype, PACKAGE_BUGREPORT, PACKAGE_STRING);
1365
1366 skip:
1367   return skip_bytes (r, n_bytes);
1368 }
1369
1370 static bool
1371 skip_extension_record (struct sfm_reader *r, int subtype)
1372 {
1373   struct sfm_extension_record record;
1374
1375   return (read_extension_record_header (r, subtype, &record)
1376           && skip_bytes (r, record.count * record.size));
1377 }
1378
1379 static void
1380 parse_header (struct sfm_reader *r, const struct sfm_header_record *header,
1381               struct any_read_info *info, struct dictionary *dict)
1382 {
1383   const char *dict_encoding = dict_get_encoding (dict);
1384   struct substring product;
1385   struct substring label;
1386   char *fixed_label;
1387
1388   /* Convert file label to UTF-8 and put it into DICT. */
1389   label = recode_substring_pool ("UTF-8", dict_encoding,
1390                                  ss_cstr (header->file_label), r->pool);
1391   ss_trim (&label, ss_cstr (" "));
1392   label.string[label.length] = '\0';
1393   fixed_label = fix_line_ends (label.string);
1394   dict_set_label (dict, fixed_label);
1395   free (fixed_label);
1396
1397   /* Put creation date and time in UTF-8 into INFO. */
1398   info->creation_date = recode_string ("UTF-8", dict_encoding,
1399                                        header->creation_date, -1);
1400   info->creation_time = recode_string ("UTF-8", dict_encoding,
1401                                        header->creation_time, -1);
1402
1403   /* Put product name into INFO, dropping eye-catcher string if present. */
1404   product = recode_substring_pool ("UTF-8", dict_encoding,
1405                                    ss_cstr (header->eye_catcher), r->pool);
1406   ss_match_string (&product, ss_cstr ("@(#) SPSS DATA FILE"));
1407   ss_trim (&product, ss_cstr (" "));
1408   info->product = ss_xstrdup (product);
1409 }
1410
1411 /* Reads a variable (type 2) record from R and adds the
1412    corresponding variable to DICT.
1413    Also skips past additional variable records for long string
1414    variables. */
1415 static bool
1416 parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
1417                         struct sfm_var_record *var_recs, size_t n_var_recs)
1418 {
1419   const char *dict_encoding = dict_get_encoding (dict);
1420   struct sfm_var_record *rec;
1421   int n_warnings = 0;
1422
1423   for (rec = var_recs; rec < &var_recs[n_var_recs]; )
1424     {
1425       struct variable *var;
1426       size_t n_values;
1427       char *name;
1428       size_t i;
1429
1430       name = recode_string_pool ("UTF-8", dict_encoding,
1431                                  rec->name, -1, r->pool);
1432       name[strcspn (name, " ")] = '\0';
1433
1434       if (!dict_id_is_valid (dict, name, false)
1435           || name[0] == '$' || name[0] == '#')
1436         {
1437           sys_error (r, rec->pos, _("Invalid variable name `%s'."), name);
1438           return false;
1439         }
1440
1441       if (rec->width < 0 || rec->width > 255)
1442         {
1443           sys_error (r, rec->pos,
1444                      _("Bad width %d for variable %s."), rec->width, name);
1445           return false;
1446         }
1447
1448       var = rec->var = dict_create_var (dict, name, rec->width);
1449       if (var == NULL)
1450         {
1451           char *new_name = dict_make_unique_var_name (dict, NULL, NULL);
1452           sys_warn (r, rec->pos, _("Renaming variable with duplicate name "
1453                                    "`%s' to `%s'."),
1454                     name, new_name);
1455           var = rec->var = dict_create_var_assert (dict, new_name, rec->width);
1456           free (new_name);
1457         }
1458
1459       /* Set the short name the same as the long name. */
1460       var_set_short_name (var, 0, name);
1461
1462       /* Get variable label, if any. */
1463       if (rec->label)
1464         {
1465           char *utf8_label;
1466
1467           utf8_label = recode_string_pool ("UTF-8", dict_encoding,
1468                                            rec->label, -1, r->pool);
1469           var_set_label (var, utf8_label);
1470         }
1471
1472       /* Set missing values. */
1473       if (rec->missing_value_code != 0)
1474         {
1475           int width = var_get_width (var);
1476           struct missing_values mv;
1477
1478           mv_init_pool (r->pool, &mv, width);
1479           if (var_is_numeric (var))
1480             {
1481               bool has_range = rec->missing_value_code < 0;
1482               int n_discrete = (has_range
1483                                 ? rec->missing_value_code == -3
1484                                 : rec->missing_value_code);
1485               int ofs = 0;
1486
1487               if (has_range)
1488                 {
1489                   double low = parse_float (r, rec->missing, 0);
1490                   double high = parse_float (r, rec->missing, 8);
1491
1492                   /* Deal with SPSS 21 change in representation. */
1493                   if (low == SYSMIS)
1494                     low = LOWEST;
1495
1496                   mv_add_range (&mv, low, high);
1497                   ofs += 16;
1498                 }
1499
1500               for (i = 0; i < n_discrete; i++)
1501                 {
1502                   mv_add_num (&mv, parse_float (r, rec->missing, ofs));
1503                   ofs += 8;
1504                 }
1505             }
1506           else
1507             for (i = 0; i < rec->missing_value_code; i++)
1508               mv_add_str (&mv, rec->missing + 8 * i, MIN (width, 8));
1509           var_set_missing_values (var, &mv);
1510         }
1511
1512       /* Set formats. */
1513       parse_format_spec (r, rec->pos + 12, rec->print_format,
1514                          PRINT_FORMAT, var, &n_warnings);
1515       parse_format_spec (r, rec->pos + 16, rec->write_format,
1516                          WRITE_FORMAT, var, &n_warnings);
1517
1518       /* Account for values.
1519          Skip long string continuation records, if any. */
1520       n_values = rec->width == 0 ? 1 : DIV_RND_UP (rec->width, 8);
1521       for (i = 1; i < n_values; i++)
1522         if (i + (rec - var_recs) >= n_var_recs || rec[i].width != -1)
1523           {
1524             sys_error (r, rec->pos, _("Missing string continuation record."));
1525             return false;
1526           }
1527       rec += n_values;
1528     }
1529
1530   return true;
1531 }
1532
1533 /* Translates the format spec from sysfile format to internal
1534    format. */
1535 static void
1536 parse_format_spec (struct sfm_reader *r, off_t pos, unsigned int format,
1537                    enum which_format which, struct variable *v,
1538                    int *n_warnings)
1539 {
1540   const int max_warnings = 8;
1541   uint8_t raw_type = format >> 16;
1542   uint8_t w = format >> 8;
1543   uint8_t d = format;
1544   struct fmt_spec f;
1545   bool ok;
1546
1547   f.w = w;
1548   f.d = d;
1549
1550   msg_disable ();
1551   ok = (fmt_from_io (raw_type, &f.type)
1552         && fmt_check_output (&f)
1553         && fmt_check_width_compat (&f, var_get_width (v)));
1554   msg_enable ();
1555
1556   if (ok)
1557     {
1558       if (which == PRINT_FORMAT)
1559         var_set_print_format (v, &f);
1560       else
1561         var_set_write_format (v, &f);
1562     }
1563   else if (format == 0)
1564     {
1565       /* Actually observed in the wild.  No point in warning about it. */
1566     }
1567   else if (++*n_warnings <= max_warnings)
1568     {
1569       if (which == PRINT_FORMAT)
1570         sys_warn (r, pos, _("Variable %s with width %d has invalid print "
1571                             "format 0x%x."),
1572                   var_get_name (v), var_get_width (v), format);
1573       else
1574         sys_warn (r, pos, _("Variable %s with width %d has invalid write "
1575                             "format 0x%x."),
1576                   var_get_name (v), var_get_width (v), format);
1577
1578       if (*n_warnings == max_warnings)
1579         sys_warn (r, -1, _("Suppressing further invalid format warnings."));
1580     }
1581 }
1582
1583 static void
1584 parse_document (struct dictionary *dict, struct sfm_document_record *record)
1585 {
1586   const char *p;
1587
1588   for (p = record->documents;
1589        p < record->documents + DOC_LINE_LENGTH * record->n_lines;
1590        p += DOC_LINE_LENGTH)
1591     {
1592       struct substring line;
1593
1594       line = recode_substring_pool ("UTF-8", dict_get_encoding (dict),
1595                                     ss_buffer (p, DOC_LINE_LENGTH), NULL);
1596       ss_rtrim (&line, ss_cstr (" "));
1597       line.string[line.length] = '\0';
1598
1599       dict_add_document_line (dict, line.string, false);
1600
1601       ss_dealloc (&line);
1602     }
1603 }
1604
1605 /* Parses record type 7, subtype 3. */
1606 static bool
1607 parse_machine_integer_info (struct sfm_reader *r,
1608                             const struct sfm_extension_record *record,
1609                             struct any_read_info *info)
1610 {
1611   int float_representation, expected_float_format;
1612   int integer_representation, expected_integer_format;
1613
1614   /* Save version info. */
1615   info->version_major = parse_int (r, record->data, 0);
1616   info->version_minor = parse_int (r, record->data, 4);
1617   info->version_revision = parse_int (r, record->data, 8);
1618
1619   /* Check floating point format. */
1620   float_representation = parse_int (r, record->data, 16);
1621   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
1622       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
1623     expected_float_format = 1;
1624   else if (r->float_format == FLOAT_Z_LONG)
1625     expected_float_format = 2;
1626   else if (r->float_format == FLOAT_VAX_G || r->float_format == FLOAT_VAX_D)
1627     expected_float_format = 3;
1628   else
1629     NOT_REACHED ();
1630   if (float_representation != expected_float_format)
1631     {
1632       sys_error (r, record->pos,
1633                  _("Floating-point representation indicated by "
1634                    "system file (%d) differs from expected (%d)."),
1635                  float_representation, expected_float_format);
1636       return false;
1637     }
1638
1639   /* Check integer format. */
1640   integer_representation = parse_int (r, record->data, 24);
1641   if (r->integer_format == INTEGER_MSB_FIRST)
1642     expected_integer_format = 1;
1643   else if (r->integer_format == INTEGER_LSB_FIRST)
1644     expected_integer_format = 2;
1645   else
1646     NOT_REACHED ();
1647   if (integer_representation != expected_integer_format)
1648     sys_warn (r, record->pos,
1649               _("Integer format indicated by system file (%d) "
1650                 "differs from expected (%d)."),
1651               integer_representation, expected_integer_format);
1652
1653   return true;
1654 }
1655
1656 /* Parses record type 7, subtype 4. */
1657 static void
1658 parse_machine_float_info (struct sfm_reader *r,
1659                           const struct sfm_extension_record *record)
1660 {
1661   double sysmis = parse_float (r, record->data, 0);
1662   double highest = parse_float (r, record->data, 8);
1663   double lowest = parse_float (r, record->data, 16);
1664
1665   if (sysmis != SYSMIS)
1666     sys_warn (r, record->pos,
1667               _("File specifies unexpected value %g (%a) as %s, "
1668                 "instead of %g (%a)."),
1669               sysmis, sysmis, "SYSMIS", SYSMIS, SYSMIS);
1670
1671   if (highest != HIGHEST)
1672     sys_warn (r, record->pos,
1673               _("File specifies unexpected value %g (%a) as %s, "
1674                 "instead of %g (%a)."),
1675               highest, highest, "HIGHEST", HIGHEST, HIGHEST);
1676
1677   /* SPSS before version 21 used a unique value just bigger than SYSMIS as
1678      LOWEST.  SPSS 21 uses SYSMIS for LOWEST, which is OK because LOWEST only
1679      appears in a context (missing values) where SYSMIS cannot. */
1680   if (lowest != LOWEST && lowest != SYSMIS)
1681     sys_warn (r, record->pos,
1682               _("File specifies unexpected value %g (%a) as %s, "
1683                 "instead of %g (%a) or %g (%a)."),
1684               lowest, lowest, "LOWEST", LOWEST, LOWEST, SYSMIS, SYSMIS);
1685 }
1686
1687 /* Parses record type 7, subtype 10. */
1688 static void
1689 parse_extra_product_info (struct sfm_reader *r,
1690                           const struct sfm_extension_record *record,
1691                           struct any_read_info *info)
1692 {
1693   struct text_record *text;
1694
1695   text = open_text_record (r, record, true);
1696   info->product_ext = fix_line_ends (text_get_all (text));
1697   close_text_record (r, text);
1698 }
1699
1700 /* Parses record type 7, subtype 7 or 19. */
1701 static void
1702 parse_mrsets (struct sfm_reader *r, const struct sfm_extension_record *record,
1703               size_t *allocated_mrsets)
1704 {
1705   struct text_record *text;
1706
1707   text = open_text_record (r, record, false);
1708   for (;;)
1709     {
1710       struct sfm_mrset *mrset;
1711       size_t allocated_vars;
1712       char delimiter;
1713
1714       /* Skip extra line feeds if present. */
1715       while (text_match (text, '\n'))
1716         continue;
1717
1718       if (r->n_mrsets >= *allocated_mrsets)
1719         r->mrsets = pool_2nrealloc (r->pool, r->mrsets, allocated_mrsets,
1720                                     sizeof *r->mrsets);
1721       mrset = &r->mrsets[r->n_mrsets];
1722       memset(mrset, 0, sizeof *mrset);
1723
1724       mrset->name = text_get_token (text, ss_cstr ("="), NULL);
1725       if (mrset->name == NULL)
1726         break;
1727
1728       if (text_match (text, 'C'))
1729         {
1730           mrset->type = MRSET_MC;
1731           if (!text_match (text, ' '))
1732             {
1733               sys_warn (r, record->pos,
1734                         _("Missing space following `%c' at offset %zu "
1735                           "in MRSETS record."), 'C', text_pos (text));
1736               break;
1737             }
1738         }
1739       else if (text_match (text, 'D'))
1740         {
1741           mrset->type = MRSET_MD;
1742           mrset->cat_source = MRSET_VARLABELS;
1743         }
1744       else if (text_match (text, 'E'))
1745         {
1746           char *number;
1747
1748           mrset->type = MRSET_MD;
1749           mrset->cat_source = MRSET_COUNTEDVALUES;
1750           if (!text_match (text, ' '))
1751             {
1752               sys_warn (r, record->pos,
1753                         _("Missing space following `%c' at offset %zu "
1754                           "in MRSETS record."), 'E',  text_pos (text));
1755               break;
1756             }
1757
1758           number = text_get_token (text, ss_cstr (" "), NULL);
1759           if (!strcmp (number, "11"))
1760             mrset->label_from_var_label = true;
1761           else if (strcmp (number, "1"))
1762             sys_warn (r, record->pos,
1763                       _("Unexpected label source value following `E' "
1764                         "at offset %zu in MRSETS record."),
1765                       text_pos (text));
1766         }
1767       else
1768         {
1769           sys_warn (r, record->pos,
1770                     _("Missing `C', `D', or `E' at offset %zu "
1771                       "in MRSETS record."),
1772                     text_pos (text));
1773           break;
1774         }
1775
1776       if (mrset->type == MRSET_MD)
1777         {
1778           mrset->counted = text_parse_counted_string (r, text);
1779           if (mrset->counted == NULL)
1780             break;
1781         }
1782
1783       mrset->label = text_parse_counted_string (r, text);
1784       if (mrset->label == NULL)
1785         break;
1786
1787       allocated_vars = 0;
1788       do
1789         {
1790           const char *var;
1791
1792           var = text_get_token (text, ss_cstr (" \n"), &delimiter);
1793           if (var == NULL)
1794             {
1795               if (delimiter != '\n')
1796                 sys_warn (r, record->pos,
1797                           _("Missing new-line parsing variable names "
1798                             "at offset %zu in MRSETS record."),
1799                           text_pos (text));
1800               break;
1801             }
1802
1803           if (mrset->n_vars >= allocated_vars)
1804             mrset->vars = pool_2nrealloc (r->pool, mrset->vars,
1805                                           &allocated_vars,
1806                                           sizeof *mrset->vars);
1807           mrset->vars[mrset->n_vars++] = var;
1808         }
1809       while (delimiter != '\n');
1810
1811       r->n_mrsets++;
1812     }
1813   close_text_record (r, text);
1814 }
1815
1816 static void
1817 decode_mrsets (struct sfm_reader *r, struct dictionary *dict)
1818 {
1819   const struct sfm_mrset *s;
1820
1821   for (s = r->mrsets; s < &r->mrsets[r->n_mrsets]; s++)
1822     {
1823       struct stringi_set var_names;
1824       struct mrset *mrset;
1825       char *name;
1826       int width;
1827       size_t i;
1828
1829       name = recode_string ("UTF-8", r->encoding, s->name, -1);
1830       if (name[0] != '$')
1831         {
1832           sys_warn (r, -1, _("Multiple response set name `%s' does not begin "
1833                              "with `$'."),
1834                     name);
1835           free (name);
1836           continue;
1837         }
1838
1839       mrset = xzalloc (sizeof *mrset);
1840       mrset->name = name;
1841       mrset->type = s->type;
1842       mrset->cat_source = s->cat_source;
1843       mrset->label_from_var_label = s->label_from_var_label;
1844       if (s->label[0] != '\0')
1845         mrset->label = recode_string ("UTF-8", r->encoding, s->label, -1);
1846
1847       stringi_set_init (&var_names);
1848       mrset->vars = xmalloc (s->n_vars * sizeof *mrset->vars);
1849       width = INT_MAX;
1850       for (i = 0; i < s->n_vars; i++)
1851         {
1852           struct variable *var;
1853           char *var_name;
1854
1855           var_name = recode_string ("UTF-8", r->encoding, s->vars[i], -1);
1856
1857           var = dict_lookup_var (dict, var_name);
1858           if (var == NULL)
1859             {
1860               free (var_name);
1861               continue;
1862             }
1863           if (!stringi_set_insert (&var_names, var_name))
1864             {
1865               sys_warn (r, -1,
1866                         _("MRSET %s contains duplicate variable name %s."),
1867                         mrset->name, var_name);
1868               free (var_name);
1869               continue;
1870             }
1871           free (var_name);
1872
1873           if (mrset->label == NULL && mrset->label_from_var_label
1874               && var_has_label (var))
1875             mrset->label = xstrdup (var_get_label (var));
1876
1877           if (mrset->n_vars
1878               && var_get_type (var) != var_get_type (mrset->vars[0]))
1879             {
1880               sys_warn (r, -1,
1881                         _("MRSET %s contains both string and "
1882                           "numeric variables."), mrset->name);
1883               continue;
1884             }
1885           width = MIN (width, var_get_width (var));
1886
1887           mrset->vars[mrset->n_vars++] = var;
1888         }
1889
1890       if (mrset->n_vars < 2)
1891         {
1892           if (mrset->n_vars == 0)
1893             sys_warn (r, -1, _("MRSET %s has no variables."), mrset->name);
1894           else
1895             sys_warn (r, -1, _("MRSET %s has only one variable."),
1896                       mrset->name);
1897           mrset_destroy (mrset);
1898           stringi_set_destroy (&var_names);
1899           continue;
1900         }
1901
1902       if (mrset->type == MRSET_MD)
1903         {
1904           mrset->width = width;
1905           value_init (&mrset->counted, width);
1906           if (width == 0)
1907             mrset->counted.f = c_strtod (s->counted, NULL);
1908           else
1909             value_copy_str_rpad (&mrset->counted, width,
1910                                  (const uint8_t *) s->counted, ' ');
1911         }
1912
1913       dict_add_mrset (dict, mrset);
1914       stringi_set_destroy (&var_names);
1915     }
1916 }
1917
1918 /* Read record type 7, subtype 11, which specifies how variables
1919    should be displayed in GUI environments. */
1920 static void
1921 parse_display_parameters (struct sfm_reader *r,
1922                          const struct sfm_extension_record *record,
1923                          struct dictionary *dict)
1924 {
1925   bool includes_width;
1926   bool warned = false;
1927   size_t n_vars;
1928   size_t ofs;
1929   size_t i;
1930
1931   n_vars = dict_get_var_cnt (dict);
1932   if (record->count == 3 * n_vars)
1933     includes_width = true;
1934   else if (record->count == 2 * n_vars)
1935     includes_width = false;
1936   else
1937     {
1938       sys_warn (r, record->pos,
1939                 _("Extension 11 has bad count %u (for %zu variables)."),
1940                 record->count, n_vars);
1941       return;
1942     }
1943
1944   ofs = 0;
1945   for (i = 0; i < n_vars; ++i)
1946     {
1947       struct variable *v = dict_get_var (dict, i);
1948       int measure, width, align;
1949
1950       measure = parse_int (r, record->data, ofs);
1951       ofs += 4;
1952
1953       if (includes_width)
1954         {
1955           width = parse_int (r, record->data, ofs);
1956           ofs += 4;
1957         }
1958       else
1959         width = 0;
1960
1961       align = parse_int (r, record->data, ofs);
1962       ofs += 4;
1963
1964       /* SPSS sometimes seems to set variables' measure to zero. */
1965       if (0 == measure)
1966         measure = 1;
1967
1968       if (measure < 1 || measure > 3 || align < 0 || align > 2)
1969         {
1970           if (!warned)
1971             sys_warn (r, record->pos,
1972                       _("Invalid variable display parameters for variable "
1973                         "%zu (%s).  Default parameters substituted."),
1974                       i, var_get_name (v));
1975           warned = true;
1976           continue;
1977         }
1978
1979       var_set_measure (v, (measure == 1 ? MEASURE_NOMINAL
1980                            : measure == 2 ? MEASURE_ORDINAL
1981                            : MEASURE_SCALE));
1982       var_set_alignment (v, (align == 0 ? ALIGN_LEFT
1983                              : align == 1 ? ALIGN_RIGHT
1984                              : ALIGN_CENTRE));
1985
1986       /* Older versions (SPSS 9.0) sometimes set the display
1987          width to zero.  This causes confusion in the GUI, so
1988          only set the width if it is nonzero. */
1989       if (width > 0)
1990         var_set_display_width (v, width);
1991     }
1992 }
1993
1994 static void
1995 rename_var_and_save_short_names (struct dictionary *dict, struct variable *var,
1996                                  const char *new_name)
1997 {
1998   size_t n_short_names;
1999   char **short_names;
2000   size_t i;
2001
2002   /* Renaming a variable may clear its short names, but we
2003      want to retain them, so we save them and re-set them
2004      afterward. */
2005   n_short_names = var_get_short_name_cnt (var);
2006   short_names = xnmalloc (n_short_names, sizeof *short_names);
2007   for (i = 0; i < n_short_names; i++)
2008     {
2009       const char *s = var_get_short_name (var, i);
2010       short_names[i] = s != NULL ? xstrdup (s) : NULL;
2011     }
2012
2013   /* Set long name. */
2014   dict_rename_var (dict, var, new_name);
2015
2016   /* Restore short names. */
2017   for (i = 0; i < n_short_names; i++)
2018     {
2019       var_set_short_name (var, i, short_names[i]);
2020       free (short_names[i]);
2021     }
2022   free (short_names);
2023 }
2024
2025 /* Parses record type 7, subtype 13, which gives the long name that corresponds
2026    to each short name.  Modifies variable names in DICT accordingly.  */
2027 static void
2028 parse_long_var_name_map (struct sfm_reader *r,
2029                          const struct sfm_extension_record *record,
2030                          struct dictionary *dict)
2031 {
2032   struct text_record *text;
2033   struct variable *var;
2034   char *long_name;
2035
2036   if (record == NULL)
2037     {
2038       /* There are no long variable names.  Use the short variable names,
2039          converted to lowercase, as the long variable names. */
2040       size_t i;
2041
2042       for (i = 0; i < dict_get_var_cnt (dict); i++)
2043         {
2044           struct variable *var = dict_get_var (dict, i);
2045           char *new_name;
2046
2047           new_name = utf8_to_lower (var_get_name (var));
2048           rename_var_and_save_short_names (dict, var, new_name);
2049           free (new_name);
2050         }
2051
2052       return;
2053     }
2054
2055   /* Rename each of the variables, one by one.  (In a correctly constructed
2056      system file, this cannot create any intermediate duplicate variable names,
2057      because all of the new variable names are longer than any of the old
2058      variable names and thus there cannot be any overlaps.) */
2059   text = open_text_record (r, record, true);
2060   while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
2061     {
2062       /* Validate long name. */
2063       if (!dict_id_is_valid (dict, long_name, false)
2064           || long_name[0] == '$' || long_name[0] == '#')
2065         {
2066           sys_warn (r, record->pos,
2067                     _("Long variable mapping from %s to invalid "
2068                       "variable name `%s'."),
2069                     var_get_name (var), long_name);
2070           continue;
2071         }
2072
2073       /* Identify any duplicates. */
2074       if (utf8_strcasecmp (var_get_short_name (var, 0), long_name)
2075           && dict_lookup_var (dict, long_name) != NULL)
2076         {
2077           sys_warn (r, record->pos,
2078                     _("Duplicate long variable name `%s'."), long_name);
2079           continue;
2080         }
2081
2082       rename_var_and_save_short_names (dict, var, long_name);
2083     }
2084   close_text_record (r, text);
2085 }
2086
2087 /* Reads record type 7, subtype 14, which gives the real length
2088    of each very long string.  Rearranges DICT accordingly. */
2089 static bool
2090 parse_long_string_map (struct sfm_reader *r,
2091                        const struct sfm_extension_record *record,
2092                        struct dictionary *dict)
2093 {
2094   struct text_record *text;
2095   struct variable *var;
2096   char *length_s;
2097
2098   text = open_text_record (r, record, true);
2099   while (read_variable_to_value_pair (r, dict, text, &var, &length_s))
2100     {
2101       size_t idx = var_get_dict_index (var);
2102       long int length;
2103       int segment_cnt;
2104       int i;
2105
2106       /* Get length. */
2107       length = strtol (length_s, NULL, 10);
2108       if (length < 1 || length > MAX_STRING)
2109         {
2110           sys_warn (r, record->pos,
2111                     _("%s listed as string of invalid length %s "
2112                       "in very long string record."),
2113                     var_get_name (var), length_s);
2114           continue;
2115         }
2116
2117       /* Check segments. */
2118       segment_cnt = sfm_width_to_segments (length);
2119       if (segment_cnt == 1)
2120         {
2121           sys_warn (r, record->pos,
2122                     _("%s listed in very long string record with width %s, "
2123                       "which requires only one segment."),
2124                     var_get_name (var), length_s);
2125           continue;
2126         }
2127       if (idx + segment_cnt > dict_get_var_cnt (dict))
2128         {
2129           sys_error (r, record->pos,
2130                      _("Very long string %s overflows dictionary."),
2131                      var_get_name (var));
2132           return false;
2133         }
2134
2135       /* Get the short names from the segments and check their
2136          lengths. */
2137       for (i = 0; i < segment_cnt; i++)
2138         {
2139           struct variable *seg = dict_get_var (dict, idx + i);
2140           int alloc_width = sfm_segment_alloc_width (length, i);
2141           int width = var_get_width (seg);
2142
2143           if (i > 0)
2144             var_set_short_name (var, i, var_get_short_name (seg, 0));
2145           if (ROUND_UP (width, 8) != ROUND_UP (alloc_width, 8))
2146             {
2147               sys_error (r, record->pos,
2148                          _("Very long string with width %ld has segment %d "
2149                            "of width %d (expected %d)."),
2150                          length, i, width, alloc_width);
2151               return false;
2152             }
2153         }
2154       dict_delete_consecutive_vars (dict, idx + 1, segment_cnt - 1);
2155       var_set_width (var, length);
2156     }
2157   close_text_record (r, text);
2158   dict_compact_values (dict);
2159
2160   return true;
2161 }
2162
2163 static bool
2164 parse_value_labels (struct sfm_reader *r, struct dictionary *dict,
2165                     const struct sfm_var_record *var_recs, size_t n_var_recs,
2166                     const struct sfm_value_label_record *record)
2167 {
2168   struct variable **vars;
2169   char **utf8_labels;
2170   size_t i;
2171
2172   utf8_labels = pool_nmalloc (r->pool, record->n_labels, sizeof *utf8_labels);
2173   for (i = 0; i < record->n_labels; i++)
2174     utf8_labels[i] = recode_string_pool ("UTF-8", dict_get_encoding (dict),
2175                                          record->labels[i].label, -1,
2176                                          r->pool);
2177
2178   vars = pool_nmalloc (r->pool, record->n_vars, sizeof *vars);
2179   for (i = 0; i < record->n_vars; i++)
2180     {
2181       vars[i] = lookup_var_by_index (r, record->pos,
2182                                      var_recs, n_var_recs, record->vars[i]);
2183       if (vars[i] == NULL)
2184         return false;
2185     }
2186
2187   for (i = 1; i < record->n_vars; i++)
2188     if (var_get_type (vars[i]) != var_get_type (vars[0]))
2189       {
2190         sys_error (r, record->pos,
2191                    _("Variables associated with value label are not all of "
2192                      "identical type.  Variable %s is %s, but variable "
2193                      "%s is %s."),
2194                    var_get_name (vars[0]),
2195                    var_is_numeric (vars[0]) ? _("numeric") : _("string"),
2196                    var_get_name (vars[i]),
2197                    var_is_numeric (vars[i]) ? _("numeric") : _("string"));
2198         return false;
2199       }
2200
2201   for (i = 0; i < record->n_vars; i++)
2202     {
2203       struct variable *var = vars[i];
2204       int width;
2205       size_t j;
2206
2207       width = var_get_width (var);
2208       if (width > 8)
2209         {
2210           sys_error (r, record->pos,
2211                      _("Value labels may not be added to long string "
2212                        "variables (e.g. %s) using records types 3 and 4."),
2213                      var_get_name (var));
2214           return false;
2215         }
2216
2217       for (j = 0; j < record->n_labels; j++)
2218         {
2219           struct sfm_value_label *label = &record->labels[j];
2220           union value value;
2221
2222           value_init (&value, width);
2223           if (width == 0)
2224             value.f = parse_float (r, label->value, 0);
2225           else
2226             memcpy (value_str_rw (&value, width), label->value, width);
2227
2228           if (!var_add_value_label (var, &value, utf8_labels[j]))
2229             {
2230               if (var_is_numeric (var))
2231                 sys_warn (r, record->pos,
2232                           _("Duplicate value label for %g on %s."),
2233                           value.f, var_get_name (var));
2234               else
2235                 sys_warn (r, record->pos,
2236                           _("Duplicate value label for `%.*s' on %s."),
2237                           width, value_str (&value, width),
2238                           var_get_name (var));
2239             }
2240
2241           value_destroy (&value, width);
2242         }
2243     }
2244
2245   pool_free (r->pool, vars);
2246   for (i = 0; i < record->n_labels; i++)
2247     pool_free (r->pool, utf8_labels[i]);
2248   pool_free (r->pool, utf8_labels);
2249
2250   return true;
2251 }
2252
2253 static struct variable *
2254 lookup_var_by_index (struct sfm_reader *r, off_t offset,
2255                      const struct sfm_var_record *var_recs, size_t n_var_recs,
2256                      int idx)
2257 {
2258   const struct sfm_var_record *rec;
2259
2260   if (idx < 1 || idx > n_var_recs)
2261     {
2262       sys_error (r, offset,
2263                  _("Variable index %d not in valid range 1...%zu."),
2264                  idx, n_var_recs);
2265       return NULL;
2266     }
2267
2268   rec = &var_recs[idx - 1];
2269   if (rec->var == NULL)
2270     {
2271       sys_error (r, offset,
2272                  _("Variable index %d refers to long string continuation."),
2273                  idx);
2274       return NULL;
2275     }
2276
2277   return rec->var;
2278 }
2279
2280 /* Parses a set of custom attributes from TEXT into ATTRS.
2281    ATTRS may be a null pointer, in which case the attributes are
2282    read but discarded. */
2283 static void
2284 parse_attributes (struct sfm_reader *r, struct text_record *text,
2285                   struct attrset *attrs)
2286 {
2287   do
2288     {
2289       struct attribute *attr;
2290       char *key;
2291       int index;
2292
2293       /* Parse the key. */
2294       key = text_get_token (text, ss_cstr ("("), NULL);
2295       if (key == NULL)
2296         return;
2297
2298       attr = attribute_create (key);
2299       for (index = 1; ; index++)
2300         {
2301           /* Parse the value. */
2302           char *value;
2303           size_t length;
2304
2305           value = text_get_token (text, ss_cstr ("\n"), NULL);
2306           if (value == NULL)
2307             {
2308               text_warn (r, text, _("Error parsing attribute value %s[%d]."),
2309                          key, index);
2310               break;
2311             }
2312
2313           length = strlen (value);
2314           if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'')
2315             {
2316               value[length - 1] = '\0';
2317               attribute_add_value (attr, value + 1);
2318             }
2319           else
2320             {
2321               text_warn (r, text,
2322                          _("Attribute value %s[%d] is not quoted: %s."),
2323                          key, index, value);
2324               attribute_add_value (attr, value);
2325             }
2326
2327           /* Was this the last value for this attribute? */
2328           if (text_match (text, ')'))
2329             break;
2330         }
2331       if (attrs != NULL)
2332         attrset_add (attrs, attr);
2333       else
2334         attribute_destroy (attr);
2335     }
2336   while (!text_match (text, '/'));
2337 }
2338
2339 /* Reads record type 7, subtype 17, which lists custom
2340    attributes on the data file.  */
2341 static void
2342 parse_data_file_attributes (struct sfm_reader *r,
2343                             const struct sfm_extension_record *record,
2344                             struct dictionary *dict)
2345 {
2346   struct text_record *text = open_text_record (r, record, true);
2347   parse_attributes (r, text, dict_get_attributes (dict));
2348   close_text_record (r, text);
2349 }
2350
2351 /* Parses record type 7, subtype 18, which lists custom
2352    attributes on individual variables.  */
2353 static void
2354 parse_variable_attributes (struct sfm_reader *r,
2355                            const struct sfm_extension_record *record,
2356                            struct dictionary *dict)
2357 {
2358   struct text_record *text;
2359   struct variable *var;
2360
2361   text = open_text_record (r, record, true);
2362   while (text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
2363     parse_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
2364   close_text_record (r, text);
2365 }
2366
2367 static void
2368 assign_variable_roles (struct sfm_reader *r, struct dictionary *dict)
2369 {
2370   size_t n_warnings = 0;
2371   size_t i;
2372
2373   for (i = 0; i < dict_get_var_cnt (dict); i++)
2374     {
2375       struct variable *var = dict_get_var (dict, i);
2376       struct attrset *attrs = var_get_attributes (var);
2377       const struct attribute *attr = attrset_lookup (attrs, "$@Role");
2378       if (attr != NULL)
2379         {
2380           int value = atoi (attribute_get_value (attr, 0));
2381           enum var_role role;
2382
2383           switch (value)
2384             {
2385             case 0:
2386               role = ROLE_INPUT;
2387               break;
2388
2389             case 1:
2390               role = ROLE_TARGET;
2391               break;
2392
2393             case 2:
2394               role = ROLE_BOTH;
2395               break;
2396
2397             case 3:
2398               role = ROLE_NONE;
2399               break;
2400
2401             case 4:
2402               role = ROLE_PARTITION;
2403               break;
2404
2405             case 5:
2406               role = ROLE_SPLIT;
2407               break;
2408
2409             default:
2410               role = ROLE_INPUT;
2411               if (n_warnings++ == 0)
2412                 sys_warn (r, -1, _("Invalid role for variable %s."),
2413                           var_get_name (var));
2414             }
2415
2416           var_set_role (var, role);
2417         }
2418     }
2419
2420   if (n_warnings > 1)
2421     sys_warn (r, -1, _("%zu other variables had invalid roles."),
2422               n_warnings - 1);
2423 }
2424
2425 static bool
2426 check_overflow (struct sfm_reader *r,
2427                 const struct sfm_extension_record *record,
2428                 size_t ofs, size_t length)
2429 {
2430   size_t end = record->size * record->count;
2431   if (length >= end || ofs + length > end)
2432     {
2433       sys_warn (r, record->pos + end,
2434                 _("Extension record subtype %d ends unexpectedly."),
2435                 record->subtype);
2436       return false;
2437     }
2438   return true;
2439 }
2440
2441 static void
2442 parse_long_string_value_labels (struct sfm_reader *r,
2443                                 const struct sfm_extension_record *record,
2444                                 struct dictionary *dict)
2445 {
2446   const char *dict_encoding = dict_get_encoding (dict);
2447   size_t end = record->size * record->count;
2448   size_t ofs = 0;
2449
2450   while (ofs < end)
2451     {
2452       char *var_name;
2453       size_t n_labels, i;
2454       struct variable *var;
2455       union value value;
2456       int var_name_len;
2457       int width;
2458
2459       /* Parse variable name length. */
2460       if (!check_overflow (r, record, ofs, 4))
2461         return;
2462       var_name_len = parse_int (r, record->data, ofs);
2463       ofs += 4;
2464
2465       /* Parse variable name, width, and number of labels. */
2466       if (!check_overflow (r, record, ofs, var_name_len)
2467           || !check_overflow (r, record, ofs, var_name_len + 8))
2468         return;
2469       var_name = recode_string_pool ("UTF-8", dict_encoding,
2470                                      (const char *) record->data + ofs,
2471                                      var_name_len, r->pool);
2472       width = parse_int (r, record->data, ofs + var_name_len);
2473       n_labels = parse_int (r, record->data, ofs + var_name_len + 4);
2474       ofs += var_name_len + 8;
2475
2476       /* Look up 'var' and validate. */
2477       var = dict_lookup_var (dict, var_name);
2478       if (var == NULL)
2479         sys_warn (r, record->pos + ofs,
2480                   _("Ignoring long string value label record for "
2481                     "unknown variable %s."), var_name);
2482       else if (var_is_numeric (var))
2483         {
2484           sys_warn (r, record->pos + ofs,
2485                     _("Ignoring long string value label record for "
2486                       "numeric variable %s."), var_name);
2487           var = NULL;
2488         }
2489       else if (width != var_get_width (var))
2490         {
2491           sys_warn (r, record->pos + ofs,
2492                     _("Ignoring long string value label record for variable "
2493                       "%s because the record's width (%d) does not match the "
2494                       "variable's width (%d)."),
2495                     var_name, width, var_get_width (var));
2496           var = NULL;
2497         }
2498
2499       /* Parse values. */
2500       value_init_pool (r->pool, &value, width);
2501       for (i = 0; i < n_labels; i++)
2502         {
2503           size_t value_length, label_length;
2504           bool skip = var == NULL;
2505
2506           /* Parse value length. */
2507           if (!check_overflow (r, record, ofs, 4))
2508             return;
2509           value_length = parse_int (r, record->data, ofs);
2510           ofs += 4;
2511
2512           /* Parse value. */
2513           if (!check_overflow (r, record, ofs, value_length))
2514             return;
2515           if (!skip)
2516             {
2517               if (value_length == width)
2518                 memcpy (value_str_rw (&value, width),
2519                         (const uint8_t *) record->data + ofs, width);
2520               else
2521                 {
2522                   sys_warn (r, record->pos + ofs,
2523                             _("Ignoring long string value label %zu for "
2524                               "variable %s, with width %d, that has bad value "
2525                               "width %zu."),
2526                             i, var_get_name (var), width, value_length);
2527                   skip = true;
2528                 }
2529             }
2530           ofs += value_length;
2531
2532           /* Parse label length. */
2533           if (!check_overflow (r, record, ofs, 4))
2534             return;
2535           label_length = parse_int (r, record->data, ofs);
2536           ofs += 4;
2537
2538           /* Parse label. */
2539           if (!check_overflow (r, record, ofs, label_length))
2540             return;
2541           if (!skip)
2542             {
2543               char *label;
2544
2545               label = recode_string_pool ("UTF-8", dict_encoding,
2546                                           (const char *) record->data + ofs,
2547                                           label_length, r->pool);
2548               if (!var_add_value_label (var, &value, label))
2549                 sys_warn (r, record->pos + ofs,
2550                           _("Duplicate value label for `%.*s' on %s."),
2551                           width, value_str (&value, width),
2552                           var_get_name (var));
2553               pool_free (r->pool, label);
2554             }
2555           ofs += label_length;
2556         }
2557     }
2558 }
2559
2560 static void
2561 parse_long_string_missing_values (struct sfm_reader *r,
2562                                   const struct sfm_extension_record *record,
2563                                   struct dictionary *dict)
2564 {
2565   const char *dict_encoding = dict_get_encoding (dict);
2566   size_t end = record->size * record->count;
2567   size_t ofs = 0;
2568
2569   while (ofs < end)
2570     {
2571       struct missing_values mv;
2572       char *var_name;
2573       struct variable *var;
2574       int n_missing_values;
2575       int var_name_len;
2576       size_t i;
2577
2578       /* Parse variable name length. */
2579       if (!check_overflow (r, record, ofs, 4))
2580         return;
2581       var_name_len = parse_int (r, record->data, ofs);
2582       ofs += 4;
2583
2584       /* Parse variable name. */
2585       if (!check_overflow (r, record, ofs, var_name_len)
2586           || !check_overflow (r, record, ofs, var_name_len + 1))
2587         return;
2588       var_name = recode_string_pool ("UTF-8", dict_encoding,
2589                                      (const char *) record->data + ofs,
2590                                      var_name_len, r->pool);
2591       ofs += var_name_len;
2592
2593       /* Parse number of missing values. */
2594       n_missing_values = ((const uint8_t *) record->data)[ofs];
2595       if (n_missing_values < 1 || n_missing_values > 3)
2596         sys_warn (r, record->pos + ofs,
2597                   _("Long string missing values record says variable %s "
2598                     "has %d missing values, but only 1 to 3 missing values "
2599                     "are allowed."),
2600                   var_name, n_missing_values);
2601       ofs++;
2602
2603       /* Look up 'var' and validate. */
2604       var = dict_lookup_var (dict, var_name);
2605       if (var == NULL)
2606         sys_warn (r, record->pos + ofs,
2607                   _("Ignoring long string missing value record for "
2608                     "unknown variable %s."), var_name);
2609       else if (var_is_numeric (var))
2610         {
2611           sys_warn (r, record->pos + ofs,
2612                     _("Ignoring long string missing value record for "
2613                       "numeric variable %s."), var_name);
2614           var = NULL;
2615         }
2616
2617       /* Parse values. */
2618       mv_init_pool (r->pool, &mv, var ? var_get_width (var) : 8);
2619       for (i = 0; i < n_missing_values; i++)
2620         {
2621           size_t value_length;
2622
2623           /* Parse value length. */
2624           if (!check_overflow (r, record, ofs, 4))
2625             return;
2626           value_length = parse_int (r, record->data, ofs);
2627           ofs += 4;
2628
2629           /* Parse value. */
2630           if (!check_overflow (r, record, ofs, value_length))
2631             return;
2632           if (var != NULL
2633               && i < 3
2634               && !mv_add_str (&mv, (const uint8_t *) record->data + ofs,
2635                               value_length))
2636             sys_warn (r, record->pos + ofs,
2637                       _("Ignoring long string missing value %zu for variable "
2638                         "%s, with width %d, that has bad value width %zu."),
2639                       i, var_get_name (var), var_get_width (var),
2640                       value_length);
2641           ofs += value_length;
2642         }
2643       if (var != NULL)
2644         var_set_missing_values (var, &mv);
2645     }
2646 }
2647 \f
2648 /* Case reader. */
2649
2650 static void partial_record (struct sfm_reader *);
2651
2652 static void read_error (struct casereader *, const struct sfm_reader *);
2653
2654 static bool read_case_number (struct sfm_reader *, double *);
2655 static int read_case_string (struct sfm_reader *, uint8_t *, size_t);
2656 static int read_opcode (struct sfm_reader *);
2657 static bool read_compressed_number (struct sfm_reader *, double *);
2658 static int read_compressed_string (struct sfm_reader *, uint8_t *);
2659 static int read_whole_strings (struct sfm_reader *, uint8_t *, size_t);
2660 static bool skip_whole_strings (struct sfm_reader *, size_t);
2661
2662 /* Reads and returns one case from READER's file.  Returns a null
2663    pointer if not successful. */
2664 static struct ccase *
2665 sys_file_casereader_read (struct casereader *reader, void *r_)
2666 {
2667   struct sfm_reader *r = r_;
2668   struct ccase *c;
2669   int retval;
2670   int i;
2671
2672   if (r->error || !r->sfm_var_cnt)
2673     return NULL;
2674
2675   c = case_create (r->proto);
2676
2677   for (i = 0; i < r->sfm_var_cnt; i++)
2678     {
2679       struct sfm_var *sv = &r->sfm_vars[i];
2680       union value *v = case_data_rw_idx (c, sv->case_index);
2681
2682       if (sv->var_width == 0)
2683         retval = read_case_number (r, &v->f);
2684       else
2685         {
2686           uint8_t *s = value_str_rw (v, sv->var_width);
2687           retval = read_case_string (r, s + sv->offset, sv->segment_width);
2688           if (retval == 1)
2689             {
2690               retval = skip_whole_strings (r, ROUND_DOWN (sv->padding, 8));
2691               if (retval == 0)
2692                 sys_error (r, r->pos, _("File ends in partial string value."));
2693             }
2694         }
2695
2696       if (retval != 1)
2697         goto eof;
2698     }
2699   return c;
2700
2701 eof:
2702   if (i != 0)
2703     partial_record (r);
2704   if (r->case_cnt != -1)
2705     read_error (reader, r);
2706   case_unref (c);
2707   return NULL;
2708 }
2709
2710 /* Issues an error that R ends in a partial record. */
2711 static void
2712 partial_record (struct sfm_reader *r)
2713 {
2714   sys_error (r, r->pos, _("File ends in partial case."));
2715 }
2716
2717 /* Issues an error that an unspecified error occurred SFM, and
2718    marks R tainted. */
2719 static void
2720 read_error (struct casereader *r, const struct sfm_reader *sfm)
2721 {
2722   msg (ME, _("Error reading case from file %s."), fh_get_name (sfm->fh));
2723   casereader_force_error (r);
2724 }
2725
2726 /* Reads a number from R and stores its value in *D.
2727    If R is compressed, reads a compressed number;
2728    otherwise, reads a number in the regular way.
2729    Returns true if successful, false if end of file is
2730    reached immediately. */
2731 static bool
2732 read_case_number (struct sfm_reader *r, double *d)
2733 {
2734   if (r->compression == ANY_COMP_NONE)
2735     {
2736       uint8_t number[8];
2737       if (!try_read_bytes (r, number, sizeof number))
2738         return false;
2739       float_convert (r->float_format, number, FLOAT_NATIVE_DOUBLE, d);
2740       return true;
2741     }
2742   else
2743     return read_compressed_number (r, d);
2744 }
2745
2746 /* Reads LENGTH string bytes from R into S.  Always reads a multiple of 8
2747    bytes; if LENGTH is not a multiple of 8, then extra bytes are read and
2748    discarded without being written to S.  Reads compressed strings if S is
2749    compressed.  Returns 1 if successful, 0 if end of file is reached
2750    immediately, or -1 for some kind of error. */
2751 static int
2752 read_case_string (struct sfm_reader *r, uint8_t *s, size_t length)
2753 {
2754   size_t whole = ROUND_DOWN (length, 8);
2755   size_t partial = length % 8;
2756
2757   if (whole)
2758     {
2759       int retval = read_whole_strings (r, s, whole);
2760       if (retval != 1)
2761         return retval;
2762     }
2763
2764   if (partial)
2765     {
2766       uint8_t bounce[8];
2767       int retval = read_whole_strings (r, bounce, sizeof bounce);
2768       if (retval == -1)
2769         return -1;
2770       else if (!retval)
2771         {
2772           if (whole)
2773             {
2774               partial_record (r);
2775               return -1;
2776             }
2777           return 0;
2778         }
2779       memcpy (s + whole, bounce, partial);
2780     }
2781
2782   return 1;
2783 }
2784
2785 /* Reads and returns the next compression opcode from R. */
2786 static int
2787 read_opcode (struct sfm_reader *r)
2788 {
2789   assert (r->compression != ANY_COMP_NONE);
2790   for (;;)
2791     {
2792       int opcode;
2793       if (r->opcode_idx >= sizeof r->opcodes)
2794         {
2795
2796           int retval = try_read_compressed_bytes (r, r->opcodes,
2797                                                   sizeof r->opcodes);
2798           if (retval != 1)
2799             return -1;
2800           r->opcode_idx = 0;
2801         }
2802       opcode = r->opcodes[r->opcode_idx++];
2803
2804       if (opcode != 0)
2805         return opcode;
2806     }
2807 }
2808
2809 /* Reads a compressed number from R and stores its value in D.
2810    Returns true if successful, false if end of file is
2811    reached immediately. */
2812 static bool
2813 read_compressed_number (struct sfm_reader *r, double *d)
2814 {
2815   int opcode = read_opcode (r);
2816   switch (opcode)
2817     {
2818     case -1:
2819     case 252:
2820       return false;
2821
2822     case 253:
2823       return read_compressed_float (r, d);
2824
2825     case 254:
2826       float_convert (r->float_format, "        ", FLOAT_NATIVE_DOUBLE, d);
2827       if (!r->corruption_warning)
2828         {
2829           r->corruption_warning = true;
2830           sys_warn (r, r->pos,
2831                     _("Possible compressed data corruption: "
2832                       "compressed spaces appear in numeric field."));
2833         }
2834       break;
2835
2836     case 255:
2837       *d = SYSMIS;
2838       break;
2839
2840     default:
2841       *d = opcode - r->bias;
2842       break;
2843     }
2844
2845   return true;
2846 }
2847
2848 /* Reads a compressed 8-byte string segment from R and stores it in DST. */
2849 static int
2850 read_compressed_string (struct sfm_reader *r, uint8_t *dst)
2851 {
2852   int opcode;
2853   int retval;
2854
2855   opcode = read_opcode (r);
2856   switch (opcode)
2857     {
2858     case -1:
2859     case 252:
2860       return 0;
2861
2862     case 253:
2863       retval = read_compressed_bytes (r, dst, 8);
2864       return retval == 1 ? 1 : -1;
2865
2866     case 254:
2867       memset (dst, ' ', 8);
2868       return 1;
2869
2870     default:
2871       {
2872         double value = opcode - r->bias;
2873         float_convert (FLOAT_NATIVE_DOUBLE, &value, r->float_format, dst);
2874         if (value == 0.0)
2875           {
2876             /* This has actually been seen "in the wild".  The submitter of the
2877                file that showed that the contents decoded as spaces, but they
2878                were at the end of the field so it's possible that the null
2879                bytes just acted as null terminators. */
2880           }
2881         else if (!r->corruption_warning)
2882           {
2883             r->corruption_warning = true;
2884             sys_warn (r, r->pos,
2885                       _("Possible compressed data corruption: "
2886                         "string contains compressed integer (opcode %d)."),
2887                       opcode);
2888           }
2889       }
2890       return 1;
2891     }
2892 }
2893
2894 /* Reads LENGTH string bytes from R into S.  LENGTH must be a multiple of 8.
2895    Reads compressed strings if S is compressed.  Returns 1 if successful, 0 if
2896    end of file is reached immediately, or -1 for some kind of error. */
2897 static int
2898 read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length)
2899 {
2900   assert (length % 8 == 0);
2901   if (r->compression == ANY_COMP_NONE)
2902     return try_read_bytes (r, s, length);
2903   else
2904     {
2905       size_t ofs;
2906
2907       for (ofs = 0; ofs < length; ofs += 8)
2908         {
2909           int retval = read_compressed_string (r, s + ofs);
2910           if (retval != 1)
2911             {
2912               if (ofs != 0)
2913                 {
2914                   partial_record (r);
2915                   return -1;
2916                 }
2917               return retval;
2918             }
2919           }
2920       return 1;
2921     }
2922 }
2923
2924 /* Skips LENGTH string bytes from R.
2925    LENGTH must be a multiple of 8.
2926    (LENGTH is also limited to 1024, but that's only because the
2927    current caller never needs more than that many bytes.)
2928    Returns true if successful, false if end of file is
2929    reached immediately. */
2930 static bool
2931 skip_whole_strings (struct sfm_reader *r, size_t length)
2932 {
2933   uint8_t buffer[1024];
2934   assert (length < sizeof buffer);
2935   return read_whole_strings (r, buffer, length);
2936 }
2937 \f
2938 /* Helpers for reading records that contain structured text
2939    strings. */
2940
2941 /* Maximum number of warnings to issue for a single text
2942    record. */
2943 #define MAX_TEXT_WARNINGS 5
2944
2945 /* State. */
2946 struct text_record
2947   {
2948     struct substring buffer;    /* Record contents. */
2949     off_t start;                /* Starting offset in file. */
2950     size_t pos;                 /* Current position in buffer. */
2951     int n_warnings;             /* Number of warnings issued or suppressed. */
2952     bool recoded;               /* Recoded into UTF-8? */
2953   };
2954
2955 static struct text_record *
2956 open_text_record (struct sfm_reader *r,
2957                   const struct sfm_extension_record *record,
2958                   bool recode_to_utf8)
2959 {
2960   struct text_record *text;
2961   struct substring raw;
2962
2963   text = pool_alloc (r->pool, sizeof *text);
2964   raw = ss_buffer (record->data, record->size * record->count);
2965   text->start = record->pos;
2966   text->buffer = (recode_to_utf8
2967                   ? recode_substring_pool ("UTF-8", r->encoding, raw, r->pool)
2968                   : raw);
2969   text->pos = 0;
2970   text->n_warnings = 0;
2971   text->recoded = recode_to_utf8;
2972
2973   return text;
2974 }
2975
2976 /* Closes TEXT, frees its storage, and issues a final warning
2977    about suppressed warnings if necesary. */
2978 static void
2979 close_text_record (struct sfm_reader *r, struct text_record *text)
2980 {
2981   if (text->n_warnings > MAX_TEXT_WARNINGS)
2982     sys_warn (r, -1, _("Suppressed %d additional related warnings."),
2983               text->n_warnings - MAX_TEXT_WARNINGS);
2984   if (text->recoded)
2985     pool_free (r->pool, ss_data (text->buffer));
2986 }
2987
2988 /* Reads a variable=value pair from TEXT.
2989    Looks up the variable in DICT and stores it into *VAR.
2990    Stores a null-terminated value into *VALUE. */
2991 static bool
2992 read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict,
2993                              struct text_record *text,
2994                              struct variable **var, char **value)
2995 {
2996   for (;;)
2997     {
2998       if (!text_read_short_name (r, dict, text, ss_cstr ("="), var))
2999         return false;
3000
3001       *value = text_get_token (text, ss_buffer ("\t\0", 2), NULL);
3002       if (*value == NULL)
3003         return false;
3004
3005       text->pos += ss_span (ss_substr (text->buffer, text->pos, SIZE_MAX),
3006                             ss_buffer ("\t\0", 2));
3007
3008       if (*var != NULL)
3009         return true;
3010     }
3011 }
3012
3013 static bool
3014 text_read_variable_name (struct sfm_reader *r, struct dictionary *dict,
3015                          struct text_record *text, struct substring delimiters,
3016                          struct variable **var)
3017 {
3018   char *name;
3019
3020   name = text_get_token (text, delimiters, NULL);
3021   if (name == NULL)
3022     return false;
3023
3024   *var = dict_lookup_var (dict, name);
3025   if (*var != NULL)
3026     return true;
3027
3028   text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
3029              name);
3030   return false;
3031 }
3032
3033
3034 static bool
3035 text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
3036                       struct text_record *text, struct substring delimiters,
3037                       struct variable **var)
3038 {
3039   char *short_name = text_get_token (text, delimiters, NULL);
3040   if (short_name == NULL)
3041     return false;
3042
3043   *var = dict_lookup_var (dict, short_name);
3044   if (*var == NULL)
3045     text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
3046                short_name);
3047   return true;
3048 }
3049
3050 /* Displays a warning for the current file position, limiting the
3051    number to MAX_TEXT_WARNINGS for TEXT. */
3052 static void
3053 text_warn (struct sfm_reader *r, struct text_record *text,
3054            const char *format, ...)
3055 {
3056   if (text->n_warnings++ < MAX_TEXT_WARNINGS)
3057     {
3058       va_list args;
3059
3060       va_start (args, format);
3061       sys_msg (r, text->start + text->pos, MW, format, args);
3062       va_end (args);
3063     }
3064 }
3065
3066 static char *
3067 text_get_token (struct text_record *text, struct substring delimiters,
3068                 char *delimiter)
3069 {
3070   struct substring token;
3071   char *end;
3072
3073   if (!ss_tokenize (text->buffer, delimiters, &text->pos, &token))
3074     return NULL;
3075
3076   end = &ss_data (token)[ss_length (token)];
3077   if (delimiter != NULL)
3078     *delimiter = *end;
3079   *end = '\0';
3080   return ss_data (token);
3081 }
3082
3083 /* Reads a integer value expressed in decimal, then a space, then a string that
3084    consists of exactly as many bytes as specified by the integer, then a space,
3085    from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
3086    buffer (so the caller should not free the string). */
3087 static const char *
3088 text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
3089 {
3090   size_t start;
3091   size_t n;
3092   char *s;
3093
3094   start = text->pos;
3095   n = 0;
3096   while (text->pos < text->buffer.length)
3097     {
3098       int c = text->buffer.string[text->pos];
3099       if (c < '0' || c > '9')
3100         break;
3101       n = (n * 10) + (c - '0');
3102       text->pos++;
3103     }
3104   if (text->pos >= text->buffer.length || start == text->pos)
3105     {
3106       sys_warn (r, text->start,
3107                 _("Expecting digit at offset %zu in MRSETS record."),
3108                 text->pos);
3109       return NULL;
3110     }
3111
3112   if (!text_match (text, ' '))
3113     {
3114       sys_warn (r, text->start,
3115                 _("Expecting space at offset %zu in MRSETS record."),
3116                 text->pos);
3117       return NULL;
3118     }
3119
3120   if (text->pos + n > text->buffer.length)
3121     {
3122       sys_warn (r, text->start,
3123                 _("%zu-byte string starting at offset %zu "
3124                   "exceeds record length %zu."),
3125                 n, text->pos, text->buffer.length);
3126       return NULL;
3127     }
3128
3129   s = &text->buffer.string[text->pos];
3130   if (s[n] != ' ')
3131     {
3132       sys_warn (r, text->start,
3133                 _("Expecting space at offset %zu following %zu-byte string."),
3134                 text->pos + n, n);
3135       return NULL;
3136     }
3137   s[n] = '\0';
3138   text->pos += n + 1;
3139   return s;
3140 }
3141
3142 static bool
3143 text_match (struct text_record *text, char c)
3144 {
3145   if (text->pos >= text->buffer.length)
3146     return false;
3147
3148   if (text->buffer.string[text->pos] == c)
3149     {
3150       text->pos++;
3151       return true;
3152     }
3153   else
3154     return false;
3155 }
3156
3157 /* Returns the current byte offset (as converted to UTF-8, if it was converted)
3158    inside the TEXT's string. */
3159 static size_t
3160 text_pos (const struct text_record *text)
3161 {
3162   return text->pos;
3163 }
3164
3165 static const char *
3166 text_get_all (const struct text_record *text)
3167 {
3168   return text->buffer.string;
3169 }
3170 \f
3171 /* Messages. */
3172
3173 /* Displays a corruption message. */
3174 static void
3175 sys_msg (struct sfm_reader *r, off_t offset,
3176          int class, const char *format, va_list args)
3177 {
3178   struct msg m;
3179   struct string text;
3180
3181   ds_init_empty (&text);
3182   if (offset >= 0)
3183     ds_put_format (&text, _("`%s' near offset 0x%llx: "),
3184                    fh_get_file_name (r->fh), (long long int) offset);
3185   else
3186     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
3187   ds_put_vformat (&text, format, args);
3188
3189   m.category = msg_class_to_category (class);
3190   m.severity = msg_class_to_severity (class);
3191   m.file_name = NULL;
3192   m.first_line = 0;
3193   m.last_line = 0;
3194   m.first_column = 0;
3195   m.last_column = 0;
3196   m.text = ds_cstr (&text);
3197
3198   msg_emit (&m);
3199 }
3200
3201 /* Displays a warning for offset OFFSET in the file. */
3202 static void
3203 sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...)
3204 {
3205   va_list args;
3206
3207   va_start (args, format);
3208   sys_msg (r, offset, MW, format, args);
3209   va_end (args);
3210 }
3211
3212 /* Displays an error for the current file position and marks it as in an error
3213    state. */
3214 static void
3215 sys_error (struct sfm_reader *r, off_t offset, const char *format, ...)
3216 {
3217   va_list args;
3218
3219   va_start (args, format);
3220   sys_msg (r, offset, ME, format, args);
3221   va_end (args);
3222
3223   r->error = true;
3224 }
3225 \f
3226 /* Reads BYTE_CNT bytes into BUF.
3227    Returns 1 if exactly BYTE_CNT bytes are successfully read.
3228    Returns -1 if an I/O error or a partial read occurs.
3229    Returns 0 for an immediate end-of-file and, if EOF_IS_OK is false, reports
3230    an error. */
3231 static inline int
3232 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
3233                      void *buf, size_t byte_cnt)
3234 {
3235   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
3236   r->pos += bytes_read;
3237   if (bytes_read == byte_cnt)
3238     return 1;
3239   else if (ferror (r->file))
3240     {
3241       sys_error (r, r->pos, _("System error: %s."), strerror (errno));
3242       return -1;
3243     }
3244   else if (!eof_is_ok || bytes_read != 0)
3245     {
3246       sys_error (r, r->pos, _("Unexpected end of file."));
3247       return -1;
3248     }
3249   else
3250     return 0;
3251 }
3252
3253 /* Reads BYTE_CNT into BUF.
3254    Returns true if successful.
3255    Returns false upon I/O error or if end-of-file is encountered. */
3256 static bool
3257 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3258 {
3259   return read_bytes_internal (r, false, buf, byte_cnt) == 1;
3260 }
3261
3262 /* Reads BYTE_CNT bytes into BUF.
3263    Returns 1 if exactly BYTE_CNT bytes are successfully read.
3264    Returns 0 if an immediate end-of-file is encountered.
3265    Returns -1 if an I/O error or a partial read occurs. */
3266 static int
3267 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3268 {
3269   return read_bytes_internal (r, true, buf, byte_cnt);
3270 }
3271
3272 /* Reads a 32-bit signed integer from R and stores its value in host format in
3273    *X.  Returns true if successful, otherwise false. */
3274 static bool
3275 read_int (struct sfm_reader *r, int *x)
3276 {
3277   uint8_t integer[4];
3278   if (read_bytes (r, integer, sizeof integer) != 1)
3279     return false;
3280   *x = integer_get (r->integer_format, integer, sizeof integer);
3281   return true;
3282 }
3283
3284 static bool
3285 read_uint (struct sfm_reader *r, unsigned int *x)
3286 {
3287   bool ok;
3288   int y;
3289
3290   ok = read_int (r, &y);
3291   *x = y;
3292   return ok;
3293 }
3294
3295 /* Reads a 64-bit signed integer from R and returns its value in
3296    host format. */
3297 static bool
3298 read_int64 (struct sfm_reader *r, long long int *x)
3299 {
3300   uint8_t integer[8];
3301   if (read_bytes (r, integer, sizeof integer) != 1)
3302     return false;
3303   *x = integer_get (r->integer_format, integer, sizeof integer);
3304   return true;
3305 }
3306
3307 /* Reads a 64-bit signed integer from R and returns its value in
3308    host format. */
3309 static bool
3310 read_uint64 (struct sfm_reader *r, unsigned long long int *x)
3311 {
3312   long long int y;
3313   bool ok;
3314
3315   ok = read_int64 (r, &y);
3316   *x = y;
3317   return ok;
3318 }
3319
3320 static int
3321 parse_int (const struct sfm_reader *r, const void *data, size_t ofs)
3322 {
3323   return integer_get (r->integer_format, (const uint8_t *) data + ofs, 4);
3324 }
3325
3326 static double
3327 parse_float (const struct sfm_reader *r, const void *data, size_t ofs)
3328 {
3329   return float_get_double (r->float_format, (const uint8_t *) data + ofs);
3330 }
3331
3332 /* Reads exactly SIZE - 1 bytes into BUFFER
3333    and stores a null byte into BUFFER[SIZE - 1]. */
3334 static bool
3335 read_string (struct sfm_reader *r, char *buffer, size_t size)
3336 {
3337   bool ok;
3338
3339   assert (size > 0);
3340   ok = read_bytes (r, buffer, size - 1);
3341   if (ok)
3342     buffer[size - 1] = '\0';
3343   return ok;
3344 }
3345
3346 /* Skips BYTES bytes forward in R. */
3347 static bool
3348 skip_bytes (struct sfm_reader *r, size_t bytes)
3349 {
3350   while (bytes > 0)
3351     {
3352       char buffer[1024];
3353       size_t chunk = MIN (sizeof buffer, bytes);
3354       if (!read_bytes (r, buffer, chunk))
3355         return false;
3356       bytes -= chunk;
3357     }
3358
3359   return true;
3360 }
3361
3362 /* Returns a malloc()'d copy of S in which all lone CRs and CR LF pairs have
3363    been replaced by LFs.
3364
3365    (A product that identifies itself as VOXCO INTERVIEWER 4.3 produces system
3366    files that use CR-only line ends in the file label and extra product
3367    info.) */
3368 static char *
3369 fix_line_ends (const char *s)
3370 {
3371   char *dst, *d;
3372
3373   d = dst = xmalloc (strlen (s) + 1);
3374   while (*s != '\0')
3375     {
3376       if (*s == '\r')
3377         {
3378           s++;
3379           if (*s == '\n')
3380             s++;
3381           *d++ = '\n';
3382         }
3383       else
3384         *d++ = *s++;
3385     }
3386   *d = '\0';
3387
3388   return dst;
3389 }
3390 \f
3391 static bool
3392 read_ztrailer (struct sfm_reader *r,
3393                long long int zheader_ofs,
3394                long long int ztrailer_len);
3395
3396 static void *
3397 zalloc (voidpf pool_, uInt items, uInt size)
3398 {
3399   struct pool *pool = pool_;
3400
3401   return (!size || xalloc_oversized (items, size)
3402           ? Z_NULL
3403           : pool_malloc (pool, items * size));
3404 }
3405
3406 static void
3407 zfree (voidpf pool_, voidpf address)
3408 {
3409   struct pool *pool = pool_;
3410
3411   pool_free (pool, address);
3412 }
3413
3414 static bool
3415 read_zheader (struct sfm_reader *r)
3416 {
3417   off_t pos = r->pos;
3418   long long int zheader_ofs;
3419   long long int ztrailer_ofs;
3420   long long int ztrailer_len;
3421
3422   if (!read_int64 (r, &zheader_ofs)
3423       || !read_int64 (r, &ztrailer_ofs)
3424       || !read_int64 (r, &ztrailer_len))
3425     return false;
3426
3427   if (zheader_ofs != pos)
3428     {
3429       sys_error (r, pos, _("Wrong ZLIB data header offset %#llx "
3430                            "(expected %#llx)."),
3431                  zheader_ofs, (long long int) pos);
3432       return false;
3433     }
3434
3435   if (ztrailer_ofs < r->pos)
3436     {
3437       sys_error (r, pos, _("Impossible ZLIB trailer offset 0x%llx."),
3438                  ztrailer_ofs);
3439       return false;
3440     }
3441
3442   if (ztrailer_len < 24 || ztrailer_len % 24)
3443     {
3444       sys_error (r, pos, _("Invalid ZLIB trailer length %lld."), ztrailer_len);
3445       return false;
3446     }
3447
3448   r->ztrailer_ofs = ztrailer_ofs;
3449   if (!read_ztrailer (r, zheader_ofs, ztrailer_len))
3450     return false;
3451
3452   if (r->zin_buf == NULL)
3453     {
3454       r->zin_buf = pool_malloc (r->pool, ZIN_BUF_SIZE);
3455       r->zout_buf = pool_malloc (r->pool, ZOUT_BUF_SIZE);
3456       r->zstream.next_in = NULL;
3457       r->zstream.avail_in = 0;
3458     }
3459
3460   r->zstream.zalloc = zalloc;
3461   r->zstream.zfree = zfree;
3462   r->zstream.opaque = r->pool;
3463
3464   return open_zstream (r);
3465 }
3466
3467 static void
3468 seek (struct sfm_reader *r, off_t offset)
3469 {
3470   if (fseeko (r->file, offset, SEEK_SET))
3471     sys_error (r, 0, _("%s: seek failed (%s)."),
3472                fh_get_file_name (r->fh), strerror (errno));
3473   r->pos = offset;
3474 }
3475
3476 /* Performs some additional consistency checks on the ZLIB compressed data
3477    trailer. */
3478 static bool
3479 read_ztrailer (struct sfm_reader *r,
3480                long long int zheader_ofs,
3481                long long int ztrailer_len)
3482 {
3483   long long int expected_uncmp_ofs;
3484   long long int expected_cmp_ofs;
3485   long long int bias;
3486   long long int zero;
3487   unsigned int block_size;
3488   unsigned int n_blocks;
3489   unsigned int i;
3490   struct stat s;
3491
3492   if (fstat (fileno (r->file), &s))
3493     {
3494       sys_error (ME, 0, _("%s: stat failed (%s)."),
3495                  fh_get_file_name (r->fh), strerror (errno));
3496       return false;
3497     }
3498
3499   if (!S_ISREG (s.st_mode))
3500     {
3501       /* We can't seek to the trailer and then back to the data in this file,
3502          so skip doing extra checks. */
3503       return true;
3504     }
3505
3506   if (r->ztrailer_ofs + ztrailer_len != s.st_size)
3507     sys_warn (r, r->pos,
3508               _("End of ZLIB trailer (0x%llx) is not file size (0x%llx)."),
3509               r->ztrailer_ofs + ztrailer_len, (long long int) s.st_size);
3510
3511   seek (r, r->ztrailer_ofs);
3512
3513   /* Read fixed header from ZLIB data trailer. */
3514   if (!read_int64 (r, &bias))
3515     return false;
3516   if (-bias != r->bias)
3517     {
3518       sys_error (r, r->pos, _("ZLIB trailer bias (%lld) differs from "
3519                               "file header bias (%.2f)."),
3520                  -bias, r->bias);
3521       return false;
3522     }
3523
3524   if (!read_int64 (r, &zero))
3525     return false;
3526   if (zero != 0)
3527     sys_warn (r, r->pos,
3528               _("ZLIB trailer \"zero\" field has nonzero value %lld."), zero);
3529
3530   if (!read_uint (r, &block_size))
3531     return false;
3532   if (block_size != ZBLOCK_SIZE)
3533     sys_warn (r, r->pos,
3534               _("ZLIB trailer specifies unexpected %u-byte block size."),
3535               block_size);
3536
3537   if (!read_uint (r, &n_blocks))
3538     return false;
3539   if (n_blocks != (ztrailer_len - 24) / 24)
3540     {
3541       sys_error (r, r->pos,
3542                  _("%lld-byte ZLIB trailer specifies %u data blocks (expected "
3543                    "%lld)."),
3544                  ztrailer_len, n_blocks, (ztrailer_len - 24) / 24);
3545       return false;
3546     }
3547
3548   expected_uncmp_ofs = zheader_ofs;
3549   expected_cmp_ofs = zheader_ofs + 24;
3550   for (i = 0; i < n_blocks; i++)
3551     {
3552       off_t desc_ofs = r->pos;
3553       unsigned long long int uncompressed_ofs;
3554       unsigned long long int compressed_ofs;
3555       unsigned int uncompressed_size;
3556       unsigned int compressed_size;
3557
3558       if (!read_uint64 (r, &uncompressed_ofs)
3559           || !read_uint64 (r, &compressed_ofs)
3560           || !read_uint (r, &uncompressed_size)
3561           || !read_uint (r, &compressed_size))
3562         return false;
3563
3564       if (uncompressed_ofs != expected_uncmp_ofs)
3565         {
3566           sys_error (r, desc_ofs,
3567                      _("ZLIB block descriptor %u reported uncompressed data "
3568                        "offset %#llx, when %#llx was expected."),
3569                      i, uncompressed_ofs, expected_uncmp_ofs);
3570           return false;
3571         }
3572
3573       if (compressed_ofs != expected_cmp_ofs)
3574         {
3575           sys_error (r, desc_ofs,
3576                      _("ZLIB block descriptor %u reported compressed data "
3577                        "offset %#llx, when %#llx was expected."),
3578                      i, compressed_ofs, expected_cmp_ofs);
3579           return false;
3580         }
3581
3582       if (i < n_blocks - 1)
3583         {
3584           if (uncompressed_size != block_size)
3585             sys_warn (r, desc_ofs,
3586                       _("ZLIB block descriptor %u reported block size %#x, "
3587                         "when %#x was expected."),
3588                       i, uncompressed_size, block_size);
3589         }
3590       else
3591         {
3592           if (uncompressed_size > block_size)
3593             sys_warn (r, desc_ofs,
3594                       _("ZLIB block descriptor %u reported block size %#x, "
3595                         "when at most %#x was expected."),
3596                       i, uncompressed_size, block_size);
3597         }
3598
3599       /* http://www.zlib.net/zlib_tech.html says that the maximum expansion
3600          from compression, with worst-case parameters, is 13.5% plus 11 bytes.
3601          This code checks for an expansion of more than 14.3% plus 11
3602          bytes.  */
3603       if (compressed_size > uncompressed_size + uncompressed_size / 7 + 11)
3604         {
3605           sys_error (r, desc_ofs,
3606                      _("ZLIB block descriptor %u reports compressed size %u "
3607                        "and uncompressed size %u."),
3608                      i, compressed_size, uncompressed_size);
3609           return false;
3610         }
3611
3612       expected_uncmp_ofs += uncompressed_size;
3613       expected_cmp_ofs += compressed_size;
3614     }
3615
3616   if (expected_cmp_ofs != r->ztrailer_ofs)
3617     {
3618       sys_error (r, r->pos, _("ZLIB trailer is at offset %#llx but %#llx "
3619                               "would be expected from block descriptors."),
3620                  r->ztrailer_ofs, expected_cmp_ofs);
3621       return false;
3622     }
3623
3624   seek (r, zheader_ofs + 24);
3625   return true;
3626 }
3627
3628 static bool
3629 open_zstream (struct sfm_reader *r)
3630 {
3631   int error;
3632
3633   r->zout_pos = r->zout_end = 0;
3634   error = inflateInit (&r->zstream);
3635   if (error != Z_OK)
3636     {
3637       sys_error (r, r->pos, _("ZLIB initialization failed (%s)."),
3638                  r->zstream.msg);
3639       return false;
3640     }
3641   return true;
3642 }
3643
3644 static bool
3645 close_zstream (struct sfm_reader *r)
3646 {
3647   int error;
3648
3649   error = inflateEnd (&r->zstream);
3650   if (error != Z_OK)
3651     {
3652       sys_error (r, r->pos, _("Inconsistency at end of ZLIB stream (%s)."),
3653                  r->zstream.msg);
3654       return false;
3655     }
3656   return true;
3657 }
3658
3659 static int
3660 read_bytes_zlib (struct sfm_reader *r, void *buf_, size_t byte_cnt)
3661 {
3662   uint8_t *buf = buf_;
3663
3664   if (byte_cnt == 0)
3665     return 1;
3666
3667   for (;;)
3668     {
3669       int error;
3670
3671       /* Use already inflated data if there is any. */
3672       if (r->zout_pos < r->zout_end)
3673         {
3674           unsigned int n = MIN (byte_cnt, r->zout_end - r->zout_pos);
3675           memcpy (buf, &r->zout_buf[r->zout_pos], n);
3676           r->zout_pos += n;
3677           byte_cnt -= n;
3678           buf += n;
3679
3680           if (byte_cnt == 0)
3681             return 1;
3682         }
3683
3684       /* We need to inflate some more data.
3685          Get some more input data if we don't have any. */
3686       if (r->zstream.avail_in == 0)
3687         {
3688           unsigned int n = MIN (ZIN_BUF_SIZE, r->ztrailer_ofs - r->pos);
3689           if (n == 0)
3690             return 0;
3691           else
3692             {
3693               int retval = try_read_bytes (r, r->zin_buf, n);
3694               if (retval != 1)
3695                 return retval;
3696               r->zstream.avail_in = n;
3697               r->zstream.next_in = r->zin_buf;
3698             }
3699         }
3700
3701       /* Inflate the (remaining) input data. */
3702       r->zstream.avail_out = ZOUT_BUF_SIZE;
3703       r->zstream.next_out = r->zout_buf;
3704       error = inflate (&r->zstream, Z_SYNC_FLUSH);
3705       r->zout_pos = 0;
3706       r->zout_end = r->zstream.next_out - r->zout_buf;
3707       if (r->zout_end == 0)
3708         {
3709           if (error != Z_STREAM_END)
3710             {
3711               sys_error (r, r->pos, _("ZLIB stream inconsistency (%s)."),
3712                          r->zstream.msg);
3713               return -1;
3714             }
3715           else if (!close_zstream (r) || !open_zstream (r))
3716             return -1;
3717         }
3718       else
3719         {
3720           /* Process the output data and ignore 'error' for now.  ZLIB will
3721              present it to us again on the next inflate() call. */
3722         }
3723     }
3724 }
3725
3726 static int
3727 read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3728 {
3729   if (r->compression == ANY_COMP_SIMPLE)
3730     return read_bytes (r, buf, byte_cnt);
3731   else
3732     {
3733       int retval = read_bytes_zlib (r, buf, byte_cnt);
3734       if (retval == 0)
3735         sys_error (r, r->pos, _("Unexpected end of ZLIB compressed data."));
3736       return retval;
3737     }
3738 }
3739
3740 static int
3741 try_read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3742 {
3743   if (r->compression == ANY_COMP_SIMPLE)
3744     return try_read_bytes (r, buf, byte_cnt);
3745   else
3746     return read_bytes_zlib (r, buf, byte_cnt);
3747 }
3748
3749 /* Reads a 64-bit floating-point number from R and returns its
3750    value in host format. */
3751 static bool
3752 read_compressed_float (struct sfm_reader *r, double *d)
3753 {
3754   uint8_t number[8];
3755
3756   if (!read_compressed_bytes (r, number, sizeof number))
3757     return false;
3758
3759   *d = float_get_double (r->float_format, number);
3760   return true;
3761 }
3762 \f
3763 static const struct casereader_class sys_file_casereader_class =
3764   {
3765     sys_file_casereader_read,
3766     sys_file_casereader_destroy,
3767     NULL,
3768     NULL,
3769   };
3770
3771 const struct any_reader_class sys_file_reader_class =
3772   {
3773     N_("SPSS System File"),
3774     sfm_detect,
3775     sfm_open,
3776     sfm_close,
3777     sfm_decode,
3778     sfm_get_strings,
3779   };