sys-file-reader: Disallow system and scratch long variable names too.
[pspp] / src / data / sys-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-2000, 2006-2007, 2009-2016 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "data/sys-file-private.h"
20
21 #include <errno.h>
22 #include <float.h>
23 #include <inttypes.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26 #include <zlib.h>
27
28 #include "data/any-reader.h"
29 #include "data/attributes.h"
30 #include "data/case.h"
31 #include "data/casereader-provider.h"
32 #include "data/casereader.h"
33 #include "data/dictionary.h"
34 #include "data/file-handle-def.h"
35 #include "data/file-name.h"
36 #include "data/format.h"
37 #include "data/identifier.h"
38 #include "data/missing-values.h"
39 #include "data/mrset.h"
40 #include "data/short-names.h"
41 #include "data/value-labels.h"
42 #include "data/value.h"
43 #include "data/variable.h"
44 #include "libpspp/array.h"
45 #include "libpspp/assertion.h"
46 #include "libpspp/compiler.h"
47 #include "libpspp/i18n.h"
48 #include "libpspp/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           || long_name[0] == '$' || long_name[0] == '#')
2051         {
2052           sys_warn (r, record->pos,
2053                     _("Long variable mapping from %s to invalid "
2054                       "variable name `%s'."),
2055                     var_get_name (var), long_name);
2056           continue;
2057         }
2058
2059       /* Identify any duplicates. */
2060       if (utf8_strcasecmp (var_get_short_name (var, 0), long_name)
2061           && dict_lookup_var (dict, long_name) != NULL)
2062         {
2063           sys_warn (r, record->pos,
2064                     _("Duplicate long variable name `%s'."), long_name);
2065           continue;
2066         }
2067
2068       rename_var_and_save_short_names (dict, var, long_name);
2069     }
2070   close_text_record (r, text);
2071 }
2072
2073 /* Reads record type 7, subtype 14, which gives the real length
2074    of each very long string.  Rearranges DICT accordingly. */
2075 static bool
2076 parse_long_string_map (struct sfm_reader *r,
2077                        const struct sfm_extension_record *record,
2078                        struct dictionary *dict)
2079 {
2080   struct text_record *text;
2081   struct variable *var;
2082   char *length_s;
2083
2084   text = open_text_record (r, record, true);
2085   while (read_variable_to_value_pair (r, dict, text, &var, &length_s))
2086     {
2087       size_t idx = var_get_dict_index (var);
2088       long int length;
2089       int segment_cnt;
2090       int i;
2091
2092       /* Get length. */
2093       length = strtol (length_s, NULL, 10);
2094       if (length < 1 || length > MAX_STRING)
2095         {
2096           sys_warn (r, record->pos,
2097                     _("%s listed as string of invalid length %s "
2098                       "in very long string record."),
2099                     var_get_name (var), length_s);
2100           continue;
2101         }
2102
2103       /* Check segments. */
2104       segment_cnt = sfm_width_to_segments (length);
2105       if (segment_cnt == 1)
2106         {
2107           sys_warn (r, record->pos,
2108                     _("%s listed in very long string record with width %s, "
2109                       "which requires only one segment."),
2110                     var_get_name (var), length_s);
2111           continue;
2112         }
2113       if (idx + segment_cnt > dict_get_var_cnt (dict))
2114         {
2115           sys_error (r, record->pos,
2116                      _("Very long string %s overflows dictionary."),
2117                      var_get_name (var));
2118           return false;
2119         }
2120
2121       /* Get the short names from the segments and check their
2122          lengths. */
2123       for (i = 0; i < segment_cnt; i++)
2124         {
2125           struct variable *seg = dict_get_var (dict, idx + i);
2126           int alloc_width = sfm_segment_alloc_width (length, i);
2127           int width = var_get_width (seg);
2128
2129           if (i > 0)
2130             var_set_short_name (var, i, var_get_short_name (seg, 0));
2131           if (ROUND_UP (width, 8) != ROUND_UP (alloc_width, 8))
2132             {
2133               sys_error (r, record->pos,
2134                          _("Very long string with width %ld has segment %d "
2135                            "of width %d (expected %d)."),
2136                          length, i, width, alloc_width);
2137               return false;
2138             }
2139         }
2140       dict_delete_consecutive_vars (dict, idx + 1, segment_cnt - 1);
2141       var_set_width (var, length);
2142     }
2143   close_text_record (r, text);
2144   dict_compact_values (dict);
2145
2146   return true;
2147 }
2148
2149 static bool
2150 parse_value_labels (struct sfm_reader *r, struct dictionary *dict,
2151                     const struct sfm_var_record *var_recs, size_t n_var_recs,
2152                     const struct sfm_value_label_record *record)
2153 {
2154   struct variable **vars;
2155   char **utf8_labels;
2156   size_t i;
2157
2158   utf8_labels = pool_nmalloc (r->pool, record->n_labels, sizeof *utf8_labels);
2159   for (i = 0; i < record->n_labels; i++)
2160     utf8_labels[i] = recode_string_pool ("UTF-8", dict_get_encoding (dict),
2161                                          record->labels[i].label, -1,
2162                                          r->pool);
2163
2164   vars = pool_nmalloc (r->pool, record->n_vars, sizeof *vars);
2165   for (i = 0; i < record->n_vars; i++)
2166     {
2167       vars[i] = lookup_var_by_index (r, record->pos,
2168                                      var_recs, n_var_recs, record->vars[i]);
2169       if (vars[i] == NULL)
2170         return false;
2171     }
2172
2173   for (i = 1; i < record->n_vars; i++)
2174     if (var_get_type (vars[i]) != var_get_type (vars[0]))
2175       {
2176         sys_error (r, record->pos,
2177                    _("Variables associated with value label are not all of "
2178                      "identical type.  Variable %s is %s, but variable "
2179                      "%s is %s."),
2180                    var_get_name (vars[0]),
2181                    var_is_numeric (vars[0]) ? _("numeric") : _("string"),
2182                    var_get_name (vars[i]),
2183                    var_is_numeric (vars[i]) ? _("numeric") : _("string"));
2184         return false;
2185       }
2186
2187   for (i = 0; i < record->n_vars; i++)
2188     {
2189       struct variable *var = vars[i];
2190       int width;
2191       size_t j;
2192
2193       width = var_get_width (var);
2194       if (width > 8)
2195         {
2196           sys_error (r, record->pos,
2197                      _("Value labels may not be added to long string "
2198                        "variables (e.g. %s) using records types 3 and 4."),
2199                      var_get_name (var));
2200           return false;
2201         }
2202
2203       for (j = 0; j < record->n_labels; j++)
2204         {
2205           struct sfm_value_label *label = &record->labels[j];
2206           union value value;
2207
2208           value_init (&value, width);
2209           if (width == 0)
2210             value.f = parse_float (r, label->value, 0);
2211           else
2212             memcpy (value_str_rw (&value, width), label->value, width);
2213
2214           if (!var_add_value_label (var, &value, utf8_labels[j]))
2215             {
2216               if (var_is_numeric (var))
2217                 sys_warn (r, record->pos,
2218                           _("Duplicate value label for %g on %s."),
2219                           value.f, var_get_name (var));
2220               else
2221                 sys_warn (r, record->pos,
2222                           _("Duplicate value label for `%.*s' on %s."),
2223                           width, value_str (&value, width),
2224                           var_get_name (var));
2225             }
2226
2227           value_destroy (&value, width);
2228         }
2229     }
2230
2231   pool_free (r->pool, vars);
2232   for (i = 0; i < record->n_labels; i++)
2233     pool_free (r->pool, utf8_labels[i]);
2234   pool_free (r->pool, utf8_labels);
2235
2236   return true;
2237 }
2238
2239 static struct variable *
2240 lookup_var_by_index (struct sfm_reader *r, off_t offset,
2241                      const struct sfm_var_record *var_recs, size_t n_var_recs,
2242                      int idx)
2243 {
2244   const struct sfm_var_record *rec;
2245
2246   if (idx < 1 || idx > n_var_recs)
2247     {
2248       sys_error (r, offset,
2249                  _("Variable index %d not in valid range 1...%zu."),
2250                  idx, n_var_recs);
2251       return NULL;
2252     }
2253
2254   rec = &var_recs[idx - 1];
2255   if (rec->var == NULL)
2256     {
2257       sys_error (r, offset,
2258                  _("Variable index %d refers to long string continuation."),
2259                  idx);
2260       return NULL;
2261     }
2262
2263   return rec->var;
2264 }
2265
2266 /* Parses a set of custom attributes from TEXT into ATTRS.
2267    ATTRS may be a null pointer, in which case the attributes are
2268    read but discarded. */
2269 static void
2270 parse_attributes (struct sfm_reader *r, struct text_record *text,
2271                   struct attrset *attrs)
2272 {
2273   do
2274     {
2275       struct attribute *attr;
2276       char *key;
2277       int index;
2278
2279       /* Parse the key. */
2280       key = text_get_token (text, ss_cstr ("("), NULL);
2281       if (key == NULL)
2282         return;
2283
2284       attr = attribute_create (key);
2285       for (index = 1; ; index++)
2286         {
2287           /* Parse the value. */
2288           char *value;
2289           size_t length;
2290
2291           value = text_get_token (text, ss_cstr ("\n"), NULL);
2292           if (value == NULL)
2293             {
2294               text_warn (r, text, _("Error parsing attribute value %s[%d]."),
2295                          key, index);
2296               break;
2297             }              
2298
2299           length = strlen (value);
2300           if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') 
2301             {
2302               value[length - 1] = '\0';
2303               attribute_add_value (attr, value + 1); 
2304             }
2305           else 
2306             {
2307               text_warn (r, text,
2308                          _("Attribute value %s[%d] is not quoted: %s."),
2309                          key, index, value);
2310               attribute_add_value (attr, value); 
2311             }
2312
2313           /* Was this the last value for this attribute? */
2314           if (text_match (text, ')'))
2315             break;
2316         }
2317       if (attrs != NULL)
2318         attrset_add (attrs, attr);
2319       else
2320         attribute_destroy (attr);
2321     }
2322   while (!text_match (text, '/'));
2323 }
2324
2325 /* Reads record type 7, subtype 17, which lists custom
2326    attributes on the data file.  */
2327 static void
2328 parse_data_file_attributes (struct sfm_reader *r,
2329                             const struct sfm_extension_record *record,
2330                             struct dictionary *dict)
2331 {
2332   struct text_record *text = open_text_record (r, record, true);
2333   parse_attributes (r, text, dict_get_attributes (dict));
2334   close_text_record (r, text);
2335 }
2336
2337 /* Parses record type 7, subtype 18, which lists custom
2338    attributes on individual variables.  */
2339 static void
2340 parse_variable_attributes (struct sfm_reader *r,
2341                            const struct sfm_extension_record *record,
2342                            struct dictionary *dict)
2343 {
2344   struct text_record *text;
2345   struct variable *var;
2346
2347   text = open_text_record (r, record, true);
2348   while (text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
2349     parse_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
2350   close_text_record (r, text);
2351 }
2352
2353 static void
2354 assign_variable_roles (struct sfm_reader *r, struct dictionary *dict)
2355 {
2356   size_t n_warnings = 0;
2357   size_t i;
2358
2359   for (i = 0; i < dict_get_var_cnt (dict); i++)
2360     {
2361       struct variable *var = dict_get_var (dict, i);
2362       struct attrset *attrs = var_get_attributes (var);
2363       const struct attribute *attr = attrset_lookup (attrs, "$@Role");
2364       if (attr != NULL)
2365         {
2366           int value = atoi (attribute_get_value (attr, 0));
2367           enum var_role role;
2368
2369           switch (value)
2370             {
2371             case 0:
2372               role = ROLE_INPUT;
2373               break;
2374
2375             case 1:
2376               role = ROLE_TARGET;
2377               break;
2378
2379             case 2:
2380               role = ROLE_BOTH;
2381               break;
2382
2383             case 3:
2384               role = ROLE_NONE;
2385               break;
2386
2387             case 4:
2388               role = ROLE_PARTITION;
2389               break;
2390
2391             case 5:
2392               role = ROLE_SPLIT;
2393               break;
2394
2395             default:
2396               role = ROLE_INPUT;
2397               if (n_warnings++ == 0)
2398                 sys_warn (r, -1, _("Invalid role for variable %s."),
2399                           var_get_name (var));
2400             }
2401
2402           var_set_role (var, role);
2403         }
2404     }
2405
2406   if (n_warnings > 1)
2407     sys_warn (r, -1, _("%zu other variables had invalid roles."),
2408               n_warnings - 1);
2409 }
2410
2411 static bool
2412 check_overflow (struct sfm_reader *r,
2413                 const struct sfm_extension_record *record,
2414                 size_t ofs, size_t length)
2415 {
2416   size_t end = record->size * record->count;
2417   if (length >= end || ofs + length > end)
2418     {
2419       sys_warn (r, record->pos + end,
2420                 _("Extension record subtype %d ends unexpectedly."),
2421                 record->subtype);
2422       return false;
2423     }
2424   return true;
2425 }
2426
2427 static void
2428 parse_long_string_value_labels (struct sfm_reader *r,
2429                                 const struct sfm_extension_record *record,
2430                                 struct dictionary *dict)
2431 {
2432   const char *dict_encoding = dict_get_encoding (dict);
2433   size_t end = record->size * record->count;
2434   size_t ofs = 0;
2435
2436   while (ofs < end)
2437     {
2438       char *var_name;
2439       size_t n_labels, i;
2440       struct variable *var;
2441       union value value;
2442       int var_name_len;
2443       int width;
2444
2445       /* Parse variable name length. */
2446       if (!check_overflow (r, record, ofs, 4))
2447         return;
2448       var_name_len = parse_int (r, record->data, ofs);
2449       ofs += 4;
2450
2451       /* Parse variable name, width, and number of labels. */
2452       if (!check_overflow (r, record, ofs, var_name_len + 8))
2453         return;
2454       var_name = recode_string_pool ("UTF-8", dict_encoding,
2455                                      (const char *) record->data + ofs,
2456                                      var_name_len, r->pool);
2457       width = parse_int (r, record->data, ofs + var_name_len);
2458       n_labels = parse_int (r, record->data, ofs + var_name_len + 4);
2459       ofs += var_name_len + 8;
2460
2461       /* Look up 'var' and validate. */
2462       var = dict_lookup_var (dict, var_name);
2463       if (var == NULL)
2464         sys_warn (r, record->pos + ofs,
2465                   _("Ignoring long string value label record for "
2466                     "unknown variable %s."), var_name);
2467       else if (var_is_numeric (var))
2468         {
2469           sys_warn (r, record->pos + ofs,
2470                     _("Ignoring long string value label record for "
2471                       "numeric variable %s."), var_name);
2472           var = NULL;
2473         }
2474       else if (width != var_get_width (var))
2475         {
2476           sys_warn (r, record->pos + ofs,
2477                     _("Ignoring long string value label record for variable "
2478                       "%s because the record's width (%d) does not match the "
2479                       "variable's width (%d)."),
2480                     var_name, width, var_get_width (var));
2481           var = NULL;
2482         }
2483
2484       /* Parse values. */
2485       value_init_pool (r->pool, &value, width);
2486       for (i = 0; i < n_labels; i++)
2487         {
2488           size_t value_length, label_length;
2489           bool skip = var == NULL;
2490
2491           /* Parse value length. */
2492           if (!check_overflow (r, record, ofs, 4))
2493             return;
2494           value_length = parse_int (r, record->data, ofs);
2495           ofs += 4;
2496
2497           /* Parse value. */
2498           if (!check_overflow (r, record, ofs, value_length))
2499             return;
2500           if (!skip)
2501             {
2502               if (value_length == width)
2503                 memcpy (value_str_rw (&value, width),
2504                         (const uint8_t *) record->data + ofs, width);
2505               else
2506                 {
2507                   sys_warn (r, record->pos + ofs,
2508                             _("Ignoring long string value label %zu for "
2509                               "variable %s, with width %d, that has bad value "
2510                               "width %zu."),
2511                             i, var_get_name (var), width, value_length);
2512                   skip = true;
2513                 }
2514             }
2515           ofs += value_length;
2516
2517           /* Parse label length. */
2518           if (!check_overflow (r, record, ofs, 4))
2519             return;
2520           label_length = parse_int (r, record->data, ofs);
2521           ofs += 4;
2522
2523           /* Parse label. */
2524           if (!check_overflow (r, record, ofs, label_length))
2525             return;
2526           if (!skip)
2527             {
2528               char *label;
2529
2530               label = recode_string_pool ("UTF-8", dict_encoding,
2531                                           (const char *) record->data + ofs,
2532                                           label_length, r->pool);
2533               if (!var_add_value_label (var, &value, label))
2534                 sys_warn (r, record->pos + ofs,
2535                           _("Duplicate value label for `%.*s' on %s."),
2536                           width, value_str (&value, width),
2537                           var_get_name (var));
2538               pool_free (r->pool, label);
2539             }
2540           ofs += label_length;
2541         }
2542     }
2543 }
2544
2545 static void
2546 parse_long_string_missing_values (struct sfm_reader *r,
2547                                   const struct sfm_extension_record *record,
2548                                   struct dictionary *dict)
2549 {
2550   const char *dict_encoding = dict_get_encoding (dict);
2551   size_t end = record->size * record->count;
2552   size_t ofs = 0;
2553
2554   while (ofs < end)
2555     {
2556       struct missing_values mv;
2557       char *var_name;
2558       struct variable *var;
2559       int n_missing_values;
2560       int var_name_len;
2561       size_t i;
2562
2563       /* Parse variable name length. */
2564       if (!check_overflow (r, record, ofs, 4))
2565         return;
2566       var_name_len = parse_int (r, record->data, ofs);
2567       ofs += 4;
2568
2569       /* Parse variable name. */
2570       if (!check_overflow (r, record, ofs, var_name_len + 1))
2571         return;
2572       var_name = recode_string_pool ("UTF-8", dict_encoding,
2573                                      (const char *) record->data + ofs,
2574                                      var_name_len, r->pool);
2575       ofs += var_name_len;
2576
2577       /* Parse number of missing values. */
2578       n_missing_values = ((const uint8_t *) record->data)[ofs];
2579       if (n_missing_values < 1 || n_missing_values > 3)
2580         sys_warn (r, record->pos + ofs,
2581                   _("Long string missing values record says variable %s "
2582                     "has %d missing values, but only 1 to 3 missing values "
2583                     "are allowed."),
2584                   var_name, n_missing_values);
2585       ofs++;
2586
2587       /* Look up 'var' and validate. */
2588       var = dict_lookup_var (dict, var_name);
2589       if (var == NULL)
2590         sys_warn (r, record->pos + ofs,
2591                   _("Ignoring long string missing value record for "
2592                     "unknown variable %s."), var_name);
2593       else if (var_is_numeric (var))
2594         {
2595           sys_warn (r, record->pos + ofs,
2596                     _("Ignoring long string missing value record for "
2597                       "numeric variable %s."), var_name);
2598           var = NULL;
2599         }
2600
2601       /* Parse values. */
2602       mv_init_pool (r->pool, &mv, var ? var_get_width (var) : 8);
2603       for (i = 0; i < n_missing_values; i++)
2604         {
2605           size_t value_length;
2606
2607           /* Parse value length. */
2608           if (!check_overflow (r, record, ofs, 4))
2609             return;
2610           value_length = parse_int (r, record->data, ofs);
2611           ofs += 4;
2612
2613           /* Parse value. */
2614           if (!check_overflow (r, record, ofs, value_length))
2615             return;
2616           if (var != NULL
2617               && i < 3
2618               && !mv_add_str (&mv, (const uint8_t *) record->data + ofs,
2619                               value_length))
2620             sys_warn (r, record->pos + ofs,
2621                       _("Ignoring long string missing value %zu for variable "
2622                         "%s, with width %d, that has bad value width %zu."),
2623                       i, var_get_name (var), var_get_width (var),
2624                       value_length);
2625           ofs += value_length;
2626         }
2627       if (var != NULL)
2628         var_set_missing_values (var, &mv);
2629     }
2630 }
2631 \f
2632 /* Case reader. */
2633
2634 static void partial_record (struct sfm_reader *);
2635
2636 static void read_error (struct casereader *, const struct sfm_reader *);
2637
2638 static bool read_case_number (struct sfm_reader *, double *);
2639 static int read_case_string (struct sfm_reader *, uint8_t *, size_t);
2640 static int read_opcode (struct sfm_reader *);
2641 static bool read_compressed_number (struct sfm_reader *, double *);
2642 static int read_compressed_string (struct sfm_reader *, uint8_t *);
2643 static int read_whole_strings (struct sfm_reader *, uint8_t *, size_t);
2644 static bool skip_whole_strings (struct sfm_reader *, size_t);
2645
2646 /* Reads and returns one case from READER's file.  Returns a null
2647    pointer if not successful. */
2648 static struct ccase *
2649 sys_file_casereader_read (struct casereader *reader, void *r_)
2650 {
2651   struct sfm_reader *r = r_;
2652   struct ccase *c;
2653   int retval;
2654   int i;
2655
2656   if (r->error || !r->sfm_var_cnt)
2657     return NULL;
2658
2659   c = case_create (r->proto);
2660
2661   for (i = 0; i < r->sfm_var_cnt; i++)
2662     {
2663       struct sfm_var *sv = &r->sfm_vars[i];
2664       union value *v = case_data_rw_idx (c, sv->case_index);
2665
2666       if (sv->var_width == 0)
2667         retval = read_case_number (r, &v->f);
2668       else
2669         {
2670           uint8_t *s = value_str_rw (v, sv->var_width);
2671           retval = read_case_string (r, s + sv->offset, sv->segment_width);
2672           if (retval == 1)
2673             {
2674               retval = skip_whole_strings (r, ROUND_DOWN (sv->padding, 8));
2675               if (retval == 0)
2676                 sys_error (r, r->pos, _("File ends in partial string value."));
2677             }
2678         }
2679
2680       if (retval != 1)
2681         goto eof;
2682     }
2683   return c;
2684
2685 eof:
2686   if (i != 0)
2687     partial_record (r);
2688   if (r->case_cnt != -1)
2689     read_error (reader, r);
2690   case_unref (c);
2691   return NULL;
2692 }
2693
2694 /* Issues an error that R ends in a partial record. */
2695 static void
2696 partial_record (struct sfm_reader *r)
2697 {
2698   sys_error (r, r->pos, _("File ends in partial case."));
2699 }
2700
2701 /* Issues an error that an unspecified error occurred SFM, and
2702    marks R tainted. */
2703 static void
2704 read_error (struct casereader *r, const struct sfm_reader *sfm)
2705 {
2706   msg (ME, _("Error reading case from file %s."), fh_get_name (sfm->fh));
2707   casereader_force_error (r);
2708 }
2709
2710 /* Reads a number from R and stores its value in *D.
2711    If R is compressed, reads a compressed number;
2712    otherwise, reads a number in the regular way.
2713    Returns true if successful, false if end of file is
2714    reached immediately. */
2715 static bool
2716 read_case_number (struct sfm_reader *r, double *d)
2717 {
2718   if (r->compression == ANY_COMP_NONE)
2719     {
2720       uint8_t number[8];
2721       if (!try_read_bytes (r, number, sizeof number))
2722         return false;
2723       float_convert (r->float_format, number, FLOAT_NATIVE_DOUBLE, d);
2724       return true;
2725     }
2726   else
2727     return read_compressed_number (r, d);
2728 }
2729
2730 /* Reads LENGTH string bytes from R into S.  Always reads a multiple of 8
2731    bytes; if LENGTH is not a multiple of 8, then extra bytes are read and
2732    discarded without being written to S.  Reads compressed strings if S is
2733    compressed.  Returns 1 if successful, 0 if end of file is reached
2734    immediately, or -1 for some kind of error. */
2735 static int
2736 read_case_string (struct sfm_reader *r, uint8_t *s, size_t length)
2737 {
2738   size_t whole = ROUND_DOWN (length, 8);
2739   size_t partial = length % 8;
2740
2741   if (whole)
2742     {
2743       int retval = read_whole_strings (r, s, whole);
2744       if (retval != 1)
2745         return retval;
2746     }
2747
2748   if (partial)
2749     {
2750       uint8_t bounce[8];
2751       int retval = read_whole_strings (r, bounce, sizeof bounce);
2752       if (retval == -1)
2753         return -1;
2754       else if (!retval)
2755         {
2756           if (whole)
2757             {
2758               partial_record (r);
2759               return -1;
2760             }
2761           return 0;
2762         }
2763       memcpy (s + whole, bounce, partial);
2764     }
2765
2766   return 1;
2767 }
2768
2769 /* Reads and returns the next compression opcode from R. */
2770 static int
2771 read_opcode (struct sfm_reader *r)
2772 {
2773   assert (r->compression != ANY_COMP_NONE);
2774   for (;;)
2775     {
2776       int opcode;
2777       if (r->opcode_idx >= sizeof r->opcodes)
2778         {
2779
2780           int retval = try_read_compressed_bytes (r, r->opcodes,
2781                                                   sizeof r->opcodes);
2782           if (retval != 1)
2783             return -1;
2784           r->opcode_idx = 0;
2785         }
2786       opcode = r->opcodes[r->opcode_idx++];
2787
2788       if (opcode != 0)
2789         return opcode;
2790     }
2791 }
2792
2793 /* Reads a compressed number from R and stores its value in D.
2794    Returns true if successful, false if end of file is
2795    reached immediately. */
2796 static bool
2797 read_compressed_number (struct sfm_reader *r, double *d)
2798 {
2799   int opcode = read_opcode (r);
2800   switch (opcode)
2801     {
2802     case -1:
2803     case 252:
2804       return false;
2805
2806     case 253:
2807       return read_compressed_float (r, d);
2808
2809     case 254:
2810       float_convert (r->float_format, "        ", FLOAT_NATIVE_DOUBLE, d);
2811       if (!r->corruption_warning)
2812         {
2813           r->corruption_warning = true;
2814           sys_warn (r, r->pos,
2815                     _("Possible compressed data corruption: "
2816                       "compressed spaces appear in numeric field."));
2817         }
2818       break;
2819
2820     case 255:
2821       *d = SYSMIS;
2822       break;
2823
2824     default:
2825       *d = opcode - r->bias;
2826       break;
2827     }
2828
2829   return true;
2830 }
2831
2832 /* Reads a compressed 8-byte string segment from R and stores it in DST. */
2833 static int
2834 read_compressed_string (struct sfm_reader *r, uint8_t *dst)
2835 {
2836   int opcode;
2837   int retval;
2838
2839   opcode = read_opcode (r);
2840   switch (opcode)
2841     {
2842     case -1:
2843     case 252:
2844       return 0;
2845
2846     case 253:
2847       retval = read_compressed_bytes (r, dst, 8);
2848       return retval == 1 ? 1 : -1;
2849
2850     case 254:
2851       memset (dst, ' ', 8);
2852       return 1;
2853
2854     default:
2855       {
2856         double value = opcode - r->bias;
2857         float_convert (FLOAT_NATIVE_DOUBLE, &value, r->float_format, dst);
2858         if (value == 0.0)
2859           {
2860             /* This has actually been seen "in the wild".  The submitter of the
2861                file that showed that the contents decoded as spaces, but they
2862                were at the end of the field so it's possible that the null
2863                bytes just acted as null terminators. */
2864           }
2865         else if (!r->corruption_warning)
2866           {
2867             r->corruption_warning = true;
2868             sys_warn (r, r->pos,
2869                       _("Possible compressed data corruption: "
2870                         "string contains compressed integer (opcode %d)."),
2871                       opcode);
2872           }
2873       }
2874       return 1;
2875     }
2876 }
2877
2878 /* Reads LENGTH string bytes from R into S.  LENGTH must be a multiple of 8.
2879    Reads compressed strings if S is compressed.  Returns 1 if successful, 0 if
2880    end of file is reached immediately, or -1 for some kind of error. */
2881 static int
2882 read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length)
2883 {
2884   assert (length % 8 == 0);
2885   if (r->compression == ANY_COMP_NONE)
2886     return try_read_bytes (r, s, length);
2887   else
2888     {
2889       size_t ofs;
2890
2891       for (ofs = 0; ofs < length; ofs += 8)
2892         {
2893           int retval = read_compressed_string (r, s + ofs);
2894           if (retval != 1)
2895             {
2896               if (ofs != 0)
2897                 {
2898                   partial_record (r);
2899                   return -1;
2900                 }
2901               return retval;
2902             }
2903           }
2904       return 1;
2905     }
2906 }
2907
2908 /* Skips LENGTH string bytes from R.
2909    LENGTH must be a multiple of 8.
2910    (LENGTH is also limited to 1024, but that's only because the
2911    current caller never needs more than that many bytes.)
2912    Returns true if successful, false if end of file is
2913    reached immediately. */
2914 static bool
2915 skip_whole_strings (struct sfm_reader *r, size_t length)
2916 {
2917   uint8_t buffer[1024];
2918   assert (length < sizeof buffer);
2919   return read_whole_strings (r, buffer, length);
2920 }
2921 \f
2922 /* Helpers for reading records that contain structured text
2923    strings. */
2924
2925 /* Maximum number of warnings to issue for a single text
2926    record. */
2927 #define MAX_TEXT_WARNINGS 5
2928
2929 /* State. */
2930 struct text_record
2931   {
2932     struct substring buffer;    /* Record contents. */
2933     off_t start;                /* Starting offset in file. */
2934     size_t pos;                 /* Current position in buffer. */
2935     int n_warnings;             /* Number of warnings issued or suppressed. */
2936     bool recoded;               /* Recoded into UTF-8? */
2937   };
2938
2939 static struct text_record *
2940 open_text_record (struct sfm_reader *r,
2941                   const struct sfm_extension_record *record,
2942                   bool recode_to_utf8)
2943 {
2944   struct text_record *text;
2945   struct substring raw;
2946
2947   text = pool_alloc (r->pool, sizeof *text);
2948   raw = ss_buffer (record->data, record->size * record->count);
2949   text->start = record->pos;
2950   text->buffer = (recode_to_utf8
2951                   ? recode_substring_pool ("UTF-8", r->encoding, raw, r->pool)
2952                   : raw);
2953   text->pos = 0;
2954   text->n_warnings = 0;
2955   text->recoded = recode_to_utf8;
2956
2957   return text;
2958 }
2959
2960 /* Closes TEXT, frees its storage, and issues a final warning
2961    about suppressed warnings if necesary. */
2962 static void
2963 close_text_record (struct sfm_reader *r, struct text_record *text)
2964 {
2965   if (text->n_warnings > MAX_TEXT_WARNINGS)
2966     sys_warn (r, -1, _("Suppressed %d additional related warnings."),
2967               text->n_warnings - MAX_TEXT_WARNINGS);
2968   if (text->recoded)
2969     pool_free (r->pool, ss_data (text->buffer));
2970 }
2971
2972 /* Reads a variable=value pair from TEXT.
2973    Looks up the variable in DICT and stores it into *VAR.
2974    Stores a null-terminated value into *VALUE. */
2975 static bool
2976 read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict,
2977                              struct text_record *text,
2978                              struct variable **var, char **value)
2979 {
2980   for (;;)
2981     {
2982       if (!text_read_short_name (r, dict, text, ss_cstr ("="), var))
2983         return false;
2984       
2985       *value = text_get_token (text, ss_buffer ("\t\0", 2), NULL);
2986       if (*value == NULL)
2987         return false;
2988
2989       text->pos += ss_span (ss_substr (text->buffer, text->pos, SIZE_MAX),
2990                             ss_buffer ("\t\0", 2));
2991
2992       if (*var != NULL)
2993         return true;
2994     }
2995 }
2996
2997 static bool
2998 text_read_variable_name (struct sfm_reader *r, struct dictionary *dict,
2999                          struct text_record *text, struct substring delimiters,
3000                          struct variable **var)
3001 {
3002   char *name;
3003
3004   name = text_get_token (text, delimiters, NULL);
3005   if (name == NULL)
3006     return false;
3007
3008   *var = dict_lookup_var (dict, name);
3009   if (*var != NULL)
3010     return true;
3011
3012   text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
3013              name);
3014   return false;
3015 }
3016
3017
3018 static bool
3019 text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
3020                       struct text_record *text, struct substring delimiters,
3021                       struct variable **var)
3022 {
3023   char *short_name = text_get_token (text, delimiters, NULL);
3024   if (short_name == NULL)
3025     return false;
3026
3027   *var = dict_lookup_var (dict, short_name);
3028   if (*var == NULL)
3029     text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
3030                short_name);
3031   return true;
3032 }
3033
3034 /* Displays a warning for the current file position, limiting the
3035    number to MAX_TEXT_WARNINGS for TEXT. */
3036 static void
3037 text_warn (struct sfm_reader *r, struct text_record *text,
3038            const char *format, ...)
3039 {
3040   if (text->n_warnings++ < MAX_TEXT_WARNINGS) 
3041     {
3042       va_list args;
3043
3044       va_start (args, format);
3045       sys_msg (r, text->start + text->pos, MW, format, args);
3046       va_end (args);
3047     }
3048 }
3049
3050 static char *
3051 text_get_token (struct text_record *text, struct substring delimiters,
3052                 char *delimiter)
3053 {
3054   struct substring token;
3055   char *end;
3056
3057   if (!ss_tokenize (text->buffer, delimiters, &text->pos, &token))
3058     return NULL;
3059
3060   end = &ss_data (token)[ss_length (token)];
3061   if (delimiter != NULL)
3062     *delimiter = *end;
3063   *end = '\0';
3064   return ss_data (token);
3065 }
3066
3067 /* Reads a integer value expressed in decimal, then a space, then a string that
3068    consists of exactly as many bytes as specified by the integer, then a space,
3069    from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
3070    buffer (so the caller should not free the string). */
3071 static const char *
3072 text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
3073 {
3074   size_t start;
3075   size_t n;
3076   char *s;
3077
3078   start = text->pos;
3079   n = 0;
3080   while (text->pos < text->buffer.length)
3081     {
3082       int c = text->buffer.string[text->pos];
3083       if (c < '0' || c > '9')
3084         break;
3085       n = (n * 10) + (c - '0');
3086       text->pos++;
3087     }
3088   if (text->pos >= text->buffer.length || start == text->pos)
3089     {
3090       sys_warn (r, text->start,
3091                 _("Expecting digit at offset %zu in MRSETS record."),
3092                 text->pos);
3093       return NULL;
3094     }
3095
3096   if (!text_match (text, ' '))
3097     {
3098       sys_warn (r, text->start,
3099                 _("Expecting space at offset %zu in MRSETS record."),
3100                 text->pos);
3101       return NULL;
3102     }
3103
3104   if (text->pos + n > text->buffer.length)
3105     {
3106       sys_warn (r, text->start,
3107                 _("%zu-byte string starting at offset %zu "
3108                   "exceeds record length %zu."),
3109                 n, text->pos, text->buffer.length);
3110       return NULL;
3111     }
3112
3113   s = &text->buffer.string[text->pos];
3114   if (s[n] != ' ')
3115     {
3116       sys_warn (r, text->start,
3117                 _("Expecting space at offset %zu following %zu-byte string."),
3118                 text->pos + n, n);
3119       return NULL;
3120     }
3121   s[n] = '\0';
3122   text->pos += n + 1;
3123   return s;
3124 }
3125
3126 static bool
3127 text_match (struct text_record *text, char c)
3128 {
3129   if (text->buffer.string[text->pos] == c) 
3130     {
3131       text->pos++;
3132       return true;
3133     }
3134   else
3135     return false;
3136 }
3137
3138 /* Returns the current byte offset (as converted to UTF-8, if it was converted)
3139    inside the TEXT's string. */
3140 static size_t
3141 text_pos (const struct text_record *text)
3142 {
3143   return text->pos;
3144 }
3145
3146 static const char *
3147 text_get_all (const struct text_record *text)
3148 {
3149   return text->buffer.string;
3150 }
3151 \f
3152 /* Messages. */
3153
3154 /* Displays a corruption message. */
3155 static void
3156 sys_msg (struct sfm_reader *r, off_t offset,
3157          int class, const char *format, va_list args)
3158 {
3159   struct msg m;
3160   struct string text;
3161
3162   ds_init_empty (&text);
3163   if (offset >= 0)
3164     ds_put_format (&text, _("`%s' near offset 0x%llx: "),
3165                    fh_get_file_name (r->fh), (long long int) offset);
3166   else
3167     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
3168   ds_put_vformat (&text, format, args);
3169
3170   m.category = msg_class_to_category (class);
3171   m.severity = msg_class_to_severity (class);
3172   m.file_name = NULL;
3173   m.first_line = 0;
3174   m.last_line = 0;
3175   m.first_column = 0;
3176   m.last_column = 0;
3177   m.text = ds_cstr (&text);
3178
3179   msg_emit (&m);
3180 }
3181
3182 /* Displays a warning for offset OFFSET in the file. */
3183 static void
3184 sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...)
3185 {
3186   va_list args;
3187
3188   va_start (args, format);
3189   sys_msg (r, offset, MW, format, args);
3190   va_end (args);
3191 }
3192
3193 /* Displays an error for the current file position and marks it as in an error
3194    state. */
3195 static void
3196 sys_error (struct sfm_reader *r, off_t offset, const char *format, ...)
3197 {
3198   va_list args;
3199
3200   va_start (args, format);
3201   sys_msg (r, offset, ME, format, args);
3202   va_end (args);
3203
3204   r->error = true;
3205 }
3206 \f
3207 /* Reads BYTE_CNT bytes into BUF.
3208    Returns 1 if exactly BYTE_CNT bytes are successfully read.
3209    Returns -1 if an I/O error or a partial read occurs.
3210    Returns 0 for an immediate end-of-file and, if EOF_IS_OK is false, reports
3211    an error. */
3212 static inline int
3213 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
3214                      void *buf, size_t byte_cnt)
3215 {
3216   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
3217   r->pos += bytes_read;
3218   if (bytes_read == byte_cnt)
3219     return 1;
3220   else if (ferror (r->file))
3221     {
3222       sys_error (r, r->pos, _("System error: %s."), strerror (errno));
3223       return -1;
3224     }
3225   else if (!eof_is_ok || bytes_read != 0)
3226     {
3227       sys_error (r, r->pos, _("Unexpected end of file."));
3228       return -1;
3229     }
3230   else
3231     return 0;
3232 }
3233
3234 /* Reads BYTE_CNT into BUF.
3235    Returns true if successful.
3236    Returns false upon I/O error or if end-of-file is encountered. */
3237 static bool
3238 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3239 {
3240   return read_bytes_internal (r, false, buf, byte_cnt) == 1;
3241 }
3242
3243 /* Reads BYTE_CNT bytes into BUF.
3244    Returns 1 if exactly BYTE_CNT bytes are successfully read.
3245    Returns 0 if an immediate end-of-file is encountered.
3246    Returns -1 if an I/O error or a partial read occurs. */
3247 static int
3248 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3249 {
3250   return read_bytes_internal (r, true, buf, byte_cnt);
3251 }
3252
3253 /* Reads a 32-bit signed integer from R and stores its value in host format in
3254    *X.  Returns true if successful, otherwise false. */
3255 static bool
3256 read_int (struct sfm_reader *r, int *x)
3257 {
3258   uint8_t integer[4];
3259   if (read_bytes (r, integer, sizeof integer) != 1)
3260     return false;
3261   *x = integer_get (r->integer_format, integer, sizeof integer);
3262   return true;
3263 }
3264
3265 static bool
3266 read_uint (struct sfm_reader *r, unsigned int *x)
3267 {
3268   bool ok;
3269   int y;
3270
3271   ok = read_int (r, &y);
3272   *x = y;
3273   return ok;
3274 }
3275
3276 /* Reads a 64-bit signed integer from R and returns its value in
3277    host format. */
3278 static bool
3279 read_int64 (struct sfm_reader *r, long long int *x)
3280 {
3281   uint8_t integer[8];
3282   if (read_bytes (r, integer, sizeof integer) != 1)
3283     return false;
3284   *x = integer_get (r->integer_format, integer, sizeof integer);
3285   return true;
3286 }
3287
3288 /* Reads a 64-bit signed integer from R and returns its value in
3289    host format. */
3290 static bool
3291 read_uint64 (struct sfm_reader *r, unsigned long long int *x)
3292 {
3293   long long int y;
3294   bool ok;
3295
3296   ok = read_int64 (r, &y);
3297   *x = y;
3298   return ok;
3299 }
3300
3301 static int
3302 parse_int (const struct sfm_reader *r, const void *data, size_t ofs)
3303 {
3304   return integer_get (r->integer_format, (const uint8_t *) data + ofs, 4);
3305 }
3306
3307 static double
3308 parse_float (const struct sfm_reader *r, const void *data, size_t ofs)
3309 {
3310   return float_get_double (r->float_format, (const uint8_t *) data + ofs);
3311 }
3312
3313 /* Reads exactly SIZE - 1 bytes into BUFFER
3314    and stores a null byte into BUFFER[SIZE - 1]. */
3315 static bool
3316 read_string (struct sfm_reader *r, char *buffer, size_t size)
3317 {
3318   bool ok;
3319
3320   assert (size > 0);
3321   ok = read_bytes (r, buffer, size - 1);
3322   if (ok)
3323     buffer[size - 1] = '\0';
3324   return ok;
3325 }
3326
3327 /* Skips BYTES bytes forward in R. */
3328 static bool
3329 skip_bytes (struct sfm_reader *r, size_t bytes)
3330 {
3331   while (bytes > 0)
3332     {
3333       char buffer[1024];
3334       size_t chunk = MIN (sizeof buffer, bytes);
3335       if (!read_bytes (r, buffer, chunk))
3336         return false;
3337       bytes -= chunk;
3338     }
3339
3340   return true;
3341 }
3342
3343 /* Returns a malloc()'d copy of S in which all lone CRs and CR LF pairs have
3344    been replaced by LFs.
3345
3346    (A product that identifies itself as VOXCO INTERVIEWER 4.3 produces system
3347    files that use CR-only line ends in the file label and extra product
3348    info.) */
3349 static char *
3350 fix_line_ends (const char *s)
3351 {
3352   char *dst, *d;
3353
3354   d = dst = xmalloc (strlen (s) + 1);
3355   while (*s != '\0')
3356     {
3357       if (*s == '\r')
3358         {
3359           s++;
3360           if (*s == '\n')
3361             s++;
3362           *d++ = '\n';
3363         }
3364       else
3365         *d++ = *s++;
3366     }
3367   *d = '\0';
3368
3369   return dst;
3370 }
3371 \f
3372 static bool
3373 read_ztrailer (struct sfm_reader *r,
3374                long long int zheader_ofs,
3375                long long int ztrailer_len);
3376
3377 static void *
3378 zalloc (voidpf pool_, uInt items, uInt size)
3379 {
3380   struct pool *pool = pool_;
3381
3382   return (!size || xalloc_oversized (items, size)
3383           ? Z_NULL
3384           : pool_malloc (pool, items * size));
3385 }
3386
3387 static void
3388 zfree (voidpf pool_, voidpf address)
3389 {
3390   struct pool *pool = pool_;
3391
3392   pool_free (pool, address);
3393 }
3394
3395 static bool
3396 read_zheader (struct sfm_reader *r)
3397 {
3398   off_t pos = r->pos;
3399   long long int zheader_ofs;
3400   long long int ztrailer_ofs;
3401   long long int ztrailer_len;
3402
3403   if (!read_int64 (r, &zheader_ofs)
3404       || !read_int64 (r, &ztrailer_ofs)
3405       || !read_int64 (r, &ztrailer_len))
3406     return false;
3407
3408   if (zheader_ofs != pos)
3409     {
3410       sys_error (r, pos, _("Wrong ZLIB data header offset %#llx "
3411                            "(expected %#llx)."),
3412                  zheader_ofs, (long long int) pos);
3413       return false;
3414     }
3415
3416   if (ztrailer_ofs < r->pos)
3417     {
3418       sys_error (r, pos, _("Impossible ZLIB trailer offset 0x%llx."),
3419                  ztrailer_ofs);
3420       return false;
3421     }
3422
3423   if (ztrailer_len < 24 || ztrailer_len % 24)
3424     {
3425       sys_error (r, pos, _("Invalid ZLIB trailer length %lld."), ztrailer_len);
3426       return false;
3427     }
3428
3429   r->ztrailer_ofs = ztrailer_ofs;
3430   if (!read_ztrailer (r, zheader_ofs, ztrailer_len))
3431     return false;
3432
3433   if (r->zin_buf == NULL)
3434     {
3435       r->zin_buf = pool_malloc (r->pool, ZIN_BUF_SIZE);
3436       r->zout_buf = pool_malloc (r->pool, ZOUT_BUF_SIZE);
3437       r->zstream.next_in = NULL;
3438       r->zstream.avail_in = 0;
3439     }
3440
3441   r->zstream.zalloc = zalloc;
3442   r->zstream.zfree = zfree;
3443   r->zstream.opaque = r->pool;
3444
3445   return open_zstream (r);
3446 }
3447
3448 static void
3449 seek (struct sfm_reader *r, off_t offset)
3450 {
3451   if (fseeko (r->file, offset, SEEK_SET))
3452     sys_error (r, 0, _("%s: seek failed (%s)."),
3453                fh_get_file_name (r->fh), strerror (errno));
3454   r->pos = offset;
3455 }
3456
3457 /* Performs some additional consistency checks on the ZLIB compressed data
3458    trailer. */
3459 static bool
3460 read_ztrailer (struct sfm_reader *r,
3461                long long int zheader_ofs,
3462                long long int ztrailer_len)
3463 {
3464   long long int expected_uncmp_ofs;
3465   long long int expected_cmp_ofs;
3466   long long int bias;
3467   long long int zero;
3468   unsigned int block_size;
3469   unsigned int n_blocks;
3470   unsigned int i;
3471   struct stat s;
3472
3473   if (fstat (fileno (r->file), &s))
3474     {
3475       sys_error (ME, 0, _("%s: stat failed (%s)."),
3476                  fh_get_file_name (r->fh), strerror (errno));
3477       return false;
3478     }
3479
3480   if (!S_ISREG (s.st_mode))
3481     {
3482       /* We can't seek to the trailer and then back to the data in this file,
3483          so skip doing extra checks. */
3484       return true;
3485     }
3486
3487   if (r->ztrailer_ofs + ztrailer_len != s.st_size)
3488     sys_warn (r, r->pos,
3489               _("End of ZLIB trailer (0x%llx) is not file size (0x%llx)."),
3490               r->ztrailer_ofs + ztrailer_len, (long long int) s.st_size);
3491
3492   seek (r, r->ztrailer_ofs);
3493
3494   /* Read fixed header from ZLIB data trailer. */
3495   if (!read_int64 (r, &bias))
3496     return false;
3497   if (-bias != r->bias)
3498     {
3499       sys_error (r, r->pos, _("ZLIB trailer bias (%lld) differs from "
3500                               "file header bias (%.2f)."),
3501                  -bias, r->bias);
3502       return false;
3503     }
3504
3505   if (!read_int64 (r, &zero))
3506     return false;
3507   if (zero != 0)
3508     sys_warn (r, r->pos,
3509               _("ZLIB trailer \"zero\" field has nonzero value %lld."), zero);
3510
3511   if (!read_uint (r, &block_size))
3512     return false;
3513   if (block_size != ZBLOCK_SIZE)
3514     sys_warn (r, r->pos,
3515               _("ZLIB trailer specifies unexpected %u-byte block size."),
3516               block_size);
3517
3518   if (!read_uint (r, &n_blocks))
3519     return false;
3520   if (n_blocks != (ztrailer_len - 24) / 24)
3521     {
3522       sys_error (r, r->pos,
3523                  _("%lld-byte ZLIB trailer specifies %u data blocks (expected "
3524                    "%lld)."),
3525                  ztrailer_len, n_blocks, (ztrailer_len - 24) / 24);
3526       return false;
3527     }
3528
3529   expected_uncmp_ofs = zheader_ofs;
3530   expected_cmp_ofs = zheader_ofs + 24;
3531   for (i = 0; i < n_blocks; i++)
3532     {
3533       off_t desc_ofs = r->pos;
3534       unsigned long long int uncompressed_ofs;
3535       unsigned long long int compressed_ofs;
3536       unsigned int uncompressed_size;
3537       unsigned int compressed_size;
3538
3539       if (!read_uint64 (r, &uncompressed_ofs)
3540           || !read_uint64 (r, &compressed_ofs)
3541           || !read_uint (r, &uncompressed_size)
3542           || !read_uint (r, &compressed_size))
3543         return false;
3544
3545       if (uncompressed_ofs != expected_uncmp_ofs)
3546         {
3547           sys_error (r, desc_ofs,
3548                      _("ZLIB block descriptor %u reported uncompressed data "
3549                        "offset %#llx, when %#llx was expected."),
3550                      i, uncompressed_ofs, expected_uncmp_ofs);
3551           return false;
3552         }
3553
3554       if (compressed_ofs != expected_cmp_ofs)
3555         {
3556           sys_error (r, desc_ofs,
3557                      _("ZLIB block descriptor %u reported compressed data "
3558                        "offset %#llx, when %#llx was expected."),
3559                      i, compressed_ofs, expected_cmp_ofs);
3560           return false;
3561         }
3562
3563       if (i < n_blocks - 1)
3564         {
3565           if (uncompressed_size != block_size)
3566             sys_warn (r, desc_ofs,
3567                       _("ZLIB block descriptor %u reported block size %#x, "
3568                         "when %#x was expected."),
3569                       i, uncompressed_size, block_size);
3570         }
3571       else
3572         {
3573           if (uncompressed_size > block_size)
3574             sys_warn (r, desc_ofs,
3575                       _("ZLIB block descriptor %u reported block size %#x, "
3576                         "when at most %#x was expected."),
3577                       i, uncompressed_size, block_size);
3578         }
3579
3580       /* http://www.zlib.net/zlib_tech.html says that the maximum expansion
3581          from compression, with worst-case parameters, is 13.5% plus 11 bytes.
3582          This code checks for an expansion of more than 14.3% plus 11
3583          bytes.  */
3584       if (compressed_size > uncompressed_size + uncompressed_size / 7 + 11)
3585         {
3586           sys_error (r, desc_ofs,
3587                      _("ZLIB block descriptor %u reports compressed size %u "
3588                        "and uncompressed size %u."),
3589                      i, compressed_size, uncompressed_size);
3590           return false;
3591         }
3592
3593       expected_uncmp_ofs += uncompressed_size;
3594       expected_cmp_ofs += compressed_size;
3595     }
3596
3597   if (expected_cmp_ofs != r->ztrailer_ofs)
3598     {
3599       sys_error (r, r->pos, _("ZLIB trailer is at offset %#llx but %#llx "
3600                               "would be expected from block descriptors."),
3601                  r->ztrailer_ofs, expected_cmp_ofs);
3602       return false;
3603     }
3604
3605   seek (r, zheader_ofs + 24);
3606   return true;
3607 }
3608
3609 static bool
3610 open_zstream (struct sfm_reader *r)
3611 {
3612   int error;
3613
3614   r->zout_pos = r->zout_end = 0;
3615   error = inflateInit (&r->zstream);
3616   if (error != Z_OK)
3617     {
3618       sys_error (r, r->pos, _("ZLIB initialization failed (%s)."),
3619                  r->zstream.msg);
3620       return false;
3621     }
3622   return true;
3623 }
3624
3625 static bool
3626 close_zstream (struct sfm_reader *r)
3627 {
3628   int error;
3629
3630   error = inflateEnd (&r->zstream);
3631   if (error != Z_OK)
3632     {
3633       sys_error (r, r->pos, _("Inconsistency at end of ZLIB stream (%s)."),
3634                  r->zstream.msg);
3635       return false;
3636     }
3637   return true;
3638 }
3639
3640 static int
3641 read_bytes_zlib (struct sfm_reader *r, void *buf_, size_t byte_cnt)
3642 {
3643   uint8_t *buf = buf_;
3644
3645   if (byte_cnt == 0)
3646     return 1;
3647
3648   for (;;)
3649     {
3650       int error;
3651
3652       /* Use already inflated data if there is any. */
3653       if (r->zout_pos < r->zout_end)
3654         {
3655           unsigned int n = MIN (byte_cnt, r->zout_end - r->zout_pos);
3656           memcpy (buf, &r->zout_buf[r->zout_pos], n);
3657           r->zout_pos += n;
3658           byte_cnt -= n;
3659           buf += n;
3660
3661           if (byte_cnt == 0)
3662             return 1;
3663         }
3664
3665       /* We need to inflate some more data.
3666          Get some more input data if we don't have any. */
3667       if (r->zstream.avail_in == 0)
3668         {
3669           unsigned int n = MIN (ZIN_BUF_SIZE, r->ztrailer_ofs - r->pos);
3670           if (n == 0)
3671             return 0;
3672           else
3673             {
3674               int retval = try_read_bytes (r, r->zin_buf, n);
3675               if (retval != 1)
3676                 return retval;
3677               r->zstream.avail_in = n;
3678               r->zstream.next_in = r->zin_buf;
3679             }
3680         }
3681
3682       /* Inflate the (remaining) input data. */
3683       r->zstream.avail_out = ZOUT_BUF_SIZE;
3684       r->zstream.next_out = r->zout_buf;
3685       error = inflate (&r->zstream, Z_SYNC_FLUSH);
3686       r->zout_pos = 0;
3687       r->zout_end = r->zstream.next_out - r->zout_buf;
3688       if (r->zout_end == 0)
3689         {
3690           if (error != Z_STREAM_END)
3691             {
3692               sys_error (r, r->pos, _("ZLIB stream inconsistency (%s)."),
3693                          r->zstream.msg);
3694               return -1;
3695             }
3696           else if (!close_zstream (r) || !open_zstream (r))
3697             return -1;
3698         }
3699       else
3700         {
3701           /* Process the output data and ignore 'error' for now.  ZLIB will
3702              present it to us again on the next inflate() call. */
3703         }
3704     }
3705 }
3706
3707 static int
3708 read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3709 {
3710   if (r->compression == ANY_COMP_SIMPLE)
3711     return read_bytes (r, buf, byte_cnt);
3712   else
3713     {
3714       int retval = read_bytes_zlib (r, buf, byte_cnt);
3715       if (retval == 0)
3716         sys_error (r, r->pos, _("Unexpected end of ZLIB compressed data."));
3717       return retval;
3718     }
3719 }
3720
3721 static int
3722 try_read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
3723 {
3724   if (r->compression == ANY_COMP_SIMPLE)
3725     return try_read_bytes (r, buf, byte_cnt);
3726   else
3727     return read_bytes_zlib (r, buf, byte_cnt);
3728 }
3729
3730 /* Reads a 64-bit floating-point number from R and returns its
3731    value in host format. */
3732 static bool
3733 read_compressed_float (struct sfm_reader *r, double *d)
3734 {
3735   uint8_t number[8];
3736
3737   if (!read_compressed_bytes (r, number, sizeof number))
3738     return false;
3739
3740   *d = float_get_double (r->float_format, number);
3741   return true;
3742 }
3743 \f
3744 static const struct casereader_class sys_file_casereader_class =
3745   {
3746     sys_file_casereader_read,
3747     sys_file_casereader_destroy,
3748     NULL,
3749     NULL,
3750   };
3751
3752 const struct any_reader_class sys_file_reader_class =
3753   {
3754     N_("SPSS System File"),
3755     sfm_detect,
3756     sfm_open,
3757     sfm_close,
3758     sfm_decode,
3759     sfm_get_strings,
3760   };