RetroArch/tasks/task_decompress.c

378 lines
9.8 KiB
C
Raw Normal View History

2015-11-27 20:43:49 +00:00
/* RetroArch - A frontend for libretro.
2017-01-22 12:40:32 +00:00
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2016-2017 - Brad Parker
2015-11-27 20:43:49 +00:00
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <lists/string_list.h>
2015-12-26 06:23:13 +00:00
#include <string/stdstring.h>
2015-11-27 20:43:49 +00:00
#include <file/file_path.h>
#include <file/archive_file.h>
#include <streams/file_stream.h>
#include <retro_miscellaneous.h>
#include <compat/strl.h>
2015-11-27 20:43:49 +00:00
2016-02-09 16:55:15 +00:00
#include "tasks_internal.h"
#include "../file_path_special.h"
2015-11-27 20:43:49 +00:00
#include "../verbosity.h"
#include "../msg_hash.h"
2015-11-27 20:43:49 +00:00
2018-11-25 17:49:04 +00:00
#define CALLBACK_ERROR_SIZE 4200
2016-02-03 16:41:04 +00:00
static int file_decompressed_target_file(const char *name,
const char *valid_exts,
const uint8_t *cdata,
unsigned cmode, uint32_t csize, uint32_t size,
2016-09-18 19:20:27 +00:00
uint32_t crc32, struct archive_extract_userdata *userdata)
{
/* TODO/FIXME */
return 0;
}
2016-02-03 16:41:04 +00:00
static int file_decompressed_subdir(const char *name,
const char *valid_exts,
const uint8_t *cdata,
unsigned cmode, uint32_t csize,uint32_t size,
2016-09-18 19:20:27 +00:00
uint32_t crc32, struct archive_extract_userdata *userdata)
{
2016-10-15 23:31:06 +00:00
char path_dir[PATH_MAX_LENGTH];
char path[PATH_MAX_LENGTH];
path_dir[0] = path[0] = '\0';
/* Ignore directories. */
2018-02-25 15:32:39 +00:00
if (
2019-02-03 23:49:35 +00:00
name[strlen(name) - 1] == '/' ||
2018-02-25 15:32:39 +00:00
name[strlen(name) - 1] == '\\')
goto next_file;
2016-09-18 20:05:33 +00:00
if (strstr(name, userdata->dec->subdir) != name)
return 1;
2016-09-18 20:05:33 +00:00
name += strlen(userdata->dec->subdir) + 1;
2018-02-25 15:32:39 +00:00
fill_pathname_join(path,
userdata->dec->target_dir, name, sizeof(path));
fill_pathname_basedir(path_dir, path, sizeof(path_dir));
/* Make directory */
if (!path_mkdir(path_dir))
goto error;
2016-01-24 06:42:46 +00:00
if (!file_archive_perform_mode(path, valid_exts,
cdata, cmode, csize, size, crc32, userdata))
goto error;
2016-12-15 20:21:39 +00:00
#if 0
RARCH_LOG("[deflate subdir] Path: %s, CRC32: 0x%x\n", name, crc32);
2016-12-15 20:21:39 +00:00
#endif
next_file:
return 1;
error:
2018-11-25 17:49:04 +00:00
userdata->dec->callback_error = (char*)malloc(CALLBACK_ERROR_SIZE);
2016-09-18 20:05:33 +00:00
snprintf(userdata->dec->callback_error,
2018-11-25 17:49:04 +00:00
CALLBACK_ERROR_SIZE, "Failed to deflate %s.\n", path);
return 0;
}
2015-11-27 20:43:49 +00:00
static int file_decompressed(const char *name, const char *valid_exts,
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
2016-09-18 19:20:27 +00:00
uint32_t crc32, struct archive_extract_userdata *userdata)
2015-11-27 20:43:49 +00:00
{
char path[PATH_MAX_LENGTH];
2016-09-18 20:05:33 +00:00
decompress_state_t *dec = userdata->dec;
2015-11-27 20:43:49 +00:00
path[0] = '\0';
2015-11-27 20:43:49 +00:00
/* Ignore directories. */
if ( name[strlen(name) - 1] == '/' ||
2018-02-25 15:32:39 +00:00
name[strlen(name) - 1] == '\\')
2015-11-27 20:43:49 +00:00
goto next_file;
/* Make directory */
fill_pathname_join(path, dec->target_dir, name, sizeof(path));
path_basedir_wrapper(path);
2015-11-27 20:43:49 +00:00
if (!path_mkdir(path))
goto error;
fill_pathname_join(path, dec->target_dir, name, sizeof(path));
2016-01-24 06:42:46 +00:00
if (!file_archive_perform_mode(path, valid_exts,
2015-11-27 20:43:49 +00:00
cdata, cmode, csize, size, crc32, userdata))
goto error;
2016-12-15 20:21:39 +00:00
#if 0
2015-11-27 20:43:49 +00:00
RARCH_LOG("[deflate] Path: %s, CRC32: 0x%x\n", name, crc32);
2016-12-15 20:21:39 +00:00
#endif
2015-11-27 20:43:49 +00:00
next_file:
return 1;
error:
2018-11-25 17:49:04 +00:00
dec->callback_error = (char*)malloc(CALLBACK_ERROR_SIZE);
snprintf(dec->callback_error, CALLBACK_ERROR_SIZE,
2016-02-03 16:41:04 +00:00
"Failed to deflate %s.\n", path);
2015-11-27 20:43:49 +00:00
return 0;
}
2016-05-13 08:19:53 +00:00
static void task_decompress_handler_finished(retro_task_t *task,
decompress_state_t *dec)
2015-11-27 20:43:49 +00:00
{
task_set_finished(task, true);
2015-11-27 20:43:49 +00:00
if (!task_get_error(task) && task_get_cancelled(task))
task_set_error(task, strdup("Task canceled"));
2015-11-27 20:43:49 +00:00
if (task_get_error(task))
2016-01-23 23:06:50 +00:00
free(dec->source_file);
else
2015-11-27 20:43:49 +00:00
{
decompress_task_data_t *data =
(decompress_task_data_t*)calloc(1, sizeof(*data));
2015-11-27 20:43:49 +00:00
data->source_file = dec->source_file;
task_set_data(task, data);
2015-11-27 20:43:49 +00:00
}
if (dec->subdir)
free(dec->subdir);
2015-11-27 20:43:49 +00:00
if (dec->valid_ext)
free(dec->valid_ext);
if (dec->userdata)
free(dec->userdata);
2015-11-27 20:43:49 +00:00
free(dec->target_dir);
free(dec);
}
2016-05-13 08:19:53 +00:00
static void task_decompress_handler(retro_task_t *task)
{
2016-09-19 16:29:10 +00:00
int ret;
2016-09-29 10:02:45 +00:00
bool retdec = false;
2018-02-25 15:32:39 +00:00
decompress_state_t *dec = (decompress_state_t*)
task->state;
dec->userdata->dec = dec;
strlcpy(dec->userdata->archive_path,
dec->source_file, sizeof(dec->userdata->archive_path));
2016-09-18 20:05:33 +00:00
2018-02-25 15:32:39 +00:00
ret = file_archive_parse_file_iterate(
&dec->archive,
2016-02-03 16:41:04 +00:00
&retdec, dec->source_file,
dec->valid_ext, file_decompressed, dec->userdata);
2018-02-25 15:32:39 +00:00
task_set_progress(task,
file_archive_parse_file_progress(&dec->archive));
if (task_get_cancelled(task) || ret != 0)
{
task_set_error(task, dec->callback_error);
file_archive_parse_file_iterate_stop(&dec->archive);
2016-05-13 08:19:53 +00:00
task_decompress_handler_finished(task, dec);
}
}
2016-05-13 08:19:53 +00:00
static void task_decompress_handler_target_file(retro_task_t *task)
{
2016-02-03 16:41:04 +00:00
bool retdec;
2016-09-20 01:01:20 +00:00
int ret;
2018-02-25 15:32:39 +00:00
decompress_state_t *dec = (decompress_state_t*)
task->state;
2016-09-20 01:01:20 +00:00
strlcpy(dec->userdata->archive_path,
dec->source_file, sizeof(dec->userdata->archive_path));
2016-09-20 00:58:31 +00:00
2016-09-20 01:01:20 +00:00
ret = file_archive_parse_file_iterate(&dec->archive,
2016-02-03 16:41:04 +00:00
&retdec, dec->source_file,
dec->valid_ext, file_decompressed_target_file, dec->userdata);
2018-02-25 15:32:39 +00:00
task_set_progress(task,
file_archive_parse_file_progress(&dec->archive));
if (task_get_cancelled(task) || ret != 0)
{
task_set_error(task, dec->callback_error);
file_archive_parse_file_iterate_stop(&dec->archive);
2016-05-13 08:19:53 +00:00
task_decompress_handler_finished(task, dec);
}
}
2016-05-13 08:19:53 +00:00
static void task_decompress_handler_subdir(retro_task_t *task)
{
2016-09-19 16:29:10 +00:00
int ret;
2016-02-03 16:41:04 +00:00
bool retdec;
decompress_state_t *dec = (decompress_state_t*)task->state;
dec->userdata->dec = dec;
strlcpy(dec->userdata->archive_path,
2018-02-25 15:32:39 +00:00
dec->source_file,
sizeof(dec->userdata->archive_path));
2016-09-18 19:20:27 +00:00
2018-02-25 15:32:39 +00:00
ret = file_archive_parse_file_iterate(
&dec->archive,
2016-02-03 16:41:04 +00:00
&retdec, dec->source_file,
dec->valid_ext, file_decompressed_subdir, dec->userdata);
2018-02-25 15:32:39 +00:00
task_set_progress(task,
file_archive_parse_file_progress(&dec->archive));
if (task_get_cancelled(task) || ret != 0)
{
task_set_error(task, dec->callback_error);
file_archive_parse_file_iterate_stop(&dec->archive);
2016-05-13 08:19:53 +00:00
task_decompress_handler_finished(task, dec);
}
}
2016-05-13 08:19:53 +00:00
static bool task_decompress_finder(
2016-02-09 16:47:04 +00:00
retro_task_t *task, void *user_data)
{
decompress_state_t *dec = (decompress_state_t*)task->state;
2016-05-13 08:19:53 +00:00
if (task->handler != task_decompress_handler)
return false;
2016-01-20 03:07:24 +00:00
return string_is_equal(dec->source_file, (const char*)user_data);
}
2016-05-27 16:14:47 +00:00
bool task_check_decompress(const char *source_file)
{
task_finder_data_t find_data;
/* Prepare find parameters */
2018-02-05 18:14:55 +00:00
find_data.func = task_decompress_finder;
find_data.userdata = (void *)source_file;
/* Return whether decompressing is in progress or not */
2017-05-14 18:43:39 +00:00
return task_queue_find(&find_data);
}
2016-05-27 16:14:47 +00:00
bool task_push_decompress(
const char *source_file,
const char *target_dir,
const char *target_file,
const char *subdir,
const char *valid_ext,
2016-02-09 16:47:04 +00:00
retro_task_callback_t cb,
void *user_data)
2015-11-27 20:43:49 +00:00
{
2016-10-15 23:31:06 +00:00
char tmp[PATH_MAX_LENGTH];
2018-02-25 15:32:39 +00:00
const char *ext = NULL;
2016-01-21 02:16:48 +00:00
decompress_state_t *s = NULL;
2016-02-09 16:47:04 +00:00
retro_task_t *t = NULL;
2015-11-27 20:43:49 +00:00
2016-10-15 23:31:06 +00:00
tmp[0] = '\0';
2016-01-21 02:16:48 +00:00
if (string_is_empty(target_dir) || string_is_empty(source_file))
{
2018-02-25 15:32:39 +00:00
RARCH_WARN(
"[decompress] Empty or null source file or"
2016-02-03 16:41:04 +00:00
" target directory arguments.\n");
2015-11-27 20:43:49 +00:00
return false;
}
2015-11-27 20:43:49 +00:00
2018-02-25 15:32:39 +00:00
ext = path_get_extension(source_file);
/* ZIP or APK only */
2018-02-25 15:32:39 +00:00
if (
!filestream_exists(source_file) ||
2018-02-25 16:20:22 +00:00
(
2018-03-01 13:59:37 +00:00
!string_is_equal_noncase(ext, "zip")
&& !string_is_equal_noncase(ext, "apk")
2018-02-25 15:32:39 +00:00
#ifdef HAVE_7ZIP
2018-03-01 13:59:37 +00:00
&& !string_is_equal_noncase(ext, "7z")
2018-02-25 15:32:39 +00:00
#endif
2018-02-25 16:20:22 +00:00
)
2018-02-25 15:32:39 +00:00
)
{
2018-02-25 15:32:39 +00:00
RARCH_WARN(
"[decompress] File '%s' does not exist"
" or is not a compressed file.\n",
source_file);
2015-11-27 20:43:49 +00:00
return false;
}
2015-11-27 20:43:49 +00:00
if (!valid_ext || !valid_ext[0])
2016-01-21 02:16:48 +00:00
valid_ext = NULL;
2015-11-27 20:43:49 +00:00
2016-05-27 16:14:47 +00:00
if (task_check_decompress(source_file))
{
2018-02-25 15:32:39 +00:00
RARCH_LOG(
"[decompress] File '%s' already being decompressed.\n",
2016-02-03 16:41:04 +00:00
source_file);
return false;
}
2016-01-10 12:16:55 +00:00
RARCH_LOG("[decompress] File '%s.\n", source_file);
2016-01-21 02:16:48 +00:00
s = (decompress_state_t*)calloc(1, sizeof(*s));
2015-11-27 20:43:49 +00:00
if (!s)
goto error;
2015-11-27 20:43:49 +00:00
s->source_file = strdup(source_file);
s->target_dir = strdup(target_dir);
2016-01-21 02:16:48 +00:00
s->valid_ext = valid_ext ? strdup(valid_ext) : NULL;
s->archive.type = ARCHIVE_TRANSFER_INIT;
s->userdata = (struct archive_extract_userdata*)calloc(1, sizeof(*s->userdata));
2015-11-27 20:43:49 +00:00
2016-02-09 16:47:04 +00:00
t = (retro_task_t*)calloc(1, sizeof(*t));
if (!t)
goto error;
2016-01-21 02:16:48 +00:00
t->state = s;
2016-05-13 08:19:53 +00:00
t->handler = task_decompress_handler;
2015-12-26 06:23:13 +00:00
if (!string_is_empty(subdir))
{
s->subdir = strdup(subdir);
2016-05-13 08:19:53 +00:00
t->handler = task_decompress_handler_subdir;
}
else if (!string_is_empty(target_file))
{
2016-01-26 03:29:19 +00:00
s->target_file = strdup(target_file);
2016-05-13 08:19:53 +00:00
t->handler = task_decompress_handler_target_file;
}
2015-11-27 20:43:49 +00:00
2016-01-21 02:16:48 +00:00
t->callback = cb;
t->user_data = user_data;
2015-11-27 20:43:49 +00:00
2016-02-03 16:41:04 +00:00
snprintf(tmp, sizeof(tmp), "%s '%s'",
2018-02-25 15:32:39 +00:00
msg_hash_to_str(MSG_EXTRACTING),
path_basename(source_file));
2016-02-03 16:41:04 +00:00
t->title = strdup(tmp);
2017-05-14 18:43:39 +00:00
task_queue_push(t);
2015-11-27 20:43:49 +00:00
return true;
error:
if (s)
{
if (s->userdata)
free(s->userdata);
free(s);
}
return false;
2015-11-27 20:43:49 +00:00
}