fileAPI.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2020 to 2022 David Forsgren Piuva
  4. //
  5. // This software is provided 'as-is', without any express or implied
  6. // warranty. In no event will the authors be held liable for any damages
  7. // arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it
  11. // freely, subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented; you must not
  14. // claim that you wrote the original software. If you use this software
  15. // in a product, an acknowledgment in the product documentation would be
  16. // appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such, and must not be
  19. // misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source
  22. // distribution.
  23. /*
  24. TODO:
  25. * Test that overwriting a large file with a smaller file does not leave anything from the overwritten file on any system.
  26. * bool file_createFolder(const ReadableString& path);
  27. WINBASEAPI WINBOOL WINAPI CreateDirectoryW (LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes);
  28. mkdir on Posix
  29. * bool file_remove(const ReadableString& path);
  30. WINBASEAPI WINBOOL WINAPI DeleteFileW (LPCWSTR lpFileName);
  31. */
  32. #ifndef DFPSR_API_FILE
  33. #define DFPSR_API_FILE
  34. #include "stringAPI.h"
  35. #include "bufferAPI.h"
  36. #if defined(WIN32) || defined(_WIN32)
  37. #define USE_MICROSOFT_WINDOWS
  38. #endif
  39. // A module for file access that exists to prevent cyclic dependencies between strings and buffers.
  40. // Buffers need a filename to be saved or loaded while strings use buffers to store their characters.
  41. namespace dsr {
  42. // The PathSyntax enum allow processing theoreical paths for other operating systems than the local.
  43. enum class PathSyntax { Windows, Posix };
  44. #ifdef USE_MICROSOFT_WINDOWS
  45. // Let the local syntax be for Windows.
  46. #define LOCAL_PATH_SYNTAX PathSyntax::Windows
  47. #else
  48. // Let the local syntax be for Posix.
  49. #define LOCAL_PATH_SYNTAX PathSyntax::Posix
  50. #endif
  51. // Define NO_IMPLICIT_PATH_SYNTAX before including the header if you want all PathSyntax arguments to be explicit.
  52. // If a function you are calling adds a new pathSyntax argument, defining NO_IMPLICIT_PATH_SYNTAX will make sure that you get a warning from the compiler after upgrading the library.
  53. #ifdef NO_IMPLICIT_PATH_SYNTAX
  54. // No deafult argument for PathSyntax input.
  55. #define IMPLICIT_PATH_SYNTAX
  56. #else
  57. // Local deafult argument for PathSyntax input.
  58. #define IMPLICIT_PATH_SYNTAX = LOCAL_PATH_SYNTAX
  59. #endif
  60. // Path-syntax: According to the local computer.
  61. // Post-condition:
  62. // Returns the content of the readable file referred to by file_optimizePath(filename).
  63. // If mustExist is true, then failure to load will throw an exception.
  64. // If mustExist is false, then failure to load will return an empty handle (returning false for buffer_exists).
  65. Buffer file_loadBuffer(const ReadableString& filename, bool mustExist = true);
  66. // Path-syntax: According to the local computer.
  67. // Side-effect: Saves buffer to file_optimizePath(filename) as a binary file.
  68. // Pre-condition: buffer exists.
  69. // If mustWork is true, then failure to load will throw an exception.
  70. // If mustWork is false, then failure to load will return false.
  71. // Post-condition: Returns true iff the buffer could be saved as a file.
  72. bool file_saveBuffer(const ReadableString& filename, Buffer buffer, bool mustWork = true);
  73. // Path-syntax: According to the local computer.
  74. // Pre-condition: file_getEntryType(path) == EntryType::SymbolicLink
  75. // Post-condition: Returns the destination of a symbolic link as an absolute path.
  76. // Shortcuts with file extensions are counted as files, not links.
  77. // TODO: Should shortcuts of known formats be supported anyway by parsing them?
  78. String file_followSymbolicLink(const ReadableString &path, bool mustExist = true);
  79. // Path-syntax: According to the local computer.
  80. // Get a path separator for the target operating system.
  81. // Can be used to construct a file path that works for both forward and backward slash separators.
  82. const char32_t* file_separator();
  83. // Path-syntax: Depends on pathSyntax argument.
  84. // Turns / and \ into the path convention specified by pathSyntax, which is the local system's by default.
  85. // Removes redundant . and .. to reduce the risk of running out of buffer space when calling the system.
  86. String file_optimizePath(const ReadableString &path, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
  87. // Path-syntax: Depends on pathSyntax argument.
  88. // Combines two parts into a path and automatically adding a local separator when needed.
  89. // Can be used to get the full path of a file in a folder or add another folder to the path.
  90. // b may not begin with a separator, because only a is allowed to contain the root.
  91. String file_combinePaths(const ReadableString &a, const ReadableString &b, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
  92. // Path-syntax: Depends on pathSyntax argument.
  93. // Post-condition: Returns true for relative paths true iff path contains a root, according to the path syntax.
  94. // Implicit drives on Windows using \ are treated as roots because we know that there is nothing above them.
  95. // If treatHomeFolderAsRoot is true, starting from the /home/username folder using the Posix ~ alias will be allowed as a root as well, because we can't append it behind another path.
  96. bool file_hasRoot(const ReadableString &path, bool treatHomeFolderAsRoot, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
  97. // Path-syntax: Depends on pathSyntax argument.
  98. // Returns true iff path is a root without any files nor folder names following.
  99. // Does not check if it actually exists, so use file_getEntryType on the actual folders and files for verifying existence.
  100. bool file_isRoot(const ReadableString &path, bool treatHomeFolderAsRoot, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
  101. // DSR_MAIN_CALLER is a convenient wrapper for getting input arguments as a list of portable Unicode strings.
  102. // The actual main function gets placed in DSR_MAIN_CALLER, which calls the given function.
  103. // Example:
  104. // DSR_MAIN_CALLER(dsrMain)
  105. // void dsrMain(List<String> args) {
  106. // printText("Input arguments:\n");
  107. // for (int a = 0; a < args.length(); a++) {
  108. // printText(" args[", a, "] = ", args[a], "\n");
  109. // }
  110. // }
  111. #ifdef USE_MICROSOFT_WINDOWS
  112. #define DSR_MAIN_CALLER(MAIN_NAME) \
  113. void MAIN_NAME(List<String> args); \
  114. int main() { MAIN_NAME(file_impl_getInputArguments()); return 0; }
  115. #else
  116. #define DSR_MAIN_CALLER(MAIN_NAME) \
  117. void MAIN_NAME(List<String> args); \
  118. int main(int argc, char **argv) { MAIN_NAME(file_impl_convertInputArguments(argc, (void**)argv)); return 0; }
  119. #endif
  120. // Helper functions have to be exposed for the macro handle your input arguments.
  121. // Do not call these yourself.
  122. List<String> file_impl_convertInputArguments(int argn, void **argv);
  123. List<String> file_impl_getInputArguments();
  124. // Path-syntax: According to the local computer.
  125. // Post-condition: Returns the current path, from where the application was called and relative paths start.
  126. String file_getCurrentPath();
  127. // Path-syntax: According to the local computer.
  128. // Side-effects: Sets the current path to file_optimizePath(path).
  129. // Post-condition: Returns Returns true on success and false on failure.
  130. bool file_setCurrentPath(const ReadableString &path);
  131. // Path-syntax: According to the local computer.
  132. // Post-condition: Returns the application's folder path, from where the application is stored.
  133. // If not implemented and allowFallback is true,
  134. // the current path is returned instead as a qualified guess instead of raising an exception.
  135. String file_getApplicationFolder(bool allowFallback = true);
  136. // Path-syntax: This trivial operation should work the same independent of operating system.
  137. // Otherwise you just have to add a new argument after upgrading the static library.
  138. // Post-condition: Returns the local name of the file or folder after the last path separator, or the whole path if no separator was found.
  139. ReadableString file_getPathlessName(const ReadableString &path);
  140. // Path-syntax: This trivial operation should work the same independent of operating system.
  141. // Post-condition: Returns the filename's extension, or U"" if there is none.
  142. // This function can not tell if something is a folder or not, because there are file types on Posix systems that have no extension either.
  143. // Use file_getEntryType instead if you want to know if it's a file or folder.
  144. ReadableString file_getExtension(const String& filename);
  145. // Quickly gets the relative parent folder by removing the last entry from the string or appending .. at the end.
  146. // Path-syntax: Depends on pathSyntax argument.
  147. // This pure syntax function getting the parent folder does not access the system in any way.
  148. // Does not guarantee that the resulting path is usable on the system.
  149. // It allows using ~ as the root, for writing paths compatible across different user accounts pointing to different but corresponding files.
  150. // Going outside of a relative start will add .. to the path.
  151. // Depending on which current directory the result is applied to, the absolute path may end up as a root followed by multiple .. going nowhere.
  152. // Going outside of the absolute root returns U"?" as an error code.
  153. String file_getRelativeParentFolder(const ReadableString &path, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
  154. // Gets the canonical parent folder using the current directory.
  155. // This function for getting the parent folder treats path relative to the current directory and expands the result into an absolute path.
  156. // Make sure that current directory is where you want it when calling this function, because the current directory may change over time when calling file_setCurrentPath.
  157. // Path-syntax: According to the local computer.
  158. // Pre-conditions:
  159. // path must be valid on the local system, such that you given full permissions could read or create files there relative to the current directory when this function is called.
  160. // ~ is not allowed as the root, because the point of using ~ is to reuse the same path across different user accounts, which does not refer to an absolute home directory.
  161. // Post-condition: Returns the absolute parent to the given path, or U"?" if trying to leave the root or use a tilde home alias.
  162. String file_getAbsoluteParentFolder(const ReadableString &path);
  163. // Gets the canonical absolute version of the path.
  164. // Path-syntax: According to the local computer.
  165. // Post-condition: Returns an absolute version of the path, quickly without removing redundancy.
  166. String file_getAbsolutePath(const ReadableString &path);
  167. // Path-syntax: According to the local computer.
  168. // Pre-condition: filename must refer to a file so that file_getEntryType(filename) == EntryType::File.
  169. // Post-condition: Returns a structure with information about the file at file_optimizePath(filename), or -1 if no such file exists.
  170. int64_t file_getFileSize(const ReadableString& filename);
  171. // Entry types distinguish between files folders and other things in the file system.
  172. enum class EntryType { NotFound, UnhandledType, File, Folder, SymbolicLink };
  173. String& string_toStreamIndented(String& target, const EntryType& source, const ReadableString& indentation);
  174. // Path-syntax: According to the local computer.
  175. // Post-condition: Returns what the file_optimizePath(path) points to in the filesystem.
  176. // Different comparisons on the result can be used to check if something exists.
  177. // Use file_getEntryType(filename) == EntryType::File to check if a file exists.
  178. // Use file_getEntryType(folderPath) == EntryType::Folder to check if a folder exists.
  179. // Use file_getEntryType(path) != EntryType::NotFound to check if the path leads to anything.
  180. EntryType file_getEntryType(const ReadableString &path);
  181. // Path-syntax: According to the local computer.
  182. // Side-effects: Calls action with the entry's path, name and type for everything detected in folderPath.
  183. // entryPath equals file_combinePaths(folderPath, entryName), and is used for recursive calls when entryType == EntryType::Folder.
  184. // entryName equals file_getPathlessName(entryPath).
  185. // entryType equals file_getEntryType(entryPath).
  186. // Post-condition: Returns true iff the folder could be found.
  187. bool file_getFolderContent(const ReadableString& folderPath, std::function<void(const ReadableString& entryPath, const ReadableString& entryName, EntryType entryType)> action);
  188. // A theoretical version of file_getParentFolder for evaluation on a theoretical system without actually calling file_getCurrentPath or running on the given system.
  189. // Path-syntax: Depends on pathSyntax argument.
  190. // Post-condition: Returns the absolute parent to the given path, or U"?" if trying to leave the root or use a tilde home alias.
  191. String file_getTheoreticalAbsoluteParentFolder(const ReadableString &path, const ReadableString &currentPath, PathSyntax pathSyntax);
  192. // A theoretical version of for evaluation on a theoretical system without actually calling file_getCurrentPath or running on the given system.
  193. // Path-syntax: Depends on pathSyntax argument.
  194. // Post-condition: Returns an absolute version of the path, quickly without removing redundancy.
  195. String file_getTheoreticalAbsolutePath(const ReadableString &path, const ReadableString &currentPath, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
  196. }
  197. #endif