1 /* Copyright (C) 2010-2020 The RetroArch team 2 * 3 * --------------------------------------------------------------------------------------- 4 * The following license statement only applies to this file (file_path.h). 5 * --------------------------------------------------------------------------------------- 6 * 7 * Permission is hereby granted, free of charge, 8 * to any person obtaining a copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation the rights to 10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 23 #ifndef __LIBRETRO_SDK_FILE_PATH_H 24 #define __LIBRETRO_SDK_FILE_PATH_H 25 26 #include <stdio.h> 27 #include <stdint.h> 28 #include <stddef.h> 29 #include <sys/types.h> 30 31 #include <libretro.h> 32 #include <retro_common_api.h> 33 34 #include <boolean.h> 35 36 RETRO_BEGIN_DECLS 37 38 #define PATH_REQUIRED_VFS_VERSION 3 39 40 void path_vfs_init(const struct retro_vfs_interface_info* vfs_info); 41 42 /* Order in this enum is equivalent to negative sort order in filelist 43 * (i.e. DIRECTORY is on top of PLAIN_FILE) */ 44 enum 45 { 46 RARCH_FILETYPE_UNSET, 47 RARCH_PLAIN_FILE, 48 RARCH_COMPRESSED_FILE_IN_ARCHIVE, 49 RARCH_COMPRESSED_ARCHIVE, 50 RARCH_DIRECTORY, 51 RARCH_FILE_UNSUPPORTED 52 }; 53 54 /** 55 * path_is_compressed_file: 56 * @path : path 57 * 58 * Checks if path is a compressed file. 59 * 60 * Returns: true (1) if path is a compressed file, otherwise false (0). 61 **/ 62 bool path_is_compressed_file(const char *path); 63 64 /** 65 * path_contains_compressed_file: 66 * @path : path 67 * 68 * Checks if path contains a compressed file. 69 * 70 * Currently we only check for hash symbol (#) inside the pathname. 71 * If path is ever expanded to a general URI, we should check for that here. 72 * 73 * Example: Somewhere in the path there might be a compressed file 74 * E.g.: /path/to/file.7z#mygame.img 75 * 76 * Returns: true (1) if path contains compressed file, otherwise false (0). 77 **/ 78 #define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL) 79 80 /** 81 * path_get_archive_delim: 82 * @path : path 83 * 84 * Gets delimiter of an archive file. Only the first '#' 85 * after a compression extension is considered. 86 * 87 * Returns: pointer to the delimiter in the path if it contains 88 * a compressed file, otherwise NULL. 89 */ 90 const char *path_get_archive_delim(const char *path); 91 92 /** 93 * path_get_extension: 94 * @path : path 95 * 96 * Gets extension of file. Only '.'s 97 * after the last slash are considered. 98 * 99 * Returns: extension part from the path. 100 */ 101 const char *path_get_extension(const char *path); 102 103 /** 104 * path_remove_extension: 105 * @path : path 106 * 107 * Mutates path by removing its extension. Removes all 108 * text after and including the last '.'. 109 * Only '.'s after the last slash are considered. 110 * 111 * Returns: 112 * 1) If path has an extension, returns path with the 113 * extension removed. 114 * 2) If there is no extension, returns NULL. 115 * 3) If path is empty or NULL, returns NULL 116 */ 117 char *path_remove_extension(char *path); 118 119 /** 120 * path_basename: 121 * @path : path 122 * 123 * Get basename from @path. 124 * 125 * Returns: basename from path. 126 **/ 127 const char *path_basename(const char *path); 128 129 /** 130 * path_basedir: 131 * @path : path 132 * 133 * Extracts base directory by mutating path. 134 * Keeps trailing '/'. 135 **/ 136 void path_basedir(char *path); 137 138 /** 139 * path_parent_dir: 140 * @path : path 141 * 142 * Extracts parent directory by mutating path. 143 * Assumes that path is a directory. Keeps trailing '/'. 144 * If the path was already at the root directory, returns empty string 145 **/ 146 void path_parent_dir(char *path); 147 148 /** 149 * path_resolve_realpath: 150 * @buf : input and output buffer for path 151 * @size : size of buffer 152 * @resolve_symlinks : whether to resolve symlinks or not 153 * 154 * Resolves use of ".", "..", multiple slashes etc in absolute paths. 155 * 156 * Relative paths are rebased on the current working dir. 157 * 158 * Returns: @buf if successful, NULL otherwise. 159 * Note: Not implemented on consoles 160 * Note: Symlinks are only resolved on Unix-likes 161 * Note: The current working dir might not be what you expect, 162 * e.g. on Android it is "/" 163 * Use of fill_pathname_resolve_relative() should be prefered 164 **/ 165 char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks); 166 167 /** 168 * path_relative_to: 169 * @out : buffer to write the relative path to 170 * @path : path to be expressed relatively 171 * @base : relative to this 172 * @size : size of output buffer 173 * 174 * Turns @path into a path relative to @base and writes it to @out. 175 * 176 * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'. 177 * Both @path and @base are assumed to be absolute paths without "." or "..". 178 * 179 * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp 180 **/ 181 size_t path_relative_to(char *out, const char *path, const char *base, size_t size); 182 183 /** 184 * path_is_absolute: 185 * @path : path 186 * 187 * Checks if @path is an absolute path or a relative path. 188 * 189 * Returns: true if path is absolute, false if path is relative. 190 **/ 191 bool path_is_absolute(const char *path); 192 193 /** 194 * fill_pathname: 195 * @out_path : output path 196 * @in_path : input path 197 * @replace : what to replace 198 * @size : buffer size of output path 199 * 200 * FIXME: Verify 201 * 202 * Replaces filename extension with 'replace' and outputs result to out_path. 203 * The extension here is considered to be the string from the last '.' 204 * to the end. 205 * 206 * Only '.'s after the last slash are considered as extensions. 207 * If no '.' is present, in_path and replace will simply be concatenated. 208 * 'size' is buffer size of 'out_path'. 209 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" => 210 * out_path = "/foo/bar/baz/boo.asm" 211 * E.g.: in_path = "/foo/bar/baz/boo.c", replace = "" => 212 * out_path = "/foo/bar/baz/boo" 213 */ 214 void fill_pathname(char *out_path, const char *in_path, 215 const char *replace, size_t size); 216 217 /** 218 * fill_dated_filename: 219 * @out_filename : output filename 220 * @ext : extension of output filename 221 * @size : buffer size of output filename 222 * 223 * Creates a 'dated' filename prefixed by 'RetroArch', and 224 * concatenates extension (@ext) to it. 225 * 226 * E.g.: 227 * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}" 228 **/ 229 size_t fill_dated_filename(char *out_filename, 230 const char *ext, size_t size); 231 232 /** 233 * fill_str_dated_filename: 234 * @out_filename : output filename 235 * @in_str : input string 236 * @ext : extension of output filename 237 * @size : buffer size of output filename 238 * 239 * Creates a 'dated' filename prefixed by the string @in_str, and 240 * concatenates extension (@ext) to it. 241 * 242 * E.g.: 243 * out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}" 244 **/ 245 void fill_str_dated_filename(char *out_filename, 246 const char *in_str, const char *ext, size_t size); 247 248 /** 249 * fill_pathname_noext: 250 * @out_path : output path 251 * @in_path : input path 252 * @replace : what to replace 253 * @size : buffer size of output path 254 * 255 * Appends a filename extension 'replace' to 'in_path', and outputs 256 * result in 'out_path'. 257 * 258 * Assumes in_path has no extension. If an extension is still 259 * present in 'in_path', it will be ignored. 260 * 261 */ 262 size_t fill_pathname_noext(char *out_path, const char *in_path, 263 const char *replace, size_t size); 264 265 /** 266 * find_last_slash: 267 * @str : input path 268 * 269 * Gets a pointer to the last slash in the input path. 270 * 271 * Returns: a pointer to the last slash in the input path. 272 **/ 273 char *find_last_slash(const char *str); 274 275 /** 276 * fill_pathname_dir: 277 * @in_dir : input directory path 278 * @in_basename : input basename to be appended to @in_dir 279 * @replace : replacement to be appended to @in_basename 280 * @size : size of buffer 281 * 282 * Appends basename of 'in_basename', to 'in_dir', along with 'replace'. 283 * Basename of in_basename is the string after the last '/' or '\\', 284 * i.e the filename without directories. 285 * 286 * If in_basename has no '/' or '\\', the whole 'in_basename' will be used. 287 * 'size' is buffer size of 'in_dir'. 288 * 289 * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c", 290 * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm" 291 **/ 292 size_t fill_pathname_dir(char *in_dir, const char *in_basename, 293 const char *replace, size_t size); 294 295 /** 296 * fill_pathname_base: 297 * @out : output path 298 * @in_path : input path 299 * @size : size of output path 300 * 301 * Copies basename of @in_path into @out_path. 302 **/ 303 size_t fill_pathname_base(char *out_path, const char *in_path, size_t size); 304 305 void fill_pathname_base_noext(char *out_dir, 306 const char *in_path, size_t size); 307 308 size_t fill_pathname_base_ext(char *out, 309 const char *in_path, const char *ext, 310 size_t size); 311 312 /** 313 * fill_pathname_basedir: 314 * @out_dir : output directory 315 * @in_path : input path 316 * @size : size of output directory 317 * 318 * Copies base directory of @in_path into @out_path. 319 * If in_path is a path without any slashes (relative current directory), 320 * @out_path will get path "./". 321 **/ 322 void fill_pathname_basedir(char *out_path, const char *in_path, size_t size); 323 324 void fill_pathname_basedir_noext(char *out_dir, 325 const char *in_path, size_t size); 326 327 /** 328 * fill_pathname_parent_dir_name: 329 * @out_dir : output directory 330 * @in_dir : input directory 331 * @size : size of output directory 332 * 333 * Copies only the parent directory name of @in_dir into @out_dir. 334 * The two buffers must not overlap. Removes trailing '/'. 335 * Returns true on success, false if a slash was not found in the path. 336 **/ 337 bool fill_pathname_parent_dir_name(char *out_dir, 338 const char *in_dir, size_t size); 339 340 /** 341 * fill_pathname_parent_dir: 342 * @out_dir : output directory 343 * @in_dir : input directory 344 * @size : size of output directory 345 * 346 * Copies parent directory of @in_dir into @out_dir. 347 * Assumes @in_dir is a directory. Keeps trailing '/'. 348 * If the path was already at the root directory, @out_dir will be an empty string. 349 **/ 350 void fill_pathname_parent_dir(char *out_dir, 351 const char *in_dir, size_t size); 352 353 /** 354 * fill_pathname_resolve_relative: 355 * @out_path : output path 356 * @in_refpath : input reference path 357 * @in_path : input path 358 * @size : size of @out_path 359 * 360 * Joins basedir of @in_refpath together with @in_path. 361 * If @in_path is an absolute path, out_path = in_path. 362 * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg", 363 * out_path = "/foo/bar/foobar.cg". 364 **/ 365 void fill_pathname_resolve_relative(char *out_path, const char *in_refpath, 366 const char *in_path, size_t size); 367 368 /** 369 * fill_pathname_join: 370 * @out_path : output path 371 * @dir : directory 372 * @path : path 373 * @size : size of output path 374 * 375 * Joins a directory (@dir) and path (@path) together. 376 * Makes sure not to get two consecutive slashes 377 * between directory and path. 378 **/ 379 size_t fill_pathname_join(char *out_path, const char *dir, 380 const char *path, size_t size); 381 382 size_t fill_pathname_join_special_ext(char *out_path, 383 const char *dir, const char *path, 384 const char *last, const char *ext, 385 size_t size); 386 387 size_t fill_pathname_join_concat_noext(char *out_path, 388 const char *dir, const char *path, 389 const char *concat, 390 size_t size); 391 392 size_t fill_pathname_join_concat(char *out_path, 393 const char *dir, const char *path, 394 const char *concat, 395 size_t size); 396 397 void fill_pathname_join_noext(char *out_path, 398 const char *dir, const char *path, size_t size); 399 400 /** 401 * fill_pathname_join_delim: 402 * @out_path : output path 403 * @dir : directory 404 * @path : path 405 * @delim : delimiter 406 * @size : size of output path 407 * 408 * Joins a directory (@dir) and path (@path) together 409 * using the given delimiter (@delim). 410 **/ 411 size_t fill_pathname_join_delim(char *out_path, const char *dir, 412 const char *path, const char delim, size_t size); 413 414 size_t fill_pathname_join_delim_concat(char *out_path, const char *dir, 415 const char *path, const char delim, const char *concat, 416 size_t size); 417 418 /** 419 * fill_short_pathname_representation: 420 * @out_rep : output representation 421 * @in_path : input path 422 * @size : size of output representation 423 * 424 * Generates a short representation of path. It should only 425 * be used for displaying the result; the output representation is not 426 * binding in any meaningful way (for a normal path, this is the same as basename) 427 * In case of more complex URLs, this should cut everything except for 428 * the main image file. 429 * 430 * E.g.: "/path/to/game.img" -> game.img 431 * "/path/to/myarchive.7z#folder/to/game.img" -> game.img 432 */ 433 size_t fill_short_pathname_representation(char* out_rep, 434 const char *in_path, size_t size); 435 436 void fill_short_pathname_representation_noext(char* out_rep, 437 const char *in_path, size_t size); 438 439 void fill_pathname_expand_special(char *out_path, 440 const char *in_path, size_t size); 441 442 void fill_pathname_abbreviate_special(char *out_path, 443 const char *in_path, size_t size); 444 445 /** 446 * path_basedir: 447 * @path : path 448 * 449 * Extracts base directory by mutating path. 450 * Keeps trailing '/'. 451 **/ 452 void path_basedir_wrapper(char *path); 453 454 /** 455 * path_char_is_slash: 456 * @c : character 457 * 458 * Checks if character (@c) is a slash. 459 * 460 * Returns: true (1) if character is a slash, otherwise false (0). 461 */ 462 #ifdef _WIN32 463 #define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\')) 464 #else 465 #define PATH_CHAR_IS_SLASH(c) ((c) == '/') 466 #endif 467 468 /** 469 * path_default_slash and path_default_slash_c: 470 * 471 * Gets the default slash separator. 472 * 473 * Returns: default slash separator. 474 */ 475 #ifdef _WIN32 476 #define PATH_DEFAULT_SLASH() "\\" 477 #define PATH_DEFAULT_SLASH_C() '\\' 478 #else 479 #define PATH_DEFAULT_SLASH() "/" 480 #define PATH_DEFAULT_SLASH_C() '/' 481 #endif 482 483 /** 484 * fill_pathname_slash: 485 * @path : path 486 * @size : size of path 487 * 488 * Assumes path is a directory. Appends a slash 489 * if not already there. 490 **/ 491 void fill_pathname_slash(char *path, size_t size); 492 493 #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) 494 void fill_pathname_application_path(char *buf, size_t size); 495 void fill_pathname_application_dir(char *buf, size_t size); 496 void fill_pathname_home_dir(char *buf, size_t size); 497 #endif 498 499 /** 500 * path_mkdir: 501 * @dir : directory 502 * 503 * Create directory on filesystem. 504 * 505 * Returns: true (1) if directory could be created, otherwise false (0). 506 **/ 507 bool path_mkdir(const char *dir); 508 509 /** 510 * path_is_directory: 511 * @path : path 512 * 513 * Checks if path is a directory. 514 * 515 * Returns: true (1) if path is a directory, otherwise false (0). 516 */ 517 bool path_is_directory(const char *path); 518 519 bool path_is_character_special(const char *path); 520 521 int path_stat(const char *path); 522 523 bool path_is_valid(const char *path); 524 525 int32_t path_get_size(const char *path); 526 527 bool is_path_accessible_using_standard_io(const char *path); 528 529 RETRO_END_DECLS 530 531 #endif 532