pspp-convert: Support decrypting SPV files.
[pspp] / utilities / pspp-dump-sav.c
index a10ff148bdc7fa91ce40a45b866ee38099ef6bab..0aed9cf61488ae67e925891c7eb506037919dc1b 100644 (file)
@@ -37,6 +37,7 @@
 #include "gl/progname.h"
 #include "gl/version-etc.h"
 #include "gl/xalloc.h"
+#include "gl/xsize.h"
 
 #define ID_MAX_LEN 64
 
@@ -99,7 +100,7 @@ static void read_simple_compressed_data (struct sfm_reader *, int max_cases);
 static void read_zlib_compressed_data (struct sfm_reader *);
 
 static struct text_record *open_text_record (
-  struct sfm_reader *, size_t size);
+  struct sfm_reader *, size_t size, size_t count);
 static void close_text_record (struct text_record *);
 static bool read_variable_to_value_pair (struct text_record *,
                                          char **key, char **value);
@@ -235,6 +236,8 @@ main (int argc, char *argv[])
       else if (r.compression == COMP_ZLIB)
         read_zlib_compressed_data (&r);
 
+      free (r.var_widths);
+
       fclose (r.file);
     }
 
@@ -379,6 +382,8 @@ format_name (int format)
     case 37: return "CCE";
     case 38: return "EDATE";
     case 39: return "SDATE";
+    case 40: return "MTIME";
+    case 41: return "YMDHMS";
     default: return "invalid";
     }
 }
@@ -398,7 +403,7 @@ read_variable_record (struct sfm_reader *r)
   char name[9];
 
   printf ("%08llx: variable record #%d\n",
-          (long long int) ftello (r->file), r->n_variable_records++);
+          (long long int) ftello (r->file), ++r->n_variable_records);
 
   width = read_int (r);
   has_variable_label = read_int (r);
@@ -733,7 +738,7 @@ read_extra_product_info (struct sfm_reader *r,
   const char *s;
 
   printf ("%08llx: extra product info\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   s = text_get_all (text);
   print_string (s, strlen (s));
   close_text_record (text);
@@ -747,7 +752,7 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("%08llx: multiple response sets\n",
           (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   for (;;)
     {
       const char *name;
@@ -795,7 +800,11 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count)
             }
 
           number = text_tokenize (text, ' ');
-          if (!strcmp (number, "11"))
+          if (!number)
+            sys_warn (r, "Missing label source value "
+                      "following `E' at offset %zu in MRSETS record",
+                      text_pos (text));
+          else if (!strcmp (number, "11"))
             label_from_var_label = true;
           else if (strcmp (number, "1"))
             sys_warn (r, "Unexpected label source value `%s' "
@@ -903,7 +912,7 @@ read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("%08llx: long variable names (short => long)\n",
           (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   while (read_variable_to_value_pair (text, &var, &long_name))
     printf ("\t%s => %s\n", var, long_name);
   close_text_record (text);
@@ -920,7 +929,7 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count)
 
   printf ("%08llx: very long strings (variable => length)\n",
           (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   while (read_variable_to_value_pair (text, &var, &length_s))
     printf ("\t%s => %d\n", var, atoi (length_s));
   close_text_record (text);
@@ -998,7 +1007,7 @@ read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count)
   struct text_record *text;
 
   printf ("%08llx: datafile attributes\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   read_attributes (r, text, "datafile");
   close_text_record (text);
 }
@@ -1011,6 +1020,8 @@ read_character_encoding (struct sfm_reader *r, size_t size, size_t count)
   read_string (r, encoding, count + 1);
 
   printf ("%08llx: Character Encoding: %s\n", posn, encoding);
+
+  free (encoding);
 }
 
 static void
@@ -1190,7 +1201,7 @@ read_variable_attributes (struct sfm_reader *r, size_t size, size_t count)
   struct text_record *text;
 
   printf ("%08llx: variable attributes\n", (long long int) ftello (r->file));
-  text = open_text_record (r, size * count);
+  text = open_text_record (r, size, count);
   for (;;)
     {
       const char *variable = text_tokenize (text, ':');
@@ -1383,18 +1394,23 @@ struct text_record
     size_t pos;                 /* Current position in buffer. */
   };
 
-/* Reads SIZE bytes into a text record for R,
+/* Reads SIZE * COUNT bytes into a text record for R,
    and returns the new text record. */
 static struct text_record *
-open_text_record (struct sfm_reader *r, size_t size)
+open_text_record (struct sfm_reader *r, size_t size, size_t count)
 {
   struct text_record *text = xmalloc (sizeof *text);
-  char *buffer = xmalloc (size + 1);
-  read_bytes (r, buffer, size);
-  buffer[size] = '\0';
+
+  if (size_overflow_p (xsum (1, xtimes (size, count))))
+    sys_error (r, "Extension record too large.");
+
+  size_t n_bytes = size * count;
+  char *buffer = xmalloc (n_bytes + 1);
+  read_bytes (r, buffer, n_bytes);
+  buffer[n_bytes] = '\0';
   text->reader = r;
   text->buffer = buffer;
-  text->size = size;
+  text->size = n_bytes;
   text->pos = 0;
   return text;
 }