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