Merge pull request #952 from timostrunk/compressed_file_menu

Compressed file menu
This commit is contained in:
Twinaphex 2014-09-06 22:11:03 +02:00
commit c2ef81f542
11 changed files with 359 additions and 32 deletions

View File

@ -115,7 +115,7 @@ static void file_action(enum file_action action, NSString* source, NSString* tar
{
RADirectoryItem* item = [RADirectoryItem new];
item.path = BOXSTRING(element->data);
item.isDirectory = element->attr.b;
item.isDirectory = (element->attr.i == RARCH_DIRECTORY);
return item;
}
@ -256,7 +256,7 @@ static void file_action(enum file_action action, NSString* source, NSString* tar
const char* basename = path_basename(contents->elems[i].data);
uint32_t section = isalpha(basename[0]) ? (toupper(basename[0]) - 'A') + 2 : 1;
section = contents->elems[i].attr.b ? 0 : section;
section = (contents->elems[i].attr.i == RARCH_DIRECTORY) ? 0 : section;
[self.sections[section] addObject:[RADirectoryItem directoryItemFromElement:&contents->elems[i]]];
}
@ -432,7 +432,7 @@ static void file_action(enum file_action action, NSString* source, NSString* tar
for (i = 0; i < contents->size; i ++)
{
if (contents->elems[i].attr.b)
if (contents->elems[i].attr.i == RARCH_DIRECTORY)
{
const char* basename = path_basename(contents->elems[i].data);

View File

@ -21,6 +21,7 @@
#include <string.h>
#include "../miscellaneous.h"
#include "../file_path.h"
#include "../deps/7zip/7z.h"
#include "../deps/7zip/7zAlloc.h"
@ -28,6 +29,8 @@
#include "../deps/7zip/7zFile.h"
#include "../deps/7zip/7zVersion.h"
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
static int Buf_EnsureSize(CBuf *dest, size_t size)
@ -225,7 +228,6 @@ int read_7zip_file(const char * archive_path, const char *relative_path, void **
res = ConvertUtf16toCharString(temp,infile);
UInt64 filesize = f->Size;
(void)filesize;
if (strcmp(infile,relative_path) == 0)
{
@ -267,3 +269,149 @@ int read_7zip_file(const char * archive_path, const char *relative_path, void **
RARCH_ERR("\nUnspecified error in 7-ZIP archive, error number was: #%d\n", res);
return -1;
}
struct string_list *compressed_7zip_file_list_new(const char *path,
const char* ext)
{
struct string_list *ext_list = NULL;
struct string_list *list = (struct string_list*)string_list_new();
if (!list)
{
RARCH_ERR("Could not allocate list memory in compressed_7zip_file_list_new\n.");
return NULL;
}
if (ext)
ext_list = string_split(ext, "|");
/* 7Zip part begin */
CFileInStream archiveStream;
CLookToRead lookStream;
CSzArEx db;
SRes res;
ISzAlloc allocImp;
ISzAlloc allocTempImp;
UInt16 *temp = NULL;
size_t tempSize = 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);
goto error;
}
FileInStream_CreateVTable(&archiveStream);
LookToRead_CreateVTable(&lookStream, False);
lookStream.realStream = &archiveStream.s;
LookToRead_Init(&lookStream);
CrcGenerateTable();
SzArEx_Init(&db);
res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
if (res == SZ_OK)
{
UInt32 i;
UInt32 blockIndex = 0xFFFFFFFF;
Byte *outBuffer = 0;
size_t outBufferSize = 0;
for (i = 0; i < db.db.NumFiles; i++)
{
size_t offset = 0;
size_t outSizeProcessed = 0;
const CSzFileItem *f = db.db.Files + i;
size_t len;
if (f->IsDir)
{
/* we skip over everything, which is a directory. */
continue;
}
len = SzArEx_GetFileNameUtf16(&db, i, NULL);
if (len > tempSize)
{
SzFree(NULL, temp);
tempSize = len;
temp = (UInt16 *) SzAlloc(NULL, tempSize * sizeof(temp[0]));
if (temp == 0)
{
res = SZ_ERROR_MEM;
break;
}
}
SzArEx_GetFileNameUtf16(&db, i, temp);
char infile[PATH_MAX];
res = ConvertUtf16toCharString(temp, infile);
const char *file_ext = path_get_extension(infile);
bool supported_by_core = false;
union string_list_elem_attr attr;
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))
goto error;
}
}
SzArEx_Free(&db, &allocImp);
SzFree(NULL, temp);
File_Close(&archiveStream.file);
if (res != SZ_OK)
{
//Error handling:
if (res == SZ_ERROR_UNSUPPORTED)
{
RARCH_ERR("7Zip decoder doesn't support this archive\n");
goto error;
}
else if (res == SZ_ERROR_MEM)
{
RARCH_ERR("7Zip decoder could not allocate memory\n");
goto error;
}
else if (res == SZ_ERROR_CRC)
{
RARCH_ERR("7Zip decoder encountered a CRC error in the archive\n");
goto error;
}
else
{
RARCH_ERR(
"\nUnspecified error in 7-ZIP archive, error number was: #%d\n",
res);
goto error;
}
}
string_list_free(ext_list);
return list;
error:
RARCH_ERR("Failed to open compressed_file: \"%s\"\n", path);
SzArEx_Free(&db, &allocImp);
SzFree(NULL, temp);
File_Close(&archiveStream.file);
string_list_free(list);
string_list_free(ext_list);
return NULL;
}

View File

@ -23,6 +23,9 @@ extern "C" {
int read_7zip_file(const char * archive_path,
const char *relative_path, void **buf);
struct string_list *compressed_7zip_file_list_new(const char *path,
const char* ext);
#ifdef __cplusplus
}
#endif

33
file.c
View File

@ -151,16 +151,29 @@ static ssize_t read_content_file(const char *path, void **buf)
if (g_extern.is_carchive)
{
if(archive_found)
{
/* FIXME - should use fill_pathname_relative helper function here
* to avoid errors. */
char rel_path[PATH_MAX];
snprintf(rel_path, sizeof(rel_path),
"%s", archive_found + strlen(g_extern.carchive_path) + 1);
ret = read_compressed_file(g_extern.carchive_path,
rel_path, (void**)&ret_buf);
}
if(archive_found)
{
if (strlen(path) < strlen(g_extern.carchive_path)+2)
{
/*
* This error condition happens for example, when
* carchive_path == path, or
* carchive_path + '/' == path.
*/
RARCH_ERR("Could not extract image path %s from carchive path %s.\n",
path, g_extern.carchive_path);
return -1;
}
ret = read_compressed_file(g_extern.carchive_path,
archive_found + strlen(g_extern.carchive_path) + 1, (void**)&ret_buf);
}
else
{
/* If we didn't actually find the archivename in the filename
* the given path is not inside the archive. Then we proceed to just load the file.
*/
ret = read_file(path, (void**)&ret_buf);
}
}
else
#endif

View File

@ -357,12 +357,13 @@ static int qstrcmp_dir(const void *a_, const void *b_)
{
const struct string_list_elem *a = (const struct string_list_elem*)a_;
const struct string_list_elem *b = (const struct string_list_elem*)b_;
int a_dir = a->attr.b;
int b_dir = b->attr.b;
int a_type = a->attr.i;
int b_type = b->attr.i;
/* Sort directories before files. */
if (a_dir != b_dir)
return b_dir - a_dir;
if (a_type != b_type)
return b_type - a_type;
return strcasecmp(a->data, b->data);
}
@ -375,6 +376,22 @@ void dir_list_sort(struct string_list *list, bool dir_first)
dir_first ? qstrcmp_dir : qstrcmp_plain);
}
struct string_list *compressed_file_list_new(const char *path,
const char* ext)
{
#ifdef HAVE_COMPRESSION
const char* file_ext = path_get_extension(path);
#ifdef HAVE_7ZIP
if (strcmp(file_ext,"7z") == 0)
{
return compressed_7zip_file_list_new(path,ext);
}
#endif
#endif
return NULL;
}
#ifdef _WIN32
struct string_list *dir_list_new(const char *dir,
@ -402,9 +419,21 @@ struct string_list *dir_list_new(const char *dir,
{
union string_list_elem_attr attr;
char file_path[PATH_MAX];
const char *name = ffd.cFileName;
const char *file_ext = path_get_extension(name);
bool is_dir = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
const char *name = ffd.cFileName;
const char *file_ext = path_get_extension(name);
bool is_dir = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
bool is_compressed_file = false;
bool supported_by_core = false;
attr.i = RARCH_FILETYPE_UNSET;
fill_pathname_join(file_path, dir, name, sizeof(file_path));
if (!is_dir)
{
is_compressed_file = path_is_compressed_file(file_path);
if (string_list_find_elem_prefix(ext_list, ".", file_ext))
supported_by_core = true;
}
if (!include_dirs && is_dir)
continue;
@ -412,12 +441,23 @@ struct string_list *dir_list_new(const char *dir,
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
if (!is_dir && ext_list && !string_list_find_elem_prefix(ext_list, ".", file_ext))
if (!is_compressed_file && !is_dir && ext_list && !supported_by_core)
continue;
fill_pathname_join(file_path, dir, name, sizeof(file_path));
attr.b = is_dir;
if (is_dir)
attr.i = RARCH_DIRECTORY;
if (is_compressed_file)
attr.i = RARCH_COMPRESSED_ARCHIVE;
/* The order of these ifs is important.
* If the file format is explicitly supported by the libretro-core, we
* need to immediately load it and not designate it as a compressed file.
*
* Example: .zip could be supported as a image by the core and as a
* compressed_file. In that case, we have to interpret it as a image.
*
* */
if (supported_by_core)
attr.i = RARCH_PLAIN_FILE;
if (!string_list_append(list, file_path, attr))
goto error;
@ -480,21 +520,44 @@ struct string_list *dir_list_new(const char *dir,
union string_list_elem_attr attr;
const char *name = entry->d_name;
const char *file_ext = path_get_extension(name);
bool is_compressed_file = false;
bool supported_by_core = false;
attr.i = RARCH_FILETYPE_UNSET;
fill_pathname_join(file_path, dir, name, sizeof(file_path));
is_dir = dirent_is_directory(file_path, entry);
if (!is_dir)
{
is_compressed_file = path_is_compressed_file(file_path);
if (string_list_find_elem_prefix(ext_list, ".", file_ext))
supported_by_core = true;
}
if (!include_dirs && is_dir)
continue;
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
continue;
if (!is_dir && ext_list
&& !string_list_find_elem_prefix(ext_list, ".", file_ext))
if (!is_dir && ext_list && !is_compressed_file && !supported_by_core)
continue;
attr.b = is_dir;
if (is_dir)
attr.i = RARCH_DIRECTORY;
if (is_compressed_file)
attr.i = RARCH_COMPRESSED_ARCHIVE;
/* The order of these ifs is important.
* If the file format is explicitly supported by the libretro-core, we
* need to immediately load it and not designate it as a compressed file.
*
* Example: .zip could be supported as a image by the core and as a
* compressed_file. In that case, we have to interpret it as a image.
*
* */
if (supported_by_core)
attr.i = RARCH_PLAIN_FILE;
if (!string_list_append(list, file_path, attr))
goto error;
@ -540,6 +603,20 @@ static const char *path_default_slash(void)
#endif
}
bool path_is_compressed_file(const char* path)
{
#ifdef HAVE_COMPRESSION
const char* file_ext = path_get_extension(path);
#ifdef HAVE_7ZIP
if (strcmp(file_ext,"7z") == 0)
{
return true;
}
#endif
#endif
return false;
}
bool path_is_directory(const char *path)
{

View File

@ -26,6 +26,19 @@
extern "C" {
#endif
/* Order in this enum is equivalent to negative sort order in filelist
* (i.e. DIRECTORY is on top of PLAIN_FILE) */
enum
{
RARCH_FILETYPE_UNSET,
RARCH_PLAIN_FILE,
RARCH_COMPRESSED_FILE_IN_ARCHIVE,
RARCH_COMPRESSED_ARCHIVE,
RARCH_DIRECTORY,
RARCH_FILE_UNSUPPORTED,
} FILE_TYPES;
#ifdef HAVE_COMPRESSION
long read_compressed_file(const char * archive_path, const char *relative_path, void **buf);
#endif
@ -54,6 +67,8 @@ struct string_list
size_t cap;
};
struct string_list *compressed_file_list_new(const char *filename,
const char* ext);
struct string_list *dir_list_new(const char *dir, const char *ext,
bool include_dirs);
void dir_list_sort(struct string_list *list, bool dir_first);
@ -71,6 +86,8 @@ void string_list_join_concat(char *buffer, size_t size,
void string_list_set(struct string_list *list, unsigned index,
const char *str);
/* path_is_compressed_file also means: The compressed file is supported */
bool path_is_compressed_file(const char *path);
bool path_is_directory(const char *path);
bool path_file_exists(const char *path);

View File

@ -1753,6 +1753,30 @@ static int menu_action_ok(const char *dir,
menu_entries_push(driver.menu->menu_stack,
cat_path, menu_label, type, driver.menu->selection_ptr);
}
else if (type == MENU_FILE_CARCHIVE)
{
char cat_path[PATH_MAX];
fill_pathname_join(cat_path, dir, path, sizeof(cat_path));
menu_entries_push(driver.menu->menu_stack,
cat_path, menu_label, type, driver.menu->selection_ptr);
return 0;
}
#ifdef HAVE_COMPRESSION
else if (type == MENU_FILE_IN_CARCHIVE)
{
fill_pathname_join(g_extern.fullpath, dir, path,
sizeof(g_extern.fullpath));
g_extern.is_carchive = true;
strncpy(g_extern.carchive_path,dir,sizeof(g_extern.carchive_path));
rarch_main_set_state(RARCH_ACTION_STATE_LOAD_CONTENT);
menu_flush_stack_type(driver.menu->menu_stack,MENU_SETTINGS);
driver.menu->msg_force = true;
return -1;
}
#endif
else
{
fill_pathname_join(g_extern.fullpath, dir, path,

View File

@ -959,7 +959,7 @@ static void lakka_init_items(int i, menu_category_t *category,
for (j = 0; j < num_items; j++)
{
if (list->elems[j].attr.b) // is a directory
if (list->elems[j].attr.i == RARCH_DIRECTORY) // is a directory
lakka_init_items(i, category, info, list->elems[j].data);
else
{

View File

@ -380,6 +380,16 @@ static void rgui_render(void)
type = MENU_FILE_DIRECTORY;
w = 5;
}
else if (type == MENU_FILE_CARCHIVE)
{
strlcpy(type_str, "(COMP)", sizeof(type_str));
w = 6;
}
else if (type == MENU_FILE_IN_CARCHIVE)
{
strlcpy(type_str, "(CFILE)", sizeof(type_str));
w = 7;
}
else if (type >= MENU_SETTINGS_CORE_OPTION_START)
strlcpy(
type_str,

View File

@ -66,6 +66,8 @@ typedef enum
MENU_FILE_PLAYLIST_ENTRY,
MENU_FILE_USE_DIRECTORY,
MENU_FILE_SWITCH,
MENU_FILE_CARCHIVE,
MENU_FILE_IN_CARCHIVE,
MENU_SETTINGS,
} menu_file_type_t;

View File

@ -629,6 +629,7 @@ int menu_parse_check(const char *label, unsigned menu_type)
RARCH_LOG("label is menu_parse_check: %s\n", label);
#endif
if (!((menu_type == MENU_FILE_DIRECTORY ||
menu_type == MENU_FILE_CARCHIVE ||
menu_common_type_is(label, menu_type) == MENU_SETTINGS_SHADER_OPTIONS ||
menu_common_type_is(label, menu_type) == MENU_FILE_DIRECTORY ||
!strcmp(label, "input_overlay") ||
@ -793,7 +794,16 @@ int menu_parse_and_resolve(file_list_t *list, file_list_t *menu_list)
else
exts = g_extern.system.valid_extensions;
struct string_list *str_list = dir_list_new(dir, exts, true);
struct string_list *str_list = NULL;
if (path_is_compressed_file(dir))
{
str_list = compressed_file_list_new(dir,exts);
}
else
{
str_list = dir_list_new(dir, exts, true);
}
if (!str_list)
return -1;
@ -806,7 +816,24 @@ int menu_parse_and_resolve(file_list_t *list, file_list_t *menu_list)
list_size = str_list->size;
for (i = 0; i < str_list->size; i++)
{
bool is_dir = str_list->elems[i].attr.b;
menu_file_type_t file_type = 0;
switch (str_list->elems[i].attr.i)
{
case RARCH_DIRECTORY:
file_type = MENU_FILE_DIRECTORY;
break;
case RARCH_COMPRESSED_ARCHIVE:
file_type = MENU_FILE_CARCHIVE;
break;
case RARCH_COMPRESSED_FILE_IN_ARCHIVE:
file_type = MENU_FILE_IN_CARCHIVE;
break;
case RARCH_PLAIN_FILE:
default:
file_type = MENU_FILE_PLAIN;
break;
}
bool is_dir = (file_type == MENU_FILE_DIRECTORY);
if ((menu_common_type_is(label, menu_type) == MENU_FILE_DIRECTORY) && !is_dir)
continue;
@ -827,11 +854,17 @@ int menu_parse_and_resolve(file_list_t *list, file_list_t *menu_list)
/* Push menu_type further down in the chain.
* Needed for shader manager currently. */
if (!strcmp(label, "core_list"))
{
/* Compressed cores are unsupported */
if (file_type == MENU_FILE_CARCHIVE)
continue;
file_list_push(list, path, "",
is_dir ? MENU_FILE_DIRECTORY : MENU_FILE_CORE, 0);
}
else
file_list_push(list, path, "",
is_dir ? MENU_FILE_DIRECTORY : MENU_FILE_PLAIN, 0);
file_type, 0);
}
menu_entries_push_list(driver.menu, list,