por-file-reader: Use xasprintf() to avoid need for careful buffer sizing.
[pspp] / src / data / por-file-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <ctype.h>
20 #include <errno.h>
21 #include <math.h>
22 #include <setjmp.h>
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "data/any-reader.h"
29 #include "data/casereader-provider.h"
30 #include "data/casereader.h"
31 #include "data/dictionary.h"
32 #include "data/file-handle-def.h"
33 #include "data/file-name.h"
34 #include "data/format.h"
35 #include "data/missing-values.h"
36 #include "data/short-names.h"
37 #include "data/value-labels.h"
38 #include "data/variable.h"
39 #include "libpspp/compiler.h"
40 #include "libpspp/i18n.h"
41 #include "libpspp/message.h"
42 #include "libpspp/misc.h"
43 #include "libpspp/pool.h"
44 #include "libpspp/str.h"
45
46 #include "gl/minmax.h"
47 #include "gl/xalloc.h"
48 #include "gl/xmemdup0.h"
49
50 #include "gettext.h"
51 #define _(msgid) gettext (msgid)
52 #define N_(msgid) (msgid)
53
54 /* portable_to_local[PORTABLE] translates the given portable
55    character into the local character set. */
56 static const char portable_to_local[256] =
57   {
58     "                                                                "
59     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ."
60     "<(+|&[]!$*);^-/|,%_>?`:$@'=\"      ~-   0123456789   -() {}\\     "
61     "                                                                "
62   };
63
64 /* Portable file reader. */
65 struct pfm_reader
66   {
67     struct any_reader any_reader;
68     struct pool *pool;          /* All the portable file state. */
69
70     jmp_buf bail_out;           /* longjmp() target for error handling. */
71
72     struct dictionary *dict;
73     struct any_read_info info;
74     struct file_handle *fh;     /* File handle. */
75     struct fh_lock *lock;       /* Read lock for file. */
76     FILE *file;                 /* File stream. */
77     int line_length;            /* Number of characters so far on this line. */
78     char cc;                    /* Current character. */
79     char *trans;                /* 256-byte character set translation table. */
80     int var_cnt;                /* Number of variables. */
81     int weight_index;           /* 0-based index of weight variable, or -1. */
82     struct caseproto *proto;    /* Format of output cases. */
83     bool ok;                    /* Set false on I/O error. */
84   };
85
86 static const struct casereader_class por_file_casereader_class;
87
88 static struct pfm_reader *
89 pfm_reader_cast (const struct any_reader *r_)
90 {
91   assert (r_->klass == &por_file_reader_class);
92   return UP_CAST (r_, struct pfm_reader, any_reader);
93 }
94
95 static void
96 error (struct pfm_reader *r, const char *msg,...)
97      PRINTF_FORMAT (2, 3)
98      NO_RETURN;
99
100 /* Displays MSG as an error message and aborts reading the
101    portable file via longjmp(). */
102 static void
103 error (struct pfm_reader *r, const char *msg, ...)
104 {
105   struct string text;
106   va_list args;
107
108   ds_init_empty (&text);
109   ds_put_format (&text, _("portable file %s corrupt at offset 0x%llx: "),
110                  fh_get_file_name (r->fh), (long long int) ftello (r->file));
111   va_start (args, msg);
112   ds_put_vformat (&text, msg, args);
113   va_end (args);
114
115   struct msg m = {
116     .category = MSG_C_GENERAL,
117     .severity = MSG_S_ERROR,
118     .text = ds_cstr (&text),
119   };
120   msg_emit (&m);
121
122   r->ok = false;
123
124   longjmp (r->bail_out, 1);
125 }
126
127 /* Displays MSG as an warning for the current position in
128    portable file reader R. */
129 static void
130 warning (struct pfm_reader *r, const char *msg, ...)
131 {
132   struct string text;
133   va_list args;
134
135   ds_init_empty (&text);
136   ds_put_format (&text, _("reading portable file %s at offset 0x%llx: "),
137                  fh_get_file_name (r->fh), (long long int) ftello (r->file));
138   va_start (args, msg);
139   ds_put_vformat (&text, msg, args);
140   va_end (args);
141
142   struct msg m = {
143     .category = MSG_C_GENERAL,
144     .severity = MSG_S_WARNING,
145     .text = ds_cstr (&text),
146   };
147   msg_emit (&m);
148 }
149
150 /* Close and destroy R.
151    Returns false if an error was detected on R, true otherwise. */
152 static bool
153 pfm_close (struct any_reader *r_)
154 {
155   struct pfm_reader *r = pfm_reader_cast (r_);
156   bool ok;
157
158   dict_unref (r->dict);
159   any_read_info_destroy (&r->info);
160   if (r->file)
161     {
162       if (fn_close (r->fh, r->file) == EOF)
163         {
164           msg (ME, _("Error closing portable file `%s': %s."),
165                fh_get_file_name (r->fh), strerror (errno));
166           r->ok = false;
167         }
168       r->file = NULL;
169     }
170
171   fh_unlock (r->lock);
172   fh_unref (r->fh);
173
174   ok = r->ok;
175   pool_destroy (r->pool);
176
177   return ok;
178 }
179
180 /* Closes portable file reader R, after we're done with it. */
181 static void
182 por_file_casereader_destroy (struct casereader *reader, void *r_)
183 {
184   struct pfm_reader *r = r_;
185   if (!pfm_close (&r->any_reader))
186     casereader_force_error (reader);
187 }
188
189 /* Read a single character into cur_char.  */
190 static void
191 advance (struct pfm_reader *r)
192 {
193   int c;
194
195   /* Read the next character from the file.
196      Ignore carriage returns entirely.
197      Mostly ignore new-lines, but if a new-line occurs before the
198      line has reached 80 bytes in length, then treat the
199      "missing" bytes as spaces. */
200   for (;;)
201     {
202       while ((c = getc (r->file)) == '\r')
203         continue;
204       if (c != '\n')
205         break;
206
207       if (r->line_length < 80)
208         {
209           c = ' ';
210           ungetc ('\n', r->file);
211           break;
212         }
213       r->line_length = 0;
214     }
215   if (c == EOF)
216     error (r, _("unexpected end of file"));
217
218   if (r->trans != NULL)
219     c = r->trans[c];
220   r->cc = c;
221   r->line_length++;
222 }
223
224 /* Skip a single character if present, and return whether it was
225    skipped. */
226 static inline bool
227 match (struct pfm_reader *r, int c)
228 {
229   if (r->cc == c)
230     {
231       advance (r);
232       return true;
233     }
234   else
235     return false;
236 }
237
238 static void read_header (struct pfm_reader *);
239 static void read_version_data (struct pfm_reader *, struct any_read_info *);
240 static void read_variables (struct pfm_reader *, struct dictionary *);
241 static void read_value_label (struct pfm_reader *, struct dictionary *);
242 static void read_documents (struct pfm_reader *, struct dictionary *);
243
244 /* Reads the dictionary from file with handle H, and returns it in a
245    dictionary structure.  This dictionary may be modified in order to
246    rename, reorder, and delete variables, etc. */
247 static struct any_reader *
248 pfm_open (struct file_handle *fh)
249 {
250   struct pool *volatile pool = NULL;
251   struct pfm_reader *volatile r = NULL;
252
253   /* Create and initialize reader. */
254   pool = pool_create ();
255   r = pool_alloc (pool, sizeof *r);
256   r->any_reader.klass = &por_file_reader_class;
257   r->dict = dict_create (get_default_encoding ());
258   memset (&r->info, 0, sizeof r->info);
259   r->pool = pool;
260   r->fh = fh_ref (fh);
261   r->lock = NULL;
262   r->file = NULL;
263   r->line_length = 0;
264   r->weight_index = -1;
265   r->trans = NULL;
266   r->var_cnt = 0;
267   r->proto = NULL;
268   r->ok = true;
269   if (setjmp (r->bail_out))
270     goto error;
271
272   /* Lock file. */
273   /* TRANSLATORS: this fragment will be interpolated into
274      messages in fh_lock() that identify types of files. */
275   r->lock = fh_lock (fh, FH_REF_FILE, N_("portable file"), FH_ACC_READ, false);
276   if (r->lock == NULL)
277     goto error;
278
279   /* Open file. */
280   r->file = fn_open (r->fh, "rb");
281   if (r->file == NULL)
282     {
283       msg (ME, _("An error occurred while opening `%s' for reading "
284                  "as a portable file: %s."),
285            fh_get_file_name (r->fh), strerror (errno));
286       goto error;
287     }
288
289   /* Read header, version, date info, product id, variables. */
290   read_header (r);
291   read_version_data (r, &r->info);
292   read_variables (r, r->dict);
293
294   /* Read value labels. */
295   while (match (r, 'D'))
296     read_value_label (r, r->dict);
297
298   /* Read documents. */
299   if (match (r, 'E'))
300     read_documents (r, r->dict);
301
302   /* Check that we've made it to the data. */
303   if (!match (r, 'F'))
304     error (r, _("Data record expected."));
305
306   r->proto = caseproto_ref_pool (dict_get_proto (r->dict), r->pool);
307   return &r->any_reader;
308
309  error:
310   pfm_close (&r->any_reader);
311   return NULL;
312 }
313
314 static struct casereader *
315 pfm_decode (struct any_reader *r_, const char *encoding UNUSED,
316             struct dictionary **dictp, struct any_read_info *info)
317 {
318   struct pfm_reader *r = pfm_reader_cast (r_);
319
320   *dictp = r->dict;
321   r->dict = NULL;
322
323   if (info)
324     {
325       *info = r->info;
326       memset (&r->info, 0, sizeof r->info);
327     }
328
329   return casereader_create_sequential (NULL, r->proto, CASENUMBER_MAX,
330                                        &por_file_casereader_class, r);
331 }
332 \f
333 /* Returns the value of base-30 digit C,
334    or -1 if C is not a base-30 digit. */
335 static int
336 base_30_value (unsigned char c)
337 {
338   static const char base_30_digits[] = "0123456789ABCDEFGHIJKLMNOPQRST";
339   const char *p = strchr (base_30_digits, c);
340   return p != NULL ? p - base_30_digits : -1;
341 }
342
343 /* Read a floating point value and return its value. */
344 static double
345 read_float (struct pfm_reader *r)
346 {
347   double num = 0.;
348   int exponent = 0;
349   bool got_dot = false;         /* Seen a decimal point? */
350   bool got_digit = false;       /* Seen any digits? */
351   bool negative = false;        /* Number is negative? */
352
353   /* Skip leading spaces. */
354   while (match (r, ' '))
355     continue;
356
357   /* `*' indicates system-missing. */
358   if (match (r, '*'))
359     {
360       advance (r);      /* Probably a dot (.) but doesn't appear to matter. */
361       return SYSMIS;
362     }
363
364   negative = match (r, '-');
365   for (;;)
366     {
367       int digit = base_30_value (r->cc);
368       if (digit != -1)
369         {
370           got_digit = true;
371
372           /* Make sure that multiplication by 30 will not overflow.  */
373           if (num > DBL_MAX * (1. / 30.))
374             /* The value of the digit doesn't matter, since we have already
375                gotten as many digits as can be represented in a `double'.
376                This doesn't necessarily mean the result will overflow.
377                The exponent may reduce it to within range.
378
379                We just need to record that there was another
380                digit so that we can multiply by 10 later.  */
381             ++exponent;
382           else
383             num = (num * 30.0) + digit;
384
385           /* Keep track of the number of digits after the decimal point.
386              If we just divided by 30 here, we would lose precision.  */
387           if (got_dot)
388             --exponent;
389         }
390       else if (!got_dot && r->cc == '.')
391         /* Record that we have found the decimal point.  */
392         got_dot = 1;
393       else
394         /* Any other character terminates the number.  */
395         break;
396
397       advance (r);
398     }
399
400   /* Check that we had some digits. */
401   if (!got_digit)
402     error (r, _("Number expected."));
403
404   /* Get exponent if any. */
405   if (r->cc == '+' || r->cc == '-')
406     {
407       long int exp = 0;
408       bool negative_exponent = r->cc == '-';
409       int digit;
410
411       for (advance (r); (digit = base_30_value (r->cc)) != -1; advance (r))
412         {
413           if (exp > LONG_MAX / 30)
414             {
415               exp = LONG_MAX;
416               break;
417             }
418           exp = exp * 30 + digit;
419         }
420
421       /* We don't check whether there were actually any digits, but we
422          probably should. */
423       if (negative_exponent)
424         exp = -exp;
425       exponent += exp;
426     }
427
428   /* Numbers must end with `/'. */
429   if (!match (r, '/'))
430     error (r, _("Missing numeric terminator."));
431
432   /* Multiply `num' by 30 to the `exponent' power, checking for
433      overflow.  */
434   if (exponent < 0)
435     num *= pow (30.0, (double) exponent);
436   else if (exponent > 0)
437     {
438       if (num > DBL_MAX * pow (30.0, (double) -exponent))
439         num = DBL_MAX;
440       else
441         num *= pow (30.0, (double) exponent);
442     }
443
444   return negative ? -num : num;
445 }
446
447 /* Read an integer and return its value. */
448 static int
449 read_int (struct pfm_reader *r)
450 {
451   double f = read_float (r);
452   if (floor (f) != f || f >= INT_MAX || f <= INT_MIN)
453     error (r, _("Invalid integer."));
454   return f;
455 }
456
457 /* Reads a string into BUF, which must have room for 256
458    characters. */
459 static void
460 read_string (struct pfm_reader *r, char *buf)
461 {
462   int n = read_int (r);
463   if (n < 0 || n > 255)
464     error (r, _("Bad string length %d."), n);
465
466   while (n-- > 0)
467     {
468       *buf++ = r->cc;
469       advance (r);
470     }
471   *buf = '\0';
472 }
473
474
475 /* Reads a string into BUF, which must have room for 256
476    characters.
477    Returns the number of bytes read.
478 */
479 static size_t
480 read_bytes (struct pfm_reader *r, uint8_t *buf)
481 {
482   int n = read_int (r);
483   if (n < 0 || n > 255)
484     error (r, _("Bad string length %d."), n);
485
486   while (n-- > 0)
487     {
488       *buf++ = r->cc;
489       advance (r);
490     }
491   return n;
492 }
493
494
495
496 /* Reads a string and returns a copy of it allocated from R's
497    pool. */
498 static char *
499 read_pool_string (struct pfm_reader *r)
500 {
501   char string[256];
502   read_string (r, string);
503   return pool_strdup (r->pool, string);
504 }
505 \f
506 /* Reads the 464-byte file header. */
507 static void
508 read_header (struct pfm_reader *r)
509 {
510   char *trans;
511   int i;
512
513   /* Read and ignore vanity splash strings. */
514   for (i = 0; i < 200; i++)
515     advance (r);
516
517   /* Skip the first 64 characters of the translation table.
518      We don't care about these.  They are probably all set to
519      '0', marking them as untranslatable, and that would screw
520      up our actual translation of the real '0'. */
521   for (i = 0; i < 64; i++)
522     advance (r);
523
524   /* Read the rest of the translation table. */
525   trans = pool_malloc (r->pool, 256);
526   memset (trans, 0, 256);
527   for (; i < 256; i++)
528     {
529       unsigned char c;
530
531       advance (r);
532
533       c = r->cc;
534       if (trans[c] == 0)
535         trans[c] = portable_to_local[i];
536     }
537
538   /* Set up the translation table, then read the first
539      translated character. */
540   r->trans = trans;
541   advance (r);
542
543   /* Skip and verify signature. */
544   for (i = 0; i < 8; i++)
545     if (!match (r, "SPSSPORT"[i]))
546       {
547         msg (SE, _("%s: Not a portable file."), fh_get_file_name (r->fh));
548         longjmp (r->bail_out, 1);
549       }
550 }
551
552 /* Reads the version and date info record, as well as product and
553    subproduct identification records if present. */
554 static void
555 read_version_data (struct pfm_reader *r, struct any_read_info *info)
556 {
557   static const char empty_string[] = "";
558   char *date, *time;
559   const char *product, *subproduct;
560   int i;
561
562   /* Read file. */
563   if (!match (r, 'A'))
564     error (r, _("Unrecognized version code `%c'."), r->cc);
565   date = read_pool_string (r);
566   time = read_pool_string (r);
567   product = match (r, '1') ? read_pool_string (r) : empty_string;
568   if (match (r, '2'))
569     {
570       /* Skip "author" field. */
571       read_pool_string (r);
572     }
573   subproduct = match (r, '3') ? read_pool_string (r) : empty_string;
574
575   /* Validate file. */
576   if (strlen (date) != 8)
577     error (r, _("Bad date string length %zu."), strlen (date));
578   if (strlen (time) != 6)
579     error (r, _("Bad time string length %zu."), strlen (time));
580
581   /* Save file info. */
582   if (info != NULL)
583     {
584       memset (info, 0, sizeof *info);
585
586       info->float_format = FLOAT_NATIVE_DOUBLE;
587       info->integer_format = INTEGER_NATIVE;
588       info->compression = ANY_COMP_NONE;
589       info->case_cnt = -1;
590
591       /* Date. */
592       info->creation_date = xmalloc (11);
593       for (i = 0; i < 8; i++)
594         {
595           static const int map[] = {6, 7, 8, 9, 3, 4, 0, 1};
596           info->creation_date[map[i]] = date[i];
597         }
598       info->creation_date[2] = info->creation_date[5] = ' ';
599       info->creation_date[10] = '\0';
600
601       /* Time. */
602       info->creation_time = xmalloc (9);
603       for (i = 0; i < 6; i++)
604         {
605           static const int map[] = {0, 1, 3, 4, 6, 7};
606           info->creation_time[map[i]] = time[i];
607         }
608       info->creation_time[2] = info->creation_time[5] = ' ';
609       info->creation_time[8] = 0;
610
611       /* Product. */
612       info->product = xstrdup (product);
613       info->product_ext = xstrdup (subproduct);
614     }
615 }
616
617 /* Translates a format specification read from portable file R as
618    the three integers INTS into a normal format specifier FORMAT,
619    checking that the format is appropriate for variable V. */
620 static struct fmt_spec
621 convert_format (struct pfm_reader *r, const int portable_format[3],
622                 struct variable *v, bool *report_error)
623 {
624   struct fmt_spec format;
625   bool ok;
626
627   if (!fmt_from_io (portable_format[0], &format.type))
628     {
629       if (*report_error)
630         warning (r, _("%s: Bad format specifier byte (%d).  Variable "
631                       "will be assigned a default format."),
632                  var_get_name (v), portable_format[0]);
633       goto assign_default;
634     }
635
636   format.w = portable_format[1];
637   format.d = portable_format[2];
638
639   msg_disable ();
640   ok = (fmt_check_output (&format)
641         && fmt_check_width_compat (&format, var_get_width (v)));
642   msg_enable ();
643
644   if (!ok)
645     {
646       if (*report_error)
647         {
648           char fmt_string[FMT_STRING_LEN_MAX + 1];
649           fmt_to_string (&format, fmt_string);
650           if (var_is_numeric (v))
651             warning (r, _("Numeric variable %s has invalid format "
652                           "specifier %s."),
653                      var_get_name (v), fmt_string);
654           else
655             warning (r, _("String variable %s with width %d has "
656                           "invalid format specifier %s."),
657                      var_get_name (v), var_get_width (v), fmt_string);
658         }
659       goto assign_default;
660     }
661
662   return format;
663
664 assign_default:
665   *report_error = false;
666   return fmt_default_for_width (var_get_width (v));
667 }
668
669 static void parse_value (struct pfm_reader *, int width, union value *);
670
671 /* Read information on all the variables.  */
672 static void
673 read_variables (struct pfm_reader *r, struct dictionary *dict)
674 {
675   char *weight_name = NULL;
676   int i;
677
678   if (!match (r, '4'))
679     error (r, _("Expected variable count record."));
680
681   r->var_cnt = read_int (r);
682   if (r->var_cnt <= 0)
683     error (r, _("Invalid number of variables %d."), r->var_cnt);
684
685   if (match (r, '5'))
686     read_int (r);
687
688   if (match (r, '6'))
689     {
690       weight_name = read_pool_string (r);
691       if (strlen (weight_name) > SHORT_NAME_LEN)
692         error (r, _("Weight variable name (%s) truncated."), weight_name);
693     }
694
695   for (i = 0; i < r->var_cnt; i++)
696     {
697       int width;
698       char name[256];
699       int fmt[6];
700       struct variable *v;
701       struct missing_values miss;
702       struct fmt_spec print, write;
703       bool report_error = true;
704       int j;
705
706       if (!match (r, '7'))
707         error (r, _("Expected variable record."));
708
709       width = read_int (r);
710       if (width < 0)
711         error (r, _("Invalid variable width %d."), width);
712
713       read_string (r, name);
714       for (j = 0; j < 6; j++)
715         fmt[j] = read_int (r);
716
717       if (!dict_id_is_valid (dict, name, false)
718           || *name == '#' || *name == '$')
719         error (r, _("Invalid variable name `%s' in position %d."), name, i);
720       str_uppercase (name);
721
722       if (width < 0 || width > 255)
723         error (r, _("Bad width %d for variable %s."), width, name);
724
725       v = dict_create_var (dict, name, width);
726       if (v == NULL)
727         {
728           unsigned long int i;
729           for (i = 1; ; i++)
730             {
731               char *try_name = xasprintf ("%s_%lu", name, i);
732               v = dict_create_var (dict, try_name, width);
733               free (try_name);
734               if (v != NULL)
735                 break;
736             }
737           warning (r, _("Duplicate variable name %s in position %d renamed "
738                         "to %s."), name, i, var_get_name (v));
739         }
740
741       print = convert_format (r, &fmt[0], v, &report_error);
742       write = convert_format (r, &fmt[3], v, &report_error);
743       var_set_print_format (v, &print);
744       var_set_write_format (v, &write);
745
746       /* Range missing values. */
747       mv_init (&miss, width);
748       if (match (r, 'B'))
749         {
750           double x = read_float (r);
751           double y = read_float (r);
752           mv_add_range (&miss, x, y);
753         }
754       else if (match (r, 'A'))
755         mv_add_range (&miss, read_float (r), HIGHEST);
756       else if (match (r, '9'))
757         mv_add_range (&miss, LOWEST, read_float (r));
758
759       /* Single missing values. */
760       while (match (r, '8'))
761         {
762           int mv_width = MIN (width, 8);
763           union value value;
764
765           parse_value (r, mv_width, &value);
766           value_resize (&value, mv_width, width);
767           mv_add_value (&miss, &value);
768           value_destroy (&value, width);
769         }
770
771       var_set_missing_values (v, &miss);
772       mv_destroy (&miss);
773
774       if (match (r, 'C'))
775         {
776           char label[256];
777           read_string (r, label);
778           var_set_label (v, label); /* XXX */
779         }
780     }
781
782   if (weight_name != NULL)
783     {
784       struct variable *weight_var = dict_lookup_var (dict, weight_name);
785       if (weight_var == NULL)
786         error (r, _("Weighting variable %s not present in dictionary."),
787                weight_name);
788
789       dict_set_weight (dict, weight_var);
790     }
791 }
792
793 /* Parse a value of with WIDTH into value V. */
794 static void
795 parse_value (struct pfm_reader *r, int width, union value *v)
796 {
797   value_init (v, width);
798   if (width > 0)
799     {
800       uint8_t buf[256];
801       size_t n_bytes = read_bytes (r, buf);
802       value_copy_buf_rpad (v, width, buf, n_bytes, ' ');
803     }
804   else
805     v->f = read_float (r);
806 }
807
808 /* Parse a value label record and return success. */
809 static void
810 read_value_label (struct pfm_reader *r, struct dictionary *dict)
811 {
812   /* Variables. */
813   int nv;
814   struct variable **v;
815
816   /* Labels. */
817   int n_labels;
818
819   int i;
820
821   nv = read_int (r);
822   v = pool_nalloc (r->pool, nv, sizeof *v);
823   for (i = 0; i < nv; i++)
824     {
825       char name[256];
826       read_string (r, name);
827
828       v[i] = dict_lookup_var (dict, name);
829       if (v[i] == NULL)
830         error (r, _("Unknown variable %s while parsing value labels."), name);
831
832       if (var_get_type (v[0]) != var_get_type (v[i]))
833         error (r, _("Cannot assign value labels to %s and %s, which "
834                     "have different variable types."),
835                var_get_name (v[0]), var_get_name (v[i]));
836     }
837
838   n_labels = read_int (r);
839   for (i = 0; i < n_labels; i++)
840     {
841       union value val;
842       char label[256];
843       int j;
844
845       parse_value (r, var_get_width (v[0]), &val);
846       read_string (r, label);
847
848       /* Assign the value label to each variable. */
849       for (j = 0; j < nv; j++)
850         var_replace_value_label (v[j], &val, label);
851
852       value_destroy (&val, var_get_width (v[0]));
853     }
854 }
855
856 /* Reads a set of documents from portable file R into DICT. */
857 static void
858 read_documents (struct pfm_reader *r, struct dictionary *dict)
859 {
860   int line_cnt;
861   int i;
862
863   line_cnt = read_int (r);
864   for (i = 0; i < line_cnt; i++)
865     {
866       char line[256];
867       read_string (r, line);
868       dict_add_document_line (dict, line, false);
869     }
870 }
871
872 /* Reads and returns one case from portable file R.  Returns a
873    null pointer on failure. */
874 static struct ccase *
875 por_file_casereader_read (struct casereader *reader, void *r_)
876 {
877   struct pfm_reader *r = r_;
878   struct ccase *volatile c;
879   size_t i;
880
881   c = case_create (r->proto);
882   setjmp (r->bail_out);
883   if (!r->ok)
884     {
885       casereader_force_error (reader);
886       case_unref (c);
887       return NULL;
888     }
889
890   /* Check for end of file. */
891   if (r->cc == 'Z')
892     {
893       case_unref (c);
894       return NULL;
895     }
896
897   for (i = 0; i < r->var_cnt; i++)
898     {
899       int width = caseproto_get_width (r->proto, i);
900
901       if (width == 0)
902         case_data_rw_idx (c, i)->f = read_float (r);
903       else
904         {
905           uint8_t buf[256];
906           size_t n_bytes = read_bytes (r, buf);
907           u8_buf_copy_rpad (case_str_rw_idx (c, i), width, buf, n_bytes, ' ');
908         }
909     }
910
911   return c;
912 }
913
914 /* Detects whether FILE is an SPSS portable file.  Returns 1 if so, 0 if not,
915    and a negative errno value if there is an error reading FILE. */
916 static int
917 pfm_detect (FILE *file)
918 {
919   unsigned char header[464];
920   char trans[256];
921   int cooked_cnt, raw_cnt, line_len;
922   int i;
923
924   cooked_cnt = raw_cnt = 0;
925   line_len = 0;
926   while (cooked_cnt < sizeof header)
927     {
928       int c = getc (file);
929       if (c == EOF || raw_cnt++ > 512)
930         return ferror (file) ? -errno : 0;
931       else if (c == '\n')
932         {
933           while (line_len < 80 && cooked_cnt < sizeof header)
934             {
935               header[cooked_cnt++] = ' ';
936               line_len++;
937             }
938           line_len = 0;
939         }
940       else if (c != '\r')
941         {
942           header[cooked_cnt++] = c;
943           line_len++;
944         }
945     }
946
947   memset (trans, 0, 256);
948   for (i = 64; i < 256; i++)
949     {
950       unsigned char c = header[i + 200];
951       if (trans[c] == 0)
952         trans[c] = portable_to_local[i];
953     }
954
955   for (i = 0; i < 8; i++)
956     if (trans[header[i + 456]] != "SPSSPORT"[i])
957       return 0;
958
959   return 1;
960 }
961
962 static const struct casereader_class por_file_casereader_class =
963   {
964     por_file_casereader_read,
965     por_file_casereader_destroy,
966     NULL,
967     NULL,
968   };
969
970 const struct any_reader_class por_file_reader_class =
971   {
972     N_("SPSS Portable File"),
973     pfm_detect,
974     pfm_open,
975     pfm_close,
976     pfm_decode,
977     NULL,                       /* get_strings */
978   };