Merge pull request #2482 from heuripedes/master

Implement background zip extraction for core/content download
This commit is contained in:
Twinaphex 2015-11-27 23:51:53 +01:00
commit 818f82ee1f
4 changed files with 194 additions and 33 deletions

View File

@ -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

View File

@ -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)

157
tasks/task_decompress.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include <string/string_list.h>
#include <file/file_path.h>
#include <file/file_extract.h>
#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;
}

View File

@ -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