diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index 3ee4bab5c4..c133903c75 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -85,6 +85,44 @@ end: 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 : path @@ -128,8 +166,9 @@ char *path_remove_extension(char *path) * * Checks if path contains a compressed file. * - * Currently we only check for hash symbol (#) inside the pathname. - * If path is ever expanded to a general URI, we should check for that here. + * Currently we only check for a hash symbol (#) inside the pathname + * 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 * 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 compressed = false; - -#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; + return path_get_archive_delim(path) != NULL; } /** @@ -167,20 +190,21 @@ bool path_contains_compressed_file(const char *path) **/ bool path_is_compressed_file(const char* path) { -#if defined(HAVE_COMPRESSION) && (defined(HAVE_ZLIB) || defined(HAVE_7ZIP)) - const char* file_ext = path_get_extension(path); +#ifdef HAVE_COMPRESSION + const char *ext = path_get_extension(path); #ifdef HAVE_ZLIB - if (string_is_equal_noncase(file_ext, "zip")) + if (strcasestr(ext, "zip")) return true; #endif #ifdef HAVE_7ZIP - if (string_is_equal_noncase(file_ext, "7z")) + if (strcasestr(ext, "zip")) return true; #endif #endif + 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) { - const char *ptr_bak = NULL; - const char *ptr = find_last_slash(in_path); + const char *ptr = path_basename(in_path); - (void)ptr_bak; - - if (ptr) - ptr++; - else + if (!ptr) 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); } @@ -479,7 +483,7 @@ void path_basedir(char *path) #ifdef HAVE_COMPRESSION /* We want to find the directory with the zipfile in basedir. */ - last = strchr(path,'#'); + last = path_get_archive_delim(path); if (last) *last = '\0'; #endif @@ -517,28 +521,19 @@ void path_parent_dir(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 */ -#ifdef HAVE_ZLIB - last_hash = strcasestr(path, ".zip#"); + const char *last = find_last_slash(path); - if (last_hash > last) - return last_hash + 5; -#endif +#ifdef HAVE_COMPRESSION + const char *delim = path_get_archive_delim(path); -#ifdef HAVE_7ZIP - last_hash = strcasestr(path, ".7z#"); - - if (last_hash > last) - return last_hash + 4; -#endif + if (delim) + return last + 1; #endif if (last) return last + 1; + return path; } @@ -736,7 +731,7 @@ void fill_short_pathname_representation(char* out_rep, sizeof(path_short)); #ifdef HAVE_COMPRESSION - last_hash = (char*)strchr(path_short,'#'); + last_hash = find_last_slash(path_short); if(last_hash != NULL) { /* We handle paths like: diff --git a/libretro-common/include/file/file_path.h b/libretro-common/include/file/file_path.h index 08dba54aad..43dd176138 100644 --- a/libretro-common/include/file/file_path.h +++ b/libretro-common/include/file/file_path.h @@ -84,6 +84,18 @@ bool path_contains_compressed_file(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 : path diff --git a/libretro-common/include/lists/string_list.h b/libretro-common/include/lists/string_list.h index 9b3d0e47e8..7018c6b224 100644 --- a/libretro-common/include/lists/string_list.h +++ b/libretro-common/include/lists/string_list.h @@ -109,6 +109,20 @@ struct string_list *string_list_new(void); bool string_list_append(struct string_list *list, const char *elem, 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 * @list : pointer to string list object diff --git a/libretro-common/lists/string_list.c b/libretro-common/lists/string_list.c index 3448053d6b..f0400f8363 100644 --- a/libretro-common/lists/string_list.c +++ b/libretro-common/lists/string_list.c @@ -130,6 +130,40 @@ bool string_list_append(struct string_list *list, const char *elem, 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: * @list : pointer to string list diff --git a/tasks/task_content.c b/tasks/task_content.c index 319147fc9e..e7d3a7dfd7 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -312,90 +312,48 @@ static int content_7zip_file_read( 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 - * @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. */ -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(); - unsigned len = strlen(path); - unsigned index = 0; - unsigned first = 0; - char tmp[PATH_MAX_LENGTH] = {0}; + union string_list_elem_attr attr; - if (!list) - goto error; + memset(&attr, 0, sizeof(attr)); #ifdef HAVE_COMPRESSION - while(path[index] != 0) { - if (path[index] != '#') - { - ++index; - continue; - } + char *delim = path_get_archive_delim(path); -#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) + if (delim) { - strncpy(tmp, path + first, MIN(len - first, PATH_MAX_LENGTH - 1)); + // add archive path to list first + *delim = '\0'; - union string_list_elem_attr attr; - memset(&attr, 0, sizeof(attr)); + if (!string_list_append_n(list, path, attr, delim - path)) + goto error; - if (!string_list_append(list, tmp, attr)) + // 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; } +#else + if (!string_list_append(list, path, attr)) + goto error; +#endif return list; @@ -713,7 +671,7 @@ static int content_file_compressed_read( { int ret = 0; const char* file_ext = NULL; - struct string_list *str_list = filename_split(path, "#"); + struct string_list *str_list = filename_split_archive(path); /* Safety check. * If optional_filename and optional_filename