diff --git a/Makefile.common b/Makefile.common
index 873d6ca837..057af9259d 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -801,7 +801,8 @@ endif
ifeq ($(HAVE_ZLIB), 1)
- OBJ += libretro-common/file/file_extract.o
+ OBJ += libretro-common/file/file_extract.o \
+ tasks/task_decompress.o
OBJ += $(ZLIB_OBJS)
DEFINES += -DHAVE_ZLIB
HAVE_RPNG = 1
diff --git a/menu/cbs/menu_cbs_deferred_push.c b/menu/cbs/menu_cbs_deferred_push.c
index 7a1e4c7c51..ea34ab06f8 100644
--- a/menu/cbs/menu_cbs_deferred_push.c
+++ b/menu/cbs/menu_cbs_deferred_push.c
@@ -331,39 +331,35 @@ finish:
}
}
-#ifdef HAVE_ZLIB
-static int zlib_extract_core_callback(const char *name, const char *valid_exts,
- const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
- uint32_t crc32, void *userdata)
+static void cb_decompressed(void *task_data, void *user_data, const char *err)
{
- char path[PATH_MAX_LENGTH];
+ decompress_task_data_t *dec = (decompress_task_data_t*)task_data;
+ unsigned type_hash = (uintptr_t)user_data;
- /* Make directory */
- fill_pathname_join(path, (const char*)userdata, name, sizeof(path));
- path_basedir(path);
+ if (dec && !err)
+ {
+ char msg[PATH_MAX_LENGTH];
+ if (type_hash == CB_CORE_UPDATER_DOWNLOAD)
+ event_command(EVENT_CMD_CORE_INFO_INIT);
- if (!path_mkdir(path))
- goto error;
+ snprintf(msg, sizeof(msg), "%s extracted.", path_basename(dec->source_file));
+ rarch_main_msg_queue_push(msg, 1, 90, true);
+ }
- /* Ignore directories. */
- if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\')
- return 1;
+ if (err)
+ RARCH_ERR("%s", err);
- fill_pathname_join(path, (const char*)userdata, name, sizeof(path));
+ if (dec)
+ {
+ if (path_file_exists(dec->source_file))
+ remove(dec->source_file);
- RARCH_LOG("path is: %s, CRC32: 0x%x\n", path, crc32);
- if (!zlib_perform_mode(path, valid_exts,
- cdata, cmode, csize, size, crc32, userdata))
- goto error;
- return 1;
-
-error:
- RARCH_ERR("Failed to deflate to: %s.\n", path);
- return 0;
+ free(dec->source_file);
+ free(dec);
+ }
}
-#endif
/* expects http_transfer_t*, menu_file_transfer_t* */
void cb_generic_download(void *task_data, void *user_data, const char *err)
@@ -445,7 +441,6 @@ void cb_generic_download(void *task_data, void *user_data, const char *err)
rarch_main_msg_queue_push(msg, 1, 90, true);
#ifdef HAVE_ZLIB
- /* TODO: this should generate a new task instead of blocking */
file_ext = path_get_extension(output_path);
if (!settings->network.buildbot_auto_extract_archive)
@@ -453,17 +448,18 @@ void cb_generic_download(void *task_data, void *user_data, const char *err)
if (!strcasecmp(file_ext, "zip"))
{
- if (!zlib_parse_file(output_path, NULL, zlib_extract_core_callback,
- (void*)dir_path))
- RARCH_LOG("%s\n", msg_hash_to_str(MSG_COULD_NOT_PROCESS_ZIP_FILE));
+ snprintf(msg, sizeof(msg), "Decompressing %s...",
+ path_basename(output_path));
- if (path_file_exists(output_path))
- remove(output_path);
+ rarch_main_msg_queue_push(msg, 1, 90, true);
+
+ rarch_task_push_decompress(output_path, dir_path, NULL,
+ cb_decompressed, (void*)(uintptr_t)CB_CORE_UPDATER_DOWNLOAD);
}
-#endif
-
+#else
if (transf->type_hash == CB_CORE_UPDATER_DOWNLOAD)
event_command(EVENT_CMD_CORE_INFO_INIT);
+#endif
finish:
if (err)
diff --git a/tasks/task_decompress.c b/tasks/task_decompress.c
new file mode 100644
index 0000000000..2780d063c8
--- /dev/null
+++ b/tasks/task_decompress.c
@@ -0,0 +1,157 @@
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2011-2015 - Daniel De Matteis
+ *
+ * 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 .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include
+#include
+#include
+
+#include "tasks.h"
+#include "../verbosity.h"
+
+typedef struct {
+ char *source_file;
+ char *target_dir;
+ char *valid_ext;
+
+ char *callback_error;
+
+ zlib_transfer_t zlib;
+} decompress_state_t;
+
+static int file_decompressed(const char *name, const char *valid_exts,
+ const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
+ uint32_t crc32, void *userdata)
+{
+ char path[PATH_MAX_LENGTH];
+ decompress_state_t *dec = (decompress_state_t*)userdata;
+
+ /* Ignore directories. */
+ if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\')
+ goto next_file;
+
+ /* Make directory */
+ fill_pathname_join(path, dec->target_dir, name, sizeof(path));
+ path_basedir(path);
+
+ if (!path_mkdir(path))
+ goto error;
+
+ fill_pathname_join(path, dec->target_dir, name, sizeof(path));
+
+ if (!zlib_perform_mode(path, valid_exts,
+ cdata, cmode, csize, size, crc32, userdata))
+ goto error;
+
+ RARCH_LOG("[deflate] Path: %s, CRC32: 0x%x\n", name, crc32);
+
+next_file:
+ return 1;
+
+error:
+ dec->callback_error = (char*)malloc(PATH_MAX_LENGTH);
+ snprintf(dec->callback_error, PATH_MAX_LENGTH, "Failed to deflate %s.\n", path);
+
+ return 0;
+
+}
+
+static void rarch_task_decompress_handler(rarch_task_t *task)
+{
+ decompress_state_t *dec = (decompress_state_t*)task->state;
+ decompress_task_data_t *data = NULL;
+ bool failed;
+
+ zlib_parse_file_iterate(&dec->zlib, &failed, dec->source_file,
+ dec->valid_ext, file_decompressed, dec);
+
+ if (failed)
+ {
+ task->error = dec->callback_error;
+ goto task_finished;
+ }
+
+ if (task->cancelled)
+ dec->zlib.type = ZLIB_TRANSFER_DEINIT;
+
+ /* run again to free resources */
+ if (dec->zlib.type == ZLIB_TRANSFER_DEINIT)
+ {
+ zlib_parse_file_iterate(&dec->zlib, &failed, dec->source_file,
+ dec->valid_ext, file_decompressed, dec);
+ goto task_finished;
+ }
+
+ return;
+
+task_finished:
+ task->finished = true;
+
+ if (task->cancelled)
+ task->error = strdup("Task canceled");
+
+ if (!task->error)
+ {
+ data = (decompress_task_data_t*)calloc(1, sizeof(*data));
+ data->source_file = dec->source_file;
+ task->task_data = data;
+ }
+ else
+ free(dec->source_file);
+
+ if (dec->valid_ext)
+ free(dec->valid_ext);
+ free(dec->target_dir);
+ free(dec);
+}
+
+bool rarch_task_push_decompress(const char *source_file, const char *target_dir,
+ const char *valid_ext, rarch_task_callback_t cb, void *user_data)
+{
+ decompress_state_t *s;
+ rarch_task_t *t;
+
+ if (!target_dir || !target_dir[0] || !source_file || !source_file[0])
+ return false;
+
+ /* zip only */
+ if (!path_file_exists(source_file) || strcmp("zip", path_get_extension(source_file)) != 0)
+ return false;
+
+ if (!valid_ext || !valid_ext[0])
+ valid_ext = NULL;
+
+ s = (decompress_state_t*)calloc(1, sizeof(*s));
+
+ s->source_file = strdup(source_file);
+ s->target_dir = strdup(target_dir);
+
+ s->valid_ext = valid_ext ? strdup(valid_ext) : NULL;
+ s->zlib.type = ZLIB_TRANSFER_INIT;
+
+ t = (rarch_task_t*)calloc(1, sizeof(*t));
+ t->handler = rarch_task_decompress_handler;
+ t->state = s;
+
+ t->callback = cb;
+ t->user_data = user_data;
+
+ rarch_task_push(t);
+
+ return true;
+}
diff --git a/tasks/tasks.h b/tasks/tasks.h
index c95df314e1..0c31243c52 100644
--- a/tasks/tasks.h
+++ b/tasks/tasks.h
@@ -144,6 +144,13 @@ int detect_ps1_game(const char *track_path, char *game_id);
int detect_psp_game(const char *track_path, char *game_id);
+typedef struct {
+ char *source_file;
+} decompress_task_data_t;
+
+bool rarch_task_push_decompress(const char *source_file, const char *target_dir,
+ const char *valid_ext, rarch_task_callback_t cb, void *user_data);
+
#ifdef __cplusplus
}
#endif