1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2013, 2014, 2015, 2016 Free Software Foundation, Inc.
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.
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.
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/>. */
25 #include "data/any-reader.h"
26 #include "data/casereader.h"
27 #include "data/casewriter.h"
28 #include "data/csv-file-writer.h"
29 #include "data/dictionary.h"
30 #include "data/encrypted-file.h"
31 #include "data/file-name.h"
32 #include "data/por-file-writer.h"
33 #include "data/settings.h"
34 #include "data/sys-file-writer.h"
35 #include "data/file-handle-def.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/cast.h"
38 #include "libpspp/i18n.h"
41 #include "gl/getpass.h"
42 #include "gl/progname.h"
43 #include "gl/version-etc.h"
46 #define _(msgid) gettext (msgid)
48 static void usage (void);
50 static bool decrypt_file (struct encrypted_file *enc,
51 const struct file_handle *input_filename,
52 const struct file_handle *output_filename,
54 const char *alphabet, int max_length,
55 const char *password_list);
58 main (int argc, char *argv[])
60 const char *input_filename;
61 const char *output_filename;
63 long long int max_cases = LLONG_MAX;
64 struct dictionary *dict = NULL;
65 struct casereader *reader;
66 struct file_handle *input_fh = NULL;
67 const char *encoding = NULL;
68 struct encrypted_file *enc;
70 const char *output_format = NULL;
71 struct file_handle *output_fh = NULL;
72 struct casewriter *writer;
73 const char *password = NULL;
74 struct string alphabet = DS_EMPTY_INITIALIZER;
75 const char *password_list = NULL;
78 bool recode_user_missing = false;
79 bool use_value_labels = false;
83 set_program_name (argv[0]);
92 OPT_PASSWORD_LIST = UCHAR_MAX + 1,
96 static const struct option long_options[] =
98 { "cases", required_argument, NULL, 'c' },
99 { "encoding", required_argument, NULL, 'e' },
101 { "labels", no_argument, NULL, OPT_LABELS },
102 { "recode", no_argument, NULL, OPT_RECODE },
104 { "password", required_argument, NULL, 'p' },
105 { "password-alphabet", required_argument, NULL, 'a' },
106 { "password-length", required_argument, NULL, 'l' },
107 { "password-list", required_argument, NULL, OPT_PASSWORD_LIST },
109 { "output-format", required_argument, NULL, 'O' },
111 { "help", no_argument, NULL, 'h' },
112 { "version", no_argument, NULL, 'v' },
113 { NULL, 0, NULL, 0 },
118 c = getopt_long (argc, argv, "c:e:p:a:l:O:hv", long_options, NULL);
125 max_cases = strtoull (optarg, NULL, 0);
137 length = atoi (optarg);
140 case OPT_PASSWORD_LIST:
141 password_list = optarg;
145 use_value_labels = true;
149 recode_user_missing = true;
153 for (const char *p = optarg; *p; )
154 if (p[1] == '-' && p[2] > p[0])
156 for (int ch = p[0]; ch <= p[2]; ch++)
157 ds_put_byte (&alphabet, ch);
161 ds_put_byte (&alphabet, *p++);
165 output_format = optarg;
169 version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
170 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
182 if (optind + 2 != argc)
183 error (1, 0, _("exactly two non-option arguments are required; "
184 "use --help for help"));
186 input_filename = argv[optind];
187 output_filename = argv[optind + 1];
188 input_fh = fh_create_file (NULL, input_filename, NULL, fh_default_properties ());
190 if (output_format == NULL)
192 const char *dot = strrchr (output_filename, '.');
194 error (1, 0, _("%s: cannot guess output format (use -O option)"),
197 output_format = dot + 1;
200 output_fh = fh_create_file (NULL, output_filename, NULL, fh_default_properties ());
201 if (encrypted_file_open (&enc, input_fh) > 0)
203 if (decrypt_file (enc, input_fh, output_fh, password,
204 ds_cstr (&alphabet), length, password_list))
211 reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
215 if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
217 struct csv_writer_options options;
219 csv_writer_options_init (&options);
220 options.include_var_names = true;
221 options.use_value_labels = use_value_labels;
222 options.recode_user_missing = recode_user_missing;
223 writer = csv_writer_open (output_fh, dict, &options);
225 else if (!strcmp (output_format, "sav") || !strcmp (output_format, "sys"))
227 struct sfm_write_options options;
229 options = sfm_writer_default_options ();
230 writer = sfm_open_writer (output_fh, dict, options);
232 else if (!strcmp (output_format, "por"))
234 struct pfm_write_options options;
236 options = pfm_writer_default_options ();
237 writer = pfm_open_writer (output_fh, dict, options);
241 error (1, 0, _("%s: unknown output format (use -O option)"),
246 error (1, 0, _("%s: error opening output file"), output_filename);
248 for (i = 0; i < max_cases; i++)
252 c = casereader_read (reader);
256 casewriter_write (writer, c);
259 if (!casereader_destroy (reader))
260 error (1, 0, _("%s: error reading input file"), input_filename);
261 if (!casewriter_destroy (writer))
262 error (1, 0, _("%s: error writing output file"), output_filename);
265 ds_destroy (&alphabet);
267 fh_unref (output_fh);
275 ds_destroy (&alphabet);
277 fh_unref (output_fh);
286 decrypt_file (struct encrypted_file *enc,
287 const struct file_handle *ifh,
288 const struct file_handle *ofh,
289 const char *password,
290 const char *alphabet,
292 const char *password_list)
296 const char *input_filename = fh_get_file_name (ifh);
297 const char *output_filename = fh_get_file_name (ofh);
302 if (!strcmp (password_list, "-"))
303 password_file = stdin;
306 password_file = fopen (password_list, "r");
308 error (1, errno, _("%s: error opening password file"),
312 struct string pw = DS_EMPTY_INITIALIZER;
313 unsigned int target = 100000;
314 for (unsigned int i = 0; ; i++)
317 if (!ds_read_line (&pw, password_file, SIZE_MAX))
319 if (isatty (STDOUT_FILENO))
324 error (1, 0, _("\n%s: password not in file"), password_list);
326 ds_chomp_byte (&pw, '\n');
331 if (isatty (STDOUT_FILENO))
338 if (encrypted_file_unlock__ (enc, ds_cstr (&pw)))
340 printf ("\npassword is: \"%s\"\n", ds_cstr (&pw));
341 password = ds_cstr (&pw);
346 else if (alphabet[0] && max_length)
348 size_t alphabet_size = strlen (alphabet);
349 char *pw = xmalloc (max_length + 1);
350 int *indexes = xzalloc (max_length * sizeof *indexes);
352 for (int len = password ? strlen (password) : 0;
353 len <= max_length; len++)
355 if (password && len == strlen (password))
357 for (int i = 0; i < len; i++)
359 const char *p = strchr (alphabet, password[i]);
361 error (1, 0, _("%s: '%c' is not in alphabet"),
362 password, password[i]);
363 indexes[i] = p - alphabet;
369 memset (indexes, 0, len * sizeof *indexes);
370 for (int i = 0; i < len; i++)
375 unsigned int target = 0;
376 for (unsigned int j = 0; ; j++)
381 if (isatty (STDOUT_FILENO))
383 printf ("\rlength %d: %s", len, pw);
387 if (encrypted_file_unlock__ (enc, pw))
389 printf ("\npassword is: \"%s\"\n", pw);
395 for (i = 0; i < len; i++)
396 if (++indexes[i] < alphabet_size)
398 pw[i] = alphabet[indexes[i]];
404 pw[i] = alphabet[indexes[i]];
417 if (password == NULL)
419 password = getpass ("password: ");
420 if (password == NULL)
424 if (!encrypted_file_unlock (enc, password))
425 error (1, 0, _("sorry, wrong password"));
428 out = fn_open (ofh, "wb");
430 error (1, errno, ("%s: error opening output file"), output_filename);
434 uint8_t buffer[1024];
437 n = encrypted_file_read (enc, buffer, sizeof buffer);
441 if (fwrite (buffer, 1, n, out) != n)
442 error (1, errno, ("%s: write error"), output_filename);
445 err = encrypted_file_close (enc);
447 error (1, err, ("%s: read error"), input_filename);
449 if (fflush (out) == EOF)
450 error (1, errno, ("%s: write error"), output_filename);
460 %s, a utility for converting SPSS data files to other formats.\n\
461 Usage: %s [OPTION]... INPUT OUTPUT\n\
462 where INPUT is an SPSS data file or encrypted syntax file\n\
463 and OUTPUT is the name of the desired output file.\n\
465 The desired format of OUTPUT is by default inferred from its extension:\n\
466 csv txt comma-separated value\n\
467 sav sys SPSS system file\n\
468 por SPSS portable file\n\
469 sps SPSS syntax file (encrypted syntax input files only)\n\
472 -O, --output-format=FORMAT set specific output format, where FORMAT\n\
473 is one of the extensions listed above\n\
474 -e, --encoding=CHARSET override encoding of input data file\n\
475 -c MAXCASES limit number of cases to copy (default is all cases)\n\
476 CSV output options:\n\
477 --labels write value labels to output\n\
478 --recode convert user-missing values to system-missing\n\
479 Password options (for used with encrypted files):\n\
480 -p PASSWORD individual password\n\
481 -a ALPHABET with -l, alphabet of passwords to try\n\
482 -l MAX-LENGTH with -a, maximum number of characters to try\n\
483 --password-list=FILE try all of the passwords in FILE (one per line)\n\
485 --help display this help and exit\n\
486 --version output version information and exit\n",
487 program_name, program_name);