mirror of
https://github.com/libretro/RetroArch
synced 2025-02-01 00:32:46 +00:00
create 7z archive backend, enables scanning of 7z content
This commit is contained in:
parent
0c48555ba2
commit
cb885f9c20
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 },
|
||||
|
@ -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;
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -45,30 +45,7 @@
|
||||
#include <retro_stat.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <lists/string_list.h>
|
||||
|
||||
#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 <string/stdstring.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
405
libretro-common/file/archive_file_7z.c
Normal file
405
libretro-common/file/archive_file_7z.c
Normal file
@ -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 <stdlib.h>
|
||||
|
||||
#include <file/archive_file.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <file/file_path.h>
|
||||
#include <compat/strl.h>
|
||||
#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"
|
||||
};
|
@ -25,8 +25,18 @@
|
||||
#include <compat/zlib.h>
|
||||
#include <file/archive_file.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <string.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
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"
|
||||
};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
@ -33,7 +33,7 @@
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
#include <unistd.h>
|
||||
#elif defined(PSP)
|
||||
#include <pspthreadman.h>
|
||||
#include <pspthreadman.h>
|
||||
#elif defined(VITA)
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#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. */
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
12
patch.c
12
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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user