mirror of
https://github.com/libretro/RetroArch.git
synced 2025-04-02 10:51:52 -04:00
simplify delimiting of compressed archive filenames
This commit is contained in:
parent
5275c0a45d
commit
097f326298
5 changed files with 143 additions and 130 deletions
|
@ -85,6 +85,44 @@ end:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_archive_delim:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Find delimiter of an archive file. Only the first '#'
|
||||||
|
* after a compression extension is considered.
|
||||||
|
*
|
||||||
|
* Returns: pointer to the delimiter in the path if it contains
|
||||||
|
* a compressed file, otherwise NULL.
|
||||||
|
*/
|
||||||
|
char *path_get_archive_delim(const char *path)
|
||||||
|
{
|
||||||
|
const char *last = find_last_slash(path);
|
||||||
|
|
||||||
|
#ifdef HAVE_COMPRESSION
|
||||||
|
char *delim = NULL;
|
||||||
|
|
||||||
|
#ifdef HAVE_ZLIB
|
||||||
|
if (last)
|
||||||
|
delim = strcasestr(last, ".zip#");
|
||||||
|
|
||||||
|
if (delim)
|
||||||
|
return delim + 4;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_7ZIP
|
||||||
|
if (last)
|
||||||
|
delim = strcasestr(last, ".7z#");
|
||||||
|
|
||||||
|
if (delim)
|
||||||
|
return delim + 3;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_get_extension:
|
* path_get_extension:
|
||||||
* @path : path
|
* @path : path
|
||||||
|
@ -128,8 +166,9 @@ char *path_remove_extension(char *path)
|
||||||
*
|
*
|
||||||
* Checks if path contains a compressed file.
|
* Checks if path contains a compressed file.
|
||||||
*
|
*
|
||||||
* Currently we only check for hash symbol (#) inside the pathname.
|
* Currently we only check for a hash symbol (#) inside the pathname
|
||||||
* If path is ever expanded to a general URI, we should check for that here.
|
* that is preceded by an archive extension. If path is ever expanded
|
||||||
|
* to a general URI, we should check for that here.
|
||||||
*
|
*
|
||||||
* Example: Somewhere in the path there might be a compressed file
|
* Example: Somewhere in the path there might be a compressed file
|
||||||
* E.g.: /path/to/file.7z#mygame.img
|
* E.g.: /path/to/file.7z#mygame.img
|
||||||
|
@ -138,23 +177,7 @@ char *path_remove_extension(char *path)
|
||||||
**/
|
**/
|
||||||
bool path_contains_compressed_file(const char *path)
|
bool path_contains_compressed_file(const char *path)
|
||||||
{
|
{
|
||||||
bool compressed = false;
|
return path_get_archive_delim(path) != NULL;
|
||||||
|
|
||||||
#ifdef HAVE_COMPRESSION
|
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
if (strcasestr(path, ".zip#"))
|
|
||||||
compressed = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_7ZIP
|
|
||||||
if (strcasestr(path, ".7z#"))
|
|
||||||
compressed = true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return compressed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,20 +190,21 @@ bool path_contains_compressed_file(const char *path)
|
||||||
**/
|
**/
|
||||||
bool path_is_compressed_file(const char* path)
|
bool path_is_compressed_file(const char* path)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_COMPRESSION) && (defined(HAVE_ZLIB) || defined(HAVE_7ZIP))
|
#ifdef HAVE_COMPRESSION
|
||||||
const char* file_ext = path_get_extension(path);
|
const char *ext = path_get_extension(path);
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
#ifdef HAVE_ZLIB
|
||||||
if (string_is_equal_noncase(file_ext, "zip"))
|
if (strcasestr(ext, "zip"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_7ZIP
|
#ifdef HAVE_7ZIP
|
||||||
if (string_is_equal_noncase(file_ext, "7z"))
|
if (strcasestr(ext, "zip"))
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,31 +358,11 @@ void fill_pathname_dir(char *in_dir, const char *in_basename,
|
||||||
**/
|
**/
|
||||||
void fill_pathname_base(char *out, const char *in_path, size_t size)
|
void fill_pathname_base(char *out, const char *in_path, size_t size)
|
||||||
{
|
{
|
||||||
const char *ptr_bak = NULL;
|
const char *ptr = path_basename(in_path);
|
||||||
const char *ptr = find_last_slash(in_path);
|
|
||||||
|
|
||||||
(void)ptr_bak;
|
if (!ptr)
|
||||||
|
|
||||||
if (ptr)
|
|
||||||
ptr++;
|
|
||||||
else
|
|
||||||
ptr = in_path;
|
ptr = in_path;
|
||||||
|
|
||||||
#ifdef HAVE_COMPRESSION
|
|
||||||
/* In case of compression, we also have to consider paths like
|
|
||||||
* /path/to/archive.7z#mygame.img
|
|
||||||
* and
|
|
||||||
* /path/to/archive.7z#folder/mygame.img
|
|
||||||
* basename would be mygame.img in both cases
|
|
||||||
*/
|
|
||||||
ptr_bak = ptr;
|
|
||||||
ptr = strchr(ptr_bak,'#');
|
|
||||||
if (ptr)
|
|
||||||
ptr++;
|
|
||||||
else
|
|
||||||
ptr = ptr_bak;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
retro_assert(strlcpy(out, ptr, size) < size);
|
retro_assert(strlcpy(out, ptr, size) < size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +483,7 @@ void path_basedir(char *path)
|
||||||
|
|
||||||
#ifdef HAVE_COMPRESSION
|
#ifdef HAVE_COMPRESSION
|
||||||
/* We want to find the directory with the zipfile in basedir. */
|
/* We want to find the directory with the zipfile in basedir. */
|
||||||
last = strchr(path,'#');
|
last = path_get_archive_delim(path);
|
||||||
if (last)
|
if (last)
|
||||||
*last = '\0';
|
*last = '\0';
|
||||||
#endif
|
#endif
|
||||||
|
@ -517,28 +521,19 @@ void path_parent_dir(char *path)
|
||||||
**/
|
**/
|
||||||
const char *path_basename(const char *path)
|
const char *path_basename(const char *path)
|
||||||
{
|
{
|
||||||
const char *last = find_last_slash(path);
|
|
||||||
#ifdef HAVE_COMPRESSION
|
|
||||||
const char *last_hash = NULL;
|
|
||||||
|
|
||||||
/* We cut either at the first compression-related hash or the last slash; whichever comes last */
|
/* We cut either at the first compression-related hash or the last slash; whichever comes last */
|
||||||
#ifdef HAVE_ZLIB
|
const char *last = find_last_slash(path);
|
||||||
last_hash = strcasestr(path, ".zip#");
|
|
||||||
|
|
||||||
if (last_hash > last)
|
#ifdef HAVE_COMPRESSION
|
||||||
return last_hash + 5;
|
const char *delim = path_get_archive_delim(path);
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_7ZIP
|
if (delim)
|
||||||
last_hash = strcasestr(path, ".7z#");
|
return last + 1;
|
||||||
|
|
||||||
if (last_hash > last)
|
|
||||||
return last_hash + 4;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (last)
|
if (last)
|
||||||
return last + 1;
|
return last + 1;
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,7 +731,7 @@ void fill_short_pathname_representation(char* out_rep,
|
||||||
sizeof(path_short));
|
sizeof(path_short));
|
||||||
|
|
||||||
#ifdef HAVE_COMPRESSION
|
#ifdef HAVE_COMPRESSION
|
||||||
last_hash = (char*)strchr(path_short,'#');
|
last_hash = find_last_slash(path_short);
|
||||||
if(last_hash != NULL)
|
if(last_hash != NULL)
|
||||||
{
|
{
|
||||||
/* We handle paths like:
|
/* We handle paths like:
|
||||||
|
|
|
@ -84,6 +84,18 @@ bool path_contains_compressed_file(const char *path);
|
||||||
*/
|
*/
|
||||||
bool path_file_exists(const char *path);
|
bool path_file_exists(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_get_archive_delim:
|
||||||
|
* @path : path
|
||||||
|
*
|
||||||
|
* Gets delimiter of an archive file. Only the first '#'
|
||||||
|
* after a compression extension is considered.
|
||||||
|
*
|
||||||
|
* Returns: pointer to the delimiter in the path if it contains
|
||||||
|
* a compressed file, otherwise NULL.
|
||||||
|
*/
|
||||||
|
char *path_get_archive_delim(const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* path_get_extension:
|
* path_get_extension:
|
||||||
* @path : path
|
* @path : path
|
||||||
|
|
|
@ -109,6 +109,20 @@ struct string_list *string_list_new(void);
|
||||||
bool string_list_append(struct string_list *list, const char *elem,
|
bool string_list_append(struct string_list *list, const char *elem,
|
||||||
union string_list_elem_attr attr);
|
union string_list_elem_attr attr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_append_n:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to add to the string list
|
||||||
|
* @attr : attributes of new element.
|
||||||
|
* @length : read at most this many bytes from elem
|
||||||
|
*
|
||||||
|
* Appends a new element to the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool string_list_append_n(struct string_list *list, const char *elem,
|
||||||
|
union string_list_elem_attr attr, unsigned length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* string_list_free
|
* string_list_free
|
||||||
* @list : pointer to string list object
|
* @list : pointer to string list object
|
||||||
|
|
|
@ -130,6 +130,40 @@ bool string_list_append(struct string_list *list, const char *elem,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string_list_append_n:
|
||||||
|
* @list : pointer to string list
|
||||||
|
* @elem : element to add to the string list
|
||||||
|
* @attr : attributes of new element.
|
||||||
|
* @length : read at most this many bytes from elem
|
||||||
|
*
|
||||||
|
* Appends a new element to the string list.
|
||||||
|
*
|
||||||
|
* Returns: true (1) if successful, otherwise false (0).
|
||||||
|
**/
|
||||||
|
bool string_list_append_n(struct string_list *list, const char *elem,
|
||||||
|
union string_list_elem_attr attr, unsigned length)
|
||||||
|
{
|
||||||
|
char *data_dup = NULL;
|
||||||
|
|
||||||
|
if (list->size >= list->cap &&
|
||||||
|
!string_list_capacity(list, list->cap * 2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
data_dup = (char*)malloc(length + 1);
|
||||||
|
|
||||||
|
strlcpy(data_dup, elem, length + 1);
|
||||||
|
|
||||||
|
if (!data_dup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
list->elems[list->size].data = data_dup;
|
||||||
|
list->elems[list->size].attr = attr;
|
||||||
|
|
||||||
|
list->size++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* string_list_set:
|
* string_list_set:
|
||||||
* @list : pointer to string list
|
* @list : pointer to string list
|
||||||
|
|
|
@ -312,90 +312,48 @@ static int content_7zip_file_read(
|
||||||
return outsize;
|
return outsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int try_insert_compressed_file_to_list(const char *path, const char *ext, unsigned ext_len, char *tmp, struct string_list *list, unsigned index, unsigned *first) {
|
|
||||||
char *ext_with_hash = NULL;
|
|
||||||
|
|
||||||
if(index - (*first) >= ext_len)
|
|
||||||
{
|
|
||||||
ext_with_hash = (char*)malloc(ext_len + 2);
|
|
||||||
memcpy(ext_with_hash, ext, ext_len);
|
|
||||||
ext_with_hash[ext_len] = '#';
|
|
||||||
|
|
||||||
if(strncasecmp(path + (index - ext_len), ext_with_hash, ext_len + 1) == 0)
|
|
||||||
{
|
|
||||||
(*first) = index + 1;
|
|
||||||
strncpy(tmp, path, index);
|
|
||||||
|
|
||||||
union string_list_elem_attr attr;
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
|
||||||
|
|
||||||
if (!string_list_append(list, tmp, attr))
|
|
||||||
{
|
|
||||||
free(ext_with_hash);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(tmp, 0, PATH_MAX_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ext_with_hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* filename_split:
|
* filename_split_archive:
|
||||||
* @str : filename to turn into a string list
|
* @str : filename to turn into a string list
|
||||||
* @delim : delimiter character to use for splitting the string.
|
|
||||||
*
|
*
|
||||||
* Creates a new string list based on filename @path, delimited by @delim.
|
* Creates a new string list based on filename @path, delimited by a hash (#).
|
||||||
*
|
*
|
||||||
* Returns: new string list if successful, otherwise NULL.
|
* Returns: new string list if successful, otherwise NULL.
|
||||||
*/
|
*/
|
||||||
struct string_list *filename_split(const char *path, const char *delim)
|
struct string_list *filename_split_archive(const char *path)
|
||||||
{
|
{
|
||||||
struct string_list *list = string_list_new();
|
struct string_list *list = string_list_new();
|
||||||
unsigned len = strlen(path);
|
|
||||||
unsigned index = 0;
|
|
||||||
unsigned first = 0;
|
|
||||||
char tmp[PATH_MAX_LENGTH] = {0};
|
|
||||||
|
|
||||||
if (!list)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
#ifdef HAVE_COMPRESSION
|
|
||||||
while(path[index] != 0) {
|
|
||||||
if (path[index] != '#')
|
|
||||||
{
|
|
||||||
++index;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_ZLIB
|
|
||||||
if (!try_insert_compressed_file_to_list(path, ".zip", 4, tmp, list, index, &first))
|
|
||||||
goto error;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_7ZIP
|
|
||||||
if (!try_insert_compressed_file_to_list(path, ".7z", 3, tmp, list, index, &first))
|
|
||||||
goto error;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (path + first)
|
|
||||||
{
|
|
||||||
strncpy(tmp, path + first, MIN(len - first, PATH_MAX_LENGTH - 1));
|
|
||||||
|
|
||||||
union string_list_elem_attr attr;
|
union string_list_elem_attr attr;
|
||||||
|
|
||||||
memset(&attr, 0, sizeof(attr));
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
|
||||||
if (!string_list_append(list, tmp, attr))
|
#ifdef HAVE_COMPRESSION
|
||||||
|
char *delim = path_get_archive_delim(path);
|
||||||
|
|
||||||
|
if (delim)
|
||||||
|
{
|
||||||
|
// add archive path to list first
|
||||||
|
*delim = '\0';
|
||||||
|
|
||||||
|
if (!string_list_append_n(list, path, attr, delim - path))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// now add the path within the archive
|
||||||
|
delim++;
|
||||||
|
|
||||||
|
if (*delim)
|
||||||
|
{
|
||||||
|
if (!string_list_append(list, delim, attr))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
if (!string_list_append(list, path, attr))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!string_list_append(list, path, attr))
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
|
@ -713,7 +671,7 @@ static int content_file_compressed_read(
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const char* file_ext = NULL;
|
const char* file_ext = NULL;
|
||||||
struct string_list *str_list = filename_split(path, "#");
|
struct string_list *str_list = filename_split_archive(path);
|
||||||
|
|
||||||
/* Safety check.
|
/* Safety check.
|
||||||
* If optional_filename and optional_filename
|
* If optional_filename and optional_filename
|
||||||
|
|
Loading…
Add table
Reference in a new issue