pivot table procedure conceptually works
[pspp] / utilities / pspp-convert.c
index 233bfbffbf6691b927720770e49cc36886e6cd34..ebd340ec3599e3cf942fa0e015a09d51c4c10e56 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2013 Free Software Foundation, Inc.
+   Copyright (C) 2013, 2014 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include <config.h>
 
+#include <errno.h>
 #include <getopt.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include "data/any-reader.h"
 #include "data/casereader.h"
 #include "data/casewriter.h"
 #include "data/csv-file-writer.h"
+#include "data/file-name.h"
 #include "data/por-file-writer.h"
 #include "data/settings.h"
+#include "data/sys-file-encryption.h"
 #include "data/sys-file-writer.h"
 #include "data/file-handle-def.h"
 #include "libpspp/assertion.h"
@@ -33,6 +37,7 @@
 #include "libpspp/i18n.h"
 
 #include "gl/error.h"
+#include "gl/getpass.h"
 #include "gl/progname.h"
 #include "gl/version-etc.h"
 
 
 static void usage (void);
 
+static void decrypt_sav_file (struct encrypted_sys_file *enc,
+                              const char *input_filename,
+                              const char *output_filename,
+                              const char *password);
+
 int
 main (int argc, char *argv[])
 {
   const char *input_filename;
   const char *output_filename;
 
-  struct fh_properties properties;
   long long int max_cases = LLONG_MAX;
   struct dictionary *dict;
   struct casereader *reader;
   struct file_handle *input_fh;
+  const char *encoding = NULL;
+  struct encrypted_sys_file *enc;
 
   const char *output_format = NULL;
   struct file_handle *output_fh;
   struct casewriter *writer;
+  const char *password = NULL;
 
   long long int i;
 
@@ -64,13 +76,13 @@ main (int argc, char *argv[])
   fh_init ();
   settings_init ();
 
-  properties = *fh_default_properties ();
   for (;;)
     {
       static const struct option long_options[] =
         {
           { "cases",    required_argument, NULL, 'c' },
           { "encoding", required_argument, NULL, 'e' },
+          { "password", required_argument, NULL, 'p' },
 
           { "output-format", required_argument, NULL, 'O' },
 
@@ -81,7 +93,7 @@ main (int argc, char *argv[])
 
       int c;
 
-      c = getopt_long (argc, argv, "c:e:O:hv", long_options, NULL);
+      c = getopt_long (argc, argv, "c:e:p:O:hv", long_options, NULL);
       if (c == -1)
         break;
 
@@ -92,7 +104,11 @@ main (int argc, char *argv[])
           break;
 
         case 'e':
-          properties.encoding = optarg;
+          encoding = optarg;
+          break;
+
+        case 'p':
+          password = optarg;
           break;
 
         case 'O':
@@ -129,8 +145,18 @@ main (int argc, char *argv[])
       output_format = dot + 1;
     }
 
-  input_fh = fh_create_file (NULL, input_filename, &properties);
-  reader = any_reader_open (input_fh, properties.encoding, &dict);
+  if (encrypted_sys_file_open (&enc, input_filename) > 0)
+    {
+      if (strcmp (output_format, "sav") && strcmp (output_format, "sys"))
+        error (1, 0, _("can only convert encrypted data file to sav or sys "
+                       "format"));
+
+      decrypt_sav_file (enc, input_filename, output_filename, password);
+      goto exit;
+    }
+
+  input_fh = fh_create_file (NULL, input_filename, fh_default_properties ());
+  reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
   if (reader == NULL)
     exit (1);
 
@@ -180,12 +206,58 @@ main (int argc, char *argv[])
   if (!casewriter_destroy (writer))
     error (1, 0, _("%s: error writing output file"), output_filename);
 
+exit:
   fh_done ();
   i18n_done ();
 
   return 0;
 }
 
+static void
+decrypt_sav_file (struct encrypted_sys_file *enc,
+                  const char *input_filename,
+                  const char *output_filename,
+                  const char *password)
+{
+  FILE *out;
+  int err;
+
+  if (password == NULL)
+    {
+      password = getpass ("password: ");
+      if (password == NULL)
+        exit (1);
+    }
+
+  if (!encrypted_sys_file_unlock (enc, password))
+    error (1, 0, _("sorry, wrong password"));
+
+  out = fn_open (output_filename, "wb");
+  if (out == NULL)
+    error (1, errno, ("%s: error opening output file"), output_filename);
+
+  for (;;)
+    {
+      uint8_t buffer[1024];
+      size_t n;
+
+      n = encrypted_sys_file_read (enc, buffer, sizeof buffer);
+      if (n == 0)
+        break;
+
+      if (fwrite (buffer, 1, n, out) != n)
+        error (1, errno, ("%s: write error"), output_filename);
+    }
+
+  err = encrypted_sys_file_close (enc);
+  if (err)
+    error (1, err, ("%s: read error"), input_filename);
+
+  if (fflush (out) == EOF)
+    error (1, errno, ("%s: write error"), output_filename);
+  fn_close (output_filename, out);
+}
+
 static void
 usage (void)
 {
@@ -205,6 +277,7 @@ Options:\n\
                       is one of the extensions listed above\n\
   -e, --encoding=CHARSET  override encoding of input data file\n\
   -c MAXCASES         limit number of cases to copy (default is all cases)\n\
+  -p PASSWORD         password for encrypted .sav files\n\
   --help              display this help and exit\n\
   --version           output version information and exit\n",
           program_name, program_name);