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