sys-file-reader, sys-file-writer: Use codepage numbers.
[pspp] / src / data / sys-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-2000, 2006-2007, 2009-2011 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-reader.h"
20 #include "data/sys-file-private.h"
21
22 #include <errno.h>
23 #include <float.h>
24 #include <inttypes.h>
25 #include <setjmp.h>
26 #include <stdlib.h>
27
28 #include "data/attributes.h"
29 #include "data/case.h"
30 #include "data/casereader-provider.h"
31 #include "data/casereader.h"
32 #include "data/dictionary.h"
33 #include "data/file-handle-def.h"
34 #include "data/file-name.h"
35 #include "data/format.h"
36 #include "data/identifier.h"
37 #include "data/missing-values.h"
38 #include "data/mrset.h"
39 #include "data/short-names.h"
40 #include "data/value-labels.h"
41 #include "data/value.h"
42 #include "data/variable.h"
43 #include "libpspp/array.h"
44 #include "libpspp/assertion.h"
45 #include "libpspp/compiler.h"
46 #include "libpspp/i18n.h"
47 #include "libpspp/message.h"
48 #include "libpspp/misc.h"
49 #include "libpspp/pool.h"
50 #include "libpspp/str.h"
51 #include "libpspp/stringi-set.h"
52
53 #include "gl/c-ctype.h"
54 #include "gl/inttostr.h"
55 #include "gl/localcharset.h"
56 #include "gl/minmax.h"
57 #include "gl/unlocked-io.h"
58 #include "gl/xalloc.h"
59 #include "gl/xsize.h"
60
61 #include "gettext.h"
62 #define _(msgid) gettext (msgid)
63 #define N_(msgid) (msgid)
64
65 enum
66   {
67     /* subtypes 0-2 unknown */
68     EXT_INTEGER       = 3,      /* Machine integer info. */
69     EXT_FLOAT         = 4,      /* Machine floating-point info. */
70     EXT_VAR_SETS      = 5,      /* Variable sets. */
71     EXT_DATE          = 6,      /* DATE. */
72     EXT_MRSETS        = 7,      /* Multiple response sets. */
73     EXT_DATA_ENTRY    = 8,      /* SPSS Data Entry. */
74     /* subtypes 9-10 unknown */
75     EXT_DISPLAY       = 11,     /* Variable display parameters. */
76     /* subtype 12 unknown */
77     EXT_LONG_NAMES    = 13,     /* Long variable names. */
78     EXT_LONG_STRINGS  = 14,     /* Long strings. */
79     /* subtype 15 unknown */
80     EXT_NCASES        = 16,     /* Extended number of cases. */
81     EXT_FILE_ATTRS    = 17,     /* Data file attributes. */
82     EXT_VAR_ATTRS     = 18,     /* Variable attributes. */
83     EXT_MRSETS2       = 19,     /* Multiple response sets (extended). */
84     EXT_ENCODING      = 20,     /* Character encoding. */
85     EXT_LONG_LABELS   = 21      /* Value labels for long strings. */
86   };
87
88 struct sfm_var_record
89   {
90     off_t pos;
91     int width;
92     char name[8];
93     int print_format;
94     int write_format;
95     int missing_value_code;
96     uint8_t missing[24];
97     char *label;
98     struct variable *var;
99   };
100
101 struct sfm_value_label
102   {
103     uint8_t value[8];
104     char *label;
105   };
106
107 struct sfm_value_label_record
108   {
109     off_t pos;
110     struct sfm_value_label *labels;
111     size_t n_labels;
112
113     int *vars;
114     size_t n_vars;
115   };
116
117 struct sfm_document_record
118   {
119     off_t pos;
120     char *documents;
121     size_t n_lines;
122   };
123
124 struct sfm_extension_record
125   {
126     off_t pos;                  /* Starting offset in file. */
127     size_t size;                /* Size of data elements. */
128     size_t count;               /* Number of data elements. */
129     void *data;                 /* Contents. */
130   };
131
132 /* System file reader. */
133 struct sfm_reader
134   {
135     /* Resource tracking. */
136     struct pool *pool;          /* All system file state. */
137     jmp_buf bail_out;           /* longjmp() target for error handling. */
138
139     /* File state. */
140     struct file_handle *fh;     /* File handle. */
141     struct fh_lock *lock;       /* Mutual exclusion for file handle. */
142     FILE *file;                 /* File stream. */
143     off_t pos;                  /* Position in file. */
144     bool error;                 /* I/O or corruption error? */
145     struct caseproto *proto;    /* Format of output cases. */
146
147     /* File format. */
148     enum integer_format integer_format; /* On-disk integer format. */
149     enum float_format float_format; /* On-disk floating point format. */
150     struct sfm_var *sfm_vars;   /* Variables. */
151     size_t sfm_var_cnt;         /* Number of variables. */
152     casenumber case_cnt;        /* Number of cases */
153     const char *encoding;       /* String encoding. */
154
155     /* Decompression. */
156     bool compressed;            /* File is compressed? */
157     double bias;                /* Compression bias, usually 100.0. */
158     uint8_t opcodes[8];         /* Current block of opcodes. */
159     size_t opcode_idx;          /* Next opcode to interpret, 8 if none left. */
160     bool corruption_warning;    /* Warned about possible corruption? */
161   };
162
163 static const struct casereader_class sys_file_casereader_class;
164
165 static bool close_reader (struct sfm_reader *);
166
167 static struct variable *lookup_var_by_index (struct sfm_reader *, off_t,
168                                              const struct sfm_var_record *,
169                                              size_t n, int idx);
170
171 static void sys_msg (struct sfm_reader *r, off_t, int class,
172                      const char *format, va_list args)
173      PRINTF_FORMAT (4, 0);
174 static void sys_warn (struct sfm_reader *, off_t, const char *, ...)
175      PRINTF_FORMAT (3, 4);
176 static void sys_error (struct sfm_reader *, off_t, const char *, ...)
177      PRINTF_FORMAT (3, 4)
178      NO_RETURN;
179
180 static void read_bytes (struct sfm_reader *, void *, size_t);
181 static bool try_read_bytes (struct sfm_reader *, void *, size_t);
182 static int read_int (struct sfm_reader *);
183 static double read_float (struct sfm_reader *);
184 static void read_string (struct sfm_reader *, char *, size_t);
185 static void skip_bytes (struct sfm_reader *, size_t);
186
187 static int parse_int (struct sfm_reader *, const void *data, size_t ofs);
188 static double parse_float (struct sfm_reader *, const void *data, size_t ofs);
189
190 static void read_variable_record (struct sfm_reader *,
191                                   struct sfm_var_record *);
192 static void read_value_label_record (struct sfm_reader *,
193                                      struct sfm_value_label_record *,
194                                      size_t n_vars);
195 static struct sfm_document_record *read_document_record (struct sfm_reader *);
196 static struct sfm_extension_record *read_extension_record (
197   struct sfm_reader *, int subtype);
198 static void skip_extension_record (struct sfm_reader *, int subtype);
199
200 static const char *choose_encoding (
201   struct sfm_reader *,
202   const struct sfm_extension_record *ext_integer,
203   const struct sfm_extension_record *ext_encoding);
204
205 static struct text_record *open_text_record (
206   struct sfm_reader *, const struct sfm_extension_record *,
207   bool recode_to_utf8);
208 static void close_text_record (struct sfm_reader *,
209                                struct text_record *);
210 static bool read_variable_to_value_pair (struct sfm_reader *,
211                                          struct dictionary *,
212                                          struct text_record *,
213                                          struct variable **var, char **value);
214 static void text_warn (struct sfm_reader *r, struct text_record *text,
215                        const char *format, ...)
216   PRINTF_FORMAT (3, 4);
217 static char *text_get_token (struct text_record *,
218                              struct substring delimiters, char *delimiter);
219 static bool text_match (struct text_record *, char c);
220 static bool text_read_variable_name (struct sfm_reader *, struct dictionary *,
221                                      struct text_record *,
222                                      struct substring delimiters,
223                                      struct variable **);
224 static bool text_read_short_name (struct sfm_reader *, struct dictionary *,
225                                   struct text_record *,
226                                   struct substring delimiters,
227                                   struct variable **);
228 static const char *text_parse_counted_string (struct sfm_reader *,
229                                               struct text_record *);
230 static size_t text_pos (const struct text_record *);
231
232 static bool close_reader (struct sfm_reader *r);
233 \f
234 /* Dictionary reader. */
235
236 enum which_format
237   {
238     PRINT_FORMAT,
239     WRITE_FORMAT
240   };
241
242 static void read_header (struct sfm_reader *, int *weight_idx,
243                          int *claimed_oct_cnt, struct sfm_read_info *,
244                          char **file_labelp);
245 static void parse_file_label (struct sfm_reader *, const char *file_label,
246                               struct dictionary *);
247 static void parse_variable_records (struct sfm_reader *, struct dictionary *,
248                                     struct sfm_var_record *, size_t n);
249 static void parse_format_spec (struct sfm_reader *, off_t pos,
250                                unsigned int format, enum which_format,
251                                struct variable *, int *format_warning_cnt);
252 static void parse_document (struct dictionary *, struct sfm_document_record *);
253 static void parse_display_parameters (struct sfm_reader *,
254                                       const struct sfm_extension_record *,
255                                       struct dictionary *);
256 static void parse_machine_integer_info (struct sfm_reader *,
257                                         const struct sfm_extension_record *,
258                                         struct sfm_read_info *);
259 static void parse_machine_float_info (struct sfm_reader *,
260                                       const struct sfm_extension_record *);
261 static void parse_mrsets (struct sfm_reader *,
262                           const struct sfm_extension_record *,
263                           struct dictionary *);
264 static void parse_long_var_name_map (struct sfm_reader *,
265                                      const struct sfm_extension_record *,
266                                      struct dictionary *);
267 static void parse_long_string_map (struct sfm_reader *,
268                                    const struct sfm_extension_record *,
269                                    struct dictionary *);
270 static void parse_value_labels (struct sfm_reader *, struct dictionary *,
271                                 const struct sfm_var_record *,
272                                 size_t n_var_recs,
273                                 const struct sfm_value_label_record *);
274 static void parse_data_file_attributes (struct sfm_reader *,
275                                         const struct sfm_extension_record *,
276                                         struct dictionary *);
277 static void parse_variable_attributes (struct sfm_reader *,
278                                        const struct sfm_extension_record *,
279                                        struct dictionary *);
280 static void parse_long_string_value_labels (struct sfm_reader *,
281                                             const struct sfm_extension_record *,
282                                             struct dictionary *);
283
284 /* Opens the system file designated by file handle FH for
285    reading.  Reads the system file's dictionary into *DICT.
286    If INFO is non-null, then it receives additional info about the
287    system file. */
288 struct casereader *
289 sfm_open_reader (struct file_handle *fh, struct dictionary **dictp,
290                  struct sfm_read_info *volatile info)
291 {
292   struct sfm_reader *volatile r = NULL;
293   struct sfm_read_info local_info;
294
295   struct sfm_var_record *vars;
296   size_t n_vars, allocated_vars;
297
298   struct sfm_value_label_record *labels;
299   size_t n_labels, allocated_labels;
300
301   struct sfm_document_record *document;
302
303   struct sfm_extension_record *extensions[32];
304
305   int weight_idx;
306   int claimed_oct_cnt;
307   char *file_label;
308
309   struct dictionary *dict = NULL;
310   size_t i;
311
312   /* Create and initialize reader. */
313   r = pool_create_container (struct sfm_reader, pool);
314   r->fh = fh_ref (fh);
315   r->lock = NULL;
316   r->file = NULL;
317   r->pos = 0;
318   r->error = false;
319   r->opcode_idx = sizeof r->opcodes;
320   r->corruption_warning = false;
321
322   /* TRANSLATORS: this fragment will be interpolated into
323      messages in fh_lock() that identify types of files. */
324   r->lock = fh_lock (fh, FH_REF_FILE, N_("system file"), FH_ACC_READ, false);
325   if (r->lock == NULL)
326     goto error;
327
328   r->file = fn_open (fh_get_file_name (fh), "rb");
329   if (r->file == NULL)
330     {
331       msg (ME, _("Error opening `%s' for reading as a system file: %s."),
332            fh_get_file_name (r->fh), strerror (errno));
333       goto error;
334     }
335
336   /* Initialize info. */
337   if (info == NULL)
338     info = &local_info;
339   memset (info, 0, sizeof *info);
340
341   if (setjmp (r->bail_out))
342     goto error;
343
344   /* Read header. */
345   read_header (r, &weight_idx, &claimed_oct_cnt, info, &file_label);
346
347   vars = NULL;
348   n_vars = allocated_vars = 0;
349
350   labels = NULL;
351   n_labels = allocated_labels = 0;
352
353   document = NULL;
354
355   memset (extensions, 0, sizeof extensions);
356
357   for (;;)
358     {
359       int subtype;
360       int type;
361
362       type = read_int (r);
363       if (type == 999)
364         {
365           read_int (r);         /* Skip filler. */
366           break;
367         }
368
369       switch (type)
370         {
371         case 2:
372           if (n_vars >= allocated_vars)
373             vars = pool_2nrealloc (r->pool, vars, &allocated_vars,
374                                    sizeof *vars);
375           read_variable_record (r, &vars[n_vars++]);
376           break;
377
378         case 3:
379           if (n_labels >= allocated_labels)
380             labels = pool_2nrealloc (r->pool, labels, &allocated_labels,
381                                      sizeof *labels);
382           read_value_label_record (r, &labels[n_labels++], n_vars);
383           break;
384
385         case 4:
386           /* A Type 4 record is always immediately after a type 3 record,
387              so the code for type 3 records reads the type 4 record too. */
388           sys_error (r, r->pos, _("Misplaced type 4 record."));
389
390         case 6:
391           if (document != NULL)
392             sys_error (r, r->pos, _("Duplicate type 6 (document) record."));
393           document = read_document_record (r);
394           break;
395
396         case 7:
397           subtype = read_int (r);
398           if (subtype < 0 || subtype >= sizeof extensions / sizeof *extensions)
399             {
400               sys_warn (r, r->pos,
401                         _("Unrecognized record type 7, subtype %d.  Please "
402                           "send a copy of this file, and the syntax which "
403                           "created it to %s."),
404                         subtype, PACKAGE_BUGREPORT);
405               skip_extension_record (r, subtype);
406             }
407           else if (extensions[subtype] != NULL)
408             {
409               sys_warn (r, r->pos,
410                         _("Record type 7, subtype %d found here has the same "
411                           "type as the record found near offset 0x%llx.  "
412                           "Please send a copy of this file, and the syntax "
413                           "which created it to %s."),
414                         subtype, (long long int) extensions[subtype]->pos,
415                         PACKAGE_BUGREPORT);
416               skip_extension_record (r, subtype);
417             }
418           else
419             extensions[subtype] = read_extension_record (r, subtype);
420           break;
421
422         default:
423           sys_error (r, r->pos, _("Unrecognized record type %d."), type);
424           goto error;
425         }
426     }
427
428   /* Now actually parse what we read.
429
430      First, figure out the correct character encoding, because this determines
431      how the rest of the header data is to be interpreted. */
432   dict = dict_create (choose_encoding (r, extensions[EXT_INTEGER],
433                                        extensions[EXT_ENCODING]));
434   r->encoding = dict_get_encoding (dict);
435
436   /* These records don't use variables at all. */
437   if (document != NULL)
438     parse_document (dict, document);
439
440   if (extensions[EXT_INTEGER] != NULL)
441     parse_machine_integer_info (r, extensions[EXT_INTEGER], info);
442
443   if (extensions[EXT_FLOAT] != NULL)
444     parse_machine_float_info (r, extensions[EXT_FLOAT]);
445
446   if (extensions[EXT_FILE_ATTRS] != NULL)
447     parse_data_file_attributes (r, extensions[EXT_FILE_ATTRS], dict);
448
449   parse_file_label (r, file_label, dict);
450
451   /* Parse the variable records, the basis of almost everything else. */
452   parse_variable_records (r, dict, vars, n_vars);
453
454   /* Parse value labels and the weight variable immediately after the variable
455      records.  These records use indexes into var_recs[], so we must parse them
456      before those indexes become invalidated by very long string variables. */
457   for (i = 0; i < n_labels; i++)
458     parse_value_labels (r, dict, vars, n_vars, &labels[i]);
459   if (weight_idx != 0)
460     {
461       struct variable *weight_var;
462
463       weight_var = lookup_var_by_index (r, 76, vars, n_vars, weight_idx);
464       if (var_is_numeric (weight_var))
465         dict_set_weight (dict, weight_var);
466       else
467         sys_error (r, -1, _("Weighting variable must be numeric "
468                             "(not string variable `%s')."),
469                    var_get_name (weight_var));
470     }
471
472   if (extensions[EXT_DISPLAY] != NULL)
473     parse_display_parameters (r, extensions[EXT_DISPLAY], dict);
474
475   /* The following records use short names, so they need to be parsed before
476      parse_long_var_name_map() changes short names to long names. */
477   if (extensions[EXT_MRSETS] != NULL)
478     parse_mrsets (r, extensions[EXT_MRSETS], dict);
479
480   if (extensions[EXT_MRSETS2] != NULL)
481     parse_mrsets (r, extensions[EXT_MRSETS2], dict);
482
483   if (extensions[EXT_LONG_STRINGS] != NULL)
484     parse_long_string_map (r, extensions[EXT_LONG_STRINGS], dict);
485
486   /* Now rename variables to their long names. */
487   parse_long_var_name_map (r, extensions[EXT_LONG_NAMES], dict);
488
489   /* The following records use long names, so they need to follow renaming. */
490   if (extensions[EXT_VAR_ATTRS] != NULL)
491     parse_variable_attributes (r, extensions[EXT_VAR_ATTRS], dict);
492
493   if (extensions[EXT_LONG_LABELS] != NULL)
494     parse_long_string_value_labels (r, extensions[EXT_LONG_LABELS], dict);
495
496   /* Warn if the actual amount of data per case differs from the
497      amount that the header claims.  SPSS version 13 gets this
498      wrong when very long strings are involved, so don't warn in
499      that case. */
500   if (claimed_oct_cnt != -1 && claimed_oct_cnt != n_vars
501       && info->version_major != 13)
502     sys_warn (r, -1, _("File header claims %d variable positions but "
503                        "%zu were read from file."),
504               claimed_oct_cnt, n_vars);
505
506   /* Create an index of dictionary variable widths for
507      sfm_read_case to use.  We cannot use the `struct variable's
508      from the dictionary we created, because the caller owns the
509      dictionary and may destroy or modify its variables. */
510   sfm_dictionary_to_sfm_vars (dict, &r->sfm_vars, &r->sfm_var_cnt);
511   pool_register (r->pool, free, r->sfm_vars);
512   r->proto = caseproto_ref_pool (dict_get_proto (dict), r->pool);
513
514   *dictp = dict;
515   return casereader_create_sequential
516     (NULL, r->proto,
517      r->case_cnt == -1 ? CASENUMBER_MAX: r->case_cnt,
518                                        &sys_file_casereader_class, r);
519
520 error:
521   close_reader (r);
522   dict_destroy (dict);
523   *dictp = NULL;
524   return NULL;
525 }
526
527 /* Closes a system file after we're done with it.
528    Returns true if an I/O error has occurred on READER, false
529    otherwise. */
530 static bool
531 close_reader (struct sfm_reader *r)
532 {
533   bool error;
534
535   if (r == NULL)
536     return true;
537
538   if (r->file)
539     {
540       if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
541         {
542           msg (ME, _("Error closing system file `%s': %s."),
543                fh_get_file_name (r->fh), strerror (errno));
544           r->error = true;
545         }
546       r->file = NULL;
547     }
548
549   fh_unlock (r->lock);
550   fh_unref (r->fh);
551
552   error = r->error;
553   pool_destroy (r->pool);
554
555   return !error;
556 }
557
558 /* Destroys READER. */
559 static void
560 sys_file_casereader_destroy (struct casereader *reader UNUSED, void *r_)
561 {
562   struct sfm_reader *r = r_;
563   close_reader (r);
564 }
565
566 /* Returns true if FILE is an SPSS system file,
567    false otherwise. */
568 bool
569 sfm_detect (FILE *file)
570 {
571   char rec_type[5];
572
573   if (fread (rec_type, 4, 1, file) != 1)
574     return false;
575   rec_type[4] = '\0';
576
577   return !strcmp ("$FL2", rec_type);
578 }
579 \f
580 /* Reads the global header of the system file.  Sets *WEIGHT_IDX to 0 if the
581    system file is unweighted, or to the value index of the weight variable
582    otherwise.  Sets *CLAIMED_OCT_CNT to the number of "octs" (8-byte units) per
583    case that the file claims to have (although it is not always correct).
584    Initializes INFO with header information.  Stores the file label as a string
585    in dictionary encoding into *FILE_LABELP. */
586 static void
587 read_header (struct sfm_reader *r, int *weight_idx,
588              int *claimed_oct_cnt, struct sfm_read_info *info,
589              char **file_labelp)
590 {
591   char rec_type[5];
592   char eye_catcher[61];
593   uint8_t raw_layout_code[4];
594   uint8_t raw_bias[8];
595   char creation_date[10];
596   char creation_time[9];
597   char file_label[65];
598   struct substring product;
599
600   read_string (r, rec_type, sizeof rec_type);
601   read_string (r, eye_catcher, sizeof eye_catcher);
602
603   if (strcmp ("$FL2", rec_type) != 0)
604     sys_error (r, 0, _("This is not an SPSS system file."));
605
606   /* Identify integer format. */
607   read_bytes (r, raw_layout_code, sizeof raw_layout_code);
608   if ((!integer_identify (2, raw_layout_code, sizeof raw_layout_code,
609                           &r->integer_format)
610        && !integer_identify (3, raw_layout_code, sizeof raw_layout_code,
611                              &r->integer_format))
612       || (r->integer_format != INTEGER_MSB_FIRST
613           && r->integer_format != INTEGER_LSB_FIRST))
614     sys_error (r, 64, _("This is not an SPSS system file."));
615
616   *claimed_oct_cnt = read_int (r);
617   if (*claimed_oct_cnt < 0 || *claimed_oct_cnt > INT_MAX / 16)
618     *claimed_oct_cnt = -1;
619
620   r->compressed = read_int (r) != 0;
621
622   *weight_idx = read_int (r);
623
624   r->case_cnt = read_int (r);
625   if ( r->case_cnt > INT_MAX / 2)
626     r->case_cnt = -1;
627
628   /* Identify floating-point format and obtain compression bias. */
629   read_bytes (r, raw_bias, sizeof raw_bias);
630   if (float_identify (100.0, raw_bias, sizeof raw_bias, &r->float_format) == 0)
631     {
632       uint8_t zero_bias[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
633
634       if (memcmp (raw_bias, zero_bias, 8))
635         sys_warn (r, r->pos - 8,
636                   _("Compression bias is not the usual "
637                     "value of 100, or system file uses unrecognized "
638                     "floating-point format."));
639       else
640         {
641           /* Some software is known to write all-zeros to this
642              field.  Such software also writes floating-point
643              numbers in the format that we expect by default
644              (it seems that all software most likely does, in
645              reality), so don't warn in this case. */
646         }
647
648       if (r->integer_format == INTEGER_MSB_FIRST)
649         r->float_format = FLOAT_IEEE_DOUBLE_BE;
650       else
651         r->float_format = FLOAT_IEEE_DOUBLE_LE;
652     }
653   float_convert (r->float_format, raw_bias, FLOAT_NATIVE_DOUBLE, &r->bias);
654
655   read_string (r, creation_date, sizeof creation_date);
656   read_string (r, creation_time, sizeof creation_time);
657   read_string (r, file_label, sizeof file_label);
658   skip_bytes (r, 3);
659
660   strcpy (info->creation_date, creation_date);
661   strcpy (info->creation_time, creation_time);
662   info->integer_format = r->integer_format;
663   info->float_format = r->float_format;
664   info->compressed = r->compressed;
665   info->case_cnt = r->case_cnt;
666
667   product = ss_cstr (eye_catcher);
668   ss_match_string (&product, ss_cstr ("@(#) SPSS DATA FILE"));
669   ss_trim (&product, ss_cstr (" "));
670   str_copy_buf_trunc (info->product, sizeof info->product,
671                       ss_data (product), ss_length (product));
672
673   *file_labelp = pool_strdup0 (r->pool, file_label, sizeof file_label - 1);
674 }
675
676 /* Reads a variable (type 2) record from R into RECORD. */
677 static void
678 read_variable_record (struct sfm_reader *r, struct sfm_var_record *record)
679 {
680   int has_variable_label;
681
682   memset (record, 0, sizeof *record);
683
684   record->pos = r->pos;
685   record->width = read_int (r);
686   has_variable_label = read_int (r);
687   record->missing_value_code = read_int (r);
688   record->print_format = read_int (r);
689   record->write_format = read_int (r);
690   read_bytes (r, record->name, sizeof record->name);
691
692   if (has_variable_label == 1)
693     {
694       enum { MAX_LABEL_LEN = 255 };
695       size_t len, read_len;
696
697       len = read_int (r);
698
699       /* Read up to MAX_LABEL_LEN bytes of label. */
700       read_len = MIN (MAX_LABEL_LEN, len);
701       record->label = xmalloc (read_len + 1);
702       read_string (r, record->label, read_len + 1);
703
704       /* Skip unread label bytes. */
705       skip_bytes (r, len - read_len);
706
707       /* Skip label padding up to multiple of 4 bytes. */
708       skip_bytes (r, ROUND_UP (len, 4) - len);
709     }
710   else if (has_variable_label != 0)
711     sys_error (r, record->pos,
712                _("Variable label indicator field is not 0 or 1."));
713
714   /* Set missing values. */
715   if (record->missing_value_code != 0)
716     {
717       int code = record->missing_value_code;
718       if (record->width == 0)
719         {
720           if (code < -3 || code > 3 || code == -1)
721             sys_error (r, record->pos,
722                        _("Numeric missing value indicator field is not "
723                          "-3, -2, 0, 1, 2, or 3."));
724         }
725       else
726         {
727           if (code < 1 || code > 3)
728             sys_error (r, record->pos,
729                        _("String missing value indicator field is not "
730                          "0, 1, 2, or 3."));
731         }
732
733       read_bytes (r, record->missing, 8 * abs (code));
734     }
735 }
736
737 /* Reads value labels from R into RECORD. */
738 static void
739 read_value_label_record (struct sfm_reader *r,
740                          struct sfm_value_label_record *record,
741                          size_t n_vars)
742 {
743   size_t i;
744
745   /* Read type 3 record. */
746   record->pos = r->pos;
747   record->n_labels = read_int (r);
748   if (record->n_labels > SIZE_MAX / sizeof *record->labels)
749     sys_error (r, r->pos - 4, _("Invalid number of labels %zu."),
750                record->n_labels);
751   record->labels = pool_nmalloc (r->pool, record->n_labels,
752                                  sizeof *record->labels);
753   for (i = 0; i < record->n_labels; i++)
754     {
755       struct sfm_value_label *label = &record->labels[i];
756       unsigned char label_len;
757       size_t padded_len;
758
759       read_bytes (r, label->value, sizeof label->value);
760
761       /* Read label length. */
762       read_bytes (r, &label_len, sizeof label_len);
763       padded_len = ROUND_UP (label_len + 1, 8);
764
765       /* Read label, padding. */
766       label->label = pool_malloc (r->pool, padded_len + 1);
767       read_bytes (r, label->label, padded_len - 1);
768       label->label[label_len] = '\0';
769     }
770
771   /* Read record type of type 4 record. */
772   if (read_int (r) != 4)
773     sys_error (r, r->pos - 4,
774                _("Variable index record (type 4) does not immediately "
775                  "follow value label record (type 3) as it should."));
776
777   /* Read number of variables associated with value label from type 4
778      record. */
779   record->n_vars = read_int (r);
780   if (record->n_vars < 1 || record->n_vars > n_vars)
781     sys_error (r, r->pos - 4,
782                _("Number of variables associated with a value label (%zu) "
783                  "is not between 1 and the number of variables (%zu)."),
784                record->n_vars, n_vars);
785   record->vars = pool_nmalloc (r->pool, record->n_vars, sizeof *record->vars);
786   for (i = 0; i < record->n_vars; i++)
787     record->vars[i] = read_int (r);
788 }
789
790 /* Reads a document record from R and returns it. */
791 static struct sfm_document_record *
792 read_document_record (struct sfm_reader *r)
793 {
794   struct sfm_document_record *record;
795   int n_lines;
796
797   record = pool_malloc (r->pool, sizeof *record);
798   record->pos = r->pos;
799
800   n_lines = read_int (r);
801   if (n_lines <= 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH)
802     sys_error (r, record->pos,
803                _("Number of document lines (%d) "
804                  "must be greater than 0 and less than %d."),
805                n_lines, INT_MAX / DOC_LINE_LENGTH);
806
807   record->n_lines = n_lines;
808   record->documents = pool_malloc (r->pool, DOC_LINE_LENGTH * n_lines);
809   read_bytes (r, record->documents, DOC_LINE_LENGTH * n_lines);
810
811   return record;
812 }
813
814 static void
815 read_extension_record_header (struct sfm_reader *r, int subtype,
816                               struct sfm_extension_record *record)
817 {
818   record->pos = r->pos;
819   record->size = read_int (r);
820   record->count = read_int (r);
821
822   /* Check that SIZE * COUNT + 1 doesn't overflow.  Adding 1
823      allows an extra byte for a null terminator, used by some
824      extension processing routines. */
825   if (record->size != 0
826       && size_overflow_p (xsum (1, xtimes (record->count, record->size))))
827     sys_error (r, record->pos, "Record type 7 subtype %d too large.", subtype);
828 }
829
830 /* Reads an extension record from R into RECORD. */
831 static struct sfm_extension_record *
832 read_extension_record (struct sfm_reader *r, int subtype)
833 {
834   struct extension_record_type
835     {
836       int subtype;
837       int size;
838       int count;
839     };
840
841   static const struct extension_record_type types[] =
842     {
843       /* Implemented record types. */
844       { EXT_INTEGER,      4, 8 },
845       { EXT_FLOAT,        8, 3 },
846       { EXT_MRSETS,       1, 0 },
847       { EXT_DISPLAY,      4, 0 },
848       { EXT_LONG_NAMES,   1, 0 },
849       { EXT_LONG_STRINGS, 1, 0 },
850       { EXT_NCASES,       8, 2 },
851       { EXT_FILE_ATTRS,   1, 0 },
852       { EXT_VAR_ATTRS,    1, 0 },
853       { EXT_MRSETS2,      1, 0 },
854       { EXT_ENCODING,     1, 0 },
855       { EXT_LONG_LABELS,  1, 0 },
856
857       /* Ignored record types. */
858       { EXT_VAR_SETS,     0, 0 },
859       { EXT_DATE,         0, 0 },
860       { EXT_DATA_ENTRY,   0, 0 },
861     };
862
863   const struct extension_record_type *type;
864   struct sfm_extension_record *record;
865   size_t n_bytes;
866
867   record = pool_malloc (r->pool, sizeof *record);
868   read_extension_record_header (r, subtype, record);
869   n_bytes = record->count * record->size;
870
871   for (type = types; type < &types[sizeof types / sizeof *types]; type++)
872     if (subtype == type->subtype)
873       {
874         if (type->size > 0 && record->size != type->size)
875           sys_warn (r, record->pos,
876                     _("Record type 7, subtype %d has bad size %zu "
877                       "(expected %d)."), subtype, record->size, type->size);
878         else if (type->count > 0 && record->count != type->count)
879           sys_warn (r, record->pos,
880                     _("Record type 7, subtype %d has bad count %zu "
881                       "(expected %d)."), subtype, record->count, type->count);
882         else if (type->count == 0 && type->size == 0)
883           {
884             /* Ignore this record. */
885           }
886         else
887           {
888             char *data = pool_malloc (r->pool, n_bytes + 1);
889             data[n_bytes] = '\0';
890
891             record->data = data;
892             read_bytes (r, record->data, n_bytes);
893             return record;
894           }
895
896         goto skip;
897       }
898
899   sys_warn (r, record->pos,
900             _("Unrecognized record type 7, subtype %d.  Please send a "
901               "copy of this file, and the syntax which created it to %s."),
902             subtype, PACKAGE_BUGREPORT);
903
904 skip:
905   skip_bytes (r, n_bytes);
906   return NULL;
907 }
908
909 static void
910 skip_extension_record (struct sfm_reader *r, int subtype)
911 {
912   struct sfm_extension_record record;
913
914   read_extension_record_header (r, subtype, &record);
915   skip_bytes (r, record.count * record.size);
916 }
917
918 static void
919 parse_file_label (struct sfm_reader *r, const char *file_label,
920                   struct dictionary *dict)
921 {
922   char *utf8_file_label;
923   size_t file_label_len;
924
925   utf8_file_label = recode_string_pool ("UTF-8", dict_get_encoding (dict),
926                                         file_label, -1, r->pool);
927   file_label_len = strlen (utf8_file_label);
928   while (file_label_len > 0 && utf8_file_label[file_label_len - 1] == ' ')
929     file_label_len--;
930   utf8_file_label[file_label_len] = '\0';
931   dict_set_label (dict, utf8_file_label);
932 }
933
934 /* Reads a variable (type 2) record from R and adds the
935    corresponding variable to DICT.
936    Also skips past additional variable records for long string
937    variables. */
938 static void
939 parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
940                         struct sfm_var_record *var_recs, size_t n_var_recs)
941 {
942   const char *dict_encoding = dict_get_encoding (dict);
943   struct sfm_var_record *rec;
944   int n_warnings = 0;
945
946   for (rec = var_recs; rec < &var_recs[n_var_recs]; )
947     {
948       struct variable *var;
949       size_t n_values;
950       char *name;
951       size_t i;
952
953       name = recode_string_pool ("UTF-8", dict_encoding,
954                                  rec->name, 8, r->pool);
955       name[strcspn (name, " ")] = '\0';
956
957       if (!dict_id_is_valid (dict, name, false)
958           || name[0] == '$' || name[0] == '#')
959         sys_error (r, rec->pos, _("Invalid variable name `%s'."), name);
960
961       if (rec->width < 0 || rec->width > 255)
962         sys_error (r, rec->pos,
963                    _("Bad width %d for variable %s."), rec->width, name);
964
965       var = rec->var = dict_create_var (dict, name, rec->width);
966       if (var == NULL)
967         sys_error (r, rec->pos, _("Duplicate variable name `%s'."), name);
968
969       /* Set the short name the same as the long name. */
970       var_set_short_name (var, 0, name);
971
972       /* Get variable label, if any. */
973       if (rec->label)
974         {
975           char *utf8_label;
976
977           utf8_label = recode_string_pool ("UTF-8", dict_encoding,
978                                            rec->label, -1, r->pool);
979           var_set_label (var, utf8_label, false);
980         }
981
982       /* Set missing values. */
983       if (rec->missing_value_code != 0)
984         {
985           int width = var_get_width (var);
986           struct missing_values mv;
987
988           mv_init_pool (r->pool, &mv, width);
989           if (var_is_numeric (var))
990             {
991               bool has_range = rec->missing_value_code < 0;
992               int n_discrete = (has_range
993                                 ? rec->missing_value_code == -3
994                                 : rec->missing_value_code);
995               int ofs = 0;
996
997               if (has_range)
998                 {
999                   double low = parse_float (r, rec->missing, 0);
1000                   double high = parse_float (r, rec->missing, 8);
1001                   mv_add_range (&mv, low, high);
1002                   ofs += 16;
1003                 }
1004
1005               for (i = 0; i < n_discrete; i++)
1006                 {
1007                   mv_add_num (&mv, parse_float (r, rec->missing, ofs));
1008                   ofs += 8;
1009                 }
1010             }
1011           else
1012             {
1013               union value value;
1014
1015               value_init_pool (r->pool, &value, width);
1016               value_set_missing (&value, width);
1017               for (i = 0; i < rec->missing_value_code; i++)
1018                 {
1019                   uint8_t *s = value_str_rw (&value, width);
1020                   memcpy (s, rec->missing + 8 * i, MIN (width, 8));
1021                   mv_add_str (&mv, s);
1022                 }
1023             }
1024           var_set_missing_values (var, &mv);
1025         }
1026
1027       /* Set formats. */
1028       parse_format_spec (r, rec->pos + 12, rec->print_format,
1029                          PRINT_FORMAT, var, &n_warnings);
1030       parse_format_spec (r, rec->pos + 16, rec->write_format,
1031                          WRITE_FORMAT, var, &n_warnings);
1032
1033       /* Account for values.
1034          Skip long string continuation records, if any. */
1035       n_values = rec->width == 0 ? 1 : DIV_RND_UP (rec->width, 8);
1036       for (i = 1; i < n_values; i++)
1037         if (i + (rec - var_recs) >= n_var_recs || rec[i].width != -1)
1038           sys_error (r, rec->pos, _("Missing string continuation record."));
1039       rec += n_values;
1040     }
1041 }
1042
1043 /* Translates the format spec from sysfile format to internal
1044    format. */
1045 static void
1046 parse_format_spec (struct sfm_reader *r, off_t pos, unsigned int format,
1047                    enum which_format which, struct variable *v,
1048                    int *n_warnings)
1049 {
1050   const int max_warnings = 8;
1051   uint8_t raw_type = format >> 16;
1052   uint8_t w = format >> 8;
1053   uint8_t d = format;
1054   struct fmt_spec f;
1055
1056   bool ok;
1057
1058   if (!fmt_from_io (raw_type, &f.type))
1059     sys_error (r, pos, _("Unknown variable format %"PRIu8"."), raw_type);
1060   f.w = w;
1061   f.d = d;
1062
1063   msg_disable ();
1064   ok = fmt_check_output (&f) && fmt_check_width_compat (&f, var_get_width (v));
1065   msg_enable ();
1066
1067   if (ok)
1068     {
1069       if (which == PRINT_FORMAT)
1070         var_set_print_format (v, &f);
1071       else
1072         var_set_write_format (v, &f);
1073     }
1074   else if (++*n_warnings <= max_warnings)
1075     {
1076       char fmt_string[FMT_STRING_LEN_MAX + 1];
1077       sys_warn (r, pos, _("%s variable %s has invalid %s format %s."),
1078                 var_is_numeric (v) ? _("Numeric") : _("String"),
1079                 var_get_name (v),
1080                 which == PRINT_FORMAT ? _("print") : _("write"),
1081                 fmt_to_string (&f, fmt_string));
1082
1083       if (*n_warnings == max_warnings)
1084         sys_warn (r, -1, _("Suppressing further invalid format warnings."));
1085     }
1086 }
1087
1088 static void
1089 parse_document (struct dictionary *dict, struct sfm_document_record *record)
1090 {
1091   const char *p;
1092
1093   for (p = record->documents;
1094        p < record->documents + DOC_LINE_LENGTH * record->n_lines;
1095        p += DOC_LINE_LENGTH)
1096     {
1097       struct substring line;
1098
1099       line = recode_substring_pool ("UTF-8", dict_get_encoding (dict),
1100                                     ss_buffer (p, DOC_LINE_LENGTH), NULL);
1101       ss_rtrim (&line, ss_cstr (" "));
1102       line.string[line.length] = '\0';
1103
1104       dict_add_document_line (dict, line.string, false);
1105
1106       ss_dealloc (&line);
1107     }
1108 }
1109
1110 /* Parses record type 7, subtype 3. */
1111 static void
1112 parse_machine_integer_info (struct sfm_reader *r,
1113                             const struct sfm_extension_record *record,
1114                             struct sfm_read_info *info)
1115 {
1116   int float_representation, expected_float_format;
1117   int integer_representation, expected_integer_format;
1118
1119   /* Save version info. */
1120   info->version_major = parse_int (r, record->data, 0);
1121   info->version_minor = parse_int (r, record->data, 4);
1122   info->version_revision = parse_int (r, record->data, 8);
1123
1124   /* Check floating point format. */
1125   float_representation = parse_int (r, record->data, 16);
1126   if (r->float_format == FLOAT_IEEE_DOUBLE_BE
1127       || r->float_format == FLOAT_IEEE_DOUBLE_LE)
1128     expected_float_format = 1;
1129   else if (r->float_format == FLOAT_Z_LONG)
1130     expected_float_format = 2;
1131   else if (r->float_format == FLOAT_VAX_G || r->float_format == FLOAT_VAX_D)
1132     expected_float_format = 3;
1133   else
1134     NOT_REACHED ();
1135   if (float_representation != expected_float_format)
1136     sys_error (r, record->pos, _("Floating-point representation indicated by "
1137                  "system file (%d) differs from expected (%d)."),
1138                float_representation, expected_float_format);
1139
1140   /* Check integer format. */
1141   integer_representation = parse_int (r, record->data, 24);
1142   if (r->integer_format == INTEGER_MSB_FIRST)
1143     expected_integer_format = 1;
1144   else if (r->integer_format == INTEGER_LSB_FIRST)
1145     expected_integer_format = 2;
1146   else
1147     NOT_REACHED ();
1148   if (integer_representation != expected_integer_format)
1149     sys_warn (r, record->pos,
1150               _("Integer format indicated by system file (%d) "
1151                 "differs from expected (%d)."),
1152               integer_representation, expected_integer_format);
1153
1154 }
1155
1156 static const char *
1157 choose_encoding (struct sfm_reader *r,
1158                  const struct sfm_extension_record *ext_integer,
1159                  const struct sfm_extension_record *ext_encoding)
1160 {
1161   /* The EXT_ENCODING record is a more reliable way to determine dictionary
1162      encoding. */
1163   if (ext_encoding)
1164     return ext_encoding->data;
1165
1166   /* But EXT_INTEGER is better than nothing as a fallback. */
1167   if (ext_integer)
1168     {
1169       int codepage = parse_int (r, ext_integer->data, 7 * 4);
1170       const char *encoding;
1171
1172       switch (codepage)
1173         {
1174         case 1:
1175           return "EBCDIC-US";
1176
1177         case 2:
1178         case 3:
1179           /* These ostensibly mean "7-bit ASCII" and "8-bit ASCII"[sic]
1180              respectively.  However, there are known to be many files in the wild
1181              with character code 2, yet have data which are clearly not ASCII.
1182              Therefore we ignore these values. */
1183           break;
1184
1185         case 4:
1186           return "MS_KANJI";
1187
1188         default:
1189           encoding = sys_get_encoding_from_codepage (codepage);
1190           if (encoding != NULL)
1191             return encoding;
1192           break;
1193         }
1194     }
1195
1196   return locale_charset ();
1197 }
1198
1199 /* Parses record type 7, subtype 4. */
1200 static void
1201 parse_machine_float_info (struct sfm_reader *r,
1202                           const struct sfm_extension_record *record)
1203 {
1204   double sysmis = parse_float (r, record->data, 0);
1205   double highest = parse_float (r, record->data, 8);
1206   double lowest = parse_float (r, record->data, 16);
1207
1208   if (sysmis != SYSMIS)
1209     sys_warn (r, record->pos, _("File specifies unexpected value %g as %s."),
1210               sysmis, "SYSMIS");
1211
1212   if (highest != HIGHEST)
1213     sys_warn (r, record->pos, _("File specifies unexpected value %g as %s."),
1214               highest, "HIGHEST");
1215
1216   if (lowest != LOWEST)
1217     sys_warn (r, record->pos, _("File specifies unexpected value %g as %s."),
1218               lowest, "LOWEST");
1219 }
1220
1221 /* Parses record type 7, subtype 7 or 19. */
1222 static void
1223 parse_mrsets (struct sfm_reader *r, const struct sfm_extension_record *record,
1224               struct dictionary *dict)
1225 {
1226   struct text_record *text;
1227   struct mrset *mrset;
1228
1229   text = open_text_record (r, record, false);
1230   for (;;)
1231     {
1232       const char *counted = NULL;
1233       const char *name;
1234       const char *label;
1235       struct stringi_set var_names;
1236       size_t allocated_vars;
1237       char delimiter;
1238       int width;
1239
1240       mrset = xzalloc (sizeof *mrset);
1241
1242       name = text_get_token (text, ss_cstr ("="), NULL);
1243       if (name == NULL)
1244         break;
1245       mrset->name = recode_string ("UTF-8", r->encoding, name, -1);
1246
1247       if (mrset->name[0] != '$')
1248         {
1249           sys_warn (r, record->pos,
1250                     _("`%s' does not begin with `$' at offset %zu "
1251                       "in MRSETS record."), mrset->name, text_pos (text));
1252           break;
1253         }
1254
1255       if (text_match (text, 'C'))
1256         {
1257           mrset->type = MRSET_MC;
1258           if (!text_match (text, ' '))
1259             {
1260               sys_warn (r, record->pos,
1261                         _("Missing space following `%c' at offset %zu "
1262                           "in MRSETS record."), 'C', text_pos (text));
1263               break;
1264             }
1265         }
1266       else if (text_match (text, 'D'))
1267         {
1268           mrset->type = MRSET_MD;
1269           mrset->cat_source = MRSET_VARLABELS;
1270         }
1271       else if (text_match (text, 'E'))
1272         {
1273           char *number;
1274
1275           mrset->type = MRSET_MD;
1276           mrset->cat_source = MRSET_COUNTEDVALUES;
1277           if (!text_match (text, ' '))
1278             {
1279               sys_warn (r, record->pos,
1280                         _("Missing space following `%c' at offset %zu "
1281                           "in MRSETS record."), 'E',  text_pos (text));
1282               break;
1283             }
1284
1285           number = text_get_token (text, ss_cstr (" "), NULL);
1286           if (!strcmp (number, "11"))
1287             mrset->label_from_var_label = true;
1288           else if (strcmp (number, "1"))
1289             sys_warn (r, record->pos,
1290                       _("Unexpected label source value `%s' following `E' "
1291                         "at offset %zu in MRSETS record."),
1292                       number, text_pos (text));
1293         }
1294       else
1295         {
1296           sys_warn (r, record->pos,
1297                     _("Missing `C', `D', or `E' at offset %zu "
1298                       "in MRSETS record."),
1299                     text_pos (text));
1300           break;
1301         }
1302
1303       if (mrset->type == MRSET_MD)
1304         {
1305           counted = text_parse_counted_string (r, text);
1306           if (counted == NULL)
1307             break;
1308         }
1309
1310       label = text_parse_counted_string (r, text);
1311       if (label == NULL)
1312         break;
1313       if (label[0] != '\0')
1314         mrset->label = recode_string ("UTF-8", r->encoding, label, -1);
1315
1316       stringi_set_init (&var_names);
1317       allocated_vars = 0;
1318       width = INT_MAX;
1319       do
1320         {
1321           const char *raw_var_name;
1322           struct variable *var;
1323           char *var_name;
1324
1325           raw_var_name = text_get_token (text, ss_cstr (" \n"), &delimiter);
1326           if (raw_var_name == NULL)
1327             {
1328               sys_warn (r, record->pos,
1329                         _("Missing new-line parsing variable names "
1330                           "at offset %zu in MRSETS record."),
1331                         text_pos (text));
1332               break;
1333             }
1334           var_name = recode_string ("UTF-8", r->encoding, raw_var_name, -1);
1335
1336           var = dict_lookup_var (dict, var_name);
1337           if (var == NULL)
1338             {
1339               free (var_name);
1340               continue;
1341             }
1342           if (!stringi_set_insert (&var_names, var_name))
1343             {
1344               sys_warn (r, record->pos,
1345                         _("Duplicate variable name %s "
1346                           "at offset %zu in MRSETS record."),
1347                         var_name, text_pos (text));
1348               free (var_name);
1349               continue;
1350             }
1351           free (var_name);
1352
1353           if (mrset->label == NULL && mrset->label_from_var_label
1354               && var_has_label (var))
1355             mrset->label = xstrdup (var_get_label (var));
1356
1357           if (mrset->n_vars
1358               && var_get_type (var) != var_get_type (mrset->vars[0]))
1359             {
1360               sys_warn (r, record->pos,
1361                         _("MRSET %s contains both string and "
1362                           "numeric variables."), name);
1363               continue;
1364             }
1365           width = MIN (width, var_get_width (var));
1366
1367           if (mrset->n_vars >= allocated_vars)
1368             mrset->vars = x2nrealloc (mrset->vars, &allocated_vars,
1369                                       sizeof *mrset->vars);
1370           mrset->vars[mrset->n_vars++] = var;
1371         }
1372       while (delimiter != '\n');
1373
1374       if (mrset->n_vars < 2)
1375         {
1376           sys_warn (r, record->pos,
1377                     _("MRSET %s has only %zu variables."), mrset->name,
1378                     mrset->n_vars);
1379           mrset_destroy (mrset);
1380           continue;
1381         }
1382
1383       if (mrset->type == MRSET_MD)
1384         {
1385           mrset->width = width;
1386           value_init (&mrset->counted, width);
1387           if (width == 0)
1388             mrset->counted.f = strtod (counted, NULL);
1389           else
1390             value_copy_str_rpad (&mrset->counted, width,
1391                                  (const uint8_t *) counted, ' ');
1392         }
1393
1394       dict_add_mrset (dict, mrset);
1395       mrset = NULL;
1396       stringi_set_destroy (&var_names);
1397     }
1398   mrset_destroy (mrset);
1399   close_text_record (r, text);
1400 }
1401
1402 /* Read record type 7, subtype 11, which specifies how variables
1403    should be displayed in GUI environments. */
1404 static void
1405 parse_display_parameters (struct sfm_reader *r,
1406                          const struct sfm_extension_record *record,
1407                          struct dictionary *dict)
1408 {
1409   bool includes_width;
1410   bool warned = false;
1411   size_t n_vars;
1412   size_t ofs;
1413   size_t i;
1414
1415   n_vars = dict_get_var_cnt (dict);
1416   if (record->count == 3 * n_vars)
1417     includes_width = true;
1418   else if (record->count == 2 * n_vars)
1419     includes_width = false;
1420   else
1421     {
1422       sys_warn (r, record->pos,
1423                 _("Extension 11 has bad count %zu (for %zu variables)."),
1424                 record->count, n_vars);
1425       return;
1426     }
1427
1428   ofs = 0;
1429   for (i = 0; i < n_vars; ++i)
1430     {
1431       struct variable *v = dict_get_var (dict, i);
1432       int measure, width, align;
1433
1434       measure = parse_int (r, record->data, ofs);
1435       ofs += 4;
1436
1437       if (includes_width)
1438         {
1439           width = parse_int (r, record->data, ofs);
1440           ofs += 4;
1441         }
1442       else
1443         width = 0;
1444
1445       align = parse_int (r, record->data, ofs);
1446       ofs += 4;
1447
1448       /* SPSS 14 sometimes seems to set string variables' measure
1449          to zero. */
1450       if (0 == measure && var_is_alpha (v))
1451         measure = 1;
1452
1453       if (measure < 1 || measure > 3 || align < 0 || align > 2)
1454         {
1455           if (!warned)
1456             sys_warn (r, record->pos,
1457                       _("Invalid variable display parameters for variable "
1458                         "%zu (%s).  Default parameters substituted."),
1459                       i, var_get_name (v));
1460           warned = true;
1461           continue;
1462         }
1463
1464       var_set_measure (v, (measure == 1 ? MEASURE_NOMINAL
1465                            : measure == 2 ? MEASURE_ORDINAL
1466                            : MEASURE_SCALE));
1467       var_set_alignment (v, (align == 0 ? ALIGN_LEFT
1468                              : align == 1 ? ALIGN_RIGHT
1469                              : ALIGN_CENTRE));
1470
1471       /* Older versions (SPSS 9.0) sometimes set the display
1472          width to zero.  This causes confusion in the GUI, so
1473          only set the width if it is nonzero. */
1474       if (width > 0)
1475         var_set_display_width (v, width);
1476     }
1477 }
1478
1479 static void
1480 rename_var_and_save_short_names (struct dictionary *dict, struct variable *var,
1481                                  const char *new_name)
1482 {
1483   size_t n_short_names;
1484   char **short_names;
1485   size_t i;
1486
1487   /* Renaming a variable may clear its short names, but we
1488      want to retain them, so we save them and re-set them
1489      afterward. */
1490   n_short_names = var_get_short_name_cnt (var);
1491   short_names = xnmalloc (n_short_names, sizeof *short_names);
1492   for (i = 0; i < n_short_names; i++)
1493     {
1494       const char *s = var_get_short_name (var, i);
1495       short_names[i] = s != NULL ? xstrdup (s) : NULL;
1496     }
1497
1498   /* Set long name. */
1499   dict_rename_var (dict, var, new_name);
1500
1501   /* Restore short names. */
1502   for (i = 0; i < n_short_names; i++)
1503     {
1504       var_set_short_name (var, i, short_names[i]);
1505       free (short_names[i]);
1506     }
1507   free (short_names);
1508 }
1509
1510 /* Parses record type 7, subtype 13, which gives the long name that corresponds
1511    to each short name.  Modifies variable names in DICT accordingly.  */
1512 static void
1513 parse_long_var_name_map (struct sfm_reader *r,
1514                          const struct sfm_extension_record *record,
1515                          struct dictionary *dict)
1516 {
1517   struct text_record *text;
1518   struct variable *var;
1519   char *long_name;
1520
1521   if (record == NULL)
1522     {
1523       /* Convert variable names to lowercase. */
1524       size_t i;
1525
1526       for (i = 0; i < dict_get_var_cnt (dict); i++)
1527         {
1528           struct variable *var = dict_get_var (dict, i);
1529           char *new_name;
1530
1531           new_name = xstrdup (var_get_name (var));
1532           str_lowercase (new_name);
1533
1534           rename_var_and_save_short_names (dict, var, new_name);
1535
1536           free (new_name);
1537         }
1538
1539       return;
1540     }
1541
1542   /* Rename each of the variables, one by one.  (In a correctly constructed
1543      system file, this cannot create any intermediate duplicate variable names,
1544      because all of the new variable names are longer than any of the old
1545      variable names and thus there cannot be any overlaps.) */
1546   text = open_text_record (r, record, true);
1547   while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
1548     {
1549       /* Validate long name. */
1550       /* XXX need to reencode name to UTF-8 */
1551       if (!dict_id_is_valid (dict, long_name, false))
1552         {
1553           sys_warn (r, record->pos,
1554                     _("Long variable mapping from %s to invalid "
1555                       "variable name `%s'."),
1556                     var_get_name (var), long_name);
1557           continue;
1558         }
1559
1560       /* Identify any duplicates. */
1561       if (strcasecmp (var_get_short_name (var, 0), long_name)
1562           && dict_lookup_var (dict, long_name) != NULL)
1563         {
1564           sys_warn (r, record->pos,
1565                     _("Duplicate long variable name `%s'."), long_name);
1566           continue;
1567         }
1568
1569       rename_var_and_save_short_names (dict, var, long_name);
1570     }
1571   close_text_record (r, text);
1572 }
1573
1574 /* Reads record type 7, subtype 14, which gives the real length
1575    of each very long string.  Rearranges DICT accordingly. */
1576 static void
1577 parse_long_string_map (struct sfm_reader *r,
1578                        const struct sfm_extension_record *record,
1579                        struct dictionary *dict)
1580 {
1581   struct text_record *text;
1582   struct variable *var;
1583   char *length_s;
1584
1585   text = open_text_record (r, record, true);
1586   while (read_variable_to_value_pair (r, dict, text, &var, &length_s))
1587     {
1588       size_t idx = var_get_dict_index (var);
1589       long int length;
1590       int segment_cnt;
1591       int i;
1592
1593       /* Get length. */
1594       length = strtol (length_s, NULL, 10);
1595       if (length < 1 || length > MAX_STRING)
1596         {
1597           sys_warn (r, record->pos,
1598                     _("%s listed as string of invalid length %s "
1599                       "in very long string record."),
1600                     var_get_name (var), length_s);
1601           continue;
1602         }
1603
1604       /* Check segments. */
1605       segment_cnt = sfm_width_to_segments (length);
1606       if (segment_cnt == 1)
1607         {
1608           sys_warn (r, record->pos,
1609                     _("%s listed in very long string record with width %s, "
1610                       "which requires only one segment."),
1611                     var_get_name (var), length_s);
1612           continue;
1613         }
1614       if (idx + segment_cnt > dict_get_var_cnt (dict))
1615         sys_error (r, record->pos,
1616                    _("Very long string %s overflows dictionary."),
1617                    var_get_name (var));
1618
1619       /* Get the short names from the segments and check their
1620          lengths. */
1621       for (i = 0; i < segment_cnt; i++)
1622         {
1623           struct variable *seg = dict_get_var (dict, idx + i);
1624           int alloc_width = sfm_segment_alloc_width (length, i);
1625           int width = var_get_width (seg);
1626
1627           if (i > 0)
1628             var_set_short_name (var, i, var_get_short_name (seg, 0));
1629           if (ROUND_UP (width, 8) != ROUND_UP (alloc_width, 8))
1630             sys_error (r, record->pos,
1631                        _("Very long string with width %ld has segment %d "
1632                          "of width %d (expected %d)."),
1633                        length, i, width, alloc_width);
1634         }
1635       dict_delete_consecutive_vars (dict, idx + 1, segment_cnt - 1);
1636       var_set_width (var, length);
1637     }
1638   close_text_record (r, text);
1639   dict_compact_values (dict);
1640 }
1641
1642 static void
1643 parse_value_labels (struct sfm_reader *r, struct dictionary *dict,
1644                     const struct sfm_var_record *var_recs, size_t n_var_recs,
1645                     const struct sfm_value_label_record *record)
1646 {
1647   struct variable **vars;
1648   char **utf8_labels;
1649   size_t i;
1650
1651   utf8_labels = pool_nmalloc (r->pool, sizeof *utf8_labels, record->n_labels);
1652   for (i = 0; i < record->n_labels; i++)
1653     utf8_labels[i] = recode_string_pool ("UTF-8", dict_get_encoding (dict),
1654                                          record->labels[i].label, -1,
1655                                          r->pool);
1656
1657   vars = pool_nmalloc (r->pool, record->n_vars, sizeof *vars);
1658   for (i = 0; i < record->n_vars; i++)
1659     vars[i] = lookup_var_by_index (r, record->pos,
1660                                    var_recs, n_var_recs, record->vars[i]);
1661
1662   for (i = 1; i < record->n_vars; i++)
1663     if (var_get_type (vars[i]) != var_get_type (vars[0]))
1664       sys_error (r, record->pos,
1665                  _("Variables associated with value label are not all of "
1666                    "identical type.  Variable %s is %s, but variable "
1667                    "%s is %s."),
1668                  var_get_name (vars[0]),
1669                  var_is_numeric (vars[0]) ? _("numeric") : _("string"),
1670                  var_get_name (vars[i]),
1671                  var_is_numeric (vars[i]) ? _("numeric") : _("string"));
1672
1673   for (i = 0; i < record->n_vars; i++)
1674     {
1675       struct variable *var = vars[i];
1676       int width;
1677       size_t j;
1678
1679       width = var_get_width (var);
1680       if (width > 8)
1681         sys_error (r, record->pos,
1682                    _("Value labels may not be added to long string "
1683                      "variables (e.g. %s) using records types 3 and 4."),
1684                    var_get_name (var));
1685
1686       for (j = 0; j < record->n_labels; j++)
1687         {
1688           struct sfm_value_label *label = &record->labels[j];
1689           union value value;
1690
1691           value_init (&value, width);
1692           if (width == 0)
1693             value.f = parse_float (r, label->value, 0);
1694           else
1695             memcpy (value_str_rw (&value, width), label->value, width);
1696
1697           if (!var_add_value_label (var, &value, utf8_labels[j]))
1698             {
1699               if (var_is_numeric (var))
1700                 sys_warn (r, record->pos,
1701                           _("Duplicate value label for %g on %s."),
1702                           value.f, var_get_name (var));
1703               else
1704                 sys_warn (r, record->pos,
1705                           _("Duplicate value label for `%.*s' on %s."),
1706                           width, value_str (&value, width),
1707                           var_get_name (var));
1708             }
1709
1710           value_destroy (&value, width);
1711         }
1712     }
1713
1714   pool_free (r->pool, vars);
1715   for (i = 0; i < record->n_labels; i++)
1716     pool_free (r->pool, utf8_labels[i]);
1717   pool_free (r->pool, utf8_labels);
1718 }
1719
1720 static struct variable *
1721 lookup_var_by_index (struct sfm_reader *r, off_t offset,
1722                      const struct sfm_var_record *var_recs, size_t n_var_recs,
1723                      int idx)
1724 {
1725   const struct sfm_var_record *rec;
1726
1727   if (idx < 1 || idx > n_var_recs)
1728     {
1729       sys_error (r, offset,
1730                  _("Variable index %d not in valid range 1...%zu."),
1731                  idx, n_var_recs);
1732       return NULL;
1733     }
1734
1735   rec = &var_recs[idx - 1];
1736   if (rec->var == NULL)
1737     {
1738       sys_error (r, offset,
1739                  _("Variable index %d refers to long string continuation."),
1740                  idx);
1741       return NULL;
1742     }
1743
1744   return rec->var;
1745 }
1746
1747 /* Parses a set of custom attributes from TEXT into ATTRS.
1748    ATTRS may be a null pointer, in which case the attributes are
1749    read but discarded. */
1750 static void
1751 parse_attributes (struct sfm_reader *r, struct text_record *text,
1752                   struct attrset *attrs)
1753 {
1754   do
1755     {
1756       struct attribute *attr;
1757       char *key;
1758       int index;
1759
1760       /* Parse the key. */
1761       key = text_get_token (text, ss_cstr ("("), NULL);
1762       if (key == NULL)
1763         return;
1764
1765       attr = attribute_create (key);
1766       for (index = 1; ; index++)
1767         {
1768           /* Parse the value. */
1769           char *value;
1770           size_t length;
1771
1772           value = text_get_token (text, ss_cstr ("\n"), NULL);
1773           if (value == NULL)
1774             {
1775               text_warn (r, text, _("Error parsing attribute value %s[%d]."),
1776                          key, index);
1777               break;
1778             }              
1779
1780           length = strlen (value);
1781           if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') 
1782             {
1783               value[length - 1] = '\0';
1784               attribute_add_value (attr, value + 1); 
1785             }
1786           else 
1787             {
1788               text_warn (r, text,
1789                          _("Attribute value %s[%d] is not quoted: %s."),
1790                          key, index, value);
1791               attribute_add_value (attr, value); 
1792             }
1793
1794           /* Was this the last value for this attribute? */
1795           if (text_match (text, ')'))
1796             break;
1797         }
1798       if (attrs != NULL)
1799         attrset_add (attrs, attr);
1800       else
1801         attribute_destroy (attr);
1802     }
1803   while (!text_match (text, '/'));
1804 }
1805
1806 /* Reads record type 7, subtype 17, which lists custom
1807    attributes on the data file.  */
1808 static void
1809 parse_data_file_attributes (struct sfm_reader *r,
1810                             const struct sfm_extension_record *record,
1811                             struct dictionary *dict)
1812 {
1813   struct text_record *text = open_text_record (r, record, true);
1814   parse_attributes (r, text, dict_get_attributes (dict));
1815   close_text_record (r, text);
1816 }
1817
1818 /* Parses record type 7, subtype 18, which lists custom
1819    attributes on individual variables.  */
1820 static void
1821 parse_variable_attributes (struct sfm_reader *r,
1822                            const struct sfm_extension_record *record,
1823                            struct dictionary *dict)
1824 {
1825   struct text_record *text;
1826   struct variable *var;
1827
1828   text = open_text_record (r, record, true);
1829   while (text_read_variable_name (r, dict, text, ss_cstr (":"), &var))
1830     parse_attributes (r, text, var != NULL ? var_get_attributes (var) : NULL);
1831   close_text_record (r, text);
1832 }
1833
1834 static void
1835 check_overflow (struct sfm_reader *r,
1836                 const struct sfm_extension_record *record,
1837                 size_t ofs, size_t length)
1838 {
1839   size_t end = record->size * record->count;
1840   if (length >= end || ofs + length > end)
1841     sys_error (r, record->pos + end,
1842                _("Long string value label record ends unexpectedly."));
1843 }
1844
1845 static void
1846 parse_long_string_value_labels (struct sfm_reader *r,
1847                                 const struct sfm_extension_record *record,
1848                                 struct dictionary *dict)
1849 {
1850   const char *dict_encoding = dict_get_encoding (dict);
1851   size_t end = record->size * record->count;
1852   size_t ofs = 0;
1853
1854   while (ofs < end)
1855     {
1856       char *var_name;
1857       size_t n_labels, i;
1858       struct variable *var;
1859       union value value;
1860       int var_name_len;
1861       int width;
1862
1863       /* Parse variable name length. */
1864       check_overflow (r, record, ofs, 4);
1865       var_name_len = parse_int (r, record->data, ofs);
1866       ofs += 4;
1867
1868       /* Parse variable name, width, and number of labels. */
1869       check_overflow (r, record, ofs, var_name_len + 8);
1870       var_name = recode_string_pool ("UTF-8", dict_encoding,
1871                                      (const char *) record->data + ofs,
1872                                      var_name_len, r->pool);
1873       width = parse_int (r, record->data, ofs + var_name_len);
1874       n_labels = parse_int (r, record->data, ofs + var_name_len + 4);
1875       ofs += var_name_len + 8;
1876
1877       /* Look up 'var' and validate. */
1878       var = dict_lookup_var (dict, var_name);
1879       if (var == NULL)
1880         sys_warn (r, record->pos + ofs,
1881                   _("Ignoring long string value record for "
1882                     "unknown variable %s."), var_name);
1883       else if (var_is_numeric (var))
1884         {
1885           sys_warn (r, record->pos + ofs,
1886                     _("Ignoring long string value record for "
1887                       "numeric variable %s."), var_name);
1888           var = NULL;
1889         }
1890       else if (width != var_get_width (var))
1891         {
1892           sys_warn (r, record->pos + ofs,
1893                     _("Ignoring long string value record for variable %s "
1894                       "because the record's width (%d) does not match the "
1895                       "variable's width (%d)."),
1896                     var_name, width, var_get_width (var));
1897           var = NULL;
1898         }
1899
1900       /* Parse values. */
1901       value_init_pool (r->pool, &value, width);
1902       for (i = 0; i < n_labels; i++)
1903         {
1904           size_t value_length, label_length;
1905           bool skip = var == NULL;
1906
1907           /* Parse value length. */
1908           check_overflow (r, record, ofs, 4);
1909           value_length = parse_int (r, record->data, ofs);
1910           ofs += 4;
1911
1912           /* Parse value. */
1913           check_overflow (r, record, ofs, value_length);
1914           if (!skip)
1915             {
1916               if (value_length == width)
1917                 memcpy (value_str_rw (&value, width),
1918                         (const uint8_t *) record->data + ofs, width);
1919               else
1920                 {
1921                   sys_warn (r, record->pos + ofs,
1922                             _("Ignoring long string value %zu for variable "
1923                               "%s, with width %d, that has bad value "
1924                               "width %zu."),
1925                             i, var_get_name (var), width, value_length);
1926                   skip = true;
1927                 }
1928             }
1929           ofs += value_length;
1930
1931           /* Parse label length. */
1932           check_overflow (r, record, ofs, 4);
1933           label_length = parse_int (r, record->data, ofs);
1934           ofs += 4;
1935
1936           /* Parse label. */
1937           check_overflow (r, record, ofs, label_length);
1938           if (!skip)
1939             {
1940               char *label;
1941
1942               label = recode_string_pool ("UTF-8", dict_encoding,
1943                                           (const char *) record->data + ofs,
1944                                           label_length, r->pool);
1945               if (!var_add_value_label (var, &value, label))
1946                 sys_warn (r, record->pos + ofs,
1947                           _("Duplicate value label for `%.*s' on %s."),
1948                           width, value_str (&value, width),
1949                           var_get_name (var));
1950               pool_free (r->pool, label);
1951             }
1952           ofs += label_length;
1953         }
1954     }
1955 }
1956 \f
1957 /* Case reader. */
1958
1959 static void partial_record (struct sfm_reader *r)
1960      NO_RETURN;
1961
1962 static void read_error (struct casereader *, const struct sfm_reader *);
1963
1964 static bool read_case_number (struct sfm_reader *, double *);
1965 static bool read_case_string (struct sfm_reader *, uint8_t *, size_t);
1966 static int read_opcode (struct sfm_reader *);
1967 static bool read_compressed_number (struct sfm_reader *, double *);
1968 static bool read_compressed_string (struct sfm_reader *, uint8_t *);
1969 static bool read_whole_strings (struct sfm_reader *, uint8_t *, size_t);
1970 static bool skip_whole_strings (struct sfm_reader *, size_t);
1971
1972 /* Reads and returns one case from READER's file.  Returns a null
1973    pointer if not successful. */
1974 static struct ccase *
1975 sys_file_casereader_read (struct casereader *reader, void *r_)
1976 {
1977   struct sfm_reader *r = r_;
1978   struct ccase *volatile c;
1979   int i;
1980
1981   if (r->error)
1982     return NULL;
1983
1984   c = case_create (r->proto);
1985   if (setjmp (r->bail_out))
1986     {
1987       casereader_force_error (reader);
1988       case_unref (c);
1989       return NULL;
1990     }
1991
1992   for (i = 0; i < r->sfm_var_cnt; i++)
1993     {
1994       struct sfm_var *sv = &r->sfm_vars[i];
1995       union value *v = case_data_rw_idx (c, sv->case_index);
1996
1997       if (sv->var_width == 0)
1998         {
1999           if (!read_case_number (r, &v->f))
2000             goto eof;
2001         }
2002       else
2003         {
2004           uint8_t *s = value_str_rw (v, sv->var_width);
2005           if (!read_case_string (r, s + sv->offset, sv->segment_width))
2006             goto eof;
2007           if (!skip_whole_strings (r, ROUND_DOWN (sv->padding, 8)))
2008             partial_record (r);
2009         }
2010     }
2011   return c;
2012
2013 eof:
2014   if (i != 0)
2015     partial_record (r);
2016   if (r->case_cnt != -1)
2017     read_error (reader, r);
2018   case_unref (c);
2019   return NULL;
2020 }
2021
2022 /* Issues an error that R ends in a partial record. */
2023 static void
2024 partial_record (struct sfm_reader *r)
2025 {
2026   sys_error (r, r->pos, _("File ends in partial case."));
2027 }
2028
2029 /* Issues an error that an unspecified error occurred SFM, and
2030    marks R tainted. */
2031 static void
2032 read_error (struct casereader *r, const struct sfm_reader *sfm)
2033 {
2034   msg (ME, _("Error reading case from file %s."), fh_get_name (sfm->fh));
2035   casereader_force_error (r);
2036 }
2037
2038 /* Reads a number from R and stores its value in *D.
2039    If R is compressed, reads a compressed number;
2040    otherwise, reads a number in the regular way.
2041    Returns true if successful, false if end of file is
2042    reached immediately. */
2043 static bool
2044 read_case_number (struct sfm_reader *r, double *d)
2045 {
2046   if (!r->compressed)
2047     {
2048       uint8_t number[8];
2049       if (!try_read_bytes (r, number, sizeof number))
2050         return false;
2051       float_convert (r->float_format, number, FLOAT_NATIVE_DOUBLE, d);
2052       return true;
2053     }
2054   else
2055     return read_compressed_number (r, d);
2056 }
2057
2058 /* Reads LENGTH string bytes from R into S.
2059    Always reads a multiple of 8 bytes; if LENGTH is not a
2060    multiple of 8, then extra bytes are read and discarded without
2061    being written to S.
2062    Reads compressed strings if S is compressed.
2063    Returns true if successful, false if end of file is
2064    reached immediately. */
2065 static bool
2066 read_case_string (struct sfm_reader *r, uint8_t *s, size_t length)
2067 {
2068   size_t whole = ROUND_DOWN (length, 8);
2069   size_t partial = length % 8;
2070
2071   if (whole)
2072     {
2073       if (!read_whole_strings (r, s, whole))
2074         return false;
2075     }
2076
2077   if (partial)
2078     {
2079       uint8_t bounce[8];
2080       if (!read_whole_strings (r, bounce, sizeof bounce))
2081         {
2082           if (whole)
2083             partial_record (r);
2084           return false;
2085         }
2086       memcpy (s + whole, bounce, partial);
2087     }
2088
2089   return true;
2090 }
2091
2092 /* Reads and returns the next compression opcode from R. */
2093 static int
2094 read_opcode (struct sfm_reader *r)
2095 {
2096   assert (r->compressed);
2097   for (;;)
2098     {
2099       int opcode;
2100       if (r->opcode_idx >= sizeof r->opcodes)
2101         {
2102           if (!try_read_bytes (r, r->opcodes, sizeof r->opcodes))
2103             return -1;
2104           r->opcode_idx = 0;
2105         }
2106       opcode = r->opcodes[r->opcode_idx++];
2107
2108       if (opcode != 0)
2109         return opcode;
2110     }
2111 }
2112
2113 /* Reads a compressed number from R and stores its value in D.
2114    Returns true if successful, false if end of file is
2115    reached immediately. */
2116 static bool
2117 read_compressed_number (struct sfm_reader *r, double *d)
2118 {
2119   int opcode = read_opcode (r);
2120   switch (opcode)
2121     {
2122     case -1:
2123     case 252:
2124       return false;
2125
2126     case 253:
2127       *d = read_float (r);
2128       break;
2129
2130     case 254:
2131       float_convert (r->float_format, "        ", FLOAT_NATIVE_DOUBLE, d);
2132       if (!r->corruption_warning)
2133         {
2134           r->corruption_warning = true;
2135           sys_warn (r, r->pos,
2136                     _("Possible compressed data corruption: "
2137                       "compressed spaces appear in numeric field."));
2138         }
2139       break;
2140
2141     case 255:
2142       *d = SYSMIS;
2143       break;
2144
2145     default:
2146       *d = opcode - r->bias;
2147       break;
2148     }
2149
2150   return true;
2151 }
2152
2153 /* Reads a compressed 8-byte string segment from R and stores it
2154    in DST.
2155    Returns true if successful, false if end of file is
2156    reached immediately. */
2157 static bool
2158 read_compressed_string (struct sfm_reader *r, uint8_t *dst)
2159 {
2160   int opcode = read_opcode (r);
2161   switch (opcode)
2162     {
2163     case -1:
2164     case 252:
2165       return false;
2166
2167     case 253:
2168       read_bytes (r, dst, 8);
2169       break;
2170
2171     case 254:
2172       memset (dst, ' ', 8);
2173       break;
2174
2175     default:
2176       {
2177         double value = opcode - r->bias;
2178         float_convert (FLOAT_NATIVE_DOUBLE, &value, r->float_format, dst);
2179         if (value == 0.0)
2180           {
2181             /* This has actually been seen "in the wild".  The submitter of the
2182                file that showed that the contents decoded as spaces, but they
2183                were at the end of the field so it's possible that the null
2184                bytes just acted as null terminators. */
2185           }
2186         else if (!r->corruption_warning)
2187           {
2188             r->corruption_warning = true;
2189             sys_warn (r, r->pos,
2190                       _("Possible compressed data corruption: "
2191                         "string contains compressed integer (opcode %d)."),
2192                       opcode);
2193           }
2194       }
2195       break;
2196     }
2197
2198   return true;
2199 }
2200
2201 /* Reads LENGTH string bytes from R into S.
2202    LENGTH must be a multiple of 8.
2203    Reads compressed strings if S is compressed.
2204    Returns true if successful, false if end of file is
2205    reached immediately. */
2206 static bool
2207 read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length)
2208 {
2209   assert (length % 8 == 0);
2210   if (!r->compressed)
2211     return try_read_bytes (r, s, length);
2212   else
2213     {
2214       size_t ofs;
2215       for (ofs = 0; ofs < length; ofs += 8)
2216         if (!read_compressed_string (r, s + ofs))
2217           {
2218             if (ofs != 0)
2219               partial_record (r);
2220             return false;
2221           }
2222       return true;
2223     }
2224 }
2225
2226 /* Skips LENGTH string bytes from R.
2227    LENGTH must be a multiple of 8.
2228    (LENGTH is also limited to 1024, but that's only because the
2229    current caller never needs more than that many bytes.)
2230    Returns true if successful, false if end of file is
2231    reached immediately. */
2232 static bool
2233 skip_whole_strings (struct sfm_reader *r, size_t length)
2234 {
2235   uint8_t buffer[1024];
2236   assert (length < sizeof buffer);
2237   return read_whole_strings (r, buffer, length);
2238 }
2239 \f
2240 /* Helpers for reading records that contain structured text
2241    strings. */
2242
2243 /* Maximum number of warnings to issue for a single text
2244    record. */
2245 #define MAX_TEXT_WARNINGS 5
2246
2247 /* State. */
2248 struct text_record
2249   {
2250     struct substring buffer;    /* Record contents. */
2251     off_t start;                /* Starting offset in file. */
2252     size_t pos;                 /* Current position in buffer. */
2253     int n_warnings;             /* Number of warnings issued or suppressed. */
2254     bool recoded;               /* Recoded into UTF-8? */
2255   };
2256
2257 static struct text_record *
2258 open_text_record (struct sfm_reader *r,
2259                   const struct sfm_extension_record *record,
2260                   bool recode_to_utf8)
2261 {
2262   struct text_record *text;
2263   struct substring raw;
2264
2265   text = pool_alloc (r->pool, sizeof *text);
2266   raw = ss_buffer (record->data, record->size * record->count);
2267   text->start = record->pos;
2268   text->buffer = (recode_to_utf8
2269                   ? recode_substring_pool ("UTF-8", r->encoding, raw, r->pool)
2270                   : raw);
2271   text->pos = 0;
2272   text->n_warnings = 0;
2273   text->recoded = recode_to_utf8;
2274
2275   return text;
2276 }
2277
2278 /* Closes TEXT, frees its storage, and issues a final warning
2279    about suppressed warnings if necesary. */
2280 static void
2281 close_text_record (struct sfm_reader *r, struct text_record *text)
2282 {
2283   if (text->n_warnings > MAX_TEXT_WARNINGS)
2284     sys_warn (r, -1, _("Suppressed %d additional related warnings."),
2285               text->n_warnings - MAX_TEXT_WARNINGS);
2286   if (text->recoded)
2287     pool_free (r->pool, ss_data (text->buffer));
2288 }
2289
2290 /* Reads a variable=value pair from TEXT.
2291    Looks up the variable in DICT and stores it into *VAR.
2292    Stores a null-terminated value into *VALUE. */
2293 static bool
2294 read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict,
2295                              struct text_record *text,
2296                              struct variable **var, char **value)
2297 {
2298   for (;;)
2299     {
2300       if (!text_read_short_name (r, dict, text, ss_cstr ("="), var))
2301         return false;
2302       
2303       *value = text_get_token (text, ss_buffer ("\t\0", 2), NULL);
2304       if (*value == NULL)
2305         return false;
2306
2307       text->pos += ss_span (ss_substr (text->buffer, text->pos, SIZE_MAX),
2308                             ss_buffer ("\t\0", 2));
2309
2310       if (*var != NULL)
2311         return true;
2312     }
2313 }
2314
2315 static bool
2316 text_read_variable_name (struct sfm_reader *r, struct dictionary *dict,
2317                          struct text_record *text, struct substring delimiters,
2318                          struct variable **var)
2319 {
2320   char *name;
2321
2322   name = text_get_token (text, delimiters, NULL);
2323   if (name == NULL)
2324     return false;
2325
2326   *var = dict_lookup_var (dict, name);
2327   if (*var != NULL)
2328     return true;
2329
2330   text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
2331              name);
2332   return false;
2333 }
2334
2335
2336 static bool
2337 text_read_short_name (struct sfm_reader *r, struct dictionary *dict,
2338                       struct text_record *text, struct substring delimiters,
2339                       struct variable **var)
2340 {
2341   char *short_name = text_get_token (text, delimiters, NULL);
2342   if (short_name == NULL)
2343     return false;
2344
2345   *var = dict_lookup_var (dict, short_name);
2346   if (*var == NULL)
2347     text_warn (r, text, _("Dictionary record refers to unknown variable %s."),
2348                short_name);
2349   return true;
2350 }
2351
2352 /* Displays a warning for the current file position, limiting the
2353    number to MAX_TEXT_WARNINGS for TEXT. */
2354 static void
2355 text_warn (struct sfm_reader *r, struct text_record *text,
2356            const char *format, ...)
2357 {
2358   if (text->n_warnings++ < MAX_TEXT_WARNINGS) 
2359     {
2360       va_list args;
2361
2362       va_start (args, format);
2363       sys_msg (r, text->start + text->pos, MW, format, args);
2364       va_end (args);
2365     }
2366 }
2367
2368 static char *
2369 text_get_token (struct text_record *text, struct substring delimiters,
2370                 char *delimiter)
2371 {
2372   struct substring token;
2373   char *end;
2374
2375   if (!ss_tokenize (text->buffer, delimiters, &text->pos, &token))
2376     return NULL;
2377
2378   end = &ss_data (token)[ss_length (token)];
2379   if (delimiter != NULL)
2380     *delimiter = *end;
2381   *end = '\0';
2382   return ss_data (token);
2383 }
2384
2385 /* Reads a integer value expressed in decimal, then a space, then a string that
2386    consists of exactly as many bytes as specified by the integer, then a space,
2387    from TEXT.  Returns the string, null-terminated, as a subset of TEXT's
2388    buffer (so the caller should not free the string). */
2389 static const char *
2390 text_parse_counted_string (struct sfm_reader *r, struct text_record *text)
2391 {
2392   size_t start;
2393   size_t n;
2394   char *s;
2395
2396   start = text->pos;
2397   n = 0;
2398   for (;;)
2399     {
2400       int c = text->buffer.string[text->pos];
2401       if (c < '0' || c > '9')
2402         break;
2403       n = (n * 10) + (c - '0');
2404       text->pos++;
2405     }
2406   if (start == text->pos)
2407     {
2408       sys_warn (r, text->start,
2409                 _("Expecting digit at offset %zu in MRSETS record."),
2410                 text->pos);
2411       return NULL;
2412     }
2413
2414   if (!text_match (text, ' '))
2415     {
2416       sys_warn (r, text->start,
2417                 _("Expecting space at offset %zu in MRSETS record."),
2418                 text->pos);
2419       return NULL;
2420     }
2421
2422   if (text->pos + n > text->buffer.length)
2423     {
2424       sys_warn (r, text->start,
2425                 _("%zu-byte string starting at offset %zu "
2426                   "exceeds record length %zu."),
2427                 n, text->pos, text->buffer.length);
2428       return NULL;
2429     }
2430
2431   s = &text->buffer.string[text->pos];
2432   if (s[n] != ' ')
2433     {
2434       sys_warn (r, text->start,
2435                 _("Expecting space at offset %zu following %zu-byte string."),
2436                 text->pos + n, n);
2437       return NULL;
2438     }
2439   s[n] = '\0';
2440   text->pos += n + 1;
2441   return s;
2442 }
2443
2444 static bool
2445 text_match (struct text_record *text, char c)
2446 {
2447   if (text->buffer.string[text->pos] == c) 
2448     {
2449       text->pos++;
2450       return true;
2451     }
2452   else
2453     return false;
2454 }
2455
2456 /* Returns the current byte offset (as converted to UTF-8, if it was converted)
2457    inside the TEXT's string. */
2458 static size_t
2459 text_pos (const struct text_record *text)
2460 {
2461   return text->pos;
2462 }
2463 \f
2464 /* Messages. */
2465
2466 /* Displays a corruption message. */
2467 static void
2468 sys_msg (struct sfm_reader *r, off_t offset,
2469          int class, const char *format, va_list args)
2470 {
2471   struct msg m;
2472   struct string text;
2473
2474   ds_init_empty (&text);
2475   if (offset >= 0)
2476     ds_put_format (&text, _("`%s' near offset 0x%llx: "),
2477                    fh_get_file_name (r->fh), (long long int) offset);
2478   else
2479     ds_put_format (&text, _("`%s': "), fh_get_file_name (r->fh));
2480   ds_put_vformat (&text, format, args);
2481
2482   m.category = msg_class_to_category (class);
2483   m.severity = msg_class_to_severity (class);
2484   m.file_name = NULL;
2485   m.first_line = 0;
2486   m.last_line = 0;
2487   m.first_column = 0;
2488   m.last_column = 0;
2489   m.text = ds_cstr (&text);
2490
2491   msg_emit (&m);
2492 }
2493
2494 /* Displays a warning for offset OFFSET in the file. */
2495 static void
2496 sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...)
2497 {
2498   va_list args;
2499
2500   va_start (args, format);
2501   sys_msg (r, offset, MW, format, args);
2502   va_end (args);
2503 }
2504
2505 /* Displays an error for the current file position,
2506    marks it as in an error state,
2507    and aborts reading it using longjmp. */
2508 static void
2509 sys_error (struct sfm_reader *r, off_t offset, const char *format, ...)
2510 {
2511   va_list args;
2512
2513   va_start (args, format);
2514   sys_msg (r, offset, ME, format, args);
2515   va_end (args);
2516
2517   r->error = true;
2518   longjmp (r->bail_out, 1);
2519 }
2520 \f
2521 /* Reads BYTE_CNT bytes into BUF.
2522    Returns true if exactly BYTE_CNT bytes are successfully read.
2523    Aborts if an I/O error or a partial read occurs.
2524    If EOF_IS_OK, then an immediate end-of-file causes false to be
2525    returned; otherwise, immediate end-of-file causes an abort
2526    too. */
2527 static inline bool
2528 read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
2529                    void *buf, size_t byte_cnt)
2530 {
2531   size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
2532   r->pos += bytes_read;
2533   if (bytes_read == byte_cnt)
2534     return true;
2535   else if (ferror (r->file))
2536     sys_error (r, r->pos, _("System error: %s."), strerror (errno));
2537   else if (!eof_is_ok || bytes_read != 0)
2538     sys_error (r, r->pos, _("Unexpected end of file."));
2539   else
2540     return false;
2541 }
2542
2543 /* Reads BYTE_CNT into BUF.
2544    Aborts upon I/O error or if end-of-file is encountered. */
2545 static void
2546 read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
2547 {
2548   read_bytes_internal (r, false, buf, byte_cnt);
2549 }
2550
2551 /* Reads BYTE_CNT bytes into BUF.
2552    Returns true if exactly BYTE_CNT bytes are successfully read.
2553    Returns false if an immediate end-of-file is encountered.
2554    Aborts if an I/O error or a partial read occurs. */
2555 static bool
2556 try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
2557 {
2558   return read_bytes_internal (r, true, buf, byte_cnt);
2559 }
2560
2561 /* Reads a 32-bit signed integer from R and returns its value in
2562    host format. */
2563 static int
2564 read_int (struct sfm_reader *r)
2565 {
2566   uint8_t integer[4];
2567   read_bytes (r, integer, sizeof integer);
2568   return integer_get (r->integer_format, integer, sizeof integer);
2569 }
2570
2571 /* Reads a 64-bit floating-point number from R and returns its
2572    value in host format. */
2573 static double
2574 read_float (struct sfm_reader *r)
2575 {
2576   uint8_t number[8];
2577   read_bytes (r, number, sizeof number);
2578   return float_get_double (r->float_format, number);
2579 }
2580
2581 static int
2582 parse_int (struct sfm_reader *r, const void *data, size_t ofs)
2583 {
2584   return integer_get (r->integer_format, (const uint8_t *) data + ofs, 4);
2585 }
2586
2587 static double
2588 parse_float (struct sfm_reader *r, const void *data, size_t ofs)
2589 {
2590   return float_get_double (r->float_format, (const uint8_t *) data + ofs);
2591 }
2592
2593 /* Reads exactly SIZE - 1 bytes into BUFFER
2594    and stores a null byte into BUFFER[SIZE - 1]. */
2595 static void
2596 read_string (struct sfm_reader *r, char *buffer, size_t size)
2597 {
2598   assert (size > 0);
2599   read_bytes (r, buffer, size - 1);
2600   buffer[size - 1] = '\0';
2601 }
2602
2603 /* Skips BYTES bytes forward in R. */
2604 static void
2605 skip_bytes (struct sfm_reader *r, size_t bytes)
2606 {
2607   while (bytes > 0)
2608     {
2609       char buffer[1024];
2610       size_t chunk = MIN (sizeof buffer, bytes);
2611       read_bytes (r, buffer, chunk);
2612       bytes -= chunk;
2613     }
2614 }
2615 \f
2616 static const struct casereader_class sys_file_casereader_class =
2617   {
2618     sys_file_casereader_read,
2619     sys_file_casereader_destroy,
2620     NULL,
2621     NULL,
2622   };