1 /*
2 * Copyright (C) 2017 Ingo Brückl
3 *
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 2 of the License, or
7 * (at your option) any later version.
8 *
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.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA.
18 */
19
20 #include <string.h>
21 #include "unar.h"
22 #include "7zip.h"
23 #include "interface.h"
24 #include "main.h"
25 #include "parser.h"
26 #include "string_utils.h"
27 #include "support.h"
28 #include "window.h"
29
30 #define MAXWIDTH(item, width) (strlen(item) > width ? strlen(item) - width : 0)
31
32 static gboolean data_line, last_line;
33
xa_unar_ask(XArchive * archive)34 void xa_unar_ask (XArchive *archive)
35 {
36 archive->can_test = !(archive->type == XARCHIVETYPE_AR || archive->type == XARCHIVETYPE_COMPRESS || archive->type == XARCHIVETYPE_CPIO || archive->type == XARCHIVETYPE_LZMA || archive->type == XARCHIVETYPE_TAR);
37 archive->can_extract = (archiver[archive->type].program[1] != NULL);
38 archive->can_full_path[0] = (archiver[archive->type].program[1] != NULL);
39 archive->can_overwrite = (archiver[archive->type].program[1] != NULL);
40 }
41
xa_unar_password_str(XArchive * archive)42 static gchar *xa_unar_password_str (XArchive *archive)
43 {
44 if (archive->password)
45 return g_strconcat(" -p ", archive->password, NULL);
46 else
47 return g_strdup("");
48 }
49
xa_unar_parse_output(gchar * line,XArchive * archive)50 static void xa_unar_parse_output (gchar *line, XArchive *archive)
51 {
52 XEntry *entry;
53 gpointer item[6];
54 gchar *index, *flags, *filename;
55 gboolean dir, encrypted, link;
56 guint shift;
57
58 USE_PARSER;
59
60 if (last_line)
61 return;
62
63 if (strncmp(line, " ", 5) == 0)
64 {
65 data_line = TRUE;
66 return;
67 }
68
69 if (!data_line)
70 {
71 if (strstr(line, ": Tar in "))
72 {
73 XArchiveType type = archive->type;
74
75 xa_get_compressed_tar_type(&type);
76 archiver[type].program[0] = g_strdup(archiver[archive->type].program[0]);
77 archiver[type].program[1] = g_strdup(archiver[archive->type].program[1]);
78 archive->type = type;
79 archive->can_test = FALSE;
80 }
81
82 return;
83 }
84
85 if (*line == '(')
86 {
87 last_line = TRUE;
88 return;
89 }
90
91 /* index (may exceed column width) */
92 NEXT_ITEM(index);
93 shift = MAXWIDTH(index, 4);
94
95 /* flags */
96 NEXT_ITEM(flags);
97
98 dir = (flags[0] == 'D');
99 link = (flags[2] == 'L');
100 encrypted = (flags[3] == 'E');
101
102 if (encrypted)
103 archive->has_password = TRUE;
104
105 /* file size */
106 NEXT_ITEM(item[1]);
107
108 /* ratio (may exceed column width) */
109 NEXT_ITEM(item[2]);
110 shift += MAXWIDTH(item[2], 6);
111
112 /* mode */
113 NEXT_ITEM(item[5]);
114
115 /* date */
116 NEXT_ITEM(item[3]);
117
118 /* time */
119 if (strcmp(item[3], "----------------") == 0)
120 {
121 char *item3 = (char *) item[3];
122
123 item3[10] = 0;
124 item[4] = item3 + 11;
125 }
126 else
127 NEXT_ITEM(item[4]);
128
129 /* name */
130 LAST_ITEM(filename);
131 filename += shift;
132
133 item[0] = NULL;
134
135 if (link)
136 {
137 char *l = strstr(filename, " -> ");
138
139 if (l)
140 {
141 item[0] = l + 4;
142 *l = 0;
143 }
144 }
145
146 entry = xa_set_archive_entries_for_each_row(archive, filename, item);
147
148 if (entry)
149 {
150 if (dir)
151 entry->is_dir = TRUE;
152
153 entry->is_encrypted = encrypted;
154
155 if (!entry->is_dir)
156 archive->files++;
157
158 archive->files_size += g_ascii_strtoull(item[1], NULL, 0);
159 }
160 }
161
xa_unar_list(XArchive * archive)162 void xa_unar_list (XArchive *archive)
163 {
164 const GType types[] = {GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER};
165 const gchar *titles[] = {_("Points to"), _("Original Size"), _("Saving"), _("Date"), _("Time"), _("Method")};
166 gchar *password_str, *command;
167 guint i;
168
169 if (archive->type == XARCHIVETYPE_7ZIP)
170 {
171 if (!archive->has_password)
172 archive->has_password = is7zip_mhe(archive->path[0]);
173
174 if (archive->has_password)
175 if (!xa_check_password(archive))
176 return;
177 }
178
179 data_line = FALSE;
180 last_line = FALSE;
181
182 archive->files = 0;
183 archive->files_size = 0;
184
185 password_str = xa_unar_password_str(archive);
186 command = g_strconcat(archiver[archive->type].program[0], " -l", password_str, " ", archive->path[1], NULL);
187 archive->parse_output = xa_unar_parse_output;
188 xa_spawn_async_process(archive, command);
189 g_free(command);
190 g_free(password_str);
191
192 archive->columns = 9;
193 archive->size_column = 3;
194 archive->column_types = g_malloc0(sizeof(types));
195
196 for (i = 0; i < archive->columns; i++)
197 archive->column_types[i] = types[i];
198
199 xa_create_liststore(archive, titles);
200 }
201
xa_unar_test(XArchive * archive)202 void xa_unar_test (XArchive *archive)
203 {
204 gchar *password_str, *command;
205
206 password_str = xa_unar_password_str(archive);
207 command = g_strconcat(archiver[archive->type].program[0], " -t", password_str, " ", archive->path[1], NULL);
208 g_free(password_str);
209
210 xa_run_command(archive, command);
211 g_free(command);
212 }
213
xa_unar_extract(XArchive * archive,GSList * file_list)214 gboolean xa_unar_extract (XArchive *archive, GSList *file_list)
215 {
216 GString *files;
217 gchar *extract_to, *password_str, *command;
218 gboolean result;
219
220 if (archive->do_full_path)
221 extract_to = g_strdup(archive->extraction_dir);
222 else
223 {
224 if (!xa_create_working_directory(archive))
225 return FALSE;
226
227 extract_to = g_strconcat(archive->working_dir, "/xa-tmp.XXXXXX", NULL);
228
229 if (!g_mkdtemp(extract_to))
230 {
231 g_free(extract_to);
232 return FALSE;
233 }
234 }
235
236 files = xa_quote_filenames(file_list, "*?[]\"", TRUE);
237 password_str = xa_unar_password_str(archive);
238 command = g_strconcat(archiver[archive->type].program[1], " ",
239 archive->path[1], password_str, " -D -q",
240 archive->do_overwrite ? " -f" : "",
241 " -o ", extract_to, files->str, NULL);
242
243 result = xa_run_command(archive, command);
244 g_free(command);
245
246 /* collect all files that have been extracted to move them without full path */
247 if (result && !archive->do_full_path)
248 {
249 GString *all_files = xa_collect_files_in_dir(extract_to);
250
251 archive->child_dir = g_strdup(extract_to);
252 command = g_strconcat("mv",
253 archive->do_overwrite ? " -f" : " -n",
254 all_files->str, " ", archive->extraction_dir, NULL);
255 g_string_free(all_files, TRUE);
256
257 result = xa_run_command(archive, command);
258 g_free(command);
259
260 g_free(archive->child_dir);
261 archive->child_dir = NULL;
262 }
263
264 g_free(extract_to);
265 g_free(password_str);
266 g_string_free(files, TRUE);
267
268 return result;
269 }
270