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;
80 set_program_name (argv[0]);
89 OPT_PASSWORD_LIST = UCHAR_MAX + 1,
91 static const struct option long_options[] =
93 { "cases", required_argument, NULL, 'c' },
94 { "encoding", required_argument, NULL, 'e' },
96 { "password", required_argument, NULL, 'p' },
97 { "password-alphabet", required_argument, NULL, 'a' },
98 { "password-length", required_argument, NULL, 'l' },
99 { "password-list", required_argument, NULL, OPT_PASSWORD_LIST },
101 { "output-format", required_argument, NULL, 'O' },
103 { "help", no_argument, NULL, 'h' },
104 { "version", no_argument, NULL, 'v' },
105 { NULL, 0, NULL, 0 },
110 c = getopt_long (argc, argv, "c:e:p:a:l:O:hv", long_options, NULL);
117 max_cases = strtoull (optarg, NULL, 0);
129 length = atoi (optarg);
132 case OPT_PASSWORD_LIST:
133 password_list = optarg;
137 for (const char *p = optarg; *p; )
138 if (p[1] == '-' && p[2] > p[0])
140 for (int ch = p[0]; ch <= p[2]; ch++)
141 ds_put_byte (&alphabet, ch);
145 ds_put_byte (&alphabet, *p++);
149 output_format = optarg;
153 version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
154 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
166 if (optind + 2 != argc)
167 error (1, 0, _("exactly two non-option arguments are required; "
168 "use --help for help"));
170 input_filename = argv[optind];
171 output_filename = argv[optind + 1];
172 input_fh = fh_create_file (NULL, input_filename, NULL, fh_default_properties ());
174 if (output_format == NULL)
176 const char *dot = strrchr (output_filename, '.');
178 error (1, 0, _("%s: cannot guess output format (use -O option)"),
181 output_format = dot + 1;
184 output_fh = fh_create_file (NULL, output_filename, NULL, fh_default_properties ());
185 if (encrypted_file_open (&enc, input_fh) > 0)
187 if (decrypt_file (enc, input_fh, output_fh, password,
188 ds_cstr (&alphabet), length, password_list))
195 reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
199 if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
201 struct csv_writer_options options;
203 csv_writer_options_init (&options);
204 options.include_var_names = true;
205 writer = csv_writer_open (output_fh, dict, &options);
207 else if (!strcmp (output_format, "sav") || !strcmp (output_format, "sys"))
209 struct sfm_write_options options;
211 options = sfm_writer_default_options ();
212 writer = sfm_open_writer (output_fh, dict, options);
214 else if (!strcmp (output_format, "por"))
216 struct pfm_write_options options;
218 options = pfm_writer_default_options ();
219 writer = pfm_open_writer (output_fh, dict, options);
223 error (1, 0, _("%s: unknown output format (use -O option)"),
228 error (1, 0, _("%s: error opening output file"), output_filename);
230 for (i = 0; i < max_cases; i++)
234 c = casereader_read (reader);
238 casewriter_write (writer, c);
241 if (!casereader_destroy (reader))
242 error (1, 0, _("%s: error reading input file"), input_filename);
243 if (!casewriter_destroy (writer))
244 error (1, 0, _("%s: error writing output file"), output_filename);
247 ds_destroy (&alphabet);
249 fh_unref (output_fh);
257 ds_destroy (&alphabet);
259 fh_unref (output_fh);
268 decrypt_file (struct encrypted_file *enc,
269 const struct file_handle *ifh,
270 const struct file_handle *ofh,
271 const char *password,
272 const char *alphabet,
274 const char *password_list)
278 const char *input_filename = fh_get_file_name (ifh);
279 const char *output_filename = fh_get_file_name (ofh);
284 if (!strcmp (password_list, "-"))
285 password_file = stdin;
288 password_file = fopen (password_list, "r");
290 error (1, errno, _("%s: error opening password file"),
294 struct string pw = DS_EMPTY_INITIALIZER;
295 unsigned int target = 100000;
296 for (unsigned int i = 0; ; i++)
299 if (!ds_read_line (&pw, password_file, SIZE_MAX))
301 if (isatty (STDOUT_FILENO))
306 error (1, 0, _("\n%s: password not in file"), password_list);
308 ds_chomp_byte (&pw, '\n');
313 if (isatty (STDOUT_FILENO))
320 if (encrypted_file_unlock__ (enc, ds_cstr (&pw)))
322 printf ("\npassword is: \"%s\"\n", ds_cstr (&pw));
323 password = ds_cstr (&pw);
328 else if (alphabet[0] && max_length)
330 size_t alphabet_size = strlen (alphabet);
331 char *pw = xmalloc (max_length + 1);
332 int *indexes = xzalloc (max_length * sizeof *indexes);
334 for (int len = password ? strlen (password) : 0;
335 len <= max_length; len++)
337 if (password && len == strlen (password))
339 for (int i = 0; i < len; i++)
341 const char *p = strchr (alphabet, password[i]);
343 error (1, 0, _("%s: '%c' is not in alphabet"),
344 password, password[i]);
345 indexes[i] = p - alphabet;
351 memset (indexes, 0, len * sizeof *indexes);
352 for (int i = 0; i < len; i++)
357 unsigned int target = 0;
358 for (unsigned int j = 0; ; j++)
363 if (isatty (STDOUT_FILENO))
365 printf ("\rlength %d: %s", len, pw);
369 if (encrypted_file_unlock__ (enc, pw))
371 printf ("\npassword is: \"%s\"\n", pw);
377 for (i = 0; i < len; i++)
378 if (++indexes[i] < alphabet_size)
380 pw[i] = alphabet[indexes[i]];
386 pw[i] = alphabet[indexes[i]];
399 if (password == NULL)
401 password = getpass ("password: ");
402 if (password == NULL)
406 if (!encrypted_file_unlock (enc, password))
407 error (1, 0, _("sorry, wrong password"));
410 out = fn_open (ofh, "wb");
412 error (1, errno, ("%s: error opening output file"), output_filename);
416 uint8_t buffer[1024];
419 n = encrypted_file_read (enc, buffer, sizeof buffer);
423 if (fwrite (buffer, 1, n, out) != n)
424 error (1, errno, ("%s: write error"), output_filename);
427 err = encrypted_file_close (enc);
429 error (1, err, ("%s: read error"), input_filename);
431 if (fflush (out) == EOF)
432 error (1, errno, ("%s: write error"), output_filename);
442 %s, a utility for converting SPSS data files to other formats.\n\
443 Usage: %s [OPTION]... INPUT OUTPUT\n\
444 where INPUT is an SPSS data file or encrypted syntax file\n\
445 and OUTPUT is the name of the desired output file.\n\
447 The desired format of OUTPUT is by default inferred from its extension:\n\
448 csv txt comma-separated value\n\
449 sav sys SPSS system file\n\
450 por SPSS portable file\n\
451 sps SPSS syntax file (encrypted syntax input files only)\n\
454 -O, --output-format=FORMAT set specific output format, where FORMAT\n\
455 is one of the extensions listed above\n\
456 -e, --encoding=CHARSET override encoding of input data file\n\
457 -c MAXCASES limit number of cases to copy (default is all cases)\n\
458 Password options (for used with encrypted files):\n\
459 -p PASSWORD individual password\n\
460 -a ALPHABET with -l, alphabet of passwords to try\n\
461 -l MAX-LENGTH with -a, maximum number of characters to try\n\
462 --password-list=FILE try all of the passwords in FILE (one per line)\n\
464 --help display this help and exit\n\
465 --version output version information and exit\n",
466 program_name, program_name);