From c346e1f8167f0e0af3770c816e7d4e7367aed8ab Mon Sep 17 00:00:00 2001 From: jdgleaver Date: Wed, 20 May 2020 17:03:01 +0100 Subject: [PATCH] Various file path handling optimisations --- libretro-common/file/file_path.c | 73 ++++++++++++++-------- libretro-common/include/string/stdstring.h | 5 ++ retroarch.c | 14 ++--- 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index 5d9189a5dc..e8cd688308 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -44,7 +44,6 @@ #include #include #endif -#include #include #include @@ -124,26 +123,48 @@ */ const char *path_get_archive_delim(const char *path) { - const char *last = find_last_slash(path); - const char *delim = NULL; + const char *last_slash = find_last_slash(path); + const char *delim = NULL; + char buf[5]; - if (!last) + buf[0] = '\0'; + + if (!last_slash) return NULL; - /* Test if it's .zip */ - delim = strcasestr(last, ".zip#"); + /* Find delimiter position */ + delim = strrchr(last_slash, '#'); - if (!delim) /* If it's not a .zip, test if it's .apk */ - delim = strcasestr(last, ".apk#"); + if (!delim) + return NULL; - if (delim) - return delim + 4; + /* Check whether this is a known archive type + * > Note: The code duplication here is + * deliberate, to maximise performance */ + if (delim - last_slash > 4) + { + strlcpy(buf, delim - 4, sizeof(buf)); + buf[4] = '\0'; - /* If it's not a .zip or .apk file, test if it's .7z */ - delim = strcasestr(last, ".7z#"); + string_to_lower(buf); - if (delim) - return delim + 3; + /* Check if this is a '.zip', '.apk' or '.7z' file */ + if (string_is_equal(buf, ".zip") || + string_is_equal(buf, ".apk") || + string_is_equal(buf + 1, ".7z")) + return delim; + } + else if (delim - last_slash > 3) + { + strlcpy(buf, delim - 3, sizeof(buf)); + buf[3] = '\0'; + + string_to_lower(buf); + + /* Check if this is a '.7z' file */ + if (string_is_equal(buf, ".7z")) + return delim; + } return NULL; } @@ -202,9 +223,12 @@ bool path_is_compressed_file(const char* path) { const char *ext = path_get_extension(path); - if ( strcasestr(ext, "zip") - || strcasestr(ext, "apk") - || strcasestr(ext, "7z")) + if (string_is_empty(ext)) + return false; + + if (string_is_equal_noncase(ext, "zip") || + string_is_equal_noncase(ext, "apk") || + string_is_equal_noncase(ext, "7z")) return true; return false; @@ -1029,10 +1053,11 @@ void fill_pathname_abbreviate_special(char *out_path, unsigned i; const char *candidates[3]; const char *notations[3]; - char *application_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); - char *home_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); + char application_dir[PATH_MAX_LENGTH]; + char home_dir[PATH_MAX_LENGTH]; application_dir[0] = '\0'; + home_dir[0] = '\0'; /* application_dir could be zero-string. Safeguard against this. * @@ -1049,15 +1074,13 @@ void fill_pathname_abbreviate_special(char *out_path, notations [1] = "~"; notations [2] = NULL; - fill_pathname_application_dir(application_dir, - PATH_MAX_LENGTH * sizeof(char)); - fill_pathname_home_dir(home_dir, - PATH_MAX_LENGTH * sizeof(char)); + fill_pathname_application_dir(application_dir, sizeof(application_dir)); + fill_pathname_home_dir(home_dir, sizeof(home_dir)); for (i = 0; candidates[i]; i++) { if (!string_is_empty(candidates[i]) && - strstr(in_path, candidates[i]) == in_path) + string_starts_with(in_path, candidates[i])) { size_t src_size = strlcpy(out_path, notations[i], size); @@ -1079,8 +1102,6 @@ void fill_pathname_abbreviate_special(char *out_path, } } - free(application_dir); - free(home_dir); #endif retro_assert(strlcpy(out_path, in_path, size) < size); diff --git a/libretro-common/include/string/stdstring.h b/libretro-common/include/string/stdstring.h index 08a947d4b4..18668e98db 100644 --- a/libretro-common/include/string/stdstring.h +++ b/libretro-common/include/string/stdstring.h @@ -45,6 +45,11 @@ static INLINE bool string_is_equal(const char *a, const char *b) return (a && b) ? !strcmp(a, b) : false; } +static INLINE bool string_starts_with(const char *str, const char *prefix) +{ + return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false; +} + #define STRLEN_CONST(x) ((sizeof((x))-1)) #define string_is_not_equal(a, b) !string_is_equal((a), (b)) diff --git a/retroarch.c b/retroarch.c index 1f75f4aef4..e30684d0a8 100644 --- a/retroarch.c +++ b/retroarch.c @@ -3335,14 +3335,12 @@ enum rarch_content_type path_is_media_type(const char *path) string_to_lower(ext_lower); /* hack, to detect livestreams so the ffmpeg core can be started */ - if ( - strstr(path, "udp://") || - strstr(path, "http://") || - strstr(path, "https://")|| - strstr(path, "tcp://") || - strstr(path, "rtmp://") || - strstr(path, "rtp://") - ) + if (string_starts_with(path, "udp://") || + string_starts_with(path, "http://") || + string_starts_with(path, "https://") || + string_starts_with(path, "tcp://") || + string_starts_with(path, "rtmp://") || + string_starts_with(path, "rtp://")) return RARCH_CONTENT_MOVIE; switch (msg_hash_to_file_type(msg_hash_calculate(ext_lower)))