summaryrefslogtreecommitdiff
path: root/src/fr-command-rar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fr-command-rar.c')
-rw-r--r--src/fr-command-rar.c215
1 files changed, 89 insertions, 126 deletions
diff --git a/src/fr-command-rar.c b/src/fr-command-rar.c
index e2eb8df..6bb70cd 100644
--- a/src/fr-command-rar.c
+++ b/src/fr-command-rar.c
@@ -20,6 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define _XOPEN_SOURCE 700
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -45,17 +47,31 @@ static void fr_command_rar_finalize (GObject *object);
static FrCommandClass *parent_class = NULL;
-
/* rar 5.30 and later uses YYYY-MM-DD instead DD-MM-YY in the listing output */
static gboolean date_newstyle = FALSE;
-static gboolean
-have_rar (void)
+static const struct {
+ const gchar *command;
+ FrCommandCaps capabilities;
+} candidate_commands[] = {
+ { "rar", FR_COMMAND_CAN_READ_WRITE | FR_COMMAND_CAN_CREATE_VOLUMES },
+ { "unrar", FR_COMMAND_CAN_READ },
+ { "unrar-free", FR_COMMAND_CAN_READ }
+};
+
+static const gchar *
+get_rar_command (void)
{
- return is_program_in_path ("rar");
-}
+ for (guint i = 0; i < G_N_ELEMENTS(candidate_commands); i++) {
+ if (is_program_in_path (candidate_commands[i].command))
+ return candidate_commands[i].command;
+ }
+ /* this should never happen as we shouldn't get called if none of the
+ * candidate exist, but better safe than sorry */
+ return "unrar";
+}
/* -- list -- */
@@ -76,8 +92,6 @@ Details: RAR 4
----------- --------- -------- ----- ---------- ----- -------- ----
3165 1318 41% 2
-
-
// SAMPLE RAR VERSION 5.00 TO 5.21 LISTING OUTPUT:
RAR 5.21 Copyright (c) 1993-2015 Alexander Roshal 15 Feb 2015
@@ -93,8 +107,6 @@ Details: RAR 4
----------- --------- -------- ----- -------- ----- -------- ----
3165 1318 41% 2
-
-
// SAMPLE RAR VERSION 4.20 AND OLDER LISTING OUTPUT:
RAR 4.20 Copyright (c) 1993-2012 Alexander Roshal 9 Jun 2012
@@ -118,46 +130,19 @@ static time_t
mktime_from_string (const char *date_s,
const char *time_s)
{
- struct tm tm = {0, };
- char **fields;
+ struct tm tm = {0, };
+ char *date_time_s;
tm.tm_isdst = -1;
-
- /* date */
-
- fields = g_strsplit (date_s, "-", 3);
- if (fields[0] != NULL) {
- if (date_newstyle)
- tm.tm_year = atoi (fields[0]) - 1900;
- else
- tm.tm_mday = atoi (fields[0]);
- if (fields[1] != NULL) {
- tm.tm_mon = atoi (fields[1]) - 1;
- if (fields[2] != NULL) {
- if (date_newstyle)
- tm.tm_mday = atoi (fields[2]);
- else
- tm.tm_year = 100 + atoi (fields[2]);
- }
- }
- }
- g_strfreev (fields);
-
- /* time */
-
- fields = g_strsplit (time_s, ":", 2);
- if (fields[0] != NULL) {
- tm.tm_hour = atoi (fields[0]);
- if (fields[1] != NULL)
- tm.tm_min = atoi (fields[1]);
- }
- g_strfreev (fields);
+ date_time_s = g_strjoin (" ", date_s, time_s, NULL);
+ strptime (date_time_s, date_newstyle ? "%Y-%m-%d %H:%M" : "%d-%m-%y %H:%M", &tm);
+ g_free (date_time_s);
return mktime (&tm);
}
static gboolean
-attribute_field_with_space (char *line)
+attribute_field_with_space (const char *line)
{
/* sometimes when the archive is encrypted the attributes field is
* like this: "* ..A...."
@@ -178,7 +163,7 @@ parse_name_field (char *line,
fdata->encrypted = (line[0] == '*') ? TRUE : FALSE;
- if (rar_comm->rar5)
+ if (rar_comm->output_type == FR_COMMAND_RAR_TYPE_RAR5)
/* rar-5 output adds trailing spaces to short file names :( */
name_field = g_strchomp (g_strdup (get_last_field (line, attribute_field_with_space (line) ? 9 : 8)));
else
@@ -207,8 +192,8 @@ attr_field_is_dir (const char *attr_field,
FrCommandRar *rar_comm)
{
if ((attr_field[0] == 'd') ||
- (rar_comm->rar5 && attr_field[3] == 'D') ||
- (!rar_comm->rar5 && attr_field[1] == 'D'))
+ (rar_comm->output_type == FR_COMMAND_RAR_TYPE_RAR5 && attr_field[3] == 'D') ||
+ (rar_comm->output_type != FR_COMMAND_RAR_TYPE_RAR5 && attr_field[1] == 'D'))
return TRUE;
return FALSE;
@@ -225,39 +210,27 @@ process_line (char *line,
g_return_if_fail (line != NULL);
if (! rar_comm->list_started) {
- if (strncmp (line, "RAR ", 4) == 0) {
- int version;
- sscanf (line, "RAR %d.", &version);
- rar_comm->rar5 = (version >= 5);
-
- if (version > 5)
- date_newstyle = TRUE;
- else if (version == 5)
- {
- sscanf (line, "RAR 5.%d ", &version);
- if (version >= 30)
- date_newstyle = TRUE;
- }
+ int version = 0;
- }
- else if (strncmp (line, "UNRAR ", 6) == 0) {
- int version;
- sscanf (line, "UNRAR %d.", &version);
- rar_comm->rar5 = (version >= 5);
+ if (sscanf (line, "RAR %d.", &version) == 1 || sscanf (line, "UNRAR %d.", &version) == 1) {
+ rar_comm->output_type = (version >= 5) ? FR_COMMAND_RAR_TYPE_RAR5 : FR_COMMAND_RAR_TYPE_RAR4;
if (version > 5)
date_newstyle = TRUE;
- else if (version == 5)
+ else if (version == 5 && (sscanf (line, "RAR 5.%d ", &version) == 1 ||
+ sscanf (line, "UNRAR 5.%d ", &version) == 1))
{
- sscanf (line, "UNRAR 5.%d ", &version);
if (version >= 30)
date_newstyle = TRUE;
}
-
+ }
+ else if (g_str_has_prefix (line, "unrar-free ")) {
+ rar_comm->output_type = FR_COMMAND_RAR_TYPE_UNRAR_FREE;
+ date_newstyle = FALSE;
}
else if (strncmp (line, "--------", 8) == 0) {
rar_comm->list_started = TRUE;
- if (! rar_comm->rar5)
+ if (rar_comm->output_type != FR_COMMAND_RAR_TYPE_RAR5)
rar_comm->rar4_odd_line = TRUE;
}
else if (strncmp (line, "Volume ", 7) == 0)
@@ -270,35 +243,27 @@ process_line (char *line,
return;
}
- if (rar_comm->rar4_odd_line || rar_comm->rar5)
+ if (rar_comm->rar4_odd_line || rar_comm->output_type == FR_COMMAND_RAR_TYPE_RAR5)
parse_name_field (line, rar_comm);
if (! rar_comm->rar4_odd_line) {
FileData *fdata;
const char *size_field, *ratio_field, *date_field, *time_field, *attr_field;
+ int n_fields;
+
+ if (rar_comm->output_type == FR_COMMAND_RAR_TYPE_RAR5)
+ n_fields = 6 + (attribute_field_with_space (line) != 0);
+ else if (rar_comm->output_type == FR_COMMAND_RAR_TYPE_UNRAR_FREE)
+ n_fields = 4;
+ else
+ n_fields = 6;
fdata = rar_comm->fdata;
/* read file info. */
- fields = split_line (line, attribute_field_with_space (line) ? 7 : 6);
- if (rar_comm->rar5) {
- int offset = attribute_field_with_space (line) ? 1 : 0;
-
- size_field = fields[1+offset];
- ratio_field = fields[3+offset];
- date_field = fields[4+offset];
- time_field = fields[5+offset];
- attr_field = fields[0+offset];
- }
- else {
- size_field = fields[0];
- ratio_field = fields[2];
- date_field = fields[3];
- time_field = fields[4];
- attr_field = fields[5];
- }
- if (g_strv_length (fields) < 6) {
+ fields = split_line (line, n_fields);
+ if (g_strv_length (fields) < (guint) n_fields) {
/* wrong line format, treat this line as a filename line */
g_strfreev (fields);
file_data_free (rar_comm->fdata);
@@ -307,6 +272,30 @@ process_line (char *line,
parse_name_field (line, rar_comm);
}
else {
+ if (rar_comm->output_type == FR_COMMAND_RAR_TYPE_RAR5) {
+ int offset = attribute_field_with_space (line) ? 1 : 0;
+
+ size_field = fields[1+offset];
+ ratio_field = fields[3+offset];
+ date_field = fields[4+offset];
+ time_field = fields[5+offset];
+ attr_field = fields[0+offset];
+ }
+ else if (rar_comm->output_type == FR_COMMAND_RAR_TYPE_UNRAR_FREE) {
+ size_field = fields[0];
+ date_field = fields[1];
+ time_field = fields[2];
+ attr_field = fields[3];
+ ratio_field = "";
+ }
+ else {
+ size_field = fields[0];
+ ratio_field = fields[2];
+ date_field = fields[3];
+ time_field = fields[4];
+ attr_field = fields[5];
+ }
+
if ((strcmp (ratio_field, "<->") == 0)
|| (strcmp (ratio_field, "<--") == 0))
{
@@ -347,11 +336,10 @@ process_line (char *line,
}
}
- if (! rar_comm->rar5)
+ if (rar_comm->output_type != FR_COMMAND_RAR_TYPE_RAR5)
rar_comm->rar4_odd_line = ! rar_comm->rar4_odd_line;
}
-
static void
add_password_arg (FrCommand *comm,
const char *password,
@@ -367,7 +355,6 @@ add_password_arg (FrCommand *comm,
fr_process_add_arg (comm->process, "-p-");
}
-
static void
list__begin (gpointer data)
{
@@ -376,7 +363,6 @@ list__begin (gpointer data)
comm->list_started = FALSE;
}
-
static void
fr_command_rar_list (FrCommand *comm)
{
@@ -384,10 +370,7 @@ fr_command_rar_list (FrCommand *comm)
fr_process_set_out_line_func (comm->process, process_line, comm);
- if (have_rar ())
- fr_process_begin_command (comm->process, "rar");
- else
- fr_process_begin_command (comm->process, "unrar");
+ fr_process_begin_command (comm->process, get_rar_command ());
fr_process_set_begin_func (comm->process, list__begin, comm);
fr_process_add_arg (comm->process, "v");
fr_process_add_arg (comm->process, "-c-");
@@ -404,7 +387,6 @@ fr_command_rar_list (FrCommand *comm)
fr_process_start (comm->process);
}
-
static void
parse_progress_line (FrCommand *comm,
const char *prefix,
@@ -415,7 +397,6 @@ parse_progress_line (FrCommand *comm,
fr_command_progress (comm, (double) ++comm->n_file / (comm->n_files + 1));
}
-
static void
process_line__add (char *line,
gpointer data)
@@ -451,7 +432,6 @@ process_line__add (char *line,
parse_progress_line (comm, "Adding ", _("Adding file: "), line);
}
-
static void
fr_command_rar_add (FrCommand *comm,
const char *from_file,
@@ -508,7 +488,6 @@ fr_command_rar_add (FrCommand *comm,
fr_process_end_command (comm->process);
}
-
static void
process_line__delete (char *line,
gpointer data)
@@ -529,7 +508,6 @@ process_line__delete (char *line,
parse_progress_line (comm, "Deleting ", _("Removing file: "), line);
}
-
static void
fr_command_rar_delete (FrCommand *comm,
const char *from_file,
@@ -557,7 +535,6 @@ fr_command_rar_delete (FrCommand *comm,
fr_process_end_command (comm->process);
}
-
static void
process_line__extract (char *line,
gpointer data)
@@ -578,7 +555,6 @@ process_line__extract (char *line,
parse_progress_line (comm, "Extracting ", _("Extracting file: "), line);
}
-
static void
fr_command_rar_extract (FrCommand *comm,
const char *from_file,
@@ -595,10 +571,7 @@ fr_command_rar_extract (FrCommand *comm,
process_line__extract,
comm);
- if (have_rar ())
- fr_process_begin_command (comm->process, "rar");
- else
- fr_process_begin_command (comm->process, "unrar");
+ fr_process_begin_command (comm->process, get_rar_command ());
fr_process_add_arg (comm->process, "x");
@@ -636,14 +609,10 @@ fr_command_rar_extract (FrCommand *comm,
fr_process_end_command (comm->process);
}
-
static void
fr_command_rar_test (FrCommand *comm)
{
- if (have_rar ())
- fr_process_begin_command (comm->process, "rar");
- else
- fr_process_begin_command (comm->process, "unrar");
+ fr_process_begin_command (comm->process, get_rar_command ());
fr_process_add_arg (comm->process, "t");
@@ -659,7 +628,6 @@ fr_command_rar_test (FrCommand *comm)
fr_process_end_command (comm->process);
}
-
static void
fr_command_rar_handle_error (FrCommand *comm,
FrProcError *error)
@@ -713,31 +681,31 @@ fr_command_rar_handle_error (FrCommand *comm,
}
}
-
const char *rar_mime_type[] = { "application/x-cbr",
"application/x-rar",
NULL };
-
static const char **
fr_command_rar_get_mime_types (FrCommand *comm)
{
return rar_mime_type;
}
-
-static FrCommandCap
+static FrCommandCaps
fr_command_rar_get_capabilities (FrCommand *comm,
const char *mime_type,
gboolean check_command)
{
- FrCommandCap capabilities;
+ FrCommandCaps capabilities;
capabilities = FR_COMMAND_CAN_ARCHIVE_MANY_FILES | FR_COMMAND_CAN_ENCRYPT | FR_COMMAND_CAN_ENCRYPT_HEADER;
- if (is_program_available ("rar", check_command))
- capabilities |= FR_COMMAND_CAN_READ_WRITE | FR_COMMAND_CAN_CREATE_VOLUMES;
- else if (is_program_available ("unrar", check_command))
- capabilities |= FR_COMMAND_CAN_READ;
+ /* add command-specific capabilities depending on availability */
+ for (guint i = 0; i < G_N_ELEMENTS (candidate_commands); i++) {
+ if (is_program_available (candidate_commands[i].command, check_command)) {
+ capabilities |= candidate_commands[i].capabilities;
+ break;
+ }
+ }
/* multi-volumes are read-only */
if ((comm->files->len > 0) && comm->multi_volume && (capabilities & FR_COMMAND_CAN_WRITE))
@@ -746,15 +714,13 @@ fr_command_rar_get_capabilities (FrCommand *comm,
return capabilities;
}
-
static const char *
fr_command_rar_get_packages (FrCommand *comm,
const char *mime_type)
{
- return PACKAGES ("rar,unrar");
+ return PACKAGES ("rar,unrar,unrar-free");
}
-
static void
fr_command_rar_class_init (FrCommandRarClass *class)
{
@@ -777,7 +743,6 @@ fr_command_rar_class_init (FrCommandRarClass *class)
afc->get_packages = fr_command_rar_get_packages;
}
-
static void
fr_command_rar_init (FrCommand *comm)
{
@@ -792,7 +757,6 @@ fr_command_rar_init (FrCommand *comm)
comm->propListFromFile = TRUE;
}
-
static void
fr_command_rar_finalize (GObject *object)
{
@@ -804,7 +768,6 @@ fr_command_rar_finalize (GObject *object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-
GType
fr_command_rar_get_type ()
{