Work on support for variable sets.
[pspp] / src / data / sys-file-reader.c
index 7684acbc576a40c77c78c7a2ea6b7d57360127ac..66552dc4b46b85cdc58ffb8f6b509b168058199f 100644 (file)
@@ -744,7 +744,7 @@ sfm_get_strings (const struct any_reader *r_, struct pool *pool,
   return aux.n;
 }
 
-/* Decodes the dictionary read from R, saving it into into *DICT.  Character
+/* Decodes the dictionary read from R, saving it into *DICT.  Character
    strings in R are decoded using ENCODING, or an encoding obtained from R if
    ENCODING is null, or the locale encoding if R specifies no encoding.
 
@@ -1433,8 +1433,7 @@ parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
         }
 
       struct variable *var;
-      if (!dict_id_is_valid (dict, name, false)
-          || name[0] == '$' || name[0] == '#')
+      if (!dict_id_is_valid (dict, name) || name[0] == '$' || name[0] == '#')
         {
           var = add_var_with_generated_name (dict, rec->width);
           sys_warn (r, rec->pos, _("Renaming variable with invalid name "
@@ -1541,9 +1540,9 @@ parse_format_spec (struct sfm_reader *r, off_t pos, unsigned int format,
   if (fmt_from_u32 (format, var_get_width (v), false, &f))
     {
       if (which == PRINT_FORMAT)
-        var_set_print_format (v, &f);
+        var_set_print_format (v, f);
       else
-        var_set_write_format (v, &f);
+        var_set_write_format (v, f);
     }
   else if (format == 0)
     {
@@ -1817,7 +1816,7 @@ decode_mrsets (struct sfm_reader *r, struct dictionary *dict)
       size_t i;
 
       name = recode_string ("UTF-8", r->encoding, s->name, -1);
-      if (!mrset_is_valid_name (name, dict_get_encoding (dict), false))
+      if (!mrset_is_valid_name (name, dict_get_encoding (dict)))
         {
           sys_warn (r, -1, _("Invalid multiple response set name `%s'."),
                     name);
@@ -2051,7 +2050,7 @@ parse_long_var_name_map (struct sfm_reader *r,
   while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
     {
       /* Validate long name. */
-      if (!dict_id_is_valid (dict, long_name, false)
+      if (!dict_id_is_valid (dict, long_name)
           || long_name[0] == '$' || long_name[0] == '#')
         {
           sys_warn (r, record->pos,
@@ -2478,21 +2477,28 @@ assign_variable_roles (struct sfm_reader *r, struct dictionary *dict)
 }
 
 static bool
-check_overflow (struct sfm_reader *r,
-                const struct sfm_extension_record *record,
-                size_t ofs, size_t length)
+check_overflow__ (const struct sfm_extension_record *record,
+                  size_t ofs, size_t length)
 {
   size_t end = record->size * record->count;
   if (length >= end || ofs + length > end)
-    {
-      sys_warn (r, record->pos + end,
-                _("Extension record subtype %d ends unexpectedly."),
-                record->subtype);
-      return false;
-    }
+    return false;
   return true;
 }
 
+static bool
+check_overflow (struct sfm_reader *r,
+                const struct sfm_extension_record *record,
+                size_t ofs, size_t length)
+{
+  bool ok = check_overflow__ (record, ofs, length);
+  if (!ok)
+    sys_warn (r, record->pos + record->size * record->count,
+              _("Extension record subtype %d ends unexpectedly."),
+              record->subtype);
+  return ok;
+}
+
 static void
 parse_long_string_value_labels (struct sfm_reader *r,
                                 const struct sfm_extension_record *record,
@@ -2619,6 +2625,7 @@ parse_long_string_missing_values (struct sfm_reader *r,
   size_t end = record->size * record->count;
   size_t ofs = 0;
 
+  bool warned = false;
   while (ofs < end)
     {
       struct missing_values mv;
@@ -2667,17 +2674,32 @@ parse_long_string_missing_values (struct sfm_reader *r,
           var = NULL;
         }
 
+      /* Parse value length. */
+      if (!check_overflow (r, record, ofs, 4))
+        return;
+      size_t value_length = parse_int (r, record->data, ofs);
+      ofs += 4;
+
       /* Parse values. */
       mv_init_pool (r->pool, &mv, var ? var_get_width (var) : 8);
       for (i = 0; i < n_missing_values; i++)
        {
-          size_t value_length;
-
-          /* Parse value length. */
-          if (!check_overflow (r, record, ofs, 4))
-            return;
-          value_length = parse_int (r, record->data, ofs);
-          ofs += 4;
+          /* Tolerate files written by old, buggy versions of PSPP where we
+             believed that the value_length was repeated before each missing
+             value. */
+          if (check_overflow__ (record, ofs, value_length)
+              && parse_int (r, record->data, ofs) == 8)
+            {
+              if (!warned)
+                {
+                  sys_warn (r, record->pos + ofs,
+                            _("This file has corrupted metadata written by a "
+                              "buggy version of PSPP.  To fix it, save a new "
+                              "copy of the file."));
+                  warned = true;
+                }
+              ofs += 4;
+            }
 
           /* Parse value. */
           if (!check_overflow (r, record, ofs, value_length))