diff options
Diffstat (limited to 'src/fr-command-rar.c')
-rw-r--r-- | src/fr-command-rar.c | 185 |
1 files changed, 87 insertions, 98 deletions
diff --git a/src/fr-command-rar.c b/src/fr-command-rar.c index 7794510..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> @@ -49,10 +51,26 @@ static FrCommandClass *parent_class = NULL; 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 -- */ @@ -112,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...." @@ -172,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 @@ -201,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; @@ -219,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); + int version = 0; - if (version > 5) - date_newstyle = TRUE; - else if (version == 5) - { - sscanf (line, "RAR 5.%d ", &version); - if (version >= 30) - date_newstyle = TRUE; - } - - } - 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) @@ -264,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); @@ -301,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)) { @@ -341,7 +336,7 @@ 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; } @@ -375,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-"); @@ -579,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"); @@ -623,10 +612,7 @@ fr_command_rar_extract (FrCommand *comm, 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"); @@ -713,10 +699,13 @@ fr_command_rar_get_capabilities (FrCommand *comm, 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)) @@ -729,7 +718,7 @@ 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 |