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