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