From cb885f9c206aa4ddbda3c203df41e1514fe1ea84 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 18 Sep 2016 00:38:59 -0400 Subject: [PATCH] create 7z archive backend, enables scanning of 7z content --- Makefile.common | 9 +- Makefile.ctr | 1 + config.def.h | 4 +- database_info.h | 6 +- libretro-common/encodings/encoding_utf.c | 56 +- libretro-common/file/archive_file.c | 494 +++++++----- libretro-common/file/archive_file_7z.c | 405 ++++++++++ libretro-common/file/archive_file_zlib.c | 276 ++++++- libretro-common/file/file_path.c | 4 +- libretro-common/formats/png/rpng.c | 2 +- libretro-common/formats/png/rpng_encode.c | 4 +- libretro-common/include/encodings/utf.h | 5 + libretro-common/include/file/archive_file.h | 113 ++- libretro-common/include/lists/string_list.h | 4 +- libretro-common/include/retro_miscellaneous.h | 14 +- libretro-common/lists/string_list.c | 2 +- menu/menu_displaylist.c | 4 +- msg_hash.c | 4 + patch.c | 12 +- tasks/task_content.c | 719 ++---------------- tasks/task_database.c | 66 +- tasks/task_decompress.c | 22 +- 22 files changed, 1226 insertions(+), 1000 deletions(-) create mode 100644 libretro-common/file/archive_file_7z.c diff --git a/Makefile.common b/Makefile.common index 9ee8934c3a..f7092bf8f6 100644 --- a/Makefile.common +++ b/Makefile.common @@ -989,14 +989,13 @@ ifeq ($(HAVE_7ZIP),1) deps/7zip/7zCrc.o \ deps/7zip/Lzma2Dec.o \ deps/7zip/7zBuf.o - OBJ += $(7ZOBJ) + OBJ += libretro-common/file/archive_file_7z.o \ + $(7ZOBJ) endif ifeq ($(HAVE_ZLIB), 1) - OBJ += libretro-common/file/archive_file.o \ - libretro-common/file/archive_file_zlib.o \ - tasks/task_decompress.o + OBJ += libretro-common/file/archive_file_zlib.o OBJ += $(ZLIB_OBJS) DEFINES += -DHAVE_ZLIB HAVE_COMPRESSION = 1 @@ -1147,6 +1146,8 @@ endif ifeq ($(HAVE_COMPRESSION), 1) DEFINES += -DHAVE_COMPRESSION + OBJ += libretro-common/file/archive_file.o \ + tasks/task_decompress.o endif #ifeq ($(HAVE_DIRECTX), 1) diff --git a/Makefile.ctr b/Makefile.ctr index fdaa48ea28..1539ba72aa 100644 --- a/Makefile.ctr +++ b/Makefile.ctr @@ -46,6 +46,7 @@ else CFLAGS += -DHAVE_COMPRESSION OBJS += libretro-common/file/archive_file.o OBJS += libretro-common/file/archive_file_zlib.o + OBJS += libretro-common/file/archive_file_7z.o OBJS += libretro-common/encodings/encoding_utf.o OBJS += verbosity.o OBJS += performance.o diff --git a/config.def.h b/config.def.h index 67de519f58..9ba8bc1195 100644 --- a/config.def.h +++ b/config.def.h @@ -872,7 +872,7 @@ static char buildbot_assets_server_url[] = "http://buildbot.libretro.com/assets/ /* User 1 */ static const struct retro_keybind retro_keybinds_1[] = { - /* | RetroPad button | desc | keyboard key | js btn | js axis | */ + /* | RetroPad button | desc | keyboard key | js btn | js axis | */ { true, RETRO_DEVICE_ID_JOYPAD_B, RETRO_LBL_JOYPAD_B, RETROK_z, NO_BTN, 0, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_Y, RETRO_LBL_JOYPAD_Y, RETROK_a, NO_BTN, 0, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_SELECT, RETRO_LBL_JOYPAD_SELECT, RETROK_RSHIFT, NO_BTN, 0, AXIS_NONE }, @@ -936,7 +936,7 @@ static const struct retro_keybind retro_keybinds_1[] = { /* Users 2 to MAX_USERS */ static const struct retro_keybind retro_keybinds_rest[] = { - /* | RetroPad button | desc | keyboard key | js btn | js axis | */ + /* | RetroPad button | desc | keyboard key | js btn | js axis | */ { true, RETRO_DEVICE_ID_JOYPAD_B, RETRO_LBL_JOYPAD_B, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_Y, RETRO_LBL_JOYPAD_Y, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_SELECT, RETRO_LBL_JOYPAD_SELECT, RETROK_UNKNOWN, NO_BTN, 0, AXIS_NONE }, diff --git a/database_info.h b/database_info.h index 2b9bfd0197..a3ccd17a24 100644 --- a/database_info.h +++ b/database_info.h @@ -2,7 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2016 - Daniel De Matteis * Copyright (C) 2013-2015 - Jason Fetters - * + * * 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. @@ -46,7 +46,7 @@ enum database_type { DATABASE_TYPE_NONE = 0, DATABASE_TYPE_ITERATE, - DATABASE_TYPE_ITERATE_ZIP, + DATABASE_TYPE_ITERATE_ARCHIVE, DATABASE_TYPE_ITERATE_LUTRO, DATABASE_TYPE_SERIAL_LOOKUP, DATABASE_TYPE_CRC_LOOKUP @@ -58,7 +58,7 @@ typedef struct enum database_type type; size_t list_ptr; struct string_list *list; -#ifdef HAVE_ZLIB +#ifdef HAVE_COMPRESSION file_archive_transfer_t state; #endif } database_info_handle_t; diff --git a/libretro-common/encodings/encoding_utf.c b/libretro-common/encodings/encoding_utf.c index dd584de418..443dd4c4d1 100644 --- a/libretro-common/encodings/encoding_utf.c +++ b/libretro-common/encodings/encoding_utf.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -40,7 +41,7 @@ static INLINE unsigned leading_ones(uint8_t c) return ones; } -/* Simple implementation. Assumes the sequence is +/* Simple implementation. Assumes the sequence is * properly synchronized and terminated. */ size_t utf8_conv_utf32(uint32_t *out, size_t out_chars, @@ -119,14 +120,14 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars, if (value < (((uint32_t)1) << (numAdds * 5 + 6))) break; if (out) - out[out_pos] = (char)(kUtf8Limits[numAdds - 1] + out[out_pos] = (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); out_pos++; do { numAdds--; if (out) - out[out_pos] = (char)(0x80 + out[out_pos] = (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); out_pos++; }while (numAdds != 0); @@ -136,13 +137,13 @@ bool utf16_conv_utf8(uint8_t *out, size_t *out_chars, return false; } -/* Acts mostly like strlcpy. +/* Acts mostly like strlcpy. * - * Copies the given number of UTF-8 characters, + * Copies the given number of UTF-8 characters, * but at most d_len bytes. * - * Always NULL terminates. - * Does not copy half a character. + * Always NULL terminates. + * Does not copy half a character. * * Returns number of bytes. 's' is assumed valid UTF-8. * Use only if 'chars' is considerably less than 'd_len'. */ @@ -205,20 +206,55 @@ uint32_t utf8_walk(const char **string) { uint8_t first = utf8_walkbyte(string); uint32_t ret; - + if (first<128) return first; - + ret = 0; ret = (ret<<6) | (utf8_walkbyte(string) & 0x3F); if (first >= 0xE0) ret = (ret<<6) | (utf8_walkbyte(string) & 0x3F); if (first >= 0xF0) ret = (ret<<6) | (utf8_walkbyte(string) & 0x3F); - + if (first >= 0xF0) return ret | (first&31)<<18; if (first >= 0xE0) return ret | (first&15)<<12; return ret | (first&7)<<6; } + +static bool utf16_to_char(uint8_t **utf_data, + size_t *dest_len, const uint16_t *in) +{ + unsigned len = 0; + + while (in[len] != '\0') + len++; + + utf16_conv_utf8(NULL, dest_len, in, len); + *dest_len += 1; + *utf_data = (uint8_t*)malloc(*dest_len); + if (*utf_data == 0) + return false; + + return utf16_conv_utf8(*utf_data, dest_len, in, len); +} + +bool utf16_to_char_string(const uint16_t *in, char *s, size_t len) +{ + size_t dest_len = 0; + uint8_t *utf16_data = NULL; + bool ret = utf16_to_char(&utf16_data, &dest_len, in); + + if (ret) + { + utf16_data[dest_len] = 0; + strlcpy(s, (const char*)utf16_data, len); + } + + free(utf16_data); + utf16_data = NULL; + + return ret; +} diff --git a/libretro-common/file/archive_file.c b/libretro-common/file/archive_file.c index cbb9e45d4f..8c2e34c988 100644 --- a/libretro-common/file/archive_file.c +++ b/libretro-common/file/archive_file.c @@ -45,30 +45,7 @@ #include #include #include - -#ifndef CENTRAL_FILE_HEADER_SIGNATURE -#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50 -#endif - -#ifndef END_OF_CENTRAL_DIR_SIGNATURE -#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50 -#endif - -struct zip_extract_userdata -{ - char *zip_path; - char *first_extracted_file_path; - const char *extraction_directory; - size_t zip_path_size; - struct string_list *ext; - bool found_content; -}; - -enum file_archive_compression_mode -{ - ZLIB_MODE_UNCOMPRESSED = 0, - ZLIB_MODE_DEFLATE = 8 -}; +#include typedef struct { @@ -81,7 +58,7 @@ typedef struct #ifdef HAVE_MMAP /* Closes, unmaps and frees. */ -static void file_archive_free(void *handle) +void file_archive_free(void *handle) { file_archive_file_data_t *data = (file_archive_file_data_t*)handle; @@ -95,7 +72,7 @@ static void file_archive_free(void *handle) free(data); } -static const uint8_t *file_archive_data(void *handle) +const uint8_t *file_archive_data(void *handle) { file_archive_file_data_t *data = (file_archive_file_data_t*)handle; if (!data) @@ -146,16 +123,17 @@ error: #else /* Closes, unmaps and frees. */ -static void file_archive_free(void *handle) +void file_archive_free(void *handle) { file_archive_file_data_t *data = (file_archive_file_data_t*)handle; if (!data) return; - free(data->data); + if(data->data) + free(data->data); free(data); } -static const uint8_t *file_archive_data(void *handle) +const uint8_t *file_archive_data(void *handle) { file_archive_file_data_t *data = (file_archive_file_data_t*)handle; if (!data) @@ -209,7 +187,9 @@ static int file_archive_get_file_list_cb( union string_list_elem_attr attr; struct string_list *ext_list = NULL; const char *file_ext = NULL; - struct string_list *list = (struct string_list*)userdata; + struct archive_extract_userdata *data = + (struct archive_extract_userdata*)userdata; + size_t pathLen = strlen(path); (void)cdata; (void)cmode; @@ -219,13 +199,16 @@ static int file_archive_get_file_list_cb( memset(&attr, 0, sizeof(attr)); + if (!pathLen) + return 0; + if (valid_exts) ext_list = string_split(valid_exts, "|"); if (ext_list) { /* Checks if this entry is a directory or a file. */ - char last_char = path[strlen(path)-1]; + char last_char = path[pathLen-1]; /* Skip if directory. */ if (last_char == '/' || last_char == '\\' ) @@ -233,7 +216,7 @@ static int file_archive_get_file_list_cb( file_ext = path_get_extension(path); - if (!file_ext || + if (!file_ext || !string_list_find_elem_prefix(ext_list, ".", file_ext)) goto error; @@ -241,8 +224,8 @@ static int file_archive_get_file_list_cb( string_list_free(ext_list); } - return string_list_append(list, path, attr); - + return string_list_append(data->list, path, attr); + error: string_list_free(ext_list); return 0; @@ -254,9 +237,9 @@ static int file_archive_extract_cb(const char *name, const char *valid_exts, uint32_t checksum, void *userdata) { const char *ext = path_get_extension(name); - struct zip_extract_userdata *data = (struct zip_extract_userdata*)userdata; + struct archive_extract_userdata *data = (struct archive_extract_userdata*)userdata; - /* Extract first content that matches our list. */ + /* Extract first file that matches our list. */ if (ext && string_list_find_elem(data->ext, ext)) { char new_path[PATH_MAX_LENGTH] = {0}; @@ -265,141 +248,51 @@ static int file_archive_extract_cb(const char *name, const char *valid_exts, fill_pathname_join(new_path, data->extraction_directory, path_basename(name), sizeof(new_path)); else - fill_pathname_resolve_relative(new_path, data->zip_path, + fill_pathname_resolve_relative(new_path, data->archive_path, path_basename(name), sizeof(new_path)); data->first_extracted_file_path = strdup(new_path); - data->found_content = file_archive_perform_mode(new_path, + data->found_file = file_archive_perform_mode(new_path, valid_exts, cdata, cmode, csize, size, - 0, NULL); + 0, data); return 0; } return 1; } -static uint32_t read_le(const uint8_t *data, unsigned size) -{ - unsigned i; - uint32_t val = 0; - - size *= 8; - for (i = 0; i < size; i += 8) - val |= (uint32_t)*data++ << i; - - return val; -} - -static int file_archive_parse_file_iterate_step_internal( - file_archive_transfer_t *state, char *filename, - const uint8_t **cdata, - unsigned *cmode, uint32_t *size, uint32_t *csize, - uint32_t *checksum, unsigned *payback) -{ - uint32_t offset; - uint32_t namelength, extralength, commentlength, - offsetNL, offsetEL; - uint32_t signature = read_le(state->directory + 0, 4); - - if (signature != CENTRAL_FILE_HEADER_SIGNATURE) - return 0; - - *cmode = read_le(state->directory + 10, 2); - *checksum = read_le(state->directory + 16, 4); - *csize = read_le(state->directory + 20, 4); - *size = read_le(state->directory + 24, 4); - - namelength = read_le(state->directory + 28, 2); - extralength = read_le(state->directory + 30, 2); - commentlength = read_le(state->directory + 32, 2); - - if (namelength >= PATH_MAX_LENGTH) - return -1; - - memcpy(filename, state->directory + 46, namelength); - - offset = read_le(state->directory + 42, 4); - offsetNL = read_le(state->data + offset + 26, 2); - offsetEL = read_le(state->data + offset + 28, 2); - - *cdata = state->data + offset + 30 + offsetNL + offsetEL; - - *payback = 46 + namelength + extralength + commentlength; - - return 1; -} - -static int file_archive_parse_file_iterate_step(file_archive_transfer_t *state, - const char *valid_exts, void *userdata, file_archive_file_cb file_cb) -{ - const uint8_t *cdata = NULL; - uint32_t checksum = 0; - uint32_t size = 0; - uint32_t csize = 0; - unsigned cmode = 0; - unsigned payload = 0; - char filename[PATH_MAX_LENGTH] = {0}; - int ret = file_archive_parse_file_iterate_step_internal(state, filename, - &cdata, &cmode, &size, &csize, - &checksum, &payload); - - if (ret != 1) - return ret; - -#if 0 - RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + - offsetNL + offsetEL, csize, size); -#endif - - if (!file_cb(filename, valid_exts, cdata, cmode, - csize, size, checksum, userdata)) - return 0; - - state->directory += payload; - - return 1; -} - -static int file_archive_parse_file_init(file_archive_transfer_t *state, +int file_archive_parse_file_init(file_archive_transfer_t *state, const char *file) { - state->backend = file_archive_get_default_file_backend(); + char path[PATH_MAX_LENGTH] = {0}; + strlcpy(path, file, sizeof(path)); + + char *last = (char*)path_get_archive_delim(path); + + if (last) + *last = '\0'; + + state->backend = file_archive_get_file_backend(path); if (!state->backend) return -1; - state->handle = file_archive_open(file); + state->handle = file_archive_open(path); if (!state->handle) return -1; - state->zip_size = file_archive_size(state->handle); - if (state->zip_size < 22) - return -1; - + state->archive_size = file_archive_size(state->handle); state->data = file_archive_data(state->handle); - state->footer = state->data + state->zip_size - 22; + state->footer = 0; + state->directory = 0; - for (;; state->footer--) - { - if (state->footer <= state->data + 22) - return -1; - if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE) - { - unsigned comment_len = read_le(state->footer + 20, 2); - if (state->footer + 22 + comment_len == state->data + state->zip_size) - break; - } - } - - state->directory = state->data + read_le(state->footer + 16, 4); - - return 0; + return state->backend->archive_parse_file_init(state, path); } /** * file_archive_decompress_data_to_file: * @path : filename path of archive. - * @valid_exts : Valid extensions of archive to be parsed. + * @valid_exts : Valid extensions of archive to be parsed. * If NULL, allow all. * @cdata : input data. * @csize : size of input data. @@ -420,12 +313,6 @@ static int file_archive_decompress_data_to_file( uint32_t size, uint32_t checksum) { - if (handle) - { - handle->backend->stream_free(handle->stream); - free(handle->stream); - } - if (!handle || ret == -1) { ret = 0; @@ -434,12 +321,13 @@ static int file_archive_decompress_data_to_file( handle->real_checksum = handle->backend->stream_crc_calculate( 0, handle->data, size); + handle->backend->stream_free(handle->stream); #if 0 if (handle->real_checksum != checksum) { - /* File CRC difers from ZIP CRC. */ - printf("File CRC differs from ZIP CRC. File: 0x%x, ZIP: 0x%x.\n", + /* File CRC difers from archive CRC. */ + printf("File CRC differs from archive CRC. File: 0x%x, Archive: 0x%x.\n", (unsigned)handle->real_checksum, (unsigned)checksum); } #endif @@ -456,6 +344,15 @@ end: return ret; } +void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state) +{ + if (!state || !state->handle) + return; + + state->type = ARCHIVE_TRANSFER_DEINIT; + file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL); +} + int file_archive_parse_file_iterate( file_archive_transfer_t *state, bool *returnerr, @@ -469,58 +366,81 @@ int file_archive_parse_file_iterate( switch (state->type) { - case ZLIB_TRANSFER_NONE: + case ARCHIVE_TRANSFER_NONE: break; - case ZLIB_TRANSFER_INIT: + case ARCHIVE_TRANSFER_INIT: if (file_archive_parse_file_init(state, file) == 0) - state->type = ZLIB_TRANSFER_ITERATE; - else - state->type = ZLIB_TRANSFER_DEINIT_ERROR; - break; - case ZLIB_TRANSFER_ITERATE: { - int ret = file_archive_parse_file_iterate_step(state, - valid_exts, userdata, file_cb); - if (ret != 1) - state->type = ZLIB_TRANSFER_DEINIT; - if (ret == -1) - state->type = ZLIB_TRANSFER_DEINIT_ERROR; + struct archive_extract_userdata *data = + (struct archive_extract_userdata*)userdata; + if (data) + data->context = state->stream; + state->type = ARCHIVE_TRANSFER_ITERATE; + } + else + state->type = ARCHIVE_TRANSFER_DEINIT_ERROR; + break; + case ARCHIVE_TRANSFER_ITERATE: + { + const struct file_archive_file_backend *backend = file_archive_get_file_backend(file); + + if (backend) + { + int ret = backend->archive_parse_file_iterate_step(state, + valid_exts, userdata, file_cb); + if (ret != 1) + state->type = ARCHIVE_TRANSFER_DEINIT; + if (ret == -1) + state->type = ARCHIVE_TRANSFER_DEINIT_ERROR; + + // early return to prevent deinit from never firing + return 0; + } + else + return -1; } break; - case ZLIB_TRANSFER_DEINIT_ERROR: + case ARCHIVE_TRANSFER_DEINIT_ERROR: *returnerr = false; - case ZLIB_TRANSFER_DEINIT: + case ARCHIVE_TRANSFER_DEINIT: if (state->handle) + { file_archive_free(state->handle); - state->handle = NULL; + state->handle = NULL; + } + if (state->stream && state->backend) + { + struct archive_extract_userdata *data = + (struct archive_extract_userdata*)userdata; + state->backend->stream_free(state->stream); + + if (state->stream) + free(state->stream); + + state->stream = NULL; + + if (data) + data->context = NULL; + } break; } - if (state->type == ZLIB_TRANSFER_DEINIT || - state->type == ZLIB_TRANSFER_DEINIT_ERROR) + if (state->type == ARCHIVE_TRANSFER_DEINIT || + state->type == ARCHIVE_TRANSFER_DEINIT_ERROR) return -1; return 0; } -void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state) -{ - if (!state || !state->handle) - return; - - state->type = ZLIB_TRANSFER_DEINIT; - file_archive_parse_file_iterate(state, NULL, NULL, NULL, NULL, NULL); -} - /** * file_archive_parse_file: * @file : filename path of archive - * @valid_exts : Valid extensions of archive to be parsed. + * @valid_exts : Valid extensions of archive to be parsed. * If NULL, allow all. * @file_cb : file_cb function pointer * @userdata : userdata to pass to file_cb function pointer. * - * Low-level file parsing. Enumerates over all files and calls + * Low-level file parsing. Enumerates over all files and calls * file_cb with userdata. * * Returns: true (1) on success, otherwise false (0). @@ -531,7 +451,7 @@ static bool file_archive_parse_file(const char *file, const char *valid_exts, file_archive_transfer_t state = {0}; bool returnerr = true; - state.type = ZLIB_TRANSFER_INIT; + state.type = ARCHIVE_TRANSFER_INIT; for (;;) { @@ -547,33 +467,33 @@ int file_archive_parse_file_progress(file_archive_transfer_t *state) { /* FIXME: this estimate is worse than before */ ptrdiff_t delta = state->directory - state->data; - return delta * 100 / state->zip_size; + return delta * 100 / state->archive_size; } /** - * file_archive_extract_first_content_file: - * @zip_path : filename path to ZIP archive. - * @zip_path_size : size of ZIP archive. - * @valid_exts : valid extensions for a content file. + * file_archive_extract_first_file: + * @archive_path : filename path to archive. + * @archive_path_size : size of archive. + * @valid_exts : valid extensions for the file. * @extraction_directory : the directory to extract temporary - * unzipped content to. + * file to. * - * Extract first content file from archive. + * Extract first file from archive. * * Returns : true (1) on success, otherwise false (0). **/ -bool file_archive_extract_first_content_file( - char *zip_path, - size_t zip_path_size, +bool file_archive_extract_first_file( + char *archive_path, + size_t archive_path_size, const char *valid_exts, const char *extraction_directory, char *out_path, size_t len) { struct string_list *list = NULL; bool ret = true; - struct zip_extract_userdata userdata = {0}; + struct archive_extract_userdata userdata = {0}; - /* We cannot unzip if the libretro + /* We cannot extract if the libretro * implementation does not have any valid extensions. */ if (!valid_exts) return false; @@ -585,12 +505,14 @@ bool file_archive_extract_first_content_file( goto end; } - userdata.zip_path = zip_path; - userdata.zip_path_size = zip_path_size; + userdata.archive_path = archive_path; + userdata.archive_path_size = archive_path_size; userdata.extraction_directory = extraction_directory; userdata.ext = list; + userdata.list = NULL; + userdata.context = NULL; - if (!file_archive_parse_file(zip_path, valid_exts, + if (!file_archive_parse_file(archive_path, valid_exts, file_archive_extract_cb, &userdata)) { /* Parsing file archive failed. */ @@ -598,9 +520,9 @@ bool file_archive_extract_first_content_file( goto end; } - if (!userdata.found_content) + if (!userdata.found_file) { - /* Didn't find any content that matched valid extensions + /* Didn't find any file that matched valid extensions * for libretro implementation. */ ret = false; goto end; @@ -626,20 +548,22 @@ end: struct string_list *file_archive_get_file_list(const char *path, const char *valid_exts) { - struct string_list *list = string_list_new(); + struct archive_extract_userdata userdata = {0}; - if (!list) + userdata.list = string_list_new(); + + if (!userdata.list) goto error; if (!file_archive_parse_file(path, valid_exts, - file_archive_get_file_list_cb, list)) + file_archive_get_file_list_cb, &userdata)) goto error; - return list; + return userdata.list; error: - if (list) - string_list_free(list); + if (userdata.list) + string_list_free(userdata.list); return NULL; } @@ -649,16 +573,19 @@ bool file_archive_perform_mode(const char *path, const char *valid_exts, { switch (cmode) { - case ZLIB_MODE_UNCOMPRESSED: + case ARCHIVE_MODE_UNCOMPRESSED: if (!filestream_write_file(path, cdata, size)) goto error; break; - case ZLIB_MODE_DEFLATE: + case ARCHIVE_MODE_COMPRESSED: { int ret = 0; file_archive_file_handle_t handle = {0}; - handle.backend = file_archive_get_default_file_backend(); + struct archive_extract_userdata *data = (struct archive_extract_userdata*)userdata; + + handle.backend = file_archive_get_file_backend(data->archive_path); + handle.stream = data->context; if (!handle.backend->stream_decompress_data_to_file_init(&handle, cdata, csize, size)) @@ -685,7 +612,154 @@ error: return false; } -const struct file_archive_file_backend *file_archive_get_default_file_backend(void) +/* Generic compressed file loader. + * Extracts to buf, unless optional_filename != 0 + * Then extracts to optional_filename and leaves buf alone. + */ +int file_archive_compressed_read( + const char * path, void **buf, + const char* optional_filename, ssize_t *length) +{ + int ret = 0; + const char* file_ext = NULL; + struct string_list *str_list = file_archive_filename_split(path); + + /* Safety check. + * If optional_filename and optional_filename + * exists, we simply return 0, + * hoping that optional_filename is the + * same as requested. + */ + if (optional_filename && path_file_exists(optional_filename)) + { + *length = 0; + string_list_free(str_list); + return 1; + } + + /* We assure that there is something after the '#' symbol. + * + * This error condition happens for example, when + * path = /path/to/file.7z, or + * path = /path/to/file.7z# + */ + if (str_list->size <= 1) + goto error; + + const struct file_archive_file_backend *backend = + file_archive_get_file_backend(str_list->elems[0].data); + + *length = backend->compressed_file_read(str_list->elems[0].data, + str_list->elems[1].data, buf, optional_filename); + + if (*length != -1) + ret = 1; + + string_list_free(str_list); + return ret; + +error: + //RARCH_ERR("Could not extract string and substring from: %s.\n", path); + string_list_free(str_list); + *length = 0; + return 0; +} + +struct string_list *file_archive_file_list_new(const char *path, + const char* ext) +{ +#ifdef HAVE_COMPRESSION + const char* file_ext = path_get_extension(path); + +#ifdef HAVE_7ZIP + if (string_is_equal_noncase(file_ext, "7z")) + return file_archive_get_file_list(path, ext); +#endif +#ifdef HAVE_ZLIB + if (string_is_equal_noncase(file_ext, "zip")) + return file_archive_get_file_list(path, ext); +#endif +#endif + return NULL; +} + +/** + * file_archive_filename_split: + * @str : filename to turn into a string list + * + * Creates a new string list based on filename @path, delimited by a hash (#). + * + * Returns: new string list if successful, otherwise NULL. + */ +struct string_list *file_archive_filename_split(const char *path) +{ + union string_list_elem_attr attr; + struct string_list *list = string_list_new(); + const char *delim = NULL; + + memset(&attr, 0, sizeof(attr)); + + delim = path_get_archive_delim(path); + + if (delim) + { + /* add archive path to list first */ + if (!string_list_append_n(list, path, delim - path, attr)) + goto error; + + /* now add the path within the archive */ + delim++; + + if (*delim) + { + if (!string_list_append(list, delim, attr)) + goto error; + } + } + else + if (!string_list_append(list, path, attr)) + goto error; + + return list; + +error: + string_list_free(list); + return NULL; +} + +const struct file_archive_file_backend *file_archive_get_zlib_file_backend() { return &zlib_backend; } + +const struct file_archive_file_backend *file_archive_get_7z_file_backend() +{ + return &sevenzip_backend; +} + +const struct file_archive_file_backend* file_archive_get_file_backend(const char *path) +{ + const char *file_ext = NULL; + char newpath[PATH_MAX_LENGTH] = {0}; + + strlcpy(newpath, path, sizeof(newpath)); + + char *last = (char*)path_get_archive_delim(newpath); + + if (last) + *last = '\0'; + + file_ext = path_get_extension(newpath); + + if (string_is_equal_noncase(file_ext, "7z")) + { + return &sevenzip_backend; + } + + if (string_is_equal_noncase(file_ext, "zip")) + { + return &zlib_backend; + } + + return NULL; +} diff --git a/libretro-common/file/archive_file_7z.c b/libretro-common/file/archive_file_7z.c new file mode 100644 index 0000000000..f031898557 --- /dev/null +++ b/libretro-common/file/archive_file_7z.c @@ -0,0 +1,405 @@ +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (archive_file_sevenzip.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../deps/7zip/7z.h" +#include "../../deps/7zip/7zAlloc.h" +#include "../../deps/7zip/7zCrc.h" +#include "../../deps/7zip/7zFile.h" + +#define SEVENZIP_MAGIC "7z\xBC\xAF\x27\x1C" +#define SEVENZIP_MAGIC_LEN 6 + +struct sevenzip_context_t { + CFileInStream archiveStream; + CLookToRead lookStream; + ISzAlloc allocImp; + ISzAlloc allocTempImp; + CSzArEx db; + uint32_t index; + uint8_t *output; + file_archive_file_handle_t *handle; +}; + +static void* sevenzip_stream_new() +{ + struct sevenzip_context_t *sevenzip_context = + (struct sevenzip_context_t*)calloc(1, sizeof(struct sevenzip_context_t)); + + /* These are the allocation routines - currently using + * the non-standard 7zip choices. */ + sevenzip_context->allocImp.Alloc = SzAlloc; + sevenzip_context->allocImp.Free = SzFree; + sevenzip_context->allocTempImp.Alloc = SzAllocTemp; + sevenzip_context->allocTempImp.Free = SzFreeTemp; + + return sevenzip_context; +} + +static void sevenzip_stream_free(void *data) +{ + struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)data; + + if (!sevenzip_context) + return; + + SzArEx_Free(&sevenzip_context->db, &sevenzip_context->allocImp); + File_Close(&sevenzip_context->archiveStream.file); +} + +/* Extract the relative path (needle) from a 7z archive + * (path) and allocate a buf for it to write it in. + * If optional_outfile is set, extract to that instead + * and don't allocate buffer. + */ +static int sevenzip_file_read( + const char *path, + const char *needle, void **buf, + const char *optional_outfile) +{ + CFileInStream archiveStream; + CLookToRead lookStream; + ISzAlloc allocImp; + ISzAlloc allocTempImp; + CSzArEx db; + uint8_t *output = 0; + long outsize = -1; + + /*These are the allocation routines. + * Currently using the non-standard 7zip choices. */ + allocImp.Alloc = SzAlloc; + allocImp.Free = SzFree; + allocTempImp.Alloc = SzAllocTemp; + allocTempImp.Free = SzFreeTemp; + + if (InFile_Open(&archiveStream.file, path)) + { + //RARCH_ERR("Could not open %s as 7z archive\n.", path); + return -1; + } + + FileInStream_CreateVTable(&archiveStream); + LookToRead_CreateVTable(&lookStream, False); + lookStream.realStream = &archiveStream.s; + LookToRead_Init(&lookStream); + CrcGenerateTable(); + SzArEx_Init(&db); + + if (SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) == SZ_OK) + { + uint32_t i; + bool file_found = false; + uint16_t *temp = NULL; + size_t temp_size = 0; + uint32_t block_index = 0xFFFFFFFF; + SRes res = SZ_OK; + + for (i = 0; i < db.db.NumFiles; i++) + { + size_t len; + char infile[PATH_MAX_LENGTH] = {0}; + size_t offset = 0; + size_t outSizeProcessed = 0; + const CSzFileItem *f = db.db.Files + i; + + /* We skip over everything which is not a directory. + * FIXME: Why continue then if f->IsDir is true?*/ + if (f->IsDir) + continue; + + len = SzArEx_GetFileNameUtf16(&db, i, NULL); + + if (len > temp_size) + { + if (temp) + free(temp); + temp_size = len; + temp = (uint16_t *)malloc(temp_size * sizeof(temp[0])); + + if (temp == 0) + { + res = SZ_ERROR_MEM; + break; + } + } + + SzArEx_GetFileNameUtf16(&db, i, temp); + res = SZ_ERROR_FAIL; + if (temp) + res = utf16_to_char_string(temp, infile, sizeof(infile)) + ? SZ_OK : SZ_ERROR_FAIL; + + if (string_is_equal(infile, needle)) + { + size_t output_size = 0; + + /*RARCH_LOG_OUTPUT("Opened archive %s. Now trying to extract %s\n", + path, needle);*/ + + /* C LZMA SDK does not support chunked extraction - see here: + * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/ + * */ + file_found = true; + res = SzArEx_Extract(&db, &lookStream.s, i, &block_index, + &output, &output_size, &offset, &outSizeProcessed, + &allocImp, &allocTempImp); + + if (res != SZ_OK) + break; /* This goes to the error section. */ + + outsize = outSizeProcessed; + + if (optional_outfile != NULL) + { + const void *ptr = (const void*)(output + offset); + + if (!filestream_write_file(optional_outfile, ptr, outsize)) + { + /*RARCH_ERR("Could not open outfilepath %s.\n", + optional_outfile);*/ + res = SZ_OK; + file_found = true; + outsize = -1; + } + } + else + { + /*We could either use the 7Zip allocated buffer, + * or create our own and use it. + * We would however need to realloc anyways, because RetroArch + * expects a \0 at the end, therefore we allocate new, + * copy and free the old one. */ + *buf = malloc(outsize + 1); + ((char*)(*buf))[outsize] = '\0'; + memcpy(*buf,output + offset,outsize); + } + break; + } + } + + if (temp) + free(temp); + IAlloc_Free(&allocImp, output); + + if (!(file_found && res == SZ_OK)) + { + /* Error handling */ + /*if (!file_found) + RARCH_ERR("%s: %s in %s.\n", + msg_hash_to_str(MSG_FILE_NOT_FOUND), + needle, path);*/ + + //RARCH_ERR("Failed to open compressed file inside 7zip archive.\n"); + + outsize = -1; + } + } + + SzArEx_Free(&db, &allocImp); + File_Close(&archiveStream.file); + + return outsize; +} + +static bool sevenzip_stream_decompress_data_to_file_init( + file_archive_file_handle_t *handle, + const uint8_t *cdata, uint32_t csize, uint32_t size) +{ + struct sevenzip_context_t *sevenzip_context = + (struct sevenzip_context_t*)handle->stream; + + if (!sevenzip_context) + return false; + + sevenzip_context->handle = handle; + + return true; +} + +static int sevenzip_stream_decompress_data_to_file_iterate(void *data) +{ + struct sevenzip_context_t *sevenzip_context = + (struct sevenzip_context_t*)data; + + uint32_t block_index = 0xFFFFFFFF; + size_t offset = 0; + size_t outSizeProcessed = 0; + size_t output_size = 0; + + SRes res = SzArEx_Extract(&sevenzip_context->db, &sevenzip_context->lookStream.s, sevenzip_context->index, &block_index, + &sevenzip_context->output, &output_size, &offset, &outSizeProcessed, + &sevenzip_context->allocImp, &sevenzip_context->allocTempImp); + + if (res != SZ_OK) + return -1; + + if (sevenzip_context->handle) + sevenzip_context->handle->data = sevenzip_context->output; + + return 1; +} + +static int sevenzip_parse_file_init(file_archive_transfer_t *state, + const char *file) +{ + if (state->archive_size < SEVENZIP_MAGIC_LEN) + return -1; + + if (memcmp(state->data, SEVENZIP_MAGIC, SEVENZIP_MAGIC_LEN) != 0) + return -1; + + struct sevenzip_context_t *sevenzip_context = sevenzip_stream_new(); + + if (InFile_Open(&sevenzip_context->archiveStream.file, file)) + { + //RARCH_ERR("Could not open as 7zip archive: %s.\n",path); + return -1; + } + + FileInStream_CreateVTable(&sevenzip_context->archiveStream); + LookToRead_CreateVTable(&sevenzip_context->lookStream, False); + sevenzip_context->lookStream.realStream = &sevenzip_context->archiveStream.s; + LookToRead_Init(&sevenzip_context->lookStream); + CrcGenerateTable(); + SzArEx_Init(&sevenzip_context->db); + + SzArEx_Open(&sevenzip_context->db, &sevenzip_context->lookStream.s, &sevenzip_context->allocImp, &sevenzip_context->allocTempImp); + + state->stream = sevenzip_context; + + return 0; +} + +static int sevenzip_parse_file_iterate_step_internal( + file_archive_transfer_t *state, char *filename, + const uint8_t **cdata, + unsigned *cmode, uint32_t *size, uint32_t *csize, + uint32_t *checksum, unsigned *payback) +{ + struct sevenzip_context_t *sevenzip_context = (struct sevenzip_context_t*)state->stream; + const CSzFileItem *file = sevenzip_context->db.db.Files + sevenzip_context->index; + + if (sevenzip_context->index < sevenzip_context->db.db.NumFiles) + { + size_t len = SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->index, NULL); + uint64_t compressed_size = sevenzip_context->db.db.PackSizes[sevenzip_context->index]; + + if (len < PATH_MAX_LENGTH && !file->IsDir) + { + char infile[PATH_MAX_LENGTH] = {0}; + uint16_t *temp = (uint16_t*)malloc(len * sizeof(uint16_t)); + + if (!temp) + return -1; + + SzArEx_GetFileNameUtf16(&sevenzip_context->db, sevenzip_context->index, temp); + + SRes res = SZ_ERROR_FAIL; + + if (temp) + { + res = utf16_to_char_string(temp, infile, sizeof(infile)) + ? SZ_OK : SZ_ERROR_FAIL; + free(temp); + } + + if (res != SZ_OK) + return -1; + + strlcpy(filename, infile, sizeof(infile)); + + *cmode = ARCHIVE_MODE_COMPRESSED; + *checksum = file->Crc; + *size = file->Size; + *csize = compressed_size; + } + } + + *payback = 1; + + return 1; +} + +static int sevenzip_parse_file_iterate_step(file_archive_transfer_t *state, + const char *valid_exts, void *userdata, file_archive_file_cb file_cb) +{ + const uint8_t *cdata = NULL; + uint32_t checksum = 0; + uint32_t size = 0; + uint32_t csize = 0; + unsigned cmode = 0; + unsigned payload = 0; + char filename[PATH_MAX_LENGTH] = {0}; + int ret = sevenzip_parse_file_iterate_step_internal(state, filename, + &cdata, &cmode, &size, &csize, + &checksum, &payload); + + if (ret != 1) + return ret; + + if (!file_cb(filename, valid_exts, cdata, cmode, + csize, size, checksum, userdata)) + return 0; + + struct sevenzip_context_t *sevenzip_context = + (struct sevenzip_context_t*)state->stream; + + sevenzip_context->index += payload; + + return 1; +} + +static uint32_t sevenzip_stream_crc32_calculate(uint32_t crc, + const uint8_t *data, size_t length) +{ + return CrcUpdate(crc, data, length); +} + +const struct file_archive_file_backend sevenzip_backend = { + sevenzip_stream_new, + sevenzip_stream_free, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sevenzip_stream_decompress_data_to_file_init, + sevenzip_stream_decompress_data_to_file_iterate, + NULL, + NULL, + NULL, + sevenzip_stream_crc32_calculate, + sevenzip_file_read, + sevenzip_parse_file_init, + sevenzip_parse_file_iterate_step, + "7z" +}; diff --git a/libretro-common/file/archive_file_zlib.c b/libretro-common/file/archive_file_zlib.c index fd9fb281bc..dffd13fc9e 100644 --- a/libretro-common/file/archive_file_zlib.c +++ b/libretro-common/file/archive_file_zlib.c @@ -25,8 +25,18 @@ #include #include #include +#include +#include -static void *zlib_stream_new(void) +#ifndef CENTRAL_FILE_HEADER_SIGNATURE +#define CENTRAL_FILE_HEADER_SIGNATURE 0x02014b50 +#endif + +#ifndef END_OF_CENTRAL_DIR_SIGNATURE +#define END_OF_CENTRAL_DIR_SIGNATURE 0x06054b50 +#endif + +static void* zlib_stream_new(void) { return (z_stream*)calloc(1, sizeof(z_stream)); } @@ -138,7 +148,7 @@ static bool zlib_stream_decompress_data_to_file_init( if (!(handle->stream = (z_stream*)zlib_stream_new())) goto error; - + if (inflateInit2((z_streamp)handle->stream, -MAX_WBITS) != Z_OK) goto error; @@ -197,6 +207,265 @@ static uint32_t zlib_stream_crc32_calculate(uint32_t crc, return crc32(crc, data, length); } +struct decomp_state +{ + char *opt_file; + char *needle; + void **buf; + size_t size; + bool found; +}; + +static bool zip_file_decompressed_handle( + file_archive_file_handle_t *handle, + const uint8_t *cdata, uint32_t csize, + uint32_t size, uint32_t crc32) +{ + int ret = 0; + + handle->backend = &zlib_backend; + + if (!handle->backend->stream_decompress_data_to_file_init( + handle, cdata, csize, size)) + return false; + + do{ + ret = handle->backend->stream_decompress_data_to_file_iterate( + handle->stream); + }while(ret == 0); + + handle->real_checksum = handle->backend->stream_crc_calculate(0, + handle->data, size); + + if (handle->real_checksum != crc32) + { + //RARCH_ERR("%s\n", msg_hash_to_str(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32)); + goto error; + } + + if (handle->stream) + free(handle->stream); + + return true; + +error: + if (handle->stream) + free(handle->stream); + if (handle->data) + free(handle->data); + + handle->stream = NULL; + handle->data = NULL; + + return false; +} + +/* Extract the relative path (needle) from a + * ZIP archive (path) and allocate a buffer for it to write it in. + * + * optional_outfile if not NULL will be used to extract the file to. + * buf will be 0 then. + */ + +static int zip_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) +{ + struct decomp_state *st = (struct decomp_state*)userdata; + + /* Ignore directories. */ + if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\') + return 1; + + //RARCH_LOG("[deflate] Path: %s, CRC32: 0x%x\n", name, crc32); + + if (strstr(name, st->needle)) + { + bool goto_error = false; + file_archive_file_handle_t handle = {0}; + + st->found = true; + + if (zip_file_decompressed_handle(&handle, + cdata, csize, size, crc32)) + { + if (st->opt_file != 0) + { + /* Called in case core has need_fullpath enabled. */ + char *buf = (char*)malloc(size); + + if (buf) + { + /*RARCH_LOG("%s: %s\n", + msg_hash_to_str(MSG_EXTRACTING_FILE), + st->opt_file);*/ + memcpy(buf, handle.data, size); + + if (!filestream_write_file(st->opt_file, buf, size)) + goto_error = true; + } + + free(buf); + + st->size = 0; + } + else + { + /* Called in case core has need_fullpath disabled. + * Will copy decompressed content directly into + * RetroArch's ROM buffer. */ + *st->buf = malloc(size); + memcpy(*st->buf, handle.data, size); + + st->size = size; + } + } + + if (handle.data) + free(handle.data); + + if (goto_error) + return 0; + } + + return 1; +} + +static int zip_file_read( + const char *path, + const char *needle, void **buf, + const char *optional_outfile) +{ + file_archive_transfer_t zlib; + struct decomp_state st; + bool returnerr = true; + int ret = 0; + + zlib.type = ARCHIVE_TRANSFER_INIT; + + st.needle = NULL; + st.opt_file = NULL; + st.found = false; + st.buf = buf; + + if (needle) + st.needle = strdup(needle); + if (optional_outfile) + st.opt_file = strdup(optional_outfile); + + do + { + ret = file_archive_parse_file_iterate(&zlib, &returnerr, path, + "", zip_file_decompressed, &st); + if (!returnerr) + break; + }while(ret == 0 && !st.found); + + file_archive_parse_file_iterate_stop(&zlib); + + if (st.opt_file) + free(st.opt_file); + if (st.needle) + free(st.needle); + + if (!st.found) + return -1; + + return st.size; +} + +static int zip_parse_file_init(file_archive_transfer_t *state, + const char *file) +{ + if (state->archive_size < 22) + return -1; + + state->footer = state->data + state->archive_size - 22; + + for (;; state->footer--) + { + if (state->footer <= state->data + 22) + return -1; + if (read_le(state->footer, 4) == END_OF_CENTRAL_DIR_SIGNATURE) + { + unsigned comment_len = read_le(state->footer + 20, 2); + if (state->footer + 22 + comment_len == state->data + state->archive_size) + break; + } + } + + state->directory = state->data + read_le(state->footer + 16, 4); + + return 0; +} + +static int zip_parse_file_iterate_step_internal( + file_archive_transfer_t *state, char *filename, + const uint8_t **cdata, + unsigned *cmode, uint32_t *size, uint32_t *csize, + uint32_t *checksum, unsigned *payback) +{ + uint32_t offset; + uint32_t namelength, extralength, commentlength, + offsetNL, offsetEL; + uint32_t signature = read_le(state->directory + 0, 4); + + if (signature != CENTRAL_FILE_HEADER_SIGNATURE) + return 0; + + *cmode = read_le(state->directory + 10, 2); // compression mode, 0 = store, 8 = deflate + *checksum = read_le(state->directory + 16, 4); // CRC32 + *csize = read_le(state->directory + 20, 4); // compressed size + *size = read_le(state->directory + 24, 4); // uncompressed size + + namelength = read_le(state->directory + 28, 2); // file name length + extralength = read_le(state->directory + 30, 2); // extra field length + commentlength = read_le(state->directory + 32, 2); // file comment length + + if (namelength >= PATH_MAX_LENGTH) + return -1; + + memcpy(filename, state->directory + 46, namelength); // file name + + offset = read_le(state->directory + 42, 4); // relative offset of local file header + offsetNL = read_le(state->data + offset + 26, 2); // file name length + offsetEL = read_le(state->data + offset + 28, 2); // extra field length + + *cdata = state->data + offset + 30 + offsetNL + offsetEL; + + *payback = 46 + namelength + extralength + commentlength; + + return 1; +} + +static int zip_parse_file_iterate_step(file_archive_transfer_t *state, + const char *valid_exts, void *userdata, file_archive_file_cb file_cb) +{ + const uint8_t *cdata = NULL; + uint32_t checksum = 0; + uint32_t size = 0; + uint32_t csize = 0; + unsigned cmode = 0; + unsigned payload = 0; + char filename[PATH_MAX_LENGTH] = {0}; + int ret = zip_parse_file_iterate_step_internal(state, filename, + &cdata, &cmode, &size, &csize, + &checksum, &payload); + + if (ret != 1) + return ret; + + if (!file_cb(filename, valid_exts, cdata, cmode, + csize, size, checksum, userdata)) + return 0; + + state->directory += payload; + + return 1; +} + const struct file_archive_file_backend zlib_backend = { zlib_stream_new, zlib_stream_free, @@ -212,5 +481,8 @@ const struct file_archive_file_backend zlib_backend = { zlib_stream_compress_free, zlib_stream_compress_data_to_file, zlib_stream_crc32_calculate, + zip_file_read, + zip_parse_file_init, + zip_parse_file_iterate_step, "zlib" }; diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index ed8095fe7a..7f99e489d8 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -194,12 +194,12 @@ bool path_is_compressed_file(const char* path) const char *ext = path_get_extension(path); #ifdef HAVE_ZLIB - if (strcasestr(ext, "zip")) + if (string_is_equal_noncase(ext, "zip")) return true; #endif #ifdef HAVE_7ZIP - if (strcasestr(ext, "7z")) + if (string_is_equal_noncase(ext, "7z")) return true; #endif diff --git a/libretro-common/formats/png/rpng.c b/libretro-common/formats/png/rpng.c index 47abc04e4e..8844b44918 100644 --- a/libretro-common/formats/png/rpng.c +++ b/libretro-common/formats/png/rpng.c @@ -870,7 +870,7 @@ static struct rpng_process *rpng_process_init(rpng_t *rpng, unsigned *width, uns if (!process) return NULL; - process->stream_backend = file_archive_get_default_file_backend(); + process->stream_backend = file_archive_get_zlib_file_backend(); png_pass_geom(&rpng->ihdr, rpng->ihdr.width, rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size); diff --git a/libretro-common/formats/png/rpng_encode.c b/libretro-common/formats/png/rpng_encode.c index b164c15a66..7e47899ca8 100644 --- a/libretro-common/formats/png/rpng_encode.c +++ b/libretro-common/formats/png/rpng_encode.c @@ -48,7 +48,7 @@ static bool png_write_crc(RFILE *file, const uint8_t *data, size_t size) { uint8_t crc_raw[4] = {0}; const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); uint32_t crc = stream_backend->stream_crc_calculate(0, data, size); dword_write_be(crc_raw, crc); @@ -230,7 +230,7 @@ static bool rpng_save_image(const char *path, if (!file) GOTO_END_ERROR(); - stream_backend = file_archive_get_default_file_backend(); + stream_backend = file_archive_get_zlib_file_backend(); if (filestream_write(file, png_magic, sizeof(png_magic)) != sizeof(png_magic)) GOTO_END_ERROR(); diff --git a/libretro-common/include/encodings/utf.h b/libretro-common/include/encodings/utf.h index 88585bc228..da1000cb0e 100644 --- a/libretro-common/include/encodings/utf.h +++ b/libretro-common/include/encodings/utf.h @@ -42,4 +42,9 @@ const char *utf8skip(const char *str, size_t chars); uint32_t utf8_walk(const char **string); +bool utf16_to_char(uint8_t **utf_data, + size_t *dest_len, const uint16_t *in); + +bool utf16_to_char_string(const uint16_t *in, char *s, size_t len); + #endif diff --git a/libretro-common/include/file/archive_file.h b/libretro-common/include/file/archive_file.h index 1700718acd..5c429b9b1c 100644 --- a/libretro-common/include/file/archive_file.h +++ b/libretro-common/include/file/archive_file.h @@ -30,21 +30,56 @@ enum file_archive_transfer_type { - ZLIB_TRANSFER_NONE = 0, - ZLIB_TRANSFER_INIT, - ZLIB_TRANSFER_ITERATE, - ZLIB_TRANSFER_DEINIT, - ZLIB_TRANSFER_DEINIT_ERROR + ARCHIVE_TRANSFER_NONE = 0, + ARCHIVE_TRANSFER_INIT, + ARCHIVE_TRANSFER_ITERATE, + ARCHIVE_TRANSFER_DEINIT, + ARCHIVE_TRANSFER_DEINIT_ERROR }; typedef struct file_archive_handle { void *stream; - uint8_t *data; + uint8_t *data; uint32_t real_checksum; const struct file_archive_file_backend *backend; } file_archive_file_handle_t; +typedef struct file_archive_transfer +{ + void *handle; + void *stream; + const uint8_t *footer; + const uint8_t *directory; + const uint8_t *data; + int32_t archive_size; + enum file_archive_transfer_type type; + const struct file_archive_file_backend *backend; +} file_archive_transfer_t; + +enum file_archive_compression_mode +{ + ARCHIVE_MODE_UNCOMPRESSED = 0, + ARCHIVE_MODE_COMPRESSED = 8 +}; + +struct archive_extract_userdata +{ + char *archive_path; + char *first_extracted_file_path; + const char *extraction_directory; + size_t archive_path_size; + struct string_list *ext; + struct string_list *list; + bool found_file; + void *context; +}; + +/* Returns true when parsing should continue. False to stop. */ +typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts, + const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, + uint32_t crc32, void *userdata); + struct file_archive_file_backend { void *(*stream_new)(void); @@ -63,26 +98,19 @@ struct file_archive_file_backend void (*stream_compress_free)(void *); int (*stream_compress_data_to_file)(void *); uint32_t (*stream_crc_calculate)(uint32_t, const uint8_t *, size_t); + int (*compressed_file_read)(const char *path, const char *needle, void **buf, + const char *optional_outfile); + int (*archive_parse_file_init)( + file_archive_transfer_t *state, + const char *file); + int (*archive_parse_file_iterate_step)( + file_archive_transfer_t *state, + const char *valid_exts, + void *userdata, + file_archive_file_cb file_cb); const char *ident; }; -typedef struct file_archive_transfer -{ - void *handle; - const uint8_t *footer; - const uint8_t *directory; - const uint8_t *data; - int32_t zip_size; - enum file_archive_transfer_type type; - const struct file_archive_file_backend *backend; -} file_archive_transfer_t; - - -/* Returns true when parsing should continue. False to stop. */ -typedef int (*file_archive_file_cb)(const char *name, const char *valid_exts, - const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, - uint32_t crc32, void *userdata); - int file_archive_parse_file_iterate( file_archive_transfer_t *state, bool *returnerr, @@ -96,43 +124,60 @@ void file_archive_parse_file_iterate_stop(file_archive_transfer_t *state); int file_archive_parse_file_progress(file_archive_transfer_t *state); /** - * file_archive_extract_first_content_file: + * file_archive_extract_first_file: * @zip_path : filename path to ZIP archive. * @zip_path_size : size of ZIP archive. - * @valid_exts : valid extensions for a content file. + * @valid_exts : valid extensions for a file. * @extraction_directory : the directory to extract temporary - * unzipped content to. + * unzipped file to. * - * Extract first content file from archive. + * Extract first file from archive. * * Returns : true (1) on success, otherwise false (0). **/ -bool file_archive_extract_first_content_file(char *zip_path, size_t zip_path_size, +bool file_archive_extract_first_file(char *zip_path, size_t zip_path_size, const char *valid_exts, const char *extraction_dir, char *out_path, size_t len); /** * file_archive_get_file_list: * @path : filename path of archive - * @valid_exts : Valid extensions of archive to be parsed. + * @valid_exts : Valid extensions of archive to be parsed. * If NULL, allow all. * * Returns: string listing of files from archive on success, otherwise NULL. **/ -struct string_list *file_archive_get_file_list(const char *path, const char *valid_exts); +struct string_list* file_archive_get_file_list(const char *path, const char *valid_exts); bool file_archive_perform_mode(const char *name, const char *valid_exts, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size, uint32_t crc32, void *userdata); -struct string_list *compressed_file_list_new(const char *filename, - const char* ext); - void file_archive_deflate_init(void *data, int level); -const struct file_archive_file_backend *file_archive_get_default_file_backend(void); +int file_archive_compressed_read( + const char* path, void **buf, + const char* optional_filename, ssize_t *length); + +struct string_list* file_archive_file_list_new(const char *path, + const char *ext); + +struct string_list* file_archive_filename_split(const char *path); + +const uint8_t* file_archive_data(void *handle); + +int file_archive_parse_file_init(file_archive_transfer_t *state, + const char *file); + +void file_archive_free(void *handle); + +const struct file_archive_file_backend* file_archive_get_zlib_file_backend(void); +const struct file_archive_file_backend* file_archive_get_7z_file_backend(void); + +const struct file_archive_file_backend* file_archive_get_file_backend(const char *path); extern const struct file_archive_file_backend zlib_backend; +extern const struct file_archive_file_backend sevenzip_backend; #endif diff --git a/libretro-common/include/lists/string_list.h b/libretro-common/include/lists/string_list.h index 0079bd6d9b..48bffa8b34 100644 --- a/libretro-common/include/lists/string_list.h +++ b/libretro-common/include/lists/string_list.h @@ -44,7 +44,7 @@ struct string_list_elem union string_list_elem_attr attr; }; -struct string_list +struct __attribute__ ((aligned(1))) string_list { struct string_list_elem *elems; size_t size; @@ -138,7 +138,7 @@ void string_list_free(struct string_list *list); * @list : pointer to string list. * @delim : delimiter character for @list. * - * A string list will be joined/concatenated as a + * A string list will be joined/concatenated as a * string to @buffer, delimited by @delim. */ void string_list_join_concat(char *buffer, size_t size, diff --git a/libretro-common/include/retro_miscellaneous.h b/libretro-common/include/retro_miscellaneous.h index b133550bdc..37e2b368a6 100644 --- a/libretro-common/include/retro_miscellaneous.h +++ b/libretro-common/include/retro_miscellaneous.h @@ -33,7 +33,7 @@ #elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__) #include #elif defined(PSP) -#include +#include #elif defined(VITA) #include #elif defined(_3DS) @@ -159,6 +159,18 @@ static INLINE float db_to_gain(float db) return powf(10.0f, db / 20.0f); } +static INLINE uint32_t read_le(const uint8_t *data, unsigned size) +{ + unsigned i; + uint32_t val = 0; + + size *= 8; + for (i = 0; i < size; i += 8) + val |= (uint32_t)*data++ << i; + + return val; +} + /* Helper macros and struct to keep track of many booleans. * To check for multiple bits, use &&, not &. * For OR, | can be used. */ diff --git a/libretro-common/lists/string_list.c b/libretro-common/lists/string_list.c index 2e82d22a14..ae65eb0e20 100644 --- a/libretro-common/lists/string_list.c +++ b/libretro-common/lists/string_list.c @@ -186,7 +186,7 @@ void string_list_set(struct string_list *list, * @list : pointer to string list. * @delim : delimiter character for @list. * - * A string list will be joined/concatenated as a + * A string list will be joined/concatenated as a * string to @buffer, delimited by @delim. */ void string_list_join_concat(char *buffer, size_t size, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 0e435de683..7f452b4d22 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -3372,7 +3372,9 @@ static int menu_displaylist_parse_generic( filter_ext = true; if (path_is_compressed) - str_list = compressed_file_list_new(info->path, info->exts); + { + str_list = file_archive_file_list_new(info->path, info->exts); + } else str_list = dir_list_new(info->path, filter_ext ? info->exts : NULL, diff --git a/msg_hash.c b/msg_hash.c index b9de0ef781..d2f1f3a0e8 100644 --- a/msg_hash.c +++ b/msg_hash.c @@ -198,6 +198,8 @@ uint32_t msg_hash_calculate(const char *s) #define FILE_HASH_APK 0x0b885e61U +#define HASH_EXTENSION_7Z 0x005971d6U +#define HASH_EXTENSION_7Z_UPP 0x005971b6U #define HASH_EXTENSION_ZIP 0x0b88c7d8U #define HASH_EXTENSION_ZIP_UPP 0x0b883b78U #define HASH_EXTENSION_CUE 0x0b886782U @@ -211,6 +213,8 @@ enum msg_file_type msg_hash_to_file_type(uint32_t hash) switch (hash) { case MENU_VALUE_COMP: + case HASH_EXTENSION_7Z: + case HASH_EXTENSION_7Z_UPP: case HASH_EXTENSION_ZIP: case HASH_EXTENSION_ZIP_UPP: case FILE_HASH_APK: diff --git a/patch.c b/patch.c index 39794765a3..cadfecd94a 100644 --- a/patch.c +++ b/patch.c @@ -90,7 +90,7 @@ static uint8_t bps_read(struct bps_data *bps) uint8_t data = bps->modify_data[bps->modify_offset++]; #ifdef HAVE_ZLIB const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); bps->modify_checksum = ~stream_backend->stream_crc_calculate( ~bps->modify_checksum, &data, 1); #endif @@ -118,7 +118,7 @@ static void bps_write(struct bps_data *bps, uint8_t data) { #ifdef HAVE_ZLIB const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); #endif if (!bps) return; @@ -142,7 +142,7 @@ static enum patch_error bps_apply_patch( modify_modify_checksum = 0, checksum; #ifdef HAVE_ZLIB const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); #endif if (modify_length < 19) @@ -254,7 +254,7 @@ static uint8_t ups_patch_read(struct ups_data *data) { #ifdef HAVE_ZLIB const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); #endif if (data && data->patch_offset < data->patch_length) @@ -273,7 +273,7 @@ static uint8_t ups_source_read(struct ups_data *data) { #ifdef HAVE_ZLIB const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); #endif if (data && data->source_offset < data->source_length) @@ -292,7 +292,7 @@ static void ups_target_write(struct ups_data *data, uint8_t n) { #ifdef HAVE_ZLIB const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + file_archive_get_zlib_file_backend(); #endif if (data && data->target_offset < data->target_length) diff --git a/tasks/task_content.c b/tasks/task_content.c index 236f759def..985b00967c 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -90,18 +90,10 @@ #include "../paths.h" #include "../verbosity.h" -#ifdef HAVE_7ZIP -#include "../deps/7zip/7z.h" -#include "../deps/7zip/7zAlloc.h" -#include "../deps/7zip/7zCrc.h" -#include "../deps/7zip/7zFile.h" -#endif - #ifdef HAVE_CHEEVOS #include "../cheevos.h" #endif - typedef struct content_stream { uint32_t a; @@ -116,607 +108,6 @@ static bool _content_is_inited = false; static bool core_does_not_need_content = false; static uint32_t content_crc = 0; -#ifdef HAVE_COMPRESSION -/** - * filename_split_archive: - * @str : filename to turn into a string list - * - * Creates a new string list based on filename @path, delimited by a hash (#). - * - * Returns: new string list if successful, otherwise NULL. - */ -static struct string_list *filename_split_archive(const char *path) -{ - union string_list_elem_attr attr; - struct string_list *list = string_list_new(); - const char *delim = NULL; - - memset(&attr, 0, sizeof(attr)); - - delim = path_get_archive_delim(path); - - if (delim) - { - /* add archive path to list first */ - if (!string_list_append_n(list, path, delim - path, attr)) - goto error; - - /* now add the path within the archive */ - delim++; - - if (*delim) - { - if (!string_list_append(list, delim, attr)) - goto error; - } - } - else - if (!string_list_append(list, path, attr)) - goto error; - - return list; - -error: - string_list_free(list); - return NULL; -} - -#ifdef HAVE_7ZIP -static bool utf16_to_char(uint8_t **utf_data, - size_t *dest_len, const uint16_t *in) -{ - unsigned len = 0; - - while (in[len] != '\0') - len++; - - utf16_conv_utf8(NULL, dest_len, in, len); - *dest_len += 1; - *utf_data = (uint8_t*)malloc(*dest_len); - if (*utf_data == 0) - return false; - - return utf16_conv_utf8(*utf_data, dest_len, in, len); -} - -static bool utf16_to_char_string(const uint16_t *in, char *s, size_t len) -{ - size_t dest_len = 0; - uint8_t *utf16_data = NULL; - bool ret = utf16_to_char(&utf16_data, &dest_len, in); - - if (ret) - { - utf16_data[dest_len] = 0; - strlcpy(s, (const char*)utf16_data, len); - } - - free(utf16_data); - utf16_data = NULL; - - return ret; -} - -/* Extract the relative path (needle) from a 7z archive - * (path) and allocate a buf for it to write it in. - * If optional_outfile is set, extract to that instead - * and don't allocate buffer. - */ -static int content_7zip_file_read( - const char *path, - const char *needle, void **buf, - const char *optional_outfile) -{ - CFileInStream archiveStream; - CLookToRead lookStream; - ISzAlloc allocImp; - ISzAlloc allocTempImp; - CSzArEx db; - uint8_t *output = 0; - long outsize = -1; - - /*These are the allocation routines. - * Currently using the non-standard 7zip choices. */ - allocImp.Alloc = SzAlloc; - allocImp.Free = SzFree; - allocTempImp.Alloc = SzAllocTemp; - allocTempImp.Free = SzFreeTemp; - - if (InFile_Open(&archiveStream.file, path)) - { - RARCH_ERR("Could not open %s as 7z archive\n.", path); - return -1; - } - - FileInStream_CreateVTable(&archiveStream); - LookToRead_CreateVTable(&lookStream, False); - lookStream.realStream = &archiveStream.s; - LookToRead_Init(&lookStream); - CrcGenerateTable(); - SzArEx_Init(&db); - - if (SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) == SZ_OK) - { - uint32_t i; - bool file_found = false; - uint16_t *temp = NULL; - size_t temp_size = 0; - uint32_t block_index = 0xFFFFFFFF; - SRes res = SZ_OK; - - for (i = 0; i < db.db.NumFiles; i++) - { - size_t len; - char infile[PATH_MAX_LENGTH] = {0}; - size_t offset = 0; - size_t outSizeProcessed = 0; - const CSzFileItem *f = db.db.Files + i; - - /* We skip over everything which is not a directory. - * FIXME: Why continue then if f->IsDir is true?*/ - if (f->IsDir) - continue; - - len = SzArEx_GetFileNameUtf16(&db, i, NULL); - - if (len > temp_size) - { - free(temp); - temp_size = len; - temp = (uint16_t *)malloc(temp_size * sizeof(temp[0])); - - if (temp == 0) - { - res = SZ_ERROR_MEM; - break; - } - } - - SzArEx_GetFileNameUtf16(&db, i, temp); - res = SZ_ERROR_FAIL; - if (temp) - res = utf16_to_char_string(temp, infile, sizeof(infile)) - ? SZ_OK : SZ_ERROR_FAIL; - - if (string_is_equal(infile, needle)) - { - size_t output_size = 0; - - RARCH_LOG_OUTPUT("Opened archive %s. Now trying to extract %s\n", - path, needle); - - /* C LZMA SDK does not support chunked extraction - see here: - * sourceforge.net/p/sevenzip/discussion/45798/thread/6fb59aaf/ - * */ - file_found = true; - res = SzArEx_Extract(&db, &lookStream.s, i, &block_index, - &output, &output_size, &offset, &outSizeProcessed, - &allocImp, &allocTempImp); - - if (res != SZ_OK) - break; /* This goes to the error section. */ - - outsize = outSizeProcessed; - - if (optional_outfile != NULL) - { - const void *ptr = (const void*)(output + offset); - - if (!filestream_write_file(optional_outfile, ptr, outsize)) - { - RARCH_ERR("Could not open outfilepath %s.\n", - optional_outfile); - res = SZ_OK; - file_found = true; - outsize = -1; - } - } - else - { - /*We could either use the 7Zip allocated buffer, - * or create our own and use it. - * We would however need to realloc anyways, because RetroArch - * expects a \0 at the end, therefore we allocate new, - * copy and free the old one. */ - *buf = malloc(outsize + 1); - ((char*)(*buf))[outsize] = '\0'; - memcpy(*buf,output + offset,outsize); - } - break; - } - } - - free(temp); - IAlloc_Free(&allocImp, output); - - if (!(file_found && res == SZ_OK)) - { - /* Error handling */ - if (!file_found) - RARCH_ERR("%s: %s in %s.\n", - msg_hash_to_str(MSG_FILE_NOT_FOUND), - needle, path); - - RARCH_ERR("Failed to open compressed file inside 7zip archive.\n"); - - outsize = -1; - } - } - - SzArEx_Free(&db, &allocImp); - File_Close(&archiveStream.file); - - return outsize; -} - -static struct string_list *compressed_7zip_file_list_new( - const char *path, const char* ext) -{ - CFileInStream archiveStream; - CLookToRead lookStream; - ISzAlloc allocImp; - ISzAlloc allocTempImp; - CSzArEx db; - size_t temp_size = 0; - struct string_list *list = NULL; - - /* These are the allocation routines - currently using - * the non-standard 7zip choices. */ - allocImp.Alloc = SzAlloc; - allocImp.Free = SzFree; - allocTempImp.Alloc = SzAllocTemp; - allocTempImp.Free = SzFreeTemp; - - if (InFile_Open(&archiveStream.file, path)) - { - RARCH_ERR("Could not open as 7zip archive: %s.\n",path); - return NULL; - } - - list = string_list_new(); - - if (!list) - { - File_Close(&archiveStream.file); - return NULL; - } - - FileInStream_CreateVTable(&archiveStream); - LookToRead_CreateVTable(&lookStream, False); - lookStream.realStream = &archiveStream.s; - LookToRead_Init(&lookStream); - CrcGenerateTable(); - SzArEx_Init(&db); - - if (SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp) == SZ_OK) - { - uint32_t i; - struct string_list *ext_list = ext ? string_split(ext, "|"): NULL; - SRes res = SZ_OK; - uint16_t *temp = NULL; - - for (i = 0; i < db.db.NumFiles; i++) - { - union string_list_elem_attr attr; - char infile[PATH_MAX_LENGTH] = {0}; - const char *file_ext = NULL; - size_t len = 0; - bool supported_by_core = false; - const CSzFileItem *f = db.db.Files + i; - - /* we skip over everything, which is a directory. */ - if (f->IsDir) - continue; - - len = SzArEx_GetFileNameUtf16(&db, i, NULL); - - if (len > temp_size) - { - free(temp); - temp_size = len; - temp = (uint16_t *)malloc(temp_size * sizeof(temp[0])); - - if (temp == 0) - { - res = SZ_ERROR_MEM; - break; - } - } - - SzArEx_GetFileNameUtf16(&db, i, temp); - res = SZ_ERROR_FAIL; - - if (temp) - res = utf16_to_char_string(temp, infile, sizeof(infile)) - ? SZ_OK : SZ_ERROR_FAIL; - - file_ext = path_get_extension(infile); - - if (string_list_find_elem_prefix(ext_list, ".", file_ext)) - supported_by_core = true; - - /* - * Currently we only support files without subdirs in the archives. - * Folders are not supported (differences between win and lin. - * Archives within archives should imho never be supported. - */ - - if (!supported_by_core) - continue; - - attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE; - - if (!string_list_append(list, infile, attr)) - { - res = SZ_ERROR_MEM; - break; - } - } - - string_list_free(ext_list); - free(temp); - - if (res != SZ_OK) - { - /* Error handling */ - RARCH_ERR("Failed to open compressed_file: \"%s\"\n", path); - - string_list_free(list); - list = NULL; - } - } - - SzArEx_Free(&db, &allocImp); - File_Close(&archiveStream.file); - - return list; -} -#endif - -#ifdef HAVE_ZLIB -struct decomp_state -{ - char *opt_file; - char *needle; - void **buf; - size_t size; - bool found; -}; - -static bool content_zip_file_decompressed_handle( - file_archive_file_handle_t *handle, - const uint8_t *cdata, uint32_t csize, - uint32_t size, uint32_t crc32) -{ - int ret = 0; - - handle->backend = file_archive_get_default_file_backend(); - - if (!handle->backend) - goto error; - - if (!handle->backend->stream_decompress_data_to_file_init( - handle, cdata, csize, size)) - return false; - - do{ - ret = handle->backend->stream_decompress_data_to_file_iterate( - handle->stream); - }while(ret == 0); - - handle->real_checksum = handle->backend->stream_crc_calculate(0, - handle->data, size); - - if (handle->real_checksum != crc32) - { - RARCH_ERR("%s\n", - msg_hash_to_str(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32)); - goto error; - } - - if (handle->stream) - free(handle->stream); - - return true; - -error: - if (handle->stream) - free(handle->stream); - if (handle->data) - free(handle->data); - - return false; -} - -/* Extract the relative path (needle) from a - * ZIP archive (path) and allocate a buffer for it to write it in. - * - * optional_outfile if not NULL will be used to extract the file to. - * buf will be 0 then. - */ - -static int content_zip_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) -{ - struct decomp_state *st = (struct decomp_state*)userdata; - - /* Ignore directories. */ - if (name[strlen(name) - 1] == '/' || name[strlen(name) - 1] == '\\') - return 1; - - RARCH_LOG("[deflate] Path: %s, CRC32: 0x%x\n", name, crc32); - - if (strstr(name, st->needle)) - { - bool goto_error = false; - file_archive_file_handle_t handle = {0}; - - st->found = true; - - if (content_zip_file_decompressed_handle(&handle, - cdata, csize, size, crc32)) - { - if (st->opt_file != 0) - { - /* Called in case core has need_fullpath enabled. */ - char *buf = (char*)malloc(size); - - if (buf) - { - RARCH_LOG("%s: %s\n", - msg_hash_to_str(MSG_EXTRACTING_FILE), - st->opt_file); - memcpy(buf, handle.data, size); - - if (!filestream_write_file(st->opt_file, buf, size)) - goto_error = true; - } - - free(buf); - - st->size = 0; - } - else - { - /* Called in case core has need_fullpath disabled. - * Will copy decompressed content directly into - * RetroArch's ROM buffer. */ - *st->buf = malloc(size); - memcpy(*st->buf, handle.data, size); - - st->size = size; - } - } - - if (handle.data) - free(handle.data); - - if (goto_error) - return 0; - } - - return 1; -} - -static int content_zip_file_read( - const char *path, - const char *needle, void **buf, - const char* optional_outfile) -{ - file_archive_transfer_t zlib; - struct decomp_state st; - bool returnerr = true; - int ret = 0; - - zlib.type = ZLIB_TRANSFER_INIT; - - st.needle = NULL; - st.opt_file = NULL; - st.found = false; - st.buf = buf; - - if (needle) - st.needle = strdup(needle); - if (optional_outfile) - st.opt_file = strdup(optional_outfile); - - do - { - ret = file_archive_parse_file_iterate(&zlib, &returnerr, path, - "", content_zip_file_decompressed, &st); - if (!returnerr) - break; - }while(ret == 0 && !st.found); - - file_archive_parse_file_iterate_stop(&zlib); - - if (st.opt_file) - free(st.opt_file); - if (st.needle) - free(st.needle); - - if (!st.found) - return -1; - - return st.size; -} -#endif - -#endif - -#ifdef HAVE_COMPRESSION -/* Generic compressed file loader. - * Extracts to buf, unless optional_filename != 0 - * Then extracts to optional_filename and leaves buf alone. - */ -static int content_file_compressed_read( - const char * path, void **buf, - const char* optional_filename, ssize_t *length) -{ - int ret = 0; - const char* file_ext = NULL; - struct string_list *str_list = filename_split_archive(path); - - /* Safety check. - * If optional_filename and optional_filename - * exists, we simply return 0, - * hoping that optional_filename is the - * same as requested. - */ - if (optional_filename && path_file_exists(optional_filename)) - { - *length = 0; - string_list_free(str_list); - return 1; - } - - /* We assure that there is something after the '#' symbol. - * - * This error condition happens for example, when - * path = /path/to/file.7z, or - * path = /path/to/file.7z# - */ - if (str_list->size <= 1) - goto error; - -#if defined(HAVE_7ZIP) || defined(HAVE_ZLIB) - file_ext = path_get_extension(str_list->elems[0].data); -#endif - -#ifdef HAVE_7ZIP - if (string_is_equal_noncase(file_ext, "7z")) - { - *length = content_7zip_file_read(str_list->elems[0].data, - str_list->elems[1].data, buf, optional_filename); - if (*length != -1) - ret = 1; - } -#endif -#ifdef HAVE_ZLIB - if (string_is_equal_noncase(file_ext, "zip")) - { - *length = content_zip_file_read(str_list->elems[0].data, - str_list->elems[1].data, buf, optional_filename); - if (*length != -1) - ret = 1; - } -#endif - - string_list_free(str_list); - return ret; - -error: - RARCH_ERR("Could not extract string and substring from " - ": %s.\n", path); - string_list_free(str_list); - *length = 0; - return 0; -} -#endif - /** * content_file_read: * @path : path to file. @@ -724,7 +115,7 @@ error: * file into. Needs to be freed manually. * @length : Number of items read, -1 on error. * - * Read the contents of a file into @buf. Will call content_file_compressed_read + * Read the contents of a file into @buf. Will call file_archive_compressed_read * if path contains a compressed file, otherwise will call filestream_read_file(). * * Returns: 1 if file read, 0 on error. @@ -734,31 +125,13 @@ static int content_file_read(const char *path, void **buf, ssize_t *length) #ifdef HAVE_COMPRESSION if (path_contains_compressed_file(path)) { - if (content_file_compressed_read(path, buf, NULL, length)) + if (file_archive_compressed_read(path, buf, NULL, length)) return 1; } #endif return filestream_read_file(path, buf, length); } -struct string_list *compressed_file_list_new(const char *path, - const char* ext) -{ -#if defined(HAVE_ZLIB) || defined(HAVE_7ZIP) - const char* file_ext = path_get_extension(path); -#endif - -#ifdef HAVE_7ZIP - if (string_is_equal_noncase(file_ext, "7z")) - return compressed_7zip_file_list_new(path,ext); -#endif -#ifdef HAVE_ZLIB - if (string_is_equal_noncase(file_ext, "zip")) - return file_archive_get_file_list(path, ext); -#endif - return NULL; -} - static void check_defaults_dir_create_dir(const char *path) { char new_path[PATH_MAX_LENGTH] = {0}; @@ -939,7 +312,7 @@ static void content_load_init_wrap( * If no content file can be loaded, will start up RetroArch * as-is. * - * Returns: false (0) if retroarch_main_init failed, + * Returns: false (0) if retroarch_main_init failed, * otherwise true (1). **/ static bool content_load(content_ctx_info_t *info) @@ -1046,7 +419,7 @@ static bool read_content_file(unsigned i, const char *path, void **buf, stream_info.c = *length; if (!stream_backend) - stream_backend = file_archive_get_default_file_backend(); + stream_backend = file_archive_get_zlib_file_backend(); stream_info.crc = stream_backend->stream_crc_calculate( stream_info.a, stream_info.b, stream_info.c); *content_crc_ptr = stream_info.crc; @@ -1167,7 +540,7 @@ static bool load_content_from_compressed_archive( fill_pathname_join(new_path, new_basedir, path_basename(path), sizeof(new_path)); - ret = content_file_compressed_read(path, NULL, new_path, &new_path_len); + ret = file_archive_compressed_read(path, NULL, new_path, &new_path_len); if (!ret || new_path_len < 0) { @@ -1178,7 +551,7 @@ static bool load_content_from_compressed_archive( } string_list_append(additional_path_allocs, new_path, attributes); - info[i].path = + info[i].path = additional_path_allocs->elems[additional_path_allocs->size -1 ].data; if (!string_list_append(temporary_content, new_path, attributes)) @@ -1281,7 +654,7 @@ static const struct retro_subsystem_info *init_content_file_subsystem( bool *ret, rarch_system_info_t *system) { global_t *global = global_get_ptr(); - const struct retro_subsystem_info *special = + const struct retro_subsystem_info *special = libretro_find_subsystem_info(system->subsystem.data, system->subsystem.size, global->subsystem); @@ -1326,7 +699,7 @@ error: return NULL; } -#ifdef HAVE_ZLIB +#ifdef HAVE_COMPRESSION static bool init_content_file_extract( struct string_list *temporary_content, struct string_list *content, @@ -1340,52 +713,49 @@ static bool init_content_file_extract( for (i = 0; i < content->size; i++) { - const char *ext = NULL; + bool compressed = NULL; const char *valid_ext = system->info.valid_extensions; /* Block extract check. */ if (content->elems[i].attr.i & 1) continue; - ext = path_get_extension(content->elems[i].data); + compressed = path_contains_compressed_file(content->elems[i].data); if (special) valid_ext = special->roms[i].valid_extensions; - if (!ext) + if (!compressed) continue; - if (string_is_equal_noncase(ext, "zip")) + char new_path[PATH_MAX_LENGTH] = {0}; + char temp_content[PATH_MAX_LENGTH] = {0}; + + strlcpy(temp_content, content->elems[i].data, + sizeof(temp_content)); + + if (!file_archive_extract_first_file(temp_content, + sizeof(temp_content), valid_ext, + *settings->directory.cache ? + settings->directory.cache : NULL, + new_path, sizeof(new_path))) { - char new_path[PATH_MAX_LENGTH] = {0}; - char temp_content[PATH_MAX_LENGTH] = {0}; - - strlcpy(temp_content, content->elems[i].data, - sizeof(temp_content)); - - if (!file_archive_extract_first_content_file(temp_content, - sizeof(temp_content), valid_ext, - *settings->directory.cache ? - settings->directory.cache : NULL, - new_path, sizeof(new_path))) - { - RARCH_ERR("%s: %s.\n", - msg_hash_to_str( - MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE), - temp_content); - runloop_msg_queue_push( - msg_hash_to_str(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE) - , 2, 180, true); - return false; - } - - string_list_set(content, i, new_path); - if (!string_list_append(temporary_content, - new_path, *attr)) - return false; + RARCH_ERR("%s: %s.\n", + msg_hash_to_str( + MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE), + temp_content); + runloop_msg_queue_push( + msg_hash_to_str(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE) + , 2, 180, true); + return false; } + + string_list_set(content, i, new_path); + if (!string_list_append(temporary_content, + new_path, *attr)) + return false; } - + return true; } #endif @@ -1435,7 +805,7 @@ static bool init_content_file_set_attribs( } } -#ifdef HAVE_ZLIB +#ifdef HAVE_COMPRESSION /* Try to extract all content we're going to load if appropriate. */ if (!init_content_file_extract(temporary_content, content, system, special, &attr)) @@ -1486,7 +856,7 @@ static bool content_file_init(struct string_list *temporary_content) additional_path_allocs = string_list_new(); ret = load_content(temporary_content, - info, content, special, additional_path_allocs); + info, content, special, additional_path_allocs); for (i = 0; i < content->size; i++) free((void*)info[i].data); @@ -1580,7 +950,6 @@ error: return false; } - #ifdef HAVE_MENU static void menu_content_environment_get(int *argc, char *argv[], void *args, void *params_data) @@ -1628,7 +997,7 @@ static void menu_content_environment_get(int *argc, char *argv[], * * Returns: true (1) if successful, otherwise false (0). **/ -static bool task_load_content(content_ctx_info_t *content_info, +static bool task_load_content(content_ctx_info_t *content_info, bool launched_from_menu, enum content_mode_load mode) { @@ -1652,7 +1021,7 @@ static bool task_load_content(content_ctx_info_t *content_info, /** Show loading OSD message */ if (!string_is_empty(fullpath)) { - snprintf(msg, sizeof(msg), "%s %s ...", + snprintf(msg, sizeof(msg), "%s %s ...", msg_hash_to_str(MSG_LOADING), name); runloop_msg_queue_push(msg, 2, 1, true); @@ -1723,7 +1092,7 @@ static bool task_load_content(content_ctx_info_t *content_info, break; } - if (content_push_to_history_playlist(playlist_tmp, tmp, + if (content_push_to_history_playlist(playlist_tmp, tmp, core_name, core_path)) playlist_write_file(playlist_tmp); } @@ -1905,7 +1274,7 @@ bool task_push_content_load_default( break; } - /* On targets that have no dynamic core loading support, we'd + /* On targets that have no dynamic core loading support, we'd * execute the new core from this point. If this returns false, * we assume we can dynamically load the core. */ switch (mode) @@ -1943,7 +1312,7 @@ bool task_push_content_load_default( /* Fork core? */ switch (mode) { - case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: + case CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU: if (!frontend_driver_set_fork(FRONTEND_FORK_CORE)) return false; break; @@ -1952,7 +1321,7 @@ bool task_push_content_load_default( } #endif - /* Preliminary stuff that has to be done before we + /* Preliminary stuff that has to be done before we * load the actual content. Can differ per mode. */ switch (mode) { diff --git a/tasks/task_database.c b/tasks/task_database.c index f8e6fd57da..4031bbf930 100644 --- a/tasks/task_database.c +++ b/tasks/task_database.c @@ -47,9 +47,9 @@ typedef struct database_state_handle size_t list_index; size_t entry_index; uint32_t crc; - uint32_t zip_crc; + uint32_t archive_crc; uint8_t *buf; - char zip_name[PATH_MAX_LENGTH]; + char archive_name[PATH_MAX_LENGTH]; char serial[4096]; } database_state_handle_t; @@ -69,10 +69,10 @@ static int zlib_compare_crc32(const char *name, const char *valid_exts, uint32_t crc32, void *userdata) { database_state_handle_t *db_state = (database_state_handle_t*)userdata; - + db_state->crc = crc32; - strlcpy(db_state->zip_name, name, sizeof(db_state->zip_name)); + strlcpy(db_state->archive_name, name, sizeof(db_state->archive_name)); #if 0 RARCH_LOG("Going to compare CRC 0x%x for %s\n", crc32, name); @@ -145,7 +145,7 @@ static int cue_get_serial(database_state_handle_t *db_state, char track_path[PATH_MAX_LENGTH] = {0}; int rv = find_first_data_track(name, &offset, track_path, PATH_MAX_LENGTH); - + if (rv < 0) { RARCH_LOG("%s: %s\n", @@ -167,8 +167,8 @@ static bool file_get_crc(database_state_handle_t *db_state, name, (void**)&db_state->buf, &ret); #ifdef HAVE_ZLIB - const struct file_archive_file_backend *stream_backend = - file_archive_get_default_file_backend(); + const struct file_archive_file_backend *stream_backend = + file_archive_get_zlib_file_backend(); #endif if (read_from != 1 || ret <= 0) @@ -193,12 +193,12 @@ static int task_database_iterate_playlist( switch (msg_hash_to_file_type(msg_hash_calculate(path_get_extension(name)))) { case FILE_TYPE_COMPRESSED: -#ifdef HAVE_ZLIB - db->type = DATABASE_TYPE_ITERATE_ZIP; +#ifdef HAVE_COMPRESSION + db->type = DATABASE_TYPE_ITERATE_ARCHIVE; memset(&db->state, 0, sizeof(file_archive_transfer_t)); - db_state->zip_name[0] = '\0'; - db->state.type = ZLIB_TRANSFER_INIT; - return file_get_crc(db_state, name, &db_state->zip_crc); + db_state->archive_name[0] = '\0'; + db->state.type = ARCHIVE_TRANSFER_INIT; + return file_get_crc(db_state, name, &db_state->archive_crc); #else break; #endif @@ -226,7 +226,7 @@ static int task_database_iterate_playlist( static int database_info_list_iterate_end_no_match( database_state_handle_t *db_state) { - /* Reached end of database list, + /* Reached end of database list, * CRC match probably didn't succeed. */ db_state->list_index = 0; db_state->entry_index = 0; @@ -251,7 +251,7 @@ static int database_info_list_iterate_new(database_state_handle_t *db_state, { const char *new_database = db_state->list->elems[db_state->list_index].data; #if 0 - RARCH_LOG("Check database [%d/%d] : %s\n", (unsigned)db_state->list_index, + RARCH_LOG("Check database [%d/%d] : %s\n", (unsigned)db_state->list_index, (unsigned)db_state->list->size, new_database); #endif if (db_state->info) @@ -263,7 +263,7 @@ static int database_info_list_iterate_new(database_state_handle_t *db_state, static int database_info_list_iterate_found_match( database_state_handle_t *db_state, database_info_handle_t *db, - const char *zip_name + const char *archive_name ) { char db_crc[PATH_MAX_LENGTH] = {0}; @@ -272,11 +272,11 @@ static int database_info_list_iterate_found_match( char entry_path_str[PATH_MAX_LENGTH] = {0}; playlist_t *playlist = NULL; settings_t *settings = config_get_ptr(); - const char *db_path = + const char *db_path = db_state->list->elems[db_state->list_index].data; - const char *entry_path = db ? + const char *entry_path = db ? db->list->elems[db->list_ptr].data : NULL; - database_info_t *db_info_entry = + database_info_t *db_info_entry = &db_state->info->list[db_state->entry_index]; fill_short_pathname_representation_noext(db_playlist_base_str, @@ -296,8 +296,8 @@ static int database_info_list_iterate_found_match( if (entry_path) strlcpy(entry_path_str, entry_path, sizeof(entry_path_str)); - if (!string_is_empty(zip_name)) - fill_pathname_join_delim(entry_path_str, entry_path_str, zip_name, + if (!string_is_empty(archive_name)) + fill_pathname_join_delim(entry_path_str, entry_path_str, archive_name, '#', sizeof(entry_path_str)); #if 0 @@ -308,7 +308,7 @@ static int database_info_list_iterate_found_match( RARCH_LOG("Playlist Path: %s\n", db_playlist_path); RARCH_LOG("Entry Path: %s\n", entry_path); RARCH_LOG("Playlist not NULL: %d\n", playlist != NULL); - RARCH_LOG("ZIP entry: %s\n", zip_name); + RARCH_LOG("ZIP entry: %s\n", archive_name); RARCH_LOG("entry path str: %s\n", entry_path_str); #endif @@ -332,7 +332,7 @@ static int database_info_list_iterate_found_match( return 0; } -/* End of entries in database info list and didn't find a +/* End of entries in database info list and didn't find a * match, go to the next database. */ static int database_info_list_iterate_next( database_state_handle_t *db_state @@ -353,7 +353,7 @@ static int task_database_iterate_crc_lookup( const char *zip_entry) { - if (!db_state->list || + if (!db_state->list || (unsigned)db_state->list_index == (unsigned)db_state->list->size) return database_info_list_iterate_end_no_match(db_state); @@ -362,14 +362,14 @@ static int task_database_iterate_crc_lookup( char query[50] = {0}; snprintf(query, sizeof(query), "{crc:or(b\"%08X\",b\"%08X\")}", - swap_if_big32(db_state->crc), swap_if_big32(db_state->zip_crc)); + swap_if_big32(db_state->crc), swap_if_big32(db_state->archive_crc)); database_info_list_iterate_new(db_state, query); } if (db_state->info) { - database_info_t *db_info_entry = + database_info_t *db_info_entry = &db_state->info->list[db_state->entry_index]; if (db_info_entry && db_info_entry->crc32) @@ -378,7 +378,7 @@ static int task_database_iterate_crc_lookup( RARCH_LOG("CRC32: 0x%08X , entry CRC32: 0x%08X (%s).\n", db_state->crc, db_info_entry->crc32, db_info_entry->name); #endif - if (db_state->zip_crc == db_info_entry->crc32) + if (db_state->archive_crc == db_info_entry->crc32) return database_info_list_iterate_found_match( db_state, db, NULL); if (db_state->crc == db_info_entry->crc32) @@ -404,7 +404,7 @@ static int task_database_iterate_crc_lookup( return 0; } -static int task_database_iterate_playlist_zip( +static int task_database_iterate_playlist_archive( database_state_handle_t *db_state, database_info_handle_t *db, const char *name) { @@ -412,7 +412,7 @@ static int task_database_iterate_playlist_zip( #ifdef HAVE_ZLIB if (db_state->crc != 0) return task_database_iterate_crc_lookup( - db_state, db, db_state->zip_name); + db_state, db, db_state->archive_name); if (file_archive_parse_file_iterate(&db->state, &returnerr, name, NULL, zlib_compare_crc32, @@ -468,14 +468,14 @@ static int task_database_iterate_serial_lookup( database_state_handle_t *db_state, database_info_handle_t *db, const char *name) { - if (!db_state->list || + if (!db_state->list || (unsigned)db_state->list_index == (unsigned)db_state->list->size) return database_info_list_iterate_end_no_match(db_state); if (db_state->entry_index == 0) { char query[50] = {0}; - char *serial_buf = + char *serial_buf = bin_to_hex_alloc((uint8_t*)db_state->serial, 10 * sizeof(uint8_t)); if (!serial_buf) @@ -536,8 +536,8 @@ static int task_database_iterate(database_state_handle_t *db_state, { case DATABASE_TYPE_ITERATE: return task_database_iterate_playlist(db_state, db, name); - case DATABASE_TYPE_ITERATE_ZIP: - return task_database_iterate_playlist_zip(db_state, db, name); + case DATABASE_TYPE_ITERATE_ARCHIVE: + return task_database_iterate_playlist_archive(db_state, db, name); case DATABASE_TYPE_ITERATE_LUTRO: return task_database_iterate_playlist_lutro(db_state, db, name); case DATABASE_TYPE_SERIAL_LOOKUP: @@ -569,7 +569,7 @@ static void task_database_handler(retro_task_t *task) db_handle_t *db = (db_handle_t*)task->state; database_info_handle_t *dbinfo = db->handle; database_state_handle_t *dbstate = &db->state; - const char *name = dbinfo ? + const char *name = dbinfo ? dbinfo->list->elems[dbinfo->list_ptr].data : NULL; if (!dbinfo || task->cancelled) diff --git a/tasks/task_decompress.c b/tasks/task_decompress.c index d230397c20..0427cc1670 100644 --- a/tasks/task_decompress.c +++ b/tasks/task_decompress.c @@ -35,7 +35,7 @@ typedef struct char *callback_error; - file_archive_transfer_t zlib; + file_archive_transfer_t archive; } decompress_state_t; static int file_decompressed_target_file(const char *name, @@ -159,16 +159,16 @@ static void task_decompress_handler(retro_task_t *task) { bool retdec = false; decompress_state_t *dec = (decompress_state_t*)task->state; - int ret = file_archive_parse_file_iterate(&dec->zlib, + int ret = file_archive_parse_file_iterate(&dec->archive, &retdec, dec->source_file, dec->valid_ext, file_decompressed, dec); - task->progress = file_archive_parse_file_progress(&dec->zlib); + task->progress = file_archive_parse_file_progress(&dec->archive); if (task->cancelled || ret != 0) { task->error = dec->callback_error; - file_archive_parse_file_iterate_stop(&dec->zlib); + file_archive_parse_file_iterate_stop(&dec->archive); task_decompress_handler_finished(task, dec); } @@ -178,16 +178,16 @@ static void task_decompress_handler_target_file(retro_task_t *task) { bool retdec; decompress_state_t *dec = (decompress_state_t*)task->state; - int ret = file_archive_parse_file_iterate(&dec->zlib, + int ret = file_archive_parse_file_iterate(&dec->archive, &retdec, dec->source_file, dec->valid_ext, file_decompressed_target_file, dec); - task->progress = file_archive_parse_file_progress(&dec->zlib); + task->progress = file_archive_parse_file_progress(&dec->archive); if (task->cancelled || ret != 0) { task->error = dec->callback_error; - file_archive_parse_file_iterate_stop(&dec->zlib); + file_archive_parse_file_iterate_stop(&dec->archive); task_decompress_handler_finished(task, dec); } @@ -197,16 +197,16 @@ static void task_decompress_handler_subdir(retro_task_t *task) { bool retdec; decompress_state_t *dec = (decompress_state_t*)task->state; - int ret = file_archive_parse_file_iterate(&dec->zlib, + int ret = file_archive_parse_file_iterate(&dec->archive, &retdec, dec->source_file, dec->valid_ext, file_decompressed_subdir, dec); - task->progress = file_archive_parse_file_progress(&dec->zlib); + task->progress = file_archive_parse_file_progress(&dec->archive); if (task->cancelled || ret != 0) { task->error = dec->callback_error; - file_archive_parse_file_iterate_stop(&dec->zlib); + file_archive_parse_file_iterate_stop(&dec->archive); task_decompress_handler_finished(task, dec); } @@ -286,7 +286,7 @@ bool task_push_decompress( s->target_dir = strdup(target_dir); s->valid_ext = valid_ext ? strdup(valid_ext) : NULL; - s->zlib.type = ZLIB_TRANSFER_INIT; + s->archive.type = ARCHIVE_TRANSFER_INIT; t = (retro_task_t*)calloc(1, sizeof(*t));