/* 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]) { RARCH_WARN("[decompress] Empty or null source file or target directory arguments.\n"); return false; } /* zip only */ if (!path_file_exists(source_file) || strcmp("zip", path_get_extension(source_file)) != 0) { RARCH_WARN("[decompress] File '%s' does not exist or is not a compressed file.\n", source_file); 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; }