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