a1193de767dc4618d4a8a1bdf1b0e6f6d5e33341
[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, "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 static 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 (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 /* Detects whether FILE is an SPSS system file.  Returns 1 if so, 0 if not, and
925    a negative errno value if there is an error reading FILE. */
926 static int
927 sfm_detect (FILE *file)
928 {
929   char magic[5];
930
931   if (fseek (file, 0, SEEK_SET) != 0)
932     return -errno;
933   if (fread (magic, 4, 1, file) != 1)
934     return ferror (file) ? -errno : 0;
935   magic[4] = '\0';
936
937   return (!strcmp (ASCII_MAGIC, magic)
938           || !strcmp (ASCII_ZMAGIC, magic)
939           || !strcmp (EBCDIC_MAGIC, magic));
940 }
941 \f
942 /* Reads the global header of the system file.  Initializes *HEADER and *INFO,
943    except for the string fields in *INFO, which parse_header() will initialize
944    later once the file's encoding is known. */
945 static bool
946 read_header (struct sfm_reader *r, struct any_read_info *info,
947              struct sfm_header_record *header)
948 {
949   uint8_t raw_layout_code[4];
950   uint8_t raw_bias[8];
951   int compressed;
952   bool zmagic;
953
954   if (!read_string (r, header->magic, sizeof header->magic)
955       || !read_string (r, header->eye_catcher, sizeof header->eye_catcher))
956     return false;
957
958   if (!strcmp (ASCII_MAGIC, header->magic)
959       || !strcmp (EBCDIC_MAGIC, header->magic))
960     zmagic = false;
961   else if (!strcmp (ASCII_ZMAGIC, header->magic))
962     zmagic = true;
963   else
964     {
965       sys_error (r, 0, _("This is not an SPSS system file."));
966       return false;
967     }
968
969   /* Identify integer format. */
970   if (!read_bytes (r, raw_layout_code, sizeof raw_layout_code))
971     return false;
972   if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
973                           &r->integer_format)
974        && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
975                              &r->integer_format))
976       || (r->integer_format != INTEGER_MSB_FIRST
977           && r->integer_format != INTEGER_LSB_FIRST))
978     {
979       sys_error (r, 64, _("This is not an SPSS system file."));
980       return false;
981     }
982
983   if (!read_int (r, &header->nominal_case_size))
984     return false;
985
986   if (header->nominal_case_size < 0
987       || header->nominal_case_size > INT_MAX / 16)
988     header->nominal_case_size = -1;
989
990   if (!read_int (r, &compressed))
991     return false;
992   if (!zmagic)
993     {
994       if (compressed == 0)
995         r->compression = ANY_COMP_NONE;
996       else if (compressed == 1)
997         r->compression = ANY_COMP_SIMPLE;
998       else if (compressed != 0)
999         {
1000           sys_error (r, 0, "System file header has invalid compression "
1001                      "value %d.", compressed);
1002           return false;
1003         }
1004     }
1005   else
1006     {
1007       if (compressed == 2)
1008         r->compression = ANY_COMP_ZLIB;
1009       else
1010         {
1011           sys_error (r, 0, "ZLIB-compressed system file header has invalid "
1012                      "compression value %d.", compressed);
1013           return false;
1014         }
1015     }
1016
1017   if (!read_int (r, &header->weight_idx))
1018     return false;
1019
1020   if (!read_int (r, &r->case_cnt))
1021     return false;
1022   if ( r->case_cnt > INT_MAX / 2)
1023     r->case_cnt = -1;
1024
1025   /* Identify floating-point format and obtain compression bias. */
1026   if (!read_bytes (r, raw_bias, sizeof raw_bias))
1027     return false;
1028   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
1029     {
1030       uint8_t zero_bias[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1031
1032       if (memcmp (raw_bias, zero_bias, 8))
1033         sys_warn (r, r->pos - 8,
1034                   _("Compression bias is not the usual "
1035                     "value of 100, or system file uses unrecognized "
1036                     "floating-point format."));
1037       else
1038         {
1039           /* Some software is known to write all-zeros to this
1040              field.  Such software also writes floating-point
1041              numbers in the format that we expect by default
1042              (it seems that all software most likely does, in
1043              reality), so don't warn in this case. */
1044         }
1045
1046       if (r->integer_format == INTEGER_MSB_FIRST)
1047         r->float_format = FLOAT_IEEE_DOUBLE_BE;
1048       else
1049         r->float_format = FLOAT_IEEE_DOUBLE_LE;
1050     }
1051   float_convert (r->float_format, raw_bias, FLOAT_NATIVE_DOUBLE, &r->bias);
1052
1053   if (!read_string (r, header->creation_date, sizeof header->creation_date)
1054       || !read_string (r, header->creation_time, sizeof header->creation_time)
1055       || !read_string (r, header->file_label, sizeof header->file_label)
1056       || !skip_bytes (r, 3))
1057     return false;
1058
1059   info->integer_format = r->integer_format;
1060   info->float_format = r->float_format;
1061   info->compression = r->compression;
1062   info->case_cnt = r->case_cnt;
1063
1064   return true;
1065 }
1066
1067 /* Reads a variable (type 2) record from R into RECORD. */
1068 static bool
1069 read_variable_record (struct sfm_reader *r, struct sfm_var_record *record)
1070 {
1071   int has_variable_label;
1072
1073   memset (record, 0, sizeof *record);
1074
1075   record->pos = r->pos;
1076   if (!read_int (r, &record->width)
1077       || !read_int (r, &has_variable_label)
1078       || !read_int (r, &record->missing_value_code)
1079       || !read_int (r, &record->print_format)
1080       || !read_int (r, &record->write_format)
1081       || !read_string (r, record->name, sizeof record->name))
1082     return false;
1083
1084   if (has_variable_label == 1)
1085     {
1086       enum { MAX_LABEL_LEN = 65536 };
1087       unsigned int len, read_len;
1088
1089       if (!read_uint (r, &len))
1090         return false;
1091
1092       /* Read up to MAX_LABEL_LEN bytes of label. */
1093       read_len = MIN (MAX_LABEL_LEN, len);
1094       record->label = pool_malloc (r->pool, read_len + 1);
1095       if (!read_string (r, record->label, read_len + 1))
1096         return false;
1097
1098       /* Skip unread label bytes. */
1099       if (!skip_bytes (r, len - read_len))
1100         return false;
1101
1102       /* Skip label padding up to multiple of 4 bytes. */
1103       if (!skip_bytes (r, ROUND_UP (len, 4) - len))
1104         return false;
1105     }
1106   else if (has_variable_label != 0)
1107     {
1108       sys_error (r, record->pos,
1109                  _("Variable label indicator field is not 0 or 1."));
1110       return false;
1111     }
1112
1113   /* Set missing values. */
1114   if (record->missing_value_code != 0)
1115     {
1116       int code = record->missing_value_code;
1117       if (record->width == 0)
1118         {
1119           if (code < -3 || code > 3 || code == -1)
1120             {
1121               sys_error (r, record->pos,
1122                          _("Numeric missing value indicator field is not "
1123                            "-3, -2, 0, 1, 2, or 3."));
1124               return false;
1125             }
1126         }
1127       else
1128         {
1129           if (code < 1 || code > 3)
1130             {
1131               sys_error (r, record->pos,
1132                          _("String missing value indicator field is not "
1133                            "0, 1, 2, or 3."));
1134               return false;
1135             }
1136         }
1137
1138       if (!read_bytes (r, record->missing, 8 * abs (code)))
1139         return false;
1140     }
1141
1142   return true;
1143 }
1144
1145 /* Reads value labels from R into RECORD. */
1146 static bool
1147 read_value_label_record (struct sfm_reader *r,
1148                          struct sfm_value_label_record *record)
1149 {
1150   size_t i;
1151   int type;
1152
1153   /* Read type 3 record. */
1154   record->pos = r->pos;
1155   if (!read_uint (r, &record->n_labels))
1156     return false;
1157   if (record->n_labels > UINT_MAX / sizeof *record->labels)
1158     {
1159       sys_error (r, r->pos - 4, _("Invalid number of labels %u."),
1160                  record->n_labels);
1161       return false;
1162     }
1163   record->labels = pool_nmalloc (r->pool, record->n_labels,
1164                                  sizeof *record->labels);
1165   for (i = 0; i < record->n_labels; i++)
1166     {
1167       struct sfm_value_label *label = &record->labels[i];
1168       unsigned char label_len;
1169       size_t padded_len;
1170
1171       if (!read_bytes (r, label->value, sizeof label->value))
1172         return false;
1173
1174       /* Read label length. */
1175       if (!read_bytes (r, &label_len, sizeof label_len))
1176         return false;
1177       padded_len = ROUND_UP (label_len + 1, 8);
1178
1179       /* Read label, padding. */
1180       label->label = pool_malloc (r->pool, padded_len + 1);
1181       if (!read_bytes (r, label->label, padded_len - 1))
1182         return false;
1183       label->label[label_len] = '\0';
1184     }
1185
1186   /* Read record type of type 4 record. */
1187   if (!read_int (r, &type))
1188     return false;
1189   if (type != 4)
1190     {
1191       sys_error (r, r->pos - 4,
1192                  _("Variable index record (type 4) does not immediately "
1193                    "follow value label record (type 3) as it should."));
1194       return false;
1195     }
1196
1197   /* Read number of variables associated with value label from type 4
1198      record. */
1199   if (!read_uint (r, &record->n_vars))
1200     return false;
1201   if (record->n_vars < 1 || record->n_vars > r->n_vars)
1202     {
1203       sys_error (r, r->pos - 4,
1204                  _("Number of variables associated with a value label (%u) "
1205                    "is not between 1 and the number of variables (%zu)."),
1206                  record->n_vars, r->n_vars);
1207       return false;
1208     }
1209
1210   record->vars = pool_nmalloc (r->pool, record->n_vars, sizeof *record->vars);
1211   for (i = 0; i < record->n_vars; i++)
1212     if (!read_int (r, &record->vars[i]))
1213       return false;
1214
1215   return true;
1216 }
1217
1218 /* Reads a document record from R and returns it. */
1219 static struct sfm_document_record *
1220 read_document_record (struct sfm_reader *r)
1221 {
1222   struct sfm_document_record *record;
1223   int n_lines;
1224
1225   record = pool_malloc (r->pool, sizeof *record);
1226   record->pos = r->pos;
1227
1228   if (!read_int (r, &n_lines))
1229     return NULL;
1230   if (n_lines <= 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH)
1231     {
1232       sys_error (r, record->pos,
1233                  _("Number of document lines (%d) "
1234                    "must be greater than 0 and less than %d."),
1235                  n_lines, INT_MAX / DOC_LINE_LENGTH);
1236       return NULL;
1237     }
1238
1239   record->n_lines = n_lines;
1240   record->documents = pool_malloc (r->pool, DOC_LINE_LENGTH * n_lines);
1241   if (!read_bytes (r, record->documents, DOC_LINE_LENGTH * n_lines))
1242     return NULL;
1243
1244   return record;
1245 }
1246
1247 static bool
1248 read_extension_record_header (struct sfm_reader *r, int subtype,
1249                               struct sfm_extension_record *record)
1250 {
1251   record->subtype = subtype;
1252   record->pos = r->pos;
1253   if (!read_uint (r, &record->size) || !read_uint (r, &record->count))
1254     return false;
1255
1256   /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
1257      allows an extra byte for a null terminator, used by some
1258      extension processing routines. */
1259   if (record->size != 0
1260       && xsum (1, xtimes (record->count, record->size)) >= UINT_MAX)
1261     {
1262       sys_error (r, record->pos, "Record type 7 subtype %d too large.",
1263                  subtype);
1264       return false;
1265     }
1266
1267   return true;
1268 }
1269
1270 /* Reads an extension record from R into RECORD. */
1271 static bool
1272 read_extension_record (struct sfm_reader *r, int subtype,
1273                        struct sfm_extension_record **recordp)
1274 {
1275   struct extension_record_type
1276     {
1277       int subtype;
1278       int size;
1279       int count;
1280     };
1281
1282   static const struct extension_record_type types[] =
1283     {
1284       /* Implemented record types. */
1285       { EXT_INTEGER,      4, 8 },
1286       { EXT_FLOAT,        8, 3 },
1287       { EXT_MRSETS,       1, 0 },
1288       { EXT_PRODUCT_INFO, 1, 0 },
1289       { EXT_DISPLAY,      4, 0 },
1290       { EXT_LONG_NAMES,   1, 0 },
1291       { EXT_LONG_STRINGS, 1, 0 },
1292       { EXT_NCASES,       8, 2 },
1293       { EXT_FILE_ATTRS,   1, 0 },
1294       { EXT_VAR_ATTRS,    1, 0 },
1295       { EXT_MRSETS2,      1, 0 },
1296       { EXT_ENCODING,     1, 0 },
1297       { EXT_LONG_LABELS,  1, 0 },
1298       { EXT_LONG_MISSING, 1, 0 },
1299
1300       /* Ignored record types. */
1301       { EXT_VAR_SETS,     0, 0 },
1302       { EXT_DATE,         0, 0 },
1303       { EXT_DATA_ENTRY,   0, 0 },
1304       { EXT_DATAVIEW,     0, 0 },
1305     };
1306
1307   const struct extension_record_type *type;
1308   struct sfm_extension_record *record;
1309   size_t n_bytes;
1310
1311   *recordp = NULL;
1312   record = pool_malloc (r->pool, sizeof *record);
1313   if (!read_extension_record_header (r, subtype, record))
1314     return false;
1315   n_bytes = record->count * record->size;
1316
1317   for (type = types; type < &types[sizeof types / sizeof *types]; type++)
1318     if (subtype == type->subtype)
1319       {
1320         if (type->size > 0 && record->size != type->size)
1321           sys_warn (r, record->pos,
1322                     _("Record type 7, subtype %d has bad size %u "
1323                       "(expected %d)."), subtype, record->size, type->size);
1324         else if (type->count > 0 && record->count != type->count)
1325           sys_warn (r, record->pos,
1326                     _("Record type 7, subtype %d has bad count %u "
1327                       "(expected %d)."), subtype, record->count, type->count);
1328         else if (type->count == 0 && type->size == 0)
1329           {
1330             /* Ignore this record. */
1331           }
1332         else
1333           {
1334             char *data = pool_malloc (r->pool, n_bytes + 1);
1335             data[n_bytes] = '\0';
1336
1337             record->data = data;
1338             if (!read_bytes (r, record->data, n_bytes))
1339               return false;
1340             *recordp = record;
1341             return true;
1342           }
1343
1344         goto skip;
1345       }
1346
1347   sys_warn (r, record->pos,
1348             _("Unrecognized record type 7, subtype %d.  For help, please "
1349               "send this file to %s and mention that you were using %s."),
1350             subtype, PACKAGE_BUGREPORT, PACKAGE_STRING);
1351
1352 skip:
1353   return skip_bytes (r, n_bytes);
1354 }
1355
1356 static bool
1357 skip_extension_record (struct sfm_reader *r, int subtype)
1358 {
1359   struct sfm_extension_record record;
1360
1361   return (read_extension_record_header (r, subtype, &record)
1362           && skip_bytes (r, record.count * record.size));
1363 }
1364
1365 static void
1366 parse_header (struct sfm_reader *r, const struct sfm_header_record *header,
1367               struct any_read_info *info, struct dictionary *dict)
1368 {
1369   const char *dict_encoding = dict_get_encoding (dict);
1370   struct substring product;
1371   struct substring label;
1372   char *fixed_label;
1373
1374   /* Convert file label to UTF-8 and put it into DICT. */
1375   label = recode_substring_pool ("UTF-8", dict_encoding,
1376                                  ss_cstr (header->file_label), r->pool);
1377   ss_trim (&label, ss_cstr (" "));
1378   label.string[label.length] = '\0';
1379   fixed_label = fix_line_ends (label.string);
1380   dict_set_label (dict, fixed_label);
1381   free (fixed_label);
1382
1383   /* Put creation date and time in UTF-8 into INFO. */
1384   info->creation_date = recode_string ("UTF-8", dict_encoding,
1385                                        header->creation_date, -1);
1386   info->creation_time = recode_string ("UTF-8", dict_encoding,
1387                                        header->creation_time, -1);
1388
1389   /* Put product name into INFO, dropping eye-catcher string if present. */
1390   product = recode_substring_pool ("UTF-8", dict_encoding,
1391                                    ss_cstr (header->eye_catcher), r->pool);
1392   ss_match_string (&product, ss_cstr ("@(#) SPSS DATA FILE"));
1393   ss_trim (&product, ss_cstr (" "));
1394   info->product = ss_xstrdup (product);
1395 }
1396
1397 /* Reads a variable (type 2) record from R and adds the
1398    corresponding variable to DICT.
1399    Also skips past additional variable records for long string
1400    variables. */
1401 static bool
1402 parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
1403                         struct sfm_var_record *var_recs, size_t n_var_recs)
1404 {
1405   const char *dict_encoding = dict_get_encoding (dict);
1406   struct sfm_var_record *rec;
1407   int n_warnings = 0;
1408
1409   for (rec = var_recs; rec < &var_recs[n_var_recs]; )
1410     {
1411       struct variable *var;
1412       size_t n_values;
1413       char *name;
1414       size_t i;
1415
1416       name = recode_string_pool ("UTF-8", dict_encoding,
1417                                  rec->name, -1, r->pool);
1418       name[strcspn (name, " ")] = '\0';
1419
1420       if (!dict_id_is_valid (dict, name, false)
1421           || name[0] == '$' || name[0] == '#')
1422         {
1423           sys_error (r, rec->pos, _("Invalid variable name `%s'."), name);
1424           return false;
1425         }
1426
1427       if (rec->width < 0 || rec->width > 255)
1428         {
1429           sys_error (r, rec->pos,
1430                      _("Bad width %d for variable %s."), rec->width, name);
1431           return false;
1432         }
1433
1434       var = rec->var = dict_create_var (dict, name, rec->width);
1435       if (var == NULL)
1436         {
1437           char *new_name = dict_make_unique_var_name (dict, NULL, NULL);
1438           sys_warn (r, rec->pos, _("Renaming variable with duplicate name "
1439                                    "`%s' to `%s'."),
1440                     name, new_name);
1441           var = rec->var = dict_create_var_assert (dict, new_name, rec->width);
1442           free (new_name);
1443         }
1444
1445       /* Set the short name the same as the long name. */
1446       var_set_short_name (var, 0, name);
1447
1448       /* Get variable label, if any. */
1449       if (rec->label)
1450         {
1451           char *utf8_label;
1452
1453           utf8_label = recode_string_pool ("UTF-8", dict_encoding,
1454                                            rec->label, -1, r->pool);
1455           var_set_label (var, utf8_label);
1456         }
1457
1458       /* Set missing values. */
1459       if (rec->missing_value_code != 0)
1460         {
1461           int width = var_get_width (var);
1462           struct missing_values mv;
1463
1464           mv_init_pool (r->pool, &mv, width);
1465           if (var_is_numeric (var))
1466             {
1467               bool has_range = rec->missing_value_code < 0;
1468               int n_discrete = (has_range
1469                                 ? rec->missing_value_code == -3
1470                                 : rec->missing_value_code);
1471               int ofs = 0;
1472
1473               if (has_range)
1474                 {
1475                   double low = parse_float (r, rec->missing, 0);
1476                   double high = parse_float (r, rec->missing, 8);
1477
1478                   /* Deal with SPSS 21 change in representation. */
1479                   if (low == SYSMIS)
1480                     low = LOWEST;
1481
1482                   mv_add_range (&mv, low, high);
1483                   ofs += 16;
1484                 }
1485
1486               for (i = 0; i < n_discrete; i++)
1487                 {
1488                   mv_add_num (&mv, parse_float (r, rec->missing, ofs));
1489                   ofs += 8;
1490                 }
1491             }
1492           else
1493             for (i = 0; i < rec->missing_value_code; i++)
1494               mv_add_str (&mv, rec->missing + 8 * i, MIN (width, 8));
1495           var_set_missing_values (var, &mv);
1496         }
1497
1498       /* Set formats. */
1499       parse_format_spec (r, rec->pos + 12, rec->print_format,
1500                          PRINT_FORMAT, var, &n_warnings);
1501       parse_format_spec (r, rec->pos + 16, rec->write_format,
1502                          WRITE_FORMAT, var, &n_warnings);
1503
1504       /* Account for values.
1505          Skip long string continuation records, if any. */
1506       n_values = rec->width == 0 ? 1 : DIV_RND_UP (rec->width, 8);
1507       for (i = 1; i < n_values; i++)
1508         if (i + (rec - var_recs) >= n_var_recs || rec[i].width != -1)
1509           {
1510             sys_error (r, rec->pos, _("Missing string continuation record."));
1511             return false;
1512           }
1513       rec += n_values;
1514     }
1515
1516   return true;
1517 }
1518
1519 /* Translates the format spec from sysfile format to internal
1520    format. */
1521 static void
1522 parse_format_spec (struct sfm_reader *r, off_t pos, unsigned int format,
1523                    enum which_format which, struct variable *v,
1524                    int *n_warnings)
1525 {
1526   const int max_warnings = 8;
1527   uint8_t raw_type = format >> 16;
1528   uint8_t w = format >> 8;
1529   uint8_t d = format;
1530   struct fmt_spec f;
1531   bool ok;
1532
1533   f.w = w;
1534   f.d = d;
1535
1536   msg_disable ();
1537   ok = (fmt_from_io (raw_type, &f.type)
1538         && fmt_check_output (&f)
1539         && fmt_check_width_compat (&f, var_get_width (v)));
1540   msg_enable ();
1541
1542   if (ok)
1543     {
1544       if (which == PRINT_FORMAT)
1545         var_set_print_format (v, &f);
1546       else
1547         var_set_write_format (v, &f);
1548     }
1549   else if (format == 0)
1550     {
1551       /* Actually observed in the wild.  No point in warning about it. */
1552     }
1553   else if (++*n_warnings <= max_warnings)
1554     {
1555       if (which == PRINT_FORMAT)
1556         sys_warn (r, pos, _("Variable %s with width %d has invalid print "
1557                             "format 0x%x."),
1558                   var_get_name (v), var_get_width (v), format);
1559       else
1560         sys_warn (r, pos, _("Variable %s with width %d has invalid write "
1561                             "format 0x%x."),
1562                   var_get_name (v), var_get_width (v), format);
1563
1564       if (*n_warnings == max_warnings)
1565         sys_warn (r, -1, _("Suppressing further invalid format warnings."));
1566     }
1567 }
1568
1569 static void
1570 parse_document (struct dictionary *dict, struct sfm_document_record *record)
1571 {
1572   const char *p;
1573
1574   for (p = record->documents;
1575        p < record->documents + DOC_LINE_LENGTH * record->n_lines;
1576        p += DOC_LINE_LENGTH)
1577     {
1578       struct substring line;
1579
1580       line = recode_substring_pool ("UTF-8", dict_get_encoding (dict),
1581                                     ss_buffer (p, DOC_LINE_LENGTH), NULL);
1582       ss_rtrim (&line, ss_cstr (" "));
1583       line.string[line.length] = '\0';
1584
1585       dict_add_document_line (dict, line.string, false);
1586
1587       ss_dealloc (&line);
1588     }
1589 }
1590
1591 /* Parses record type 7, subtype 3. */
1592 static bool
1593 parse_machine_integer_info (struct sfm_reader *r,
1594                             const struct sfm_extension_record *record,
1595                             struct any_read_info *info)
1596 {
1597   int float_representation, expected_float_format;
1598   int integer_representation, expected_integer_format;
1599
1600   /* Save version info. */
1601   info->version_major = parse_int (r, record->data, 0);
1602   info->version_minor = parse_int (r, record->data, 4);
1603   info->version_revision = parse_int (r, record->data, 8);
1604
1605   /* Check floating point format. */
1606   float_representation = parse_int (r, record->data, 16);
1607   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
1608       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
1609     expected_float_format = 1;
1610   else if (r->float_format == FLOAT_Z_LONG)
1611     expected_float_format = 2;
1612   else if (r->float_format == FLOAT_VAX_G || r->float_format == FLOAT_VAX_D)
1613     expected_float_format = 3;
1614   else
1615     NOT_REACHED ();
1616   if (float_representation != expected_float_format)
1617     {
1618       sys_error (r, record->pos,
1619                  _("Floating-point representation indicated by "
1620                    "system file (%d) differs from expected (%d)."),
1621                  float_representation, expected_float_format);
1622       return false;
1623     }
1624
1625   /* Check integer format. */
1626   integer_representation = parse_int (r, record->data, 24);
1627   if (r->integer_format == INTEGER_MSB_FIRST)
1628     expected_integer_format = 1;
1629   else if (r->integer_format == INTEGER_LSB_FIRST)
1630     expected_integer_format = 2;
1631   else
1632     NOT_REACHED ();
1633   if (integer_representation != expected_integer_format)
1634     sys_warn (r, record->pos,
1635               _("Integer format indicated by system file (%d) "
1636                 "differs from expected (%d)."),
1637               integer_representation, expected_integer_format);
1638
1639   return true;
1640 }
1641
1642 /* Parses record type 7, subtype 4. */
1643 static void
1644 parse_machine_float_info (struct sfm_reader *r,
1645                           const struct sfm_extension_record *record)
1646 {
1647   double sysmis = parse_float (r, record->data, 0);
1648   double highest = parse_float (r, record->data, 8);
1649   double lowest = parse_float (r, record->data, 16);
1650
1651   if (sysmis != SYSMIS)
1652     sys_warn (r, record->pos,
1653               _("File specifies unexpected value %g (%a) as %s, "
1654                 "instead of %g (%a)."),
1655               sysmis, sysmis, "SYSMIS", SYSMIS, SYSMIS);
1656
1657   if (highest != HIGHEST)
1658     sys_warn (r, record->pos,
1659               _("File specifies unexpected value %g (%a) as %s, "
1660                 "instead of %g (%a)."),
1661               highest, highest, "HIGHEST", HIGHEST, HIGHEST);
1662
1663   /* SPSS before version 21 used a unique value just bigger than SYSMIS as
1664      LOWEST.  SPSS 21 uses SYSMIS for LOWEST, which is OK because LOWEST only
1665      appears in a context (missing values) where SYSMIS cannot. */
1666   if (lowest != LOWEST && lowest != SYSMIS)
1667     sys_warn (r, record->pos,
1668               _("File specifies unexpected value %g (%a) as %s, "
1669                 "instead of %g (%a) or %g (%a)."),
1670               lowest, lowest, "LOWEST", LOWEST, LOWEST, SYSMIS, SYSMIS);
1671 }
1672
1673 /* Parses record type 7, subtype 10. */
1674 static void
1675 parse_extra_product_info (struct sfm_reader *r,
1676                           const struct sfm_extension_record *record,
1677                           struct any_read_info *info)
1678 {
1679   struct text_record *text;
1680
1681   text = open_text_record (r, record, true);
1682   info->product_ext = fix_line_ends (text_get_all (text));
1683   close_text_record (r, text);
1684 }
1685
1686 /* Parses record type 7, subtype 7 or 19. */
1687 static void
1688 parse_mrsets (struct sfm_reader *r, const struct sfm_extension_record *record,
1689               size_t *allocated_mrsets)
1690 {
1691   struct text_record *text;
1692
1693   text = open_text_record (r, record, false);
1694   for (;;)
1695     {
1696       struct sfm_mrset *mrset;
1697       size_t allocated_vars;
1698       char delimiter;
1699
1700       /* Skip extra line feeds if present. */
1701       while (text_match (text, '\n'))
1702         continue;
1703
1704       if (r->n_mrsets >= *allocated_mrsets)
1705         r->mrsets = pool_2nrealloc (r->pool, r->mrsets, allocated_mrsets,
1706                                     sizeof *r->mrsets);
1707       mrset = &r->mrsets[r->n_mrsets];
1708       memset(mrset, 0, sizeof *mrset);
1709
1710       mrset->name = text_get_token (text, ss_cstr ("="), NULL);
1711       if (mrset->name == NULL)
1712         break;
1713
1714       if (text_match (text, 'C'))
1715         {
1716           mrset->type = MRSET_MC;
1717           if (!text_match (text, ' '))
1718             {
1719               sys_warn (r, record->pos,
1720                         _("Missing space following `%c' at offset %zu "
1721                           "in MRSETS record."), 'C', text_pos (text));
1722               break;
1723             }
1724         }
1725       else if (text_match (text, 'D'))
1726         {
1727           mrset->type = MRSET_MD;
1728           mrset->cat_source = MRSET_VARLABELS;
1729         }
1730       else if (text_match (text, 'E'))
1731         {
1732           char *number;
1733
1734           mrset->type = MRSET_MD;
1735           mrset->cat_source = MRSET_COUNTEDVALUES;
1736           if (!text_match (text, ' '))
1737             {
1738               sys_warn (r, record->pos,
1739                         _("Missing space following `%c' at offset %zu "
1740                           "in MRSETS record."), 'E',  text_pos (text));
1741               break;
1742             }
1743
1744           number = text_get_token (text, ss_cstr (" "), NULL);
1745           if (!strcmp (number, "11"))
1746             mrset->label_from_var_label = true;
1747           else if (strcmp (number, "1"))
1748             sys_warn (r, record->pos,
1749                       _("Unexpected label source value following `E' "
1750                         "at offset %zu in MRSETS record."),
1751                       text_pos (text));
1752         }
1753       else
1754         {
1755           sys_warn (r, record->pos,
1756                     _("Missing `C', `D', or `E' at offset %zu "
1757                       "in MRSETS record."),
1758                     text_pos (text));
1759           break;
1760         }
1761
1762       if (mrset->type == MRSET_MD)
1763         {
1764           mrset->counted = text_parse_counted_string (r, text);
1765           if (mrset->counted == NULL)
1766             break;
1767         }
1768
1769       mrset->label = text_parse_counted_string (r, text);
1770       if (mrset->label == NULL)
1771         break;
1772
1773       allocated_vars = 0;
1774       do
1775         {
1776           const char *var;
1777
1778           var = text_get_token (text, ss_cstr (" \n"), &delimiter);
1779           if (var == NULL)
1780             {
1781               if (delimiter != '\n')
1782                 sys_warn (r, record->pos,
1783                           _("Missing new-line parsing variable names "
1784                             "at offset %zu in MRSETS record."),
1785                           text_pos (text));
1786               break;
1787             }
1788
1789           if (mrset->n_vars >= allocated_vars)
1790             mrset->vars = pool_2nrealloc (r->pool, mrset->vars,
1791                                           &allocated_vars,
1792                                           sizeof *mrset->vars);
1793           mrset->vars[mrset->n_vars++] = var;
1794         }
1795       while (delimiter != '\n');
1796
1797       r->n_mrsets++;
1798     }
1799   close_text_record (r, text);
1800 }
1801
1802 static void
1803 decode_mrsets (struct sfm_reader *r, struct dictionary *dict)
1804 {
1805   const struct sfm_mrset *s;
1806
1807   for (s = r->mrsets; s < &r->mrsets[r->n_mrsets]; s++)
1808     {
1809       struct stringi_set var_names;
1810       struct mrset *mrset;
1811       char *name;
1812       int width;
1813       size_t i;
1814
1815       name = recode_string ("UTF-8", r->encoding, s->name, -1);
1816       if (name[0] != '$')
1817         {
1818           sys_warn (r, -1, _("Multiple response set name `%s' does not begin "
1819                              "with `$'."),
1820                     name);
1821           free (name);
1822           continue;
1823         }
1824
1825       mrset = xzalloc (sizeof *mrset);
1826       mrset->name = name;
1827       mrset->type = s->type;
1828       mrset->cat_source = s->cat_source;
1829       mrset->label_from_var_label = s->label_from_var_label;
1830       if (s->label[0] != '\0')
1831         mrset->label = recode_string ("UTF-8", r->encoding, s->label, -1);
1832
1833       stringi_set_init (&var_names);
1834       mrset->vars = xmalloc (s->n_vars * sizeof *mrset->vars);
1835       width = INT_MAX;
1836       for (i = 0; i < s->n_vars; i++)
1837         {
1838           struct variable *var;
1839           char *var_name;
1840
1841           var_name = recode_string ("UTF-8", r->encoding, s->vars[i], -1);
1842
1843           var = dict_lookup_var (dict, var_name);
1844           if (var == NULL)
1845             {
1846               free (var_name);
1847               continue;
1848             }
1849           if (!stringi_set_insert (&var_names, var_name))
1850             {
1851               sys_warn (r, -1,
1852                         _("MRSET %s contains duplicate variable name %s."),
1853                         mrset->name, var_name);
1854               free (var_name);
1855               continue;
1856             }
1857           free (var_name);
1858
1859           if (mrset->label == NULL && mrset->label_from_var_label
1860               && var_has_label (var))
1861             mrset->label = xstrdup (var_get_label (var));
1862
1863           if (mrset->n_vars
1864               && var_get_type (var) != var_get_type (mrset->vars[0]))
1865             {
1866               sys_warn (r, -1,
1867                         _("MRSET %s contains both string and "
1868                           "numeric variables."), mrset->name);
1869               continue;
1870             }
1871           width = MIN (width, var_get_width (var));
1872
1873           mrset->vars[mrset->n_vars++] = var;
1874         }
1875
1876       if (mrset->n_vars < 2)
1877         {
1878           if (mrset->n_vars == 0)
1879             sys_warn (r, -1, _("MRSET %s has no variables."), mrset->name);
1880           else
1881             sys_warn (r, -1, _("MRSET %s has only one variable."),
1882                       mrset->name);
1883           mrset_destroy (mrset);
1884           stringi_set_destroy (&var_names);
1885           continue;
1886         }
1887
1888       if (mrset->type == MRSET_MD)
1889         {
1890           mrset->width = width;
1891           value_init (&mrset->counted, width);
1892           if (width == 0)
1893             mrset->counted.f = c_strtod (s->counted, NULL);
1894           else
1895             value_copy_str_rpad (&mrset->counted, width,
1896                                  (const uint8_t *) s->counted, ' ');
1897         }
1898
1899       dict_add_mrset (dict, mrset);
1900       stringi_set_destroy (&var_names);
1901     }
1902 }
1903
1904 /* Read record type 7, subtype 11, which specifies how variables
1905    should be displayed in GUI environments. */
1906 static void
1907 parse_display_parameters (struct sfm_reader *r,
1908                          const struct sfm_extension_record *record,
1909                          struct dictionary *dict)
1910 {
1911   bool includes_width;
1912   bool warned = false;
1913   size_t n_vars;
1914   size_t ofs;
1915   size_t i;
1916
1917   n_vars = dict_get_var_cnt (dict);
1918   if (record->count == 3 * n_vars)
1919     includes_width = true;
1920   else if (record->count == 2 * n_vars)
1921     includes_width = false;
1922   else
1923     {
1924       sys_warn (r, record->pos,
1925                 _("Extension 11 has bad count %u (for %zu variables)."),
1926                 record->count, n_vars);
1927       return;
1928     }
1929
1930   ofs = 0;
1931   for (i = 0; i < n_vars; ++i)
1932     {
1933       struct variable *v = dict_get_var (dict, i);
1934       int measure, width, align;
1935
1936       measure = parse_int (r, record->data, ofs);
1937       ofs += 4;
1938
1939       if (includes_width)
1940         {
1941           width = parse_int (r, record->data, ofs);
1942           ofs += 4;
1943         }
1944       else
1945         width = 0;
1946
1947       align = parse_int (r, record->data, ofs);
1948       ofs += 4;
1949
1950       /* SPSS sometimes seems to set variables' measure to zero. */
1951       if (0 == measure)
1952         measure = 1;
1953
1954       if (measure < 1 || measure > 3 || align < 0 || align > 2)
1955         {
1956           if (!warned)
1957             sys_warn (r, record->pos,
1958                       _("Invalid variable display parameters for variable "
1959                         "%zu (%s).  Default parameters substituted."),
1960                       i, var_get_name (v));
1961           warned = true;
1962           continue;
1963         }
1964
1965       var_set_measure (v, (measure == 1 ? MEASURE_NOMINAL
1966                            : measure == 2 ? MEASURE_ORDINAL
1967                            : MEASURE_SCALE));
1968       var_set_alignment (v, (align == 0 ? ALIGN_LEFT
1969                              : align == 1 ? ALIGN_RIGHT
1970                              : ALIGN_CENTRE));
1971
1972       /* Older versions (SPSS 9.0) sometimes set the display
1973          width to zero.  This causes confusion in the GUI, so
1974          only set the width if it is nonzero. */
1975       if (width > 0)
1976         var_set_display_width (v, width);
1977     }
1978 }
1979
1980 static void
1981 rename_var_and_save_short_names (struct dictionary *dict, struct variable *var,
1982                                  const char *new_name)
1983 {
1984   size_t n_short_names;
1985   char **short_names;
1986   size_t i;
1987
1988   /* Renaming a variable may clear its short names, but we
1989      want to retain them, so we save them and re-set them
1990      afterward. */
1991   n_short_names = var_get_short_name_cnt (var);
1992   short_names = xnmalloc (n_short_names, sizeof *short_names);
1993   for (i = 0; i < n_short_names; i++)
1994     {
1995       const char *s = var_get_short_name (var, i);
1996       short_names[i] = s != NULL ? xstrdup (s) : NULL;
1997     }
1998
1999   /* Set long name. */
2000   dict_rename_var (dict, var, new_name);
2001
2002   /* Restore short names. */
2003   for (i = 0; i < n_short_names; i++)
2004     {
2005       var_set_short_name (var, i, short_names[i]);
2006       free (short_names[i]);
2007     }
2008   free (short_names);
2009 }
2010
2011 /* Parses record type 7, subtype 13, which gives the long name that corresponds
2012    to each short name.  Modifies variable names in DICT accordingly.  */
2013 static void
2014 parse_long_var_name_map (struct sfm_reader *r,
2015                          const struct sfm_extension_record *record,
2016                          struct dictionary *dict)
2017 {
2018   struct text_record *text;
2019   struct variable *var;
2020   char *long_name;
2021
2022   if (record == NULL)
2023     {
2024       /* There are no long variable names.  Use the short variable names,
2025          converted to lowercase, as the long variable names. */
2026       size_t i;
2027
2028       for (i = 0; i < dict_get_var_cnt (dict); i++)
2029         {
2030           struct variable *var = dict_get_var (dict, i);
2031           char *new_name;
2032
2033           new_name = utf8_to_lower (var_get_name (var));
2034           rename_var_and_save_short_names (dict, var, new_name);
2035           free (new_name);
2036         }
2037
2038       return;
2039     }
2040
2041   /* Rename each of the variables, one by one.  (In a correctly constructed
2042      system file, this cannot create any intermediate duplicate variable names,
2043      because all of the new variable names are longer than any of the old
2044      variable names and thus there cannot be any overlaps.) */
2045   text = open_text_record (r, record, true);
2046   while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
2047     {
2048       /* Validate long name. */
2049       if (!dict_id_is_valid (dict, long_name, false))
2050         {
2051           sys_warn (r, record->pos,
2052                     _("Long variable mapping from %s to invalid "
2053                       "variable name `%s'."),
2054                     var_get_name (var), long_name);
2055           continue;
2056         }
2057
2058       /* Identify any duplicates. */
2059       if (utf8_strcasecmp (var_get_short_name (var, 0), long_name)
2060           && dict_lookup_var (dict, long_name) != NULL)
2061         {
2062           sys_warn (r, record->pos,
2063                     _("Duplicate long variable name `%s'."), long_name);
2064           continue;
2065         }
2066
2067       rename_var_and_save_short_names (dict, var, long_name);
2068     }
2069   close_text_record (r, text);
2070 }
2071
2072 /* Reads record type 7, subtype 14, which gives the real length
2073    of each very long string.  Rearranges DICT accordingly. */
2074 static bool
2075 parse_long_string_map (struct sfm_reader *r,
2076                        const struct sfm_extension_record *record,
2077                        struct dictionary *dict)
2078 {
2079   struct text_record *text;
2080   struct variable *var;
2081   char *length_s;
2082
2083   text = open_text_record (r, record, true);
2084   while (read_variable_to_value_pair (r, dict, text, &var, &length_s))
2085     {
2086       size_t idx = var_get_dict_index (var);
2087       long int length;
2088       int segment_cnt;
2089       int i;
2090
2091       /* Get length. */
2092       length = strtol (length_s, NULL, 10);
2093       if (length < 1 || length > MAX_STRING)
2094         {
2095           sys_warn (r, record->pos,
2096                     _("%s listed as string of invalid length %s "
2097                       "in very long string record."),
2098                     var_get_name (var), length_s);
2099           continue;
2100         }
2101
2102       /* Check segments. */
2103       segment_cnt = sfm_width_to_segments (length);
2104       if (segment_cnt == 1)
2105         {
2106           sys_warn (r, record->pos,
2107                     _("%s listed in very long string record with width %s, "
2108                       "which requires only one segment."),
2109                     var_get_name (var), length_s);
2110           continue;
2111         }
2112       if (idx + segment_cnt > dict_get_var_cnt (dict))
2113         {
2114           sys_error (r, record->pos,
2115                      _("Very long string %s overflows dictionary."),
2116                      var_get_name (var));
2117           return false;
2118         }
2119
2120       /* Get the short names from the segments and check their
2121          lengths. */
2122       for (i = 0; i < segment_cnt; i++)
2123         {
2124           struct variable *seg = dict_get_var (dict, idx + i);
2125           int alloc_width = sfm_segment_alloc_width (length, i);
2126           int width = var_get_width (seg);
2127
2128           if (i > 0)
2129             var_set_short_name (var, i, var_get_short_name (seg, 0));
2130           if (ROUND_UP (width, 8) != ROUND_UP (alloc_width, 8))
2131             {
2132               sys_error (r, record->pos,
2133                          _("Very long string with width %ld has segment %d "
2134                            "of width %d (expected %d)."),
2135                          length, i, width, alloc_width);
2136               return false;
2137             }
2138         }
2139       dict_delete_consecutive_vars (dict, idx + 1, segment_cnt - 1);
2140       var_set_width (var, length);
2141     }
2142   close_text_record (r, text);
2143   dict_compact_values (dict);
2144
2145   return true;
2146 }
2147
2148 static bool
2149 parse_value_labels (struct sfm_reader *r, struct dictionary *dict,
2150                     const struct sfm_var_record *var_recs, size_t n_var_recs,
2151                     const struct sfm_value_label_record *record)
2152 {
2153   struct variable **vars;
2154   char **utf8_labels;
2155   size_t i;
2156
2157   utf8_labels = pool_nmalloc (r->pool, record->n_labels, sizeof *utf8_labels);
2158   for (i = 0; i < record->n_labels; i++)
2159     utf8_labels[i] = recode_string_pool ("UTF-8", dict_get_encoding (dict),
2160                                          record->labels[i].label, -1,
2161                                          r->pool);
2162
2163   vars = pool_nmalloc (r->pool, record->n_vars, sizeof *vars);
2164   for (i = 0; i < record->n_vars; i++)
2165     {
2166       vars[i] = lookup_var_by_index (r, record->pos,
2167                                      var_recs, n_var_recs, record->vars[i]);
2168       if (vars[i] == NULL)
2169         return false;
2170     }
2171
2172   for (i = 1; i < record->n_vars; i++)
2173     if (var_get_type (vars[i]) != var_get_type (vars[0]))
2174       {
2175         sys_error (r, record->pos,
2176                    _("Variables associated with value label are not all of "
2177                      "identical type.  Variable %s is %s, but variable "
2178                      "%s is %s."),
2179                    var_get_name (vars[0]),
2180                    var_is_numeric (vars[0]) ? _("numeric") : _("string"),
2181                    var_get_name (vars[i]),
2182                    var_is_numeric (vars[i]) ? _("numeric") : _("string"));
2183         return false;
2184       }
2185
2186   for (i = 0; i < record->n_vars; i++)
2187     {
2188       struct variable *var = vars[i];
2189       int width;
2190       size_t j;
2191
2192       width = var_get_width (var);
2193       if (width > 8)
2194         {
2195           sys_error (r, record->pos,
2196                      _("Value labels may not be added to long string "
2197                        "variables (e.g. %s) using records types 3 and 4."),
2198                      var_get_name (var));
2199           return false;
2200         }
2201
2202       for (j = 0; j < record->n_labels; j++)
2203         {
2204           struct sfm_value_label *label = &record->labels[j];
2205           union value value;
2206
2207           value_init (&value, width);
2208           if (width == 0)
2209             value.f = parse_float (r, label->value, 0);
2210           else
2211             memcpy (value_str_rw (&value, width), label->value, width);
2212
2213           if (!var_add_value_label (var, &value, utf8_labels[j]))
2214             {
2215               if (var_is_numeric (var))
2216                 sys_warn (r, record->pos,
2217                           _("Duplicate value label for %g on %s."),
2218                           value.f, var_get_name (var));
2219               else
2220                 sys_warn (r, record->pos,
2221                           _("Duplicate value label for `%.*s' on %s."),
2222                           width, value_str (&value, width),
2223                           var_get_name (var));
2224             }
2225
2226           value_destroy (&value, width);
2227         }
2228     }
2229
2230   pool_free (r->pool, vars);
2231   for (i = 0; i < record->n_labels; i++)
2232     pool_free (r->pool, utf8_labels[i]);
2233   pool_free (r->pool, utf8_labels);
2234
2235   return true;
2236 }
2237
2238 static struct variable *
2239 lookup_var_by_index (struct sfm_reader *r, off_t offset,
2240                      const struct sfm_var_record *var_recs, size_t n_var_recs,
2241                      int idx)
2242 {
2243   const struct sfm_var_record *rec;
2244
2245   if (idx < 1 || idx > n_var_recs)
2246     {
2247       sys_error (r, offset,
2248                  _("Variable index %d not in valid range 1...%zu."),
2249                  idx, n_var_recs);
2250       return NULL;
2251     }
2252
2253   rec = &var_recs[idx - 1];
2254   if (rec->var == NULL)
2255     {
2256       sys_error (r, offset,
2257                  _("Variable index %d refers to long string continuation."),
2258                  idx);
2259       return NULL;
2260     }
2261
2262   return rec->var;
2263 }
2264
2265 /* Parses a set of custom attributes from TEXT into ATTRS.
2266    ATTRS may be a null pointer, in which case the attributes are
2267    read but discarded. */
2268 static void
2269 parse_attributes (struct sfm_reader *r, struct text_record *text,
2270                   struct attrset *attrs)
2271 {
2272   do
2273     {
2274       struct attribute *attr;
2275       char *key;
2276       int index;
2277
2278       /* Parse the key. */
2279       key = text_get_token (text, ss_cstr ("("), NULL);
2280       if (key == NULL)
2281         return;
2282
2283       attr = attribute_create (key);
2284       for (index = 1; ; index++)
2285         {
2286           /* Parse the value. */
2287           char *value;
2288           size_t length;
2289
2290           value = text_get_token (text, ss_cstr ("\n"), NULL);
2291           if (value == NULL)
2292             {
2293               text_warn (r, text, _("Error parsing attribute value %s[%d]."),
2294                          key, index);
2295               break;
2296             }              
2297
2298           length = strlen (value);
2299           if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') 
2300             {
2301               value[length - 1] = '\0';
2302               attribute_add_value (attr, value + 1); 
2303             }
2304           else 
2305             {
2306               text_warn (r, text,
2307                          _("Attribute value %s[%d] is not quoted: %s."),
2308                          key, index, value);
2309               attribute_add_value (attr, value); 
2310             }
2311
2312           /* Was this the last value for this attribute? */
2313           if (text_match (text, ')'))
2314             break;
2315         }
2316       if (attrs != NULL)
2317         attrset_add (attrs, attr);
2318       else
2319         attribute_destroy (attr);
2320     }
2321   while (!text_match (text, '/'));
2322 }
2323
2324 /* Reads record type 7, subtype 17, which lists custom
2325    attributes on the data file.  */
2326 static void
2327 parse_data_file_attributes (struct sfm_reader *r,
2328                             const struct sfm_extension_record *record,
2329                             struct dictionary *dict)
2330 {
2331   struct text_record *text = open_text_record (r, record, true);
2332   parse_attributes (r, text, dict_get_attributes (dict));
2333   close_text_record (r, text);
2334 }
2335
2336 /* Parses record type 7, subtype 18, which lists custom
2337    attributes on individual variables.  */
2338 static void
2339 parse_variable_attributes (struct sfm_reader *r,
2340                            const struct sfm_extension_record *record,
2341                            struct dictionary *dict)
2342 {
2343   struct text_record *text;
2344   struct variable *var;
2345
2346   text = open_text_record (r, record, true);
2347   while (text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
2348     parse_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
2349   close_text_record (r, text);
2350 }
2351
2352 static void
2353 assign_variable_roles (struct sfm_reader *r, struct dictionary *dict)
2354 {
2355   size_t n_warnings = 0;
2356   size_t i;
2357
2358   for (i = 0; i < dict_get_var_cnt (dict); i++)
2359     {
2360       struct variable *var = dict_get_var (dict, i);
2361       struct attrset *attrs = var_get_attributes (var);
2362       const struct attribute *attr = attrset_lookup (attrs, "$@Role");
2363       if (attr != NULL)
2364         {
2365           int value = atoi (attribute_get_value (attr, 0));
2366           enum var_role role;
2367
2368           switch (value)
2369             {
2370             case 0:
2371               role = ROLE_INPUT;
2372               break;
2373
2374             case 1:
2375               role = ROLE_TARGET;
2376               break;
2377
2378             case 2:
2379               role = ROLE_BOTH;
2380               break;
2381
2382             case 3:
2383               role = ROLE_NONE;
2384               break;
2385
2386             case 4:
2387               role = ROLE_PARTITION;
2388               break;
2389
2390             case 5:
2391               role = ROLE_SPLIT;
2392               break;
2393
2394             default:
2395               role = ROLE_INPUT;
2396               if (n_warnings++ == 0)
2397                 sys_warn (r, -1, _("Invalid role for variable %s."),
2398                           var_get_name (var));
2399             }
2400
2401           var_set_role (var, role);
2402         }
2403     }
2404
2405   if (n_warnings > 1)
2406     sys_warn (r, -1, _("%zu other variables had invalid roles."),
2407               n_warnings - 1);
2408 }
2409
2410 static bool
2411 check_overflow (struct sfm_reader *r,
2412                 const struct sfm_extension_record *record,
2413                 size_t ofs, size_t length)
2414 {
2415   size_t end = record->size * record->count;
2416   if (length >= end || ofs + length > end)
2417     {
2418       sys_warn (r, record->pos + end,
2419                 _("Extension record subtype %d ends unexpectedly."),
2420                 record->subtype);
2421       return false;
2422     }
2423   return true;
2424 }
2425
2426 static void
2427 parse_long_string_value_labels (struct sfm_reader *r,
2428                                 const struct sfm_extension_record *record,
2429                                 struct dictionary *dict)
2430 {
2431   const char *dict_encoding = dict_get_encoding (dict);
2432   size_t end = record->size * record->count;
2433   size_t ofs = 0;
2434
2435   while (ofs < end)
2436     {
2437       char *var_name;
2438       size_t n_labels, i;
2439       struct variable *var;
2440       union value value;
2441       int var_name_len;
2442       int width;
2443
2444       /* Parse variable name length. */
2445       if (!check_overflow (r, record, ofs, 4))
2446         return;
2447       var_name_len = parse_int (r, record->data, ofs);
2448       ofs += 4;
2449
2450       /* Parse variable name, width, and number of labels. */
2451       if (!check_overflow (r, record, ofs, var_name_len + 8))
2452         return;
2453       var_name = recode_string_pool ("UTF-8", dict_encoding,
2454                                      (const char *) record->data + ofs,
2455                                      var_name_len, r->pool);
2456       width = parse_int (r, record->data, ofs + var_name_len);
2457       n_labels = parse_int (r, record->data, ofs + var_name_len + 4);
2458       ofs += var_name_len + 8;
2459
2460       /* Look up 'var' and validate. */
2461       var = dict_lookup_var (dict, var_name);
2462       if (var == NULL)
2463         sys_warn (r, record->pos + ofs,
2464                   _("Ignoring long string value label record for "
2465                     "unknown variable %s."), var_name);
2466       else if (var_is_numeric (var))
2467         {
2468           sys_warn (r, record->pos + ofs,
2469                     _("Ignoring long string value label record for "
2470                       "numeric variable %s."), var_name);
2471           var = NULL;
2472         }
2473       else if (width != var_get_width (var))
2474         {
2475           sys_warn (r, record->pos + ofs,
2476                     _("Ignoring long string value label record for variable "
2477                       "%s because the record's width (%d) does not match the "
2478                       "variable's width (%d)."),
2479                     var_name, width, var_get_width (var));
2480           var = NULL;
2481         }
2482
2483       /* Parse values. */
2484       value_init_pool (r->pool, &value, width);
2485       for (i = 0; i < n_labels; i++)
2486         {
2487           size_t value_length, label_length;
2488           bool skip = var == NULL;
2489
2490           /* Parse value length. */
2491           if (!check_overflow (r, record, ofs, 4))
2492             return;
2493           value_length = parse_int (r, record->data, ofs);
2494           ofs += 4;
2495
2496           /* Parse value. */
2497           if (!check_overflow (r, record, ofs, value_length))
2498             return;
2499           if (!skip)
2500             {
2501               if (value_length == width)
2502                 memcpy (value_str_rw (&value, width),
2503                         (const uint8_t *) record->data + ofs, width);
2504               else
2505                 {
2506                   sys_warn (r, record->pos + ofs,
2507                             _("Ignoring long string value label %zu for "
2508                               "variable %s, with width %d, that has bad value "
2509                               "width %zu."),
2510                             i, var_get_name (var), width, value_length);
2511                   skip = true;
2512                 }
2513             }
2514           ofs += value_length;
2515
2516           /* Parse label length. */
2517           if (!check_overflow (r, record, ofs, 4))
2518             return;
2519           label_length = parse_int (r, record->data, ofs);
2520           ofs += 4;
2521
2522           /* Parse label. */
2523           if (!check_overflow (r, record, ofs, label_length))
2524             return;
2525           if (!skip)
2526             {
2527               char *label;
2528
2529               label = recode_string_pool ("UTF-8", dict_encoding,
2530                                           (const char *) record->data + ofs,
2531                                           label_length, r->pool);
2532               if (!var_add_value_label (var, &value, label))
2533                 sys_warn (r, record->pos + ofs,
2534                           _("Duplicate value label for `%.*s' on %s."),
2535                           width, value_str (&value, width),
2536                           var_get_name (var));
2537               pool_free (r->pool, label);
2538             }
2539           ofs += label_length;
2540         }
2541     }
2542 }
2543
2544 static void
2545 parse_long_string_missing_values (struct sfm_reader *r,
2546                                   const struct sfm_extension_record *record,
2547                                   struct dictionary *dict)
2548 {
2549   const char *dict_encoding = dict_get_encoding (dict);
2550   size_t end = record->size * record->count;
2551   size_t ofs = 0;
2552
2553   while (ofs < end)
2554     {
2555       struct missing_values mv;
2556       char *var_name;
2557       struct variable *var;
2558       int n_missing_values;
2559       int var_name_len;
2560       size_t i;
2561
2562       /* Parse variable name length. */
2563       if (!check_overflow (r, record, ofs, 4))
2564         return;
2565       var_name_len = parse_int (r, record->data, ofs);
2566       ofs += 4;
2567
2568       /* Parse variable name. */
2569       if (!check_overflow (r, record, ofs, var_name_len + 1))
2570         return;
2571       var_name = recode_string_pool ("UTF-8", dict_encoding,
2572                                      (const char *) record->data + ofs,
2573                                      var_name_len, r->pool);
2574       ofs += var_name_len;
2575
2576       /* Parse number of missing values. */
2577       n_missing_values = ((const uint8_t *) record->data)[ofs];
2578       if (n_missing_values < 1 || n_missing_values > 3)
2579         sys_warn (r, record->pos + ofs,
2580                   _("Long string missing values record says variable %s "
2581                     "has %d missing values, but only 1 to 3 missing values "
2582                     "are allowed."),
2583                   var_name, n_missing_values);
2584       ofs++;
2585
2586       /* Look up 'var' and validate. */
2587       var = dict_lookup_var (dict, var_name);
2588       if (var == NULL)
2589         sys_warn (r, record->pos + ofs,
2590                   _("Ignoring long string missing value record for "
2591                     "unknown variable %s."), var_name);
2592       else if (var_is_numeric (var))
2593         {
2594           sys_warn (r, record->pos + ofs,
2595                     _("Ignoring long string missing value record for "
2596                       "numeric variable %s."), var_name);
2597           var = NULL;
2598         }
2599
2600       /* Parse values. */
2601       mv_init_pool (r->pool, &mv, var ? var_get_width (var) : 8);
2602       for (i = 0; i < n_missing_values; i++)
2603         {
2604           size_t value_length;
2605
2606           /* Parse value length. */
2607           if (!check_overflow (r, record, ofs, 4))
2608             return;
2609           value_length = parse_int (r, record->data, ofs);
2610           ofs += 4;
2611
2612           /* Parse value. */
2613           if (!check_overflow (r, record, ofs, value_length))
2614             return;
2615           if (var != NULL
2616               && i < 3
2617               && !mv_add_str (&mv, (const uint8_t *) record->data + ofs,
2618                               value_length))
2619             sys_warn (r, record->pos + ofs,
2620                       _("Ignoring long string missing value %zu for variable "
2621                         "%s, with width %d, that has bad value width %zu."),
2622                       i, var_get_name (var), var_get_width (var),
2623                       value_length);
2624           ofs += value_length;
2625         }
2626       if (var != NULL)
2627         var_set_missing_values (var, &mv);
2628     }
2629 }
2630 \f
2631 /* Case reader. */
2632
2633 static void partial_record (struct sfm_reader *);
2634
2635 static void read_error (struct casereader *, const struct sfm_reader *);
2636
2637 static bool read_case_number (struct sfm_reader *, double *);
2638 static int read_case_string (struct sfm_reader *, uint8_t *, size_t);
2639 static int read_opcode (struct sfm_reader *);
2640 static bool read_compressed_number (struct sfm_reader *, double *);
2641 static int read_compressed_string (struct sfm_reader *, uint8_t *);
2642 static int read_whole_strings (struct sfm_reader *, uint8_t *, size_t);
2643 static bool skip_whole_strings (struct sfm_reader *, size_t);
2644
2645 /* Reads and returns one case from READER's file.  Returns a null
2646    pointer if not successful. */
2647 static struct ccase *
2648 sys_file_casereader_read (struct casereader *reader, void *r_)
2649 {
2650   struct sfm_reader *r = r_;
2651   struct ccase *c;
2652   int retval;
2653   int i;
2654
2655   if (r->error || !r->sfm_var_cnt)
2656     return NULL;
2657
2658   c = case_create (r->proto);
2659
2660   for (i = 0; i < r->sfm_var_cnt; i++)
2661     {
2662       struct sfm_var *sv = &r->sfm_vars[i];
2663       union value *v = case_data_rw_idx (c, sv->case_index);
2664
2665       if (sv->var_width == 0)
2666         retval = read_case_number (r, &v->f);
2667       else
2668         {
2669           uint8_t *s = value_str_rw (v, sv->var_width);
2670           retval = read_case_string (r, s + sv->offset, sv->segment_width);
2671           if (retval == 1)
2672             {
2673               retval = skip_whole_strings (r, ROUND_DOWN (sv->padding, 8));
2674               if (retval == 0)
2675                 sys_error (r, r->pos, _("File ends in partial string value."));
2676             }
2677         }
2678
2679       if (retval != 1)
2680         goto eof;
2681     }
2682   return c;
2683
2684 eof:
2685   if (i != 0)
2686     partial_record (r);
2687   if (r->case_cnt != -1)
2688     read_error (reader, r);
2689   case_unref (c);
2690   return NULL;
2691 }
2692
2693 /* Issues an error that R ends in a partial record. */
2694 static void
2695 partial_record (struct sfm_reader *r)
2696 {
2697   sys_error (r, r->pos, _("File ends in partial case."));
2698 }
2699
2700 /* Issues an error that an unspecified error occurred SFM, and
2701    marks R tainted. */
2702 static void
2703 read_error (struct casereader *r, const struct sfm_reader *sfm)
2704 {
2705   msg (ME, _("Error reading case from file %s."), fh_get_name (sfm->fh));
2706   casereader_force_error (r);
2707 }
2708
2709 /* Reads a number from R and stores its value in *D.
2710    If R is compressed, reads a compressed number;
2711    otherwise, reads a number in the regular way.
2712    Returns true if successful, false if end of file is
2713    reached immediately. */
2714 static bool
2715 read_case_number (struct sfm_reader *r, double *d)
2716 {
2717   if (r->compression == ANY_COMP_NONE)
2718     {
2719       uint8_t number[8];
2720       if (!try_read_bytes (r, number, sizeof number))
2721         return false;
2722       float_convert (r->float_format, number, FLOAT_NATIVE_DOUBLE, d);
2723       return true;
2724     }
2725   else
2726     return read_compressed_number (r, d);
2727 }
2728
2729 /* Reads LENGTH string bytes from R into S.  Always reads a multiple of 8
2730    bytes; if LENGTH is not a multiple of 8, then extra bytes are read and
2731    discarded without being written to S.  Reads compressed strings if S is
2732    compressed.  Returns 1 if successful, 0 if end of file is reached
2733    immediately, or -1 for some kind of error. */
2734 static int
2735 read_case_string (struct sfm_reader *r, uint8_t *s, size_t length)
2736 {
2737   size_t whole = ROUND_DOWN (length, 8);
2738   size_t partial = length % 8;
2739
2740   if (whole)
2741     {
2742       int retval = read_whole_strings (r, s, whole);
2743       if (retval != 1)
2744         return retval;
2745     }
2746
2747   if (partial)
2748     {
2749       uint8_t bounce[8];
2750       int retval = read_whole_strings (r, bounce, sizeof bounce);
2751       if (retval == -1)
2752         return -1;
2753       else if (!retval)
2754         {
2755           if (whole)
2756             {
2757               partial_record (r);
2758               return -1;
2759             }
2760           return 0;
2761         }
2762       memcpy (s + whole, bounce, partial);
2763     }
2764
2765   return 1;
2766 }
2767
2768 /* Reads and returns the next compression opcode from R. */
2769 static int
2770 read_opcode (struct sfm_reader *r)
2771 {
2772   assert (r->compression != ANY_COMP_NONE);
2773   for (;;)
2774     {
2775       int opcode;
2776       if (r->opcode_idx >= sizeof r->opcodes)
2777         {
2778
2779           int retval = try_read_compressed_bytes (r, r->opcodes,
2780                                                   sizeof r->opcodes);
2781           if (retval != 1)
2782             return -1;
2783           r->opcode_idx = 0;
2784         }
2785       opcode = r->opcodes[r->opcode_idx++];
2786
2787       if (opcode != 0)
2788         return opcode;
2789     }
2790 }
2791
2792 /* Reads a compressed number from R and stores its value in D.
2793    Returns true if successful, false if end of file is
2794    reached immediately. */
2795 static bool
2796 read_compressed_number (struct sfm_reader *r, double *d)
2797 {
2798   int opcode = read_opcode (r);
2799   switch (opcode)
2800     {
2801     case -1:
2802     case 252:
2803       return false;
2804
2805     case 253:
2806       return read_compressed_float (r, d);
2807
2808     case 254:
2809       float_convert (r->float_format, "        ", FLOAT_NATIVE_DOUBLE, d);
2810       if (!r->corruption_warning)
2811         {
2812           r->corruption_warning = true;
2813           sys_warn (r, r->pos,
2814                     _("Possible compressed data corruption: "
2815                       "compressed spaces appear in numeric field."));
2816         }
2817       break;
2818
2819     case 255:
2820       *d = SYSMIS;
2821       break;
2822
2823     default:
2824       *d = opcode - r->bias;
2825       break;
2826     }
2827
2828   return true;
2829 }
2830
2831 /* Reads a compressed 8-byte string segment from R and stores it in DST. */
2832 static int
2833 read_compressed_string (struct sfm_reader *r, uint8_t *dst)
2834 {
2835   int opcode;
2836   int retval;
2837
2838   opcode = read_opcode (r);
2839   switch (opcode)
2840     {
2841     case -1:
2842     case 252:
2843       return 0;
2844
2845     case 253:
2846       retval = read_compressed_bytes (r, dst, 8);
2847       return retval == 1 ? 1 : -1;
2848
2849     case 254:
2850       memset (dst, ' ', 8);
2851       return 1;
2852
2853     default:
2854       {
2855         double value = opcode - r->bias;
2856         float_convert (FLOAT_NATIVE_DOUBLE, &value, r->float_format, dst);
2857         if (value == 0.0)
2858           {
2859             /* This has actually been seen "in the wild".  The submitter of the
2860                file that showed that the contents decoded as spaces, but they
2861                were at the end of the field so it's possible that the null
2862                bytes just acted as null terminators. */
2863           }
2864         else if (!r->corruption_warning)
2865           {
2866             r->corruption_warning = true;
2867             sys_warn (r, r->pos,
2868                       _("Possible compressed data corruption: "
2869                         "string contains compressed integer (opcode %d)."),
2870                       opcode);
2871           }
2872       }
2873       return 1;
2874     }
2875 }
2876
2877 /* Reads LENGTH string bytes from R into S.  LENGTH must be a multiple of 8.
2878    Reads compressed strings if S is compressed.  Returns 1 if successful, 0 if
2879    end of file is reached immediately, or -1 for some kind of error. */
2880 static int
2881 read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length)
2882 {
2883   assert (length % 8 == 0);
2884   if (r->compression == ANY_COMP_NONE)
2885     return try_read_bytes (r, s, length);
2886   else
2887     {
2888       size_t ofs;
2889
2890       for (ofs = 0; ofs < length; ofs += 8)
2891         {
2892           int retval = read_compressed_string (r, s + ofs);
2893           if (retval != 1)
2894             {
2895               if (ofs != 0)
2896                 {
2897                   partial_record (r);
2898                   return -1;
2899                 }
2900               return retval;
2901             }
2902           }
2903       return 1;
2904     }
2905 }
2906
2907 /* Skips LENGTH string bytes from R.
2908    LENGTH must be a multiple of 8.
2909    (LENGTH is also limited to 1024, but that's only because the
2910    current caller never needs more than that many bytes.)
2911    Returns true if successful, false if end of file is
2912    reached immediately. */
2913 static bool
2914 skip_whole_strings (struct sfm_reader *r, size_t length)
2915 {
2916   uint8_t buffer[1024];
2917   assert (length < sizeof buffer);
2918   return read_whole_strings (r, buffer, length);
2919 }
2920 \f
2921 /* Helpers for reading records that contain structured text
2922    strings. */
2923
2924 /* Maximum number of warnings to issue for a single text
2925    record. */
2926 #define MAX_TEXT_WARNINGS 5
2927
2928 /* State. */
2929 struct text_record
2930   {
2931     struct substring buffer;    /* Record contents. */
2932     off_t start;                /* Starting offset in file. */
2933     size_t pos;                 /* Current position in buffer. */
2934     int n_warnings;             /* Number of warnings issued or suppressed. */
2935     bool recoded;               /* Recoded into UTF-8? */
2936   };
2937
2938 static struct text_record *
2939 open_text_record (struct sfm_reader *r,
2940                   const struct sfm_extension_record *record,
2941                   bool recode_to_utf8)
2942 {
2943   struct text_record *text;
2944   struct substring raw;
2945
2946   text = pool_alloc (r->pool, sizeof *text);
2947   raw = ss_buffer (record->data, record->size * record->count);
2948   text->start = record->pos;
2949   text->buffer = (recode_to_utf8
2950                   ? recode_substring_pool ("UTF-8", r->encoding, raw, r->pool)
2951                   : raw);
2952   text->pos = 0;
2953   text->n_warnings = 0;
2954   text->recoded = recode_to_utf8;
2955
2956   return text;
2957 }
2958
2959 /* Closes TEXT, frees its storage, and issues a final warning
2960    about suppressed warnings if necesary. */
2961 static void
2962 close_text_record (struct sfm_reader *r, struct text_record *text)
2963 {
2964   if (text->n_warnings > MAX_TEXT_WARNINGS)
2965     sys_warn (r, -1, _("Suppressed %d additional related warnings."),
2966               text->n_warnings - MAX_TEXT_WARNINGS);
2967   if (text->recoded)
2968     pool_free (r->pool, ss_data (text->buffer));
2969 }
2970
2971 /* Reads a variable=value pair from TEXT.
2972    Looks up the variable in DICT and stores it into *VAR.
2973    Stores a null-terminated value into *VALUE. */
2974 static bool
2975 read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict,
2976                              struct text_record *text,
2977                              struct variable **var, char **value)
2978 {
2979   for (;;)
2980     {
2981       if (!text_read_short_name (r, dict, text, ss_cstr ("="), var))
2982         return false;
2983       
2984       *value = text_get_token (text, ss_buffer ("\t\0", 2), NULL);
2985       if (*value == NULL)
2986         return false;
2987
2988       text->pos += ss_span (ss_substr (text->buffer, text->pos, SIZE_MAX),
2989                             ss_buffer ("\t\0", 2));
2990
2991       if (*var != NULL)
2992         return true;
2993     }
2994 }
2995
2996 static bool
2997 text_read_variable_name (struct sfm_reader *r, struct dictionary *dict,
2998                          struct text_record *text, struct substring delimiters,
2999                          struct variable **var)
3000 {
3001   char *name;
3002
3003   name = text_get_token (text, delimiters, NULL);
3004   if (name == NULL)
3005     return false;
3006
3007   *var = dict_lookup_var (dict, name);
3008   if (*var != NULL)
3009     return true;
3010
3011   text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
3012              name);
3013   return false;
3014 }
3015
3016
3017 static bool
3018 text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
3019                       struct text_record *text, struct substring delimiters,
3020                       struct variable **var)
3021 {
3022   char *short_name = text_get_token (text, delimiters, NULL);
3023   if (short_name == NULL)
3024     return false;
3025
3026   *var = dict_lookup_var (dict, short_name);
3027   if (*var == NULL)
3028     text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
3029                short_name);
3030   return true;
3031 }
3032
3033 /* Displays a warning for the current file position, limiting the
3034    number to MAX_TEXT_WARNINGS for TEXT. */
3035 static void
3036 text_warn (struct sfm_reader *r, struct text_record *text,
3037            const char *format, ...)
3038 {
3039   if (text->n_warnings++ < MAX_TEXT_WARNINGS) 
3040     {
3041       va_list args;
3042
3043       va_start (args, format);
3044       sys_msg (r, text->start + text->pos, MW, format, args);
3045       va_end (args);
3046     }
3047 }
3048
3049 static char *
3050 text_get_token (struct text_record *text, struct substring delimiters,
3051                 char *delimiter)
3052 {
3053   struct substring token;
3054   char *end;
3055
3056   if (!ss_tokenize (text->buffer, delimiters, &text->pos, &token))
3057     return NULL;
3058
3059   end = &ss_data (token)[ss_length (token)];
3060   if (delimiter != NULL)
3061     *delimiter = *end;
3062   *end = '\0';
3063   return ss_data (token);
3064 }
3065
3066 /* Reads a integer value expressed in decimal, then a space, then a string that
3067    consists of exactly as many bytes as specified by the integer, then a space,
3068    from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
3069    buffer (so the caller should not free the string). */
3070 static const char *
3071 text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
3072 {
3073   size_t start;
3074   size_t n;
3075   char *s;
3076
3077   start = text->pos;
3078   n = 0;
3079   while (text->pos < text->buffer.length)
3080     {
3081       int c = text->buffer.string[text->pos];
3082       if (c < '0' || c > '9')
3083         break;
3084       n = (n * 10) + (c - '0');
3085       text->pos++;
3086     }
3087   if (text->pos >= text->buffer.length || start == text->pos)
3088     {
3089       sys_warn (r, text->start,
3090                 _("Expecting digit at offset %zu in MRSETS record."),
3091                 text->pos);
3092       return NULL;
3093     }
3094
3095   if (!text_match (text, ' '))
3096     {
3097       sys_warn (r, text->start,
3098                 _("Expecting space at offset %zu in MRSETS record."),
3099                 text->pos);
3100       return NULL;
3101     }
3102
3103   if (text->pos + n > text->buffer.length)
3104     {
3105       sys_warn (r, text->start,
3106                 _("%zu-byte string starting at offset %zu "
3107                   "exceeds record length %zu."),
3108                 n, text->pos, text->buffer.length);
3109       return NULL;
3110     }
3111
3112   s = &text->buffer.string[text->pos];
3113   if (s[n] != ' ')
3114     {
3115       sys_warn (r, text->start,
3116                 _("Expecting space at offset %zu following %zu-byte string."),
3117                 text->pos + n, n);
3118       return NULL;
3119     }
3120   s[n] = '\0';
3121   text->pos += n + 1;
3122   return s;
3123 }
3124
3125 static bool
3126 text_match (struct text_record *text, char c)
3127 {
3128   if (text->buffer.string[text->pos] == c) 
3129     {
3130       text->pos++;
3131       return true;
3132     }
3133   else
3134     return false;
3135 }
3136
3137 /* Returns the current byte offset (as converted to UTF-8, if it was converted)
3138    inside the TEXT's string. */
3139 static size_t
3140 text_pos (const struct text_record *text)
3141 {
3142   return text->pos;
3143 }
3144
3145 static const char *
3146 text_get_all (const struct text_record *text)
3147 {
3148   return text->buffer.string;
3149 }
3150 \f
3151 /* Messages. */
3152
3153 /* Displays a corruption message. */
3154 static void
3155 sys_msg (struct sfm_reader *r, off_t offset,
3156          int class, const char *format, va_list args)
3157 {
3158   struct msg m;
3159   struct string text;
3160
3161   ds_init_empty (&text);
3162   if (offset >= 0)
3163     ds_put_format (&text, _("`%s' near offset 0x%llx: "),
3164                    fh_get_file_name (r->fh), (long long int) offset);
3165   else
3166     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
3167   ds_put_vformat (&text, format, args);
3168
3169   m.category = msg_class_to_category (class);
3170   m.severity = msg_class_to_severity (class);
3171   m.file_name = NULL;
3172   m.first_line = 0;
3173   m.last_line = 0;
3174   m.first_column = 0;
3175   m.last_column = 0;
3176   m.text = ds_cstr (&text);
3177
3178   msg_emit (&m);
3179 }
3180
3181 /* Displays a warning for offset OFFSET in the file. */
3182 static void
3183 sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...)
3184 {
3185   va_list args;
3186
3187   va_start (args, format);
3188   sys_msg (r, offset, MW, format, args);
3189   va_end (args);
3190 }
3191
3192 /* Displays an error for the current file position and marks it as in an error
3193    state. */
3194 static void
3195 sys_error (struct sfm_reader *r, off_t offset, const char *format, ...)
3196 {
3197   va_list args;
3198
3199   va_start (args, format);
3200   sys_msg (r, offset, ME, format, args);
3201   va_end (args);
3202
3203   r->error = true;
3204 }
3205 \f
3206 /* Reads BYTE_CNT bytes into BUF.
3207    Returns 1 if exactly BYTE_CNT bytes are successfully read.
3208    Returns -1 if an I/O error or a partial read occurs.
3209    Returns 0 for an immediate end-of-file and, if EOF_IS_OK is false, reports
3210    an error. */
3211 static inline int
3212 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
3213                      void *buf, size_t byte_cnt)
3214 {
3215   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
3216   r->pos += bytes_read;
3217   if (bytes_read == byte_cnt)
3218     return 1;
3219   else if (ferror (r->file))
3220     {
3221       sys_error (r, r->pos, _("System error: %s."), strerror (errno));
3222       return -1;
3223     }
3224   else if (!eof_is_ok || bytes_read != 0)
3225     {
3226       sys_error (r, r->pos, _("Unexpected end of file."));
3227       return -1;
3228     }
3229   else
3230     return 0;
3231 }
3232
3233 /* Reads BYTE_CNT into BUF.
3234    Returns true if successful.
3235    Returns false upon I/O error or if end-of-file is encountered. */
3236 static bool
3237 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3238 {
3239   return read_bytes_internal (r, false, buf, byte_cnt) == 1;
3240 }
3241
3242 /* Reads BYTE_CNT bytes into BUF.
3243    Returns 1 if exactly BYTE_CNT bytes are successfully read.
3244    Returns 0 if an immediate end-of-file is encountered.
3245    Returns -1 if an I/O error or a partial read occurs. */
3246 static int
3247 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3248 {
3249   return read_bytes_internal (r, true, buf, byte_cnt);
3250 }
3251
3252 /* Reads a 32-bit signed integer from R and stores its value in host format in
3253    *X.  Returns true if successful, otherwise false. */
3254 static bool
3255 read_int (struct sfm_reader *r, int *x)
3256 {
3257   uint8_t integer[4];
3258   if (read_bytes (r, integer, sizeof integer) != 1)
3259     return false;
3260   *x = integer_get (r->integer_format, integer, sizeof integer);
3261   return true;
3262 }
3263
3264 static bool
3265 read_uint (struct sfm_reader *r, unsigned int *x)
3266 {
3267   bool ok;
3268   int y;
3269
3270   ok = read_int (r, &y);
3271   *x = y;
3272   return ok;
3273 }
3274
3275 /* Reads a 64-bit signed integer from R and returns its value in
3276    host format. */
3277 static bool
3278 read_int64 (struct sfm_reader *r, long long int *x)
3279 {
3280   uint8_t integer[8];
3281   if (read_bytes (r, integer, sizeof integer) != 1)
3282     return false;
3283   *x = integer_get (r->integer_format, integer, sizeof integer);
3284   return true;
3285 }
3286
3287 /* Reads a 64-bit signed integer from R and returns its value in
3288    host format. */
3289 static bool
3290 read_uint64 (struct sfm_reader *r, unsigned long long int *x)
3291 {
3292   long long int y;
3293   bool ok;
3294
3295   ok = read_int64 (r, &y);
3296   *x = y;
3297   return ok;
3298 }
3299
3300 static int
3301 parse_int (const struct sfm_reader *r, const void *data, size_t ofs)
3302 {
3303   return integer_get (r->integer_format, (const uint8_t *) data + ofs, 4);
3304 }
3305
3306 static double
3307 parse_float (const struct sfm_reader *r, const void *data, size_t ofs)
3308 {
3309   return float_get_double (r->float_format, (const uint8_t *) data + ofs);
3310 }
3311
3312 /* Reads exactly SIZE - 1 bytes into BUFFER
3313    and stores a null byte into BUFFER[SIZE - 1]. */
3314 static bool
3315 read_string (struct sfm_reader *r, char *buffer, size_t size)
3316 {
3317   bool ok;
3318
3319   assert (size > 0);
3320   ok = read_bytes (r, buffer, size - 1);
3321   if (ok)
3322     buffer[size - 1] = '\0';
3323   return ok;
3324 }
3325
3326 /* Skips BYTES bytes forward in R. */
3327 static bool
3328 skip_bytes (struct sfm_reader *r, size_t bytes)
3329 {
3330   while (bytes > 0)
3331     {
3332       char buffer[1024];
3333       size_t chunk = MIN (sizeof buffer, bytes);
3334       if (!read_bytes (r, buffer, chunk))
3335         return false;
3336       bytes -= chunk;
3337     }
3338
3339   return true;
3340 }
3341
3342 /* Returns a malloc()'d copy of S in which all lone CRs and CR LF pairs have
3343    been replaced by LFs.
3344
3345    (A product that identifies itself as VOXCO INTERVIEWER 4.3 produces system
3346    files that use CR-only line ends in the file label and extra product
3347    info.) */
3348 static char *
3349 fix_line_ends (const char *s)
3350 {
3351   char *dst, *d;
3352
3353   d = dst = xmalloc (strlen (s) + 1);
3354   while (*s != '\0')
3355     {
3356       if (*s == '\r')
3357         {
3358           s++;
3359           if (*s == '\n')
3360             s++;
3361           *d++ = '\n';
3362         }
3363       else
3364         *d++ = *s++;
3365     }
3366   *d = '\0';
3367
3368   return dst;
3369 }
3370 \f
3371 static bool
3372 read_ztrailer (struct sfm_reader *r,
3373                long long int zheader_ofs,
3374                long long int ztrailer_len);
3375
3376 static void *
3377 zalloc (voidpf pool_, uInt items, uInt size)
3378 {
3379   struct pool *pool = pool_;
3380
3381   return (!size || xalloc_oversized (items, size)
3382           ? Z_NULL
3383           : pool_malloc (pool, items * size));
3384 }
3385
3386 static void
3387 zfree (voidpf pool_, voidpf address)
3388 {
3389   struct pool *pool = pool_;
3390
3391   pool_free (pool, address);
3392 }
3393
3394 static bool
3395 read_zheader (struct sfm_reader *r)
3396 {
3397   off_t pos = r->pos;
3398   long long int zheader_ofs;
3399   long long int ztrailer_ofs;
3400   long long int ztrailer_len;
3401
3402   if (!read_int64 (r, &zheader_ofs)
3403       || !read_int64 (r, &ztrailer_ofs)
3404       || !read_int64 (r, &ztrailer_len))
3405     return false;
3406
3407   if (zheader_ofs != pos)
3408     {
3409       sys_error (r, pos, _("Wrong ZLIB data header offset %#llx "
3410                            "(expected %#llx)."),
3411                  zheader_ofs, (long long int) pos);
3412       return false;
3413     }
3414
3415   if (ztrailer_ofs < r->pos)
3416     {
3417       sys_error (r, pos, _("Impossible ZLIB trailer offset 0x%llx."),
3418                  ztrailer_ofs);
3419       return false;
3420     }
3421
3422   if (ztrailer_len < 24 || ztrailer_len % 24)
3423     {
3424       sys_error (r, pos, _("Invalid ZLIB trailer length %lld."), ztrailer_len);
3425       return false;
3426     }
3427
3428   r->ztrailer_ofs = ztrailer_ofs;
3429   if (!read_ztrailer (r, zheader_ofs, ztrailer_len))
3430     return false;
3431
3432   if (r->zin_buf == NULL)
3433     {
3434       r->zin_buf = pool_malloc (r->pool, ZIN_BUF_SIZE);
3435       r->zout_buf = pool_malloc (r->pool, ZOUT_BUF_SIZE);
3436       r->zstream.next_in = NULL;
3437       r->zstream.avail_in = 0;
3438     }
3439
3440   r->zstream.zalloc = zalloc;
3441   r->zstream.zfree = zfree;
3442   r->zstream.opaque = r->pool;
3443
3444   return open_zstream (r);
3445 }
3446
3447 static void
3448 seek (struct sfm_reader *r, off_t offset)
3449 {
3450   if (fseeko (r->file, offset, SEEK_SET))
3451     sys_error (r, 0, _("%s: seek failed (%s)."),
3452                fh_get_file_name (r->fh), strerror (errno));
3453   r->pos = offset;
3454 }
3455
3456 /* Performs some additional consistency checks on the ZLIB compressed data
3457    trailer. */
3458 static bool
3459 read_ztrailer (struct sfm_reader *r,
3460                long long int zheader_ofs,
3461                long long int ztrailer_len)
3462 {
3463   long long int expected_uncmp_ofs;
3464   long long int expected_cmp_ofs;
3465   long long int bias;
3466   long long int zero;
3467   unsigned int block_size;
3468   unsigned int n_blocks;
3469   unsigned int i;
3470   struct stat s;
3471
3472   if (fstat (fileno (r->file), &s))
3473     {
3474       sys_error (ME, 0, _("%s: stat failed (%s)."),
3475                  fh_get_file_name (r->fh), strerror (errno));
3476       return false;
3477     }
3478
3479   if (!S_ISREG (s.st_mode))
3480     {
3481       /* We can't seek to the trailer and then back to the data in this file,
3482          so skip doing extra checks. */
3483       return true;
3484     }
3485
3486   if (r->ztrailer_ofs + ztrailer_len != s.st_size)
3487     sys_warn (r, r->pos,
3488               _("End of ZLIB trailer (0x%llx) is not file size (0x%llx)."),
3489               r->ztrailer_ofs + ztrailer_len, (long long int) s.st_size);
3490
3491   seek (r, r->ztrailer_ofs);
3492
3493   /* Read fixed header from ZLIB data trailer. */
3494   if (!read_int64 (r, &bias))
3495     return false;
3496   if (-bias != r->bias)
3497     {
3498       sys_error (r, r->pos, _("ZLIB trailer bias (%lld) differs from "
3499                               "file header bias (%.2f)."),
3500                  -bias, r->bias);
3501       return false;
3502     }
3503
3504   if (!read_int64 (r, &zero))
3505     return false;
3506   if (zero != 0)
3507     sys_warn (r, r->pos,
3508               _("ZLIB trailer \"zero\" field has nonzero value %lld."), zero);
3509
3510   if (!read_uint (r, &block_size))
3511     return false;
3512   if (block_size != ZBLOCK_SIZE)
3513     sys_warn (r, r->pos,
3514               _("ZLIB trailer specifies unexpected %u-byte block size."),
3515               block_size);
3516
3517   if (!read_uint (r, &n_blocks))
3518     return false;
3519   if (n_blocks != (ztrailer_len - 24) / 24)
3520     {
3521       sys_error (r, r->pos,
3522                  _("%lld-byte ZLIB trailer specifies %u data blocks (expected "
3523                    "%lld)."),
3524                  ztrailer_len, n_blocks, (ztrailer_len - 24) / 24);
3525       return false;
3526     }
3527
3528   expected_uncmp_ofs = zheader_ofs;
3529   expected_cmp_ofs = zheader_ofs + 24;
3530   for (i = 0; i < n_blocks; i++)
3531     {
3532       off_t desc_ofs = r->pos;
3533       unsigned long long int uncompressed_ofs;
3534       unsigned long long int compressed_ofs;
3535       unsigned int uncompressed_size;
3536       unsigned int compressed_size;
3537
3538       if (!read_uint64 (r, &uncompressed_ofs)
3539           || !read_uint64 (r, &compressed_ofs)
3540           || !read_uint (r, &uncompressed_size)
3541           || !read_uint (r, &compressed_size))
3542         return false;
3543
3544       if (uncompressed_ofs != expected_uncmp_ofs)
3545         {
3546           sys_error (r, desc_ofs,
3547                      _("ZLIB block descriptor %u reported uncompressed data "
3548                        "offset %#llx, when %#llx was expected."),
3549                      i, uncompressed_ofs, expected_uncmp_ofs);
3550           return false;
3551         }
3552
3553       if (compressed_ofs != expected_cmp_ofs)
3554         {
3555           sys_error (r, desc_ofs,
3556                      _("ZLIB block descriptor %u reported compressed data "
3557                        "offset %#llx, when %#llx was expected."),
3558                      i, compressed_ofs, expected_cmp_ofs);
3559           return false;
3560         }
3561
3562       if (i < n_blocks - 1)
3563         {
3564           if (uncompressed_size != block_size)
3565             sys_warn (r, desc_ofs,
3566                       _("ZLIB block descriptor %u reported block size %#x, "
3567                         "when %#x was expected."),
3568                       i, uncompressed_size, block_size);
3569         }
3570       else
3571         {
3572           if (uncompressed_size > block_size)
3573             sys_warn (r, desc_ofs,
3574                       _("ZLIB block descriptor %u reported block size %#x, "
3575                         "when at most %#x was expected."),
3576                       i, uncompressed_size, block_size);
3577         }
3578
3579       /* http://www.zlib.net/zlib_tech.html says that the maximum expansion
3580          from compression, with worst-case parameters, is 13.5% plus 11 bytes.
3581          This code checks for an expansion of more than 14.3% plus 11
3582          bytes.  */
3583       if (compressed_size > uncompressed_size + uncompressed_size / 7 + 11)
3584         {
3585           sys_error (r, desc_ofs,
3586                      _("ZLIB block descriptor %u reports compressed size %u "
3587                        "and uncompressed size %u."),
3588                      i, compressed_size, uncompressed_size);
3589           return false;
3590         }
3591
3592       expected_uncmp_ofs += uncompressed_size;
3593       expected_cmp_ofs += compressed_size;
3594     }
3595
3596   if (expected_cmp_ofs != r->ztrailer_ofs)
3597     {
3598       sys_error (r, r->pos, _("ZLIB trailer is at offset %#llx but %#llx "
3599                               "would be expected from block descriptors."),
3600                  r->ztrailer_ofs, expected_cmp_ofs);
3601       return false;
3602     }
3603
3604   seek (r, zheader_ofs + 24);
3605   return true;
3606 }
3607
3608 static bool
3609 open_zstream (struct sfm_reader *r)
3610 {
3611   int error;
3612
3613   r->zout_pos = r->zout_end = 0;
3614   error = inflateInit (&r->zstream);
3615   if (error != Z_OK)
3616     {
3617       sys_error (r, r->pos, _("ZLIB initialization failed (%s)."),
3618                  r->zstream.msg);
3619       return false;
3620     }
3621   return true;
3622 }
3623
3624 static bool
3625 close_zstream (struct sfm_reader *r)
3626 {
3627   int error;
3628
3629   error = inflateEnd (&r->zstream);
3630   if (error != Z_OK)
3631     {
3632       sys_error (r, r->pos, _("Inconsistency at end of ZLIB stream (%s)."),
3633                  r->zstream.msg);
3634       return false;
3635     }
3636   return true;
3637 }
3638
3639 static int
3640 read_bytes_zlib (struct sfm_reader *r, void *buf_, size_t byte_cnt)
3641 {
3642   uint8_t *buf = buf_;
3643
3644   if (byte_cnt == 0)
3645     return 1;
3646
3647   for (;;)
3648     {
3649       int error;
3650
3651       /* Use already inflated data if there is any. */
3652       if (r->zout_pos < r->zout_end)
3653         {
3654           unsigned int n = MIN (byte_cnt, r->zout_end - r->zout_pos);
3655           memcpy (buf, &r->zout_buf[r->zout_pos], n);
3656           r->zout_pos += n;
3657           byte_cnt -= n;
3658           buf += n;
3659
3660           if (byte_cnt == 0)
3661             return 1;
3662         }
3663
3664       /* We need to inflate some more data.
3665          Get some more input data if we don't have any. */
3666       if (r->zstream.avail_in == 0)
3667         {
3668           unsigned int n = MIN (ZIN_BUF_SIZE, r->ztrailer_ofs - r->pos);
3669           if (n == 0)
3670             return 0;
3671           else
3672             {
3673               int retval = try_read_bytes (r, r->zin_buf, n);
3674               if (retval != 1)
3675                 return retval;
3676               r->zstream.avail_in = n;
3677               r->zstream.next_in = r->zin_buf;
3678             }
3679         }
3680
3681       /* Inflate the (remaining) input data. */
3682       r->zstream.avail_out = ZOUT_BUF_SIZE;
3683       r->zstream.next_out = r->zout_buf;
3684       error = inflate (&r->zstream, Z_SYNC_FLUSH);
3685       r->zout_pos = 0;
3686       r->zout_end = r->zstream.next_out - r->zout_buf;
3687       if (r->zout_end == 0)
3688         {
3689           if (error != Z_STREAM_END)
3690             {
3691               sys_error (r, r->pos, _("ZLIB stream inconsistency (%s)."),
3692                          r->zstream.msg);
3693               return -1;
3694             }
3695           else if (!close_zstream (r) || !open_zstream (r))
3696             return -1;
3697         }
3698       else
3699         {
3700           /* Process the output data and ignore 'error' for now.  ZLIB will
3701              present it to us again on the next inflate() call. */
3702         }
3703     }
3704 }
3705
3706 static int
3707 read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3708 {
3709   if (r->compression == ANY_COMP_SIMPLE)
3710     return read_bytes (r, buf, byte_cnt);
3711   else
3712     {
3713       int retval = read_bytes_zlib (r, buf, byte_cnt);
3714       if (retval == 0)
3715         sys_error (r, r->pos, _("Unexpected end of ZLIB compressed data."));
3716       return retval;
3717     }
3718 }
3719
3720 static int
3721 try_read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3722 {
3723   if (r->compression == ANY_COMP_SIMPLE)
3724     return try_read_bytes (r, buf, byte_cnt);
3725   else
3726     return read_bytes_zlib (r, buf, byte_cnt);
3727 }
3728
3729 /* Reads a 64-bit floating-point number from R and returns its
3730    value in host format. */
3731 static bool
3732 read_compressed_float (struct sfm_reader *r, double *d)
3733 {
3734   uint8_t number[8];
3735
3736   if (!read_compressed_bytes (r, number, sizeof number))
3737     return false;
3738
3739   *d = float_get_double (r->float_format, number);
3740   return true;
3741 }
3742 \f
3743 static const struct casereader_class sys_file_casereader_class =
3744   {
3745     sys_file_casereader_read,
3746     sys_file_casereader_destroy,
3747     NULL,
3748     NULL,
3749   };
3750
3751 const struct any_reader_class sys_file_reader_class =
3752   {
3753     N_("SPSS System File"),
3754     sfm_detect,
3755     sfm_open,
3756     sfm_close,
3757     sfm_decode,
3758     sfm_get_strings,
3759   };