diff --git a/Makefile.common b/Makefile.common index cc26800513..667078668a 100644 --- a/Makefile.common +++ b/Makefile.common @@ -96,6 +96,7 @@ OBJ += frontend/frontend.o \ dir_list.o \ libretro-sdk/string/string_list.o \ rarch_file_path.o \ + file_path.o \ rarch_compr_file_path.o \ hash.o \ driver.o \ @@ -632,8 +633,7 @@ endif JOYCONFIG_OBJ += tools/retroarch-joyconfig.o \ conf/config_file.o \ - rarch_file_path.o \ - rarch_compr_file_path.o \ + file_path.o \ libretro-sdk/string/string_list.o \ libretro-sdk/compat/compat.o \ tools/input_common_joyconfig.o diff --git a/Makefile.ps3.salamander b/Makefile.ps3.salamander index f1a244c9e1..f28c134f68 100644 --- a/Makefile.ps3.salamander +++ b/Makefile.ps3.salamander @@ -19,7 +19,7 @@ endif STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe PPU_CFLAGS += -I. -Ilibretro-sdk/include -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC -DRARCH_INTERNAL -PPU_SRCS = frontend/frontend_salamander.c frontend/frontend_context.c frontend/platform/platform_ps3.c frontend/platform/platform_null.c rarch_file_path.c dir_list.c libretro-sdk/string/string_list.c libretro-sdk/compat/compat.c conf/config_file.c +PPU_SRCS = frontend/frontend_salamander.c frontend/frontend_context.c frontend/platform/platform_ps3.c frontend/platform/platform_null.c file_path.c dir_list.c libretro-sdk/string/string_list.c libretro-sdk/compat/compat.c conf/config_file.c ifeq ($(HAVE_LOGGER), 1) PPU_CFLAGS += -DHAVE_LOGGER -Ilogger/netlogger diff --git a/Makefile.psp1.salamander b/Makefile.psp1.salamander index 18c4652c7b..c6d6a7c389 100644 --- a/Makefile.psp1.salamander +++ b/Makefile.psp1.salamander @@ -31,7 +31,7 @@ PSP_EBOOT_TITLE = RetroArch PSP_EBOOT_ICON = psp1/ICON0.PNG PSP_EBOOT_PIC1 = psp1/PIC1.PNG -OBJS = frontend/frontend_salamander.o frontend/frontend_context.o frontend/platform/platform_psp.o frontend/platform/platform_null.o rarch_file_path.o libretro-sdk/string/string_list.o dir_list.o libretro-sdk/compat/compat.o conf/config_file.o psp1/kernel_functions.o +OBJS = frontend/frontend_salamander.o frontend/frontend_context.o frontend/platform/platform_psp.o frontend/platform/platform_null.o file_path.o libretro-sdk/string/string_list.o dir_list.o libretro-sdk/compat/compat.o conf/config_file.o psp1/kernel_functions.o PSPSDK=$(shell psp-config --pspsdk-path) include $(PSPSDK)/lib/build.mak diff --git a/Makefile.wii.salamander b/Makefile.wii.salamander index 6c48cf2a48..95867eee20 100644 --- a/Makefile.wii.salamander +++ b/Makefile.wii.salamander @@ -39,7 +39,7 @@ LIBS := -lfat -lwiiuse -logc -lbte APP_BOOTER_DIR = wii/app_booter -OBJ = frontend/frontend_salamander.o frontend/frontend_context.o frontend/platform/platform_gx.o frontend/platform/platform_wii.o frontend/platform/platform_null.o rarch_file_path.o libretro-sdk/string/string_list.o dir_list.o libretro-sdk/compat/compat.o conf/config_file.o $(APP_BOOTER_DIR)/app_booter.binobj +OBJ = frontend/frontend_salamander.o frontend/frontend_context.o frontend/platform/platform_gx.o frontend/platform/platform_wii.o frontend/platform/platform_null.o file_path.o libretro-sdk/string/string_list.o dir_list.o libretro-sdk/compat/compat.o conf/config_file.o $(APP_BOOTER_DIR)/app_booter.binobj ifeq ($(HAVE_LOGGER), 1) CFLAGS += -DHAVE_LOGGER diff --git a/file.c b/file.c index 9cb41f7978..0ecdfd09bc 100644 --- a/file.c +++ b/file.c @@ -15,6 +15,7 @@ #include "file.h" #include "file_path.h" +#include "rarch_file_path.h" #include "general.h" #include #include diff --git a/file_extract.c b/file_extract.c index 709ae40383..055ffe0f72 100644 --- a/file_extract.c +++ b/file_extract.c @@ -14,7 +14,7 @@ */ #include "file_extract.h" -#include "file_path.h" +#include "rarch_file_path.h" #include #include #include "retroarch_logger.h" diff --git a/file_path.c b/file_path.c new file mode 100644 index 0000000000..d2ee57bc2e --- /dev/null +++ b/file_path.c @@ -0,0 +1,611 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2014 - Daniel De Matteis + * + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "file_path.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __HAIKU__ +#include +#endif + +#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP) +#include /* stat() is defined here */ +#endif + +#if defined(__CELLOS_LV2__) + +#ifndef S_ISDIR +#define S_ISDIR(x) (x & 0040000) +#endif + +#endif + +#if defined(_WIN32) +#ifdef _MSC_VER +#define setmode _setmode +#endif +#ifdef _XBOX +#include +#define INVALID_FILE_ATTRIBUTES -1 +#else +#include +#include +#include +#include +#endif +#else +#include +#include +#include +#include +#endif + +const char *path_get_extension(const char *path) +{ + const char *ext = strrchr(path_basename(path), '.'); + if (ext) + return ext + 1; + return ""; +} + +char *path_remove_extension(char *path) +{ + char *last = (char*)strrchr(path_basename(path), '.'); + if (*last) + *last = '\0'; + return last; +} + +static bool path_char_is_slash(char c) +{ +#ifdef _WIN32 + return (c == '/') || (c == '\\'); +#else + return (c == '/'); +#endif +} + +static const char *path_default_slash(void) +{ +#ifdef _WIN32 + return "\\"; +#else + return "/"; +#endif +} + +bool path_contains_compressed_file(const char *path) +{ + /* + * 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. + */ + return (strchr(path,'#') != NULL); +} + +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 +#ifdef HAVE_ZLIB + if (strcmp(file_ext,"zip") == 0) + return true; +#endif + +#endif + return false; +} + +bool path_is_directory(const char *path) +{ +#ifdef _WIN32 + DWORD ret = GetFileAttributes(path); + return (ret & FILE_ATTRIBUTE_DIRECTORY) && (ret != INVALID_FILE_ATTRIBUTES); +#else + struct stat buf; + if (stat(path, &buf) < 0) + return false; + + return S_ISDIR(buf.st_mode); +#endif +} + +bool path_file_exists(const char *path) +{ + FILE *dummy = fopen(path, "rb"); + + if (dummy) + { + fclose(dummy); + return true; + } + + return false; +} + +void fill_pathname(char *out_path, const char *in_path, + const char *replace, size_t size) +{ + char tmp_path[PATH_MAX]; + char *tok; + + rarch_assert(strlcpy(tmp_path, in_path, + sizeof(tmp_path)) < sizeof(tmp_path)); + if ((tok = (char*)strrchr(path_basename(tmp_path), '.'))) + *tok = '\0'; + + rarch_assert(strlcpy(out_path, tmp_path, size) < size); + rarch_assert(strlcat(out_path, replace, size) < size); +} + +void fill_pathname_noext(char *out_path, const char *in_path, + const char *replace, size_t size) +{ + rarch_assert(strlcpy(out_path, in_path, size) < size); + rarch_assert(strlcat(out_path, replace, size) < size); +} + +static char *find_last_slash(const char *str) +{ + const char *slash = strrchr(str, '/'); +#ifdef _WIN32 + const char *backslash = strrchr(str, '\\'); + + if (backslash && ((slash && backslash > slash) || !slash)) + slash = backslash; +#endif + + return (char*)slash; +} + +/* Assumes path is a directory. Appends a slash + * if not already there. */ +void fill_pathname_slash(char *path, size_t size) +{ + size_t path_len = strlen(path); + const char *last_slash = find_last_slash(path); + + // Try to preserve slash type. + if (last_slash && (last_slash != (path + path_len - 1))) + { + char join_str[2] = {*last_slash}; + rarch_assert(strlcat(path, join_str, size) < size); + } + else if (!last_slash) + rarch_assert(strlcat(path, path_default_slash(), size) < size); +} + +void fill_pathname_dir(char *in_dir, const char *in_basename, + const char *replace, size_t size) +{ + fill_pathname_slash(in_dir, size); + const char *base = path_basename(in_basename); + rarch_assert(strlcat(in_dir, base, size) < size); + rarch_assert(strlcat(in_dir, replace, size) < size); +} + +void fill_pathname_base(char *out, const char *in_path, size_t size) +{ + const char *ptr = find_last_slash(in_path); + + if (ptr) + ptr++; + else + ptr = in_path; + + /* 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 + */ + +#ifdef HAVE_COMPRESSION + const char *ptr_bak = ptr; + ptr = strchr(ptr_bak,'#'); + if (ptr) + ptr++; + else + ptr = ptr_bak; +#endif + + rarch_assert(strlcpy(out, ptr, size) < size); +} + +void fill_pathname_basedir(char *out_dir, + const char *in_path, size_t size) +{ + rarch_assert(strlcpy(out_dir, in_path, size) < size); + path_basedir(out_dir); +} + +void fill_pathname_parent_dir(char *out_dir, + const char *in_dir, size_t size) +{ + rarch_assert(strlcpy(out_dir, in_dir, size) < size); + path_parent_dir(out_dir); +} + +void fill_dated_filename(char *out_filename, + const char *ext, size_t size) +{ + time_t cur_time; + time(&cur_time); + + strftime(out_filename, size, + "RetroArch-%m%d-%H%M%S.", localtime(&cur_time)); + strlcat(out_filename, ext, size); +} + +void path_basedir(char *path) +{ + if (strlen(path) < 2) + return; + + char *last; + +#ifdef HAVE_COMPRESSION + /* We want to find the directory with the zipfile in basedir. */ + last = strchr(path,'#'); + if (last) + *last = '\0'; +#endif + + last = find_last_slash(path); + + if (last) + last[1] = '\0'; + else + snprintf(path, 3, ".%s", path_default_slash()); +} + +void path_parent_dir(char *path) +{ + size_t len = strlen(path); + if (len && path_char_is_slash(path[len - 1])) + path[len - 1] = '\0'; + path_basedir(path); +} + +const char *path_basename(const char *path) +{ + const char *last = find_last_slash(path); + + /* We cut either at the last hash or the last slash; whichever comes last */ +#ifdef HAVE_COMPRESSION + const char *last_hash = strchr(path,'#'); + if (last_hash > last) + { + return last_hash + 1; + } +#endif + + if (last) + return last + 1; + return path; +} + +bool path_is_absolute(const char *path) +{ +#ifdef _WIN32 + /* Many roads lead to Rome ... */ + return path[0] == '/' || (strstr(path, "\\\\") == path) + || strstr(path, ":/") || strstr(path, ":\\") || strstr(path, ":\\\\"); +#else + return path[0] == '/'; +#endif +} + +void path_resolve_realpath(char *buf, size_t size) +{ +#ifndef RARCH_CONSOLE + char tmp[PATH_MAX]; + strlcpy(tmp, buf, sizeof(tmp)); + +#ifdef _WIN32 + if (!_fullpath(buf, tmp, size)) + strlcpy(buf, tmp, size); +#else + rarch_assert(size >= PATH_MAX); + + /* NOTE: realpath() expects at least PATH_MAX bytes in buf. + * Technically, PATH_MAX needn't be defined, but we rely on it anyways. + * POSIX 2008 can automatically allocate for you, + * but don't rely on that. */ + if (!realpath(tmp, buf)) + strlcpy(buf, tmp, size); +#endif + +#else + (void)buf; + (void)size; +#endif +} + +static bool path_mkdir_norecurse(const char *dir) +{ + int ret; +#if defined(_WIN32) + ret = _mkdir(dir); +#elif defined(IOS) + ret = mkdir(dir, 0755); +#else + ret = mkdir(dir, 0750); +#endif + /* Don't treat this as an error. */ + if (ret < 0 && errno == EEXIST && path_is_directory(dir)) + ret = 0; + if (ret < 0) + RARCH_ERR("mkdir(%s) error: %s.\n", dir, strerror(errno)); + return ret == 0; +} + +bool path_mkdir(const char *dir) +{ + const char *target = NULL; + /* Use heap. Real chance of stack overflow if we recurse too hard. */ + char *basedir = strdup(dir); + bool ret = true; + + if (!basedir) + return false; + + path_parent_dir(basedir); + if (!*basedir || !strcmp(basedir, dir)) + { + ret = false; + goto end; + } + + if (path_is_directory(basedir)) + { + target = dir; + ret = path_mkdir_norecurse(dir); + } + else + { + target = basedir; + ret = path_mkdir(basedir); + if (ret) + { + target = dir; + ret = path_mkdir_norecurse(dir); + } + } + +end: + if (target && !ret) + RARCH_ERR("Failed to create directory: \"%s\".\n", target); + free(basedir); + return ret; +} + +void fill_pathname_resolve_relative(char *out_path, + const char *in_refpath, const char *in_path, size_t size) +{ + if (path_is_absolute(in_path)) + rarch_assert(strlcpy(out_path, in_path, size) < size); + else + { + rarch_assert(strlcpy(out_path, in_refpath, size) < size); + path_basedir(out_path); + rarch_assert(strlcat(out_path, in_path, size) < size); + } +} + +void fill_pathname_join(char *out_path, + const char *dir, const char *path, size_t size) +{ + rarch_assert(strlcpy(out_path, dir, size) < size); + + if (*out_path) + fill_pathname_slash(out_path, size); + + rarch_assert(strlcat(out_path, path, size) < size); +} + +void fill_pathname_join_delim(char *out_path, const char *dir, + const char *path, const char delim, size_t size) +{ + size_t copied = strlcpy(out_path, dir, size); + rarch_assert(copied < size+1); + + out_path[copied]=delim; + out_path[copied+1] = '\0'; + + rarch_assert(strlcat(out_path, path, size) < size); +} + +void fill_pathname_expand_special(char *out_path, + const char *in_path, size_t size) +{ +#if !defined(RARCH_CONSOLE) + if (*in_path == '~') + { + const char *home = getenv("HOME"); + if (home) + { + size_t src_size = strlcpy(out_path, home, size); + rarch_assert(src_size < size); + + out_path += src_size; + size -= src_size; + in_path++; + } + } + else if ((in_path[0] == ':') && +#ifdef _WIN32 + ((in_path[1] == '/') || (in_path[1] == '\\')) +#else + (in_path[1] == '/') +#endif + ) + { + char application_dir[PATH_MAX]; + fill_pathname_application_path(application_dir, sizeof(application_dir)); + path_basedir(application_dir); + + size_t src_size = strlcpy(out_path, application_dir, size); + rarch_assert(src_size < size); + + out_path += src_size; + size -= src_size; + in_path += 2; + } +#endif + + rarch_assert(strlcpy(out_path, in_path, size) < size); +} + +void fill_short_pathname_representation(char* out_rep, + const char *in_path, size_t size) +{ + char path_short[PATH_MAX]; + fill_pathname(path_short, path_basename(in_path), "", + sizeof(path_short)); + + char* last_hash = strchr(path_short,'#'); + /* We handle paths like: + * /path/to/file.7z#mygame.img + * short_name: mygame.img: + */ + if(last_hash != NULL) + { + /* We check whether something is actually + * after the hash to avoid going over the buffer. + */ + rarch_assert(strlen(last_hash) > 1); + strlcpy(out_rep,last_hash + 1, size); + } + else + strlcpy(out_rep,path_short, size); +} + + +void fill_pathname_abbreviate_special(char *out_path, + const char *in_path, size_t size) +{ +#if !defined(RARCH_CONSOLE) + unsigned i; + + const char *home = getenv("HOME"); + char application_dir[PATH_MAX]; + fill_pathname_application_path(application_dir, sizeof(application_dir)); + path_basedir(application_dir); + + /* application_dir could be zero-string. Safeguard against this. + * + * Keep application dir in front of home, moving app dir to a + * new location inside home would break otherwise. */ + + const char *candidates[3] = { application_dir, home, NULL }; + const char *notations[3] = { ":", "~", NULL }; + + for (i = 0; candidates[i]; i++) + { + if (*candidates[i] && strstr(in_path, candidates[i]) == in_path) + { + size_t src_size = strlcpy(out_path, notations[i], size); + rarch_assert(src_size < size); + + out_path += src_size; + size -= src_size; + in_path += strlen(candidates[i]); + + if (!path_char_is_slash(*in_path)) + { + rarch_assert(strlcpy(out_path, path_default_slash(), size) < size); + out_path++; + size--; + } + + break; /* Don't allow more abbrevs to take place. */ + } + } +#endif + + rarch_assert(strlcpy(out_path, in_path, size) < size); +} + +#ifndef RARCH_CONSOLE +void fill_pathname_application_path(char *buf, size_t size) +{ + size_t i; + (void)i; + if (!size) + return; + +#ifdef _WIN32 + DWORD ret = GetModuleFileName(GetModuleHandle(NULL), buf, size - 1); + buf[ret] = '\0'; +#elif defined(__APPLE__) + CFBundleRef bundle = CFBundleGetMainBundle(); + if (bundle) + { + CFURLRef bundle_url = CFBundleCopyBundleURL(bundle); + CFStringRef bundle_path = CFURLCopyPath(bundle_url); + CFStringGetCString(bundle_path, buf, size, kCFStringEncodingUTF8); + CFRelease(bundle_path); + CFRelease(bundle_url); + + rarch_assert(strlcat(buf, "nobin", size) < size); + return; + } +#elif defined(__HAIKU__) + image_info info; + int32 cookie = 0; + + while (get_next_image_info(0, &cookie, &info) == B_OK) + { + if (info.type == B_APP_IMAGE) + { + strlcpy(buf, info.name, size); + return; + } + } +#else + *buf = '\0'; + pid_t pid = getpid(); + char link_path[PATH_MAX]; + /* Linux, BSD and Solaris paths. Not standardized. */ + static const char *exts[] = { "exe", "file", "path/a.out" }; + for (i = 0; i < ARRAY_SIZE(exts); i++) + { + snprintf(link_path, sizeof(link_path), "/proc/%u/%s", + (unsigned)pid, exts[i]); + ssize_t ret = readlink(link_path, buf, size - 1); + if (ret >= 0) + { + buf[ret] = '\0'; + return; + } + } + + RARCH_ERR("Cannot resolve application path! This should not happen.\n"); +#endif +} +#endif diff --git a/file_path.h b/file_path.h index 780c6a3508..e7943ce145 100644 --- a/file_path.h +++ b/file_path.h @@ -14,8 +14,8 @@ * If not, see . */ -#ifndef __RARCH_FILE_PATH_H -#define __RARCH_FILE_PATH_H +#ifndef __LIBRETRO_SDK_FILE_PATH_H +#define __LIBRETRO_SDK_FILE_PATH_H #include #include @@ -41,22 +41,6 @@ enum }; -#ifdef HAVE_COMPRESSION -long read_compressed_file(const char * path, void **buf, - const char* optional_filename); -#endif - -long read_file(const char *path, void **buf); - -bool read_file_string(const char *path, char **buf); - -bool write_file(const char *path, const void *buf, size_t size); - -bool write_empty_file(const char *path); - -struct string_list *compressed_file_list_new(const char *filename, - const char* ext); - /* path_is_compressed_file also means: The compressed file is supported */ bool path_is_compressed_file(const char *path); diff --git a/frontend/menu/menu_entries.c b/frontend/menu/menu_entries.c index 1cebb8d6ca..a228fd0f83 100644 --- a/frontend/menu/menu_entries.c +++ b/frontend/menu/menu_entries.c @@ -17,7 +17,7 @@ #include "menu_entries.h" #include "menu_action.h" #include "menu_list.h" -#include "../../file_path.h" +#include "../../rarch_file_path.h" #include "../../dir_list.h" #include "../../settings_data.h" #include "../../performance.h" diff --git a/gfx/image/image_rpng.c b/gfx/image/image_rpng.c index 601fa90ffd..025c840ab2 100644 --- a/gfx/image/image_rpng.c +++ b/gfx/image/image_rpng.c @@ -19,7 +19,7 @@ #include "image.h" #include "../../file.h" -#include "../../file_path.h" +#include "../../rarch_file_path.h" #include #include diff --git a/gfx/py_state/py_state.c b/gfx/py_state/py_state.c index 03e24d0677..1a7deafb9b 100644 --- a/gfx/py_state/py_state.c +++ b/gfx/py_state/py_state.c @@ -26,7 +26,7 @@ #include #include "../../input/input_common.h" #include "../../file.h" -#include "../../file_path.h" +#include "../../rarch_file_path.h" static PyObject* py_read_wram(PyObject *self, PyObject *args) { diff --git a/gfx/shader/shader_glsl.c b/gfx/shader/shader_glsl.c index f26f566e42..fe18e078bb 100644 --- a/gfx/shader/shader_glsl.c +++ b/gfx/shader/shader_glsl.c @@ -21,7 +21,7 @@ #include "../state_tracker.h" #include "../../dynamic.h" #include "../../file.h" -#include "../../file_path.h" +#include "../../rarch_file_path.h" #ifdef HAVE_CONFIG_H #include "../../config.h" diff --git a/griffin/griffin.c b/griffin/griffin.c index 8bf6873b2d..71c1153ad5 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -520,6 +520,7 @@ DYNAMIC FILE ============================================================ */ #include "../file.c" +#include "../file_path.c" #include "../dir_list.c" #include "../libretro-sdk/string/string_list.c" #include "../rarch_file_path.c" diff --git a/rarch_compr_file_path.c b/rarch_compr_file_path.c index d08dc4aaaa..ed276bc516 100644 --- a/rarch_compr_file_path.c +++ b/rarch_compr_file_path.c @@ -137,29 +137,3 @@ struct string_list *compressed_file_list_new(const char *path, #endif return NULL; } - -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 -#ifdef HAVE_ZLIB - if (strcmp(file_ext,"zip") == 0) - return true; -#endif - -#endif - return false; -} - -bool path_contains_compressed_file(const char *path) -{ - /* - * 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. - */ - return (strchr(path,'#') != NULL); -} diff --git a/rarch_file_path.c b/rarch_file_path.c index e3c576fdbf..3f66caed15 100644 --- a/rarch_file_path.c +++ b/rarch_file_path.c @@ -14,7 +14,7 @@ * If not, see . */ -#include "file_path.h" +#include "rarch_file_path.h" #include #include #include @@ -192,527 +192,3 @@ error: free(*buf); return false; } - -const char *path_get_extension(const char *path) -{ - const char *ext = strrchr(path_basename(path), '.'); - if (ext) - return ext + 1; - return ""; -} - -char *path_remove_extension(char *path) -{ - char *last = (char*)strrchr(path_basename(path), '.'); - if (*last) - *last = '\0'; - return last; -} - -static bool path_char_is_slash(char c) -{ -#ifdef _WIN32 - return (c == '/') || (c == '\\'); -#else - return (c == '/'); -#endif -} - -static const char *path_default_slash(void) -{ -#ifdef _WIN32 - return "\\"; -#else - return "/"; -#endif -} - -bool path_is_directory(const char *path) -{ -#ifdef _WIN32 - DWORD ret = GetFileAttributes(path); - return (ret & FILE_ATTRIBUTE_DIRECTORY) && (ret != INVALID_FILE_ATTRIBUTES); -#else - struct stat buf; - if (stat(path, &buf) < 0) - return false; - - return S_ISDIR(buf.st_mode); -#endif -} - -bool path_file_exists(const char *path) -{ - FILE *dummy = fopen(path, "rb"); - - if (dummy) - { - fclose(dummy); - return true; - } - - return false; -} - -void fill_pathname(char *out_path, const char *in_path, - const char *replace, size_t size) -{ - char tmp_path[PATH_MAX]; - char *tok; - - rarch_assert(strlcpy(tmp_path, in_path, - sizeof(tmp_path)) < sizeof(tmp_path)); - if ((tok = (char*)strrchr(path_basename(tmp_path), '.'))) - *tok = '\0'; - - rarch_assert(strlcpy(out_path, tmp_path, size) < size); - rarch_assert(strlcat(out_path, replace, size) < size); -} - -void fill_pathname_noext(char *out_path, const char *in_path, - const char *replace, size_t size) -{ - rarch_assert(strlcpy(out_path, in_path, size) < size); - rarch_assert(strlcat(out_path, replace, size) < size); -} - -static char *find_last_slash(const char *str) -{ - const char *slash = strrchr(str, '/'); -#ifdef _WIN32 - const char *backslash = strrchr(str, '\\'); - - if (backslash && ((slash && backslash > slash) || !slash)) - slash = backslash; -#endif - - return (char*)slash; -} - -/* Assumes path is a directory. Appends a slash - * if not already there. */ -void fill_pathname_slash(char *path, size_t size) -{ - size_t path_len = strlen(path); - const char *last_slash = find_last_slash(path); - - // Try to preserve slash type. - if (last_slash && (last_slash != (path + path_len - 1))) - { - char join_str[2] = {*last_slash}; - rarch_assert(strlcat(path, join_str, size) < size); - } - else if (!last_slash) - rarch_assert(strlcat(path, path_default_slash(), size) < size); -} - -void fill_pathname_dir(char *in_dir, const char *in_basename, - const char *replace, size_t size) -{ - fill_pathname_slash(in_dir, size); - const char *base = path_basename(in_basename); - rarch_assert(strlcat(in_dir, base, size) < size); - rarch_assert(strlcat(in_dir, replace, size) < size); -} - -void fill_pathname_base(char *out, const char *in_path, size_t size) -{ - const char *ptr = find_last_slash(in_path); - - if (ptr) - ptr++; - else - 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 - */ - - const char *ptr_bak = ptr; - ptr = strchr(ptr_bak,'#'); - if (ptr) - ptr++; - else - ptr = ptr_bak; -#endif - - rarch_assert(strlcpy(out, ptr, size) < size); -} - -void fill_pathname_basedir(char *out_dir, - const char *in_path, size_t size) -{ - rarch_assert(strlcpy(out_dir, in_path, size) < size); - path_basedir(out_dir); -} - -void fill_pathname_parent_dir(char *out_dir, - const char *in_dir, size_t size) -{ - rarch_assert(strlcpy(out_dir, in_dir, size) < size); - path_parent_dir(out_dir); -} - -void fill_dated_filename(char *out_filename, - const char *ext, size_t size) -{ - time_t cur_time; - time(&cur_time); - - strftime(out_filename, size, - "RetroArch-%m%d-%H%M%S.", localtime(&cur_time)); - strlcat(out_filename, ext, size); -} - -void path_basedir(char *path) -{ - if (strlen(path) < 2) - return; - - char *last; - -#ifdef HAVE_COMPRESSION - /* We want to find the directory with the zipfile in basedir. */ - last = strchr(path,'#'); - if (last) - *last = '\0'; -#endif - - last = find_last_slash(path); - - if (last) - last[1] = '\0'; - else - snprintf(path, 3, ".%s", path_default_slash()); -} - -void path_parent_dir(char *path) -{ - size_t len = strlen(path); - if (len && path_char_is_slash(path[len - 1])) - path[len - 1] = '\0'; - path_basedir(path); -} - -const char *path_basename(const char *path) -{ - const char *last = find_last_slash(path); - - /* We cut either at the last hash or the last slash; whichever comes last */ -#ifdef HAVE_COMPRESSION - const char *last_hash = strchr(path,'#'); - if (last_hash > last) - { - return last_hash + 1; - } -#endif - - if (last) - return last + 1; - return path; -} - -bool path_is_absolute(const char *path) -{ -#ifdef _WIN32 - /* Many roads lead to Rome ... */ - return path[0] == '/' || (strstr(path, "\\\\") == path) - || strstr(path, ":/") || strstr(path, ":\\") || strstr(path, ":\\\\"); -#else - return path[0] == '/'; -#endif -} - -void path_resolve_realpath(char *buf, size_t size) -{ -#ifndef RARCH_CONSOLE - char tmp[PATH_MAX]; - strlcpy(tmp, buf, sizeof(tmp)); - -#ifdef _WIN32 - if (!_fullpath(buf, tmp, size)) - strlcpy(buf, tmp, size); -#else - rarch_assert(size >= PATH_MAX); - - /* NOTE: realpath() expects at least PATH_MAX bytes in buf. - * Technically, PATH_MAX needn't be defined, but we rely on it anyways. - * POSIX 2008 can automatically allocate for you, - * but don't rely on that. */ - if (!realpath(tmp, buf)) - strlcpy(buf, tmp, size); -#endif - -#else - (void)buf; - (void)size; -#endif -} - -static bool path_mkdir_norecurse(const char *dir) -{ - int ret; -#if defined(_WIN32) - ret = _mkdir(dir); -#elif defined(IOS) - ret = mkdir(dir, 0755); -#else - ret = mkdir(dir, 0750); -#endif - /* Don't treat this as an error. */ - if (ret < 0 && errno == EEXIST && path_is_directory(dir)) - ret = 0; - if (ret < 0) - RARCH_ERR("mkdir(%s) error: %s.\n", dir, strerror(errno)); - return ret == 0; -} - -bool path_mkdir(const char *dir) -{ - const char *target = NULL; - /* Use heap. Real chance of stack overflow if we recurse too hard. */ - char *basedir = strdup(dir); - bool ret = true; - - if (!basedir) - return false; - - path_parent_dir(basedir); - if (!*basedir || !strcmp(basedir, dir)) - { - ret = false; - goto end; - } - - if (path_is_directory(basedir)) - { - target = dir; - ret = path_mkdir_norecurse(dir); - } - else - { - target = basedir; - ret = path_mkdir(basedir); - if (ret) - { - target = dir; - ret = path_mkdir_norecurse(dir); - } - } - -end: - if (target && !ret) - RARCH_ERR("Failed to create directory: \"%s\".\n", target); - free(basedir); - return ret; -} - -void fill_pathname_resolve_relative(char *out_path, - const char *in_refpath, const char *in_path, size_t size) -{ - if (path_is_absolute(in_path)) - rarch_assert(strlcpy(out_path, in_path, size) < size); - else - { - rarch_assert(strlcpy(out_path, in_refpath, size) < size); - path_basedir(out_path); - rarch_assert(strlcat(out_path, in_path, size) < size); - } -} - -void fill_pathname_join(char *out_path, - const char *dir, const char *path, size_t size) -{ - rarch_assert(strlcpy(out_path, dir, size) < size); - - if (*out_path) - fill_pathname_slash(out_path, size); - - rarch_assert(strlcat(out_path, path, size) < size); -} - -void fill_pathname_join_delim(char *out_path, const char *dir, - const char *path, const char delim, size_t size) -{ - size_t copied = strlcpy(out_path, dir, size); - rarch_assert(copied < size+1); - - out_path[copied]=delim; - out_path[copied+1] = '\0'; - - rarch_assert(strlcat(out_path, path, size) < size); -} - -void fill_pathname_expand_special(char *out_path, - const char *in_path, size_t size) -{ -#if !defined(RARCH_CONSOLE) - if (*in_path == '~') - { - const char *home = getenv("HOME"); - if (home) - { - size_t src_size = strlcpy(out_path, home, size); - rarch_assert(src_size < size); - - out_path += src_size; - size -= src_size; - in_path++; - } - } - else if ((in_path[0] == ':') && -#ifdef _WIN32 - ((in_path[1] == '/') || (in_path[1] == '\\')) -#else - (in_path[1] == '/') -#endif - ) - { - char application_dir[PATH_MAX]; - fill_pathname_application_path(application_dir, sizeof(application_dir)); - path_basedir(application_dir); - - size_t src_size = strlcpy(out_path, application_dir, size); - rarch_assert(src_size < size); - - out_path += src_size; - size -= src_size; - in_path += 2; - } -#endif - - rarch_assert(strlcpy(out_path, in_path, size) < size); -} - -void fill_short_pathname_representation(char* out_rep, - const char *in_path, size_t size) -{ - char path_short[PATH_MAX]; - fill_pathname(path_short, path_basename(in_path), "", - sizeof(path_short)); - - char* last_hash = strchr(path_short,'#'); - /* We handle paths like: - * /path/to/file.7z#mygame.img - * short_name: mygame.img: - */ - if(last_hash != NULL) - { - /* We check whether something is actually - * after the hash to avoid going over the buffer. - */ - rarch_assert(strlen(last_hash) > 1); - strlcpy(out_rep,last_hash + 1, size); - } - else - strlcpy(out_rep,path_short, size); -} - - -void fill_pathname_abbreviate_special(char *out_path, - const char *in_path, size_t size) -{ -#if !defined(RARCH_CONSOLE) - unsigned i; - - const char *home = getenv("HOME"); - char application_dir[PATH_MAX]; - fill_pathname_application_path(application_dir, sizeof(application_dir)); - path_basedir(application_dir); - - /* application_dir could be zero-string. Safeguard against this. - * - * Keep application dir in front of home, moving app dir to a - * new location inside home would break otherwise. */ - - const char *candidates[3] = { application_dir, home, NULL }; - const char *notations[3] = { ":", "~", NULL }; - - for (i = 0; candidates[i]; i++) - { - if (*candidates[i] && strstr(in_path, candidates[i]) == in_path) - { - size_t src_size = strlcpy(out_path, notations[i], size); - rarch_assert(src_size < size); - - out_path += src_size; - size -= src_size; - in_path += strlen(candidates[i]); - - if (!path_char_is_slash(*in_path)) - { - rarch_assert(strlcpy(out_path, path_default_slash(), size) < size); - out_path++; - size--; - } - - break; /* Don't allow more abbrevs to take place. */ - } - } -#endif - - rarch_assert(strlcpy(out_path, in_path, size) < size); -} - -#ifndef RARCH_CONSOLE -void fill_pathname_application_path(char *buf, size_t size) -{ - size_t i; - (void)i; - if (!size) - return; - -#ifdef _WIN32 - DWORD ret = GetModuleFileName(GetModuleHandle(NULL), buf, size - 1); - buf[ret] = '\0'; -#elif defined(__APPLE__) - CFBundleRef bundle = CFBundleGetMainBundle(); - if (bundle) - { - CFURLRef bundle_url = CFBundleCopyBundleURL(bundle); - CFStringRef bundle_path = CFURLCopyPath(bundle_url); - CFStringGetCString(bundle_path, buf, size, kCFStringEncodingUTF8); - CFRelease(bundle_path); - CFRelease(bundle_url); - - rarch_assert(strlcat(buf, "nobin", size) < size); - return; - } -#elif defined(__HAIKU__) - image_info info; - int32 cookie = 0; - - while (get_next_image_info(0, &cookie, &info) == B_OK) - { - if (info.type == B_APP_IMAGE) - { - strlcpy(buf, info.name, size); - return; - } - } -#else - *buf = '\0'; - pid_t pid = getpid(); - char link_path[PATH_MAX]; - /* Linux, BSD and Solaris paths. Not standardized. */ - static const char *exts[] = { "exe", "file", "path/a.out" }; - for (i = 0; i < ARRAY_SIZE(exts); i++) - { - snprintf(link_path, sizeof(link_path), "/proc/%u/%s", - (unsigned)pid, exts[i]); - ssize_t ret = readlink(link_path, buf, size - 1); - if (ret >= 0) - { - buf[ret] = '\0'; - return; - } - } - - RARCH_ERR("Cannot resolve application path! This should not happen.\n"); -#endif -} -#endif diff --git a/rarch_file_path.h b/rarch_file_path.h new file mode 100644 index 0000000000..d3d9270a0a --- /dev/null +++ b/rarch_file_path.h @@ -0,0 +1,52 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2014 - Daniel De Matteis + * + * 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. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __RARCH_FILE_PATH_H +#define __RARCH_FILE_PATH_H + +#include +#include +#include +#include +#include +#include +#include "file_path.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_COMPRESSION +long read_compressed_file(const char * path, void **buf, + const char* optional_filename); +#endif + +long read_file(const char *path, void **buf); + +bool read_file_string(const char *path, char **buf); + +bool write_file(const char *path, const void *buf, size_t size); + +bool write_empty_file(const char *path); + +struct string_list *compressed_file_list_new(const char *filename, + const char* ext); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/retroarch.c b/retroarch.c index 0ca55d6c66..b7c246ed43 100644 --- a/retroarch.c +++ b/retroarch.c @@ -22,7 +22,7 @@ #include #include #include -#include "file_path.h" +#include "rarch_file_path.h" #include "dir_list.h" #include "general.h" #include