| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- // zlib open source license
- //
- // Copyright (c) 2020 to 2022 David Forsgren Piuva
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would be
- // appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such, and must not be
- // misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source
- // distribution.
- #ifndef DFPSR_API_FILE
- #define DFPSR_API_FILE
- #include "stringAPI.h"
- #include "bufferAPI.h"
- #include "../base/Handle.h"
- #include "../settings.h"
- // The file API exists to save and load buffers of data for any type of file.
- // Any file format that is implemented against the Buffer type instead of hardcoding against the file stream can easily be
- // reused for additional layers of processing such as checksums, archiving, compression, encryption, sending over a network...
- // The file API also has functions for processing paths to the filesystem and calling other programs.
- namespace dsr {
- // The PathSyntax enum allow processing theoreical paths for other operating systems than the local.
- enum class PathSyntax { Windows, Posix };
- #if defined(USE_MICROSOFT_WINDOWS)
- // Let the local syntax be for Windows.
- #define LOCAL_PATH_SYNTAX dsr::PathSyntax::Windows
- #elif defined(USE_POSIX)
- // Let the local syntax be for Posix.
- #define LOCAL_PATH_SYNTAX dsr::PathSyntax::Posix
- #else
- #error "The target platform was not recognized as one of the supported operating systems in the file API!\n"
- #endif
- // Define NO_IMPLICIT_PATH_SYNTAX before including the header if you want all PathSyntax arguments to be explicit.
- // 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.
- #ifdef NO_IMPLICIT_PATH_SYNTAX
- // No deafult argument for PathSyntax input.
- #define IMPLICIT_PATH_SYNTAX
- #else
- // Local deafult argument for PathSyntax input.
- #define IMPLICIT_PATH_SYNTAX = LOCAL_PATH_SYNTAX
- #endif
- // Path-syntax: According to the local computer.
- // Post-condition:
- // Returns the content of the readable file referred to by file_optimizePath(filename).
- // If mustExist is true, then failure to load will throw an exception.
- // If mustExist is false, then failure to load will return an empty handle (returning false for buffer_exists).
- Buffer file_loadBuffer(const ReadableString& filename, bool mustExist = true);
- // Path-syntax: According to the local computer.
- // Side-effect: Saves buffer to file_optimizePath(filename) as a binary file.
- // Pre-condition: buffer exists.
- // If mustWork is true, then failure to load will throw an exception.
- // If mustWork is false, then failure to load will return false.
- // Post-condition: Returns true iff the buffer could be saved as a file.
- bool file_saveBuffer(const ReadableString& filename, Buffer buffer, bool mustWork = true);
- // Path-syntax: According to the local computer.
- // Pre-condition: file_getEntryType(path) == EntryType::SymbolicLink
- // Post-condition: Returns the destination of a symbolic link as an absolute path.
- // Shortcuts with file extensions are counted as files, not links.
- String file_followSymbolicLink(const ReadableString &path, bool mustExist = true);
- // Path-syntax: According to the local computer.
- // Get a path separator for the target operating system.
- // Can be used to construct a file path that works for both forward and backward slash separators.
- const char32_t* file_separator();
- // Path-syntax: This operation can handle separators given from any supported platform.
- // because separators will be corrected by file_optimizePath when used to access files.
- // Post-condition: Returns true iff the character C is a folder separator, currently / and \ are accepted as folder separators.
- bool file_isSeparator(DsrChar c);
- // Path-syntax: This operation can handle separators given from any supported platform.
- // Post-condition: Returns the base-zero index of the first path separator (as defined by file_isSeparator) starting from startIndex, or defaultIndex if not found.
- // If the result is not equal to defaultIndex, it is guaranteed to be equal to or greater than startIndex.
- // Similar to string_findFirst, but with the character to find repalced with a replacable default index.
- int64_t file_findFirstSeparator(const ReadableString &path, int64_t defaultIndex = -1, int64_t startIndex = 0);
- // Path-syntax: This operation can handle separators given from any supported platform.
- // Post-condition: Returns the base-zero index of the last path separator (as defined by file_isSeparator), or defaultIndex if not found.
- // Similar to string_findLast, but with the character to find repalced with a replacable default index.
- int64_t file_findLastSeparator(const ReadableString &path, int64_t defaultIndex = -1);
- // Returns callbacks for non-empty entries between separator characters.
- // This includes folder names, filenames, symbolic links, drive letter.
- // This excludes blank space before the first or after the last separator, so the implicit Windows drive \ and Posix system root / will not be included.
- // Path-syntax: This operation can handle separators given from any supported platform.
- // It should handle both / and \, with and without spaces in filenames.
- // Side-effect: Returns a callback for each selectable non-empty entry in the path, from left to right.
- // The first argument in the callback is the entry name, and the integers are an inclusive base-zero index range from first to last characters in path.
- // The first entry must be something selectable to be included. Otherwise it is ignored.
- // C: would be returned as an entry, because other drives can be selected.
- // The implicit Windows drive \ and Posix system root / will not be returned, because they are implicit and can't be replaced in the path.
- void file_getPathEntries(const ReadableString& path, std::function<void(ReadableString, int64_t, int64_t)> action);
- // Path-syntax: Depends on pathSyntax argument.
- // Turns / and \ into the path convention specified by pathSyntax, which is the local system's by default.
- // Removes redundant . and .. to reduce the risk of running out of buffer space when calling the system.
- String file_optimizePath(const ReadableString &path, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // Path-syntax: Depends on pathSyntax argument.
- // Combines two parts into a path and automatically adding a local separator when needed.
- // Can be used to get the full path of a file in a folder or add another folder to the path.
- // b may not begin with a separator, because only a is allowed to contain the root.
- String file_combinePaths(const ReadableString &a, const ReadableString &b, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // Extended to allow combining three or more paths.
- // Example:
- // String fullPath = file_combinePaths(myApplicationPath, U"myFolder", U"myOtherFolder, U"myFile.txt");
- template<typename... TAIL>
- inline String file_combinePaths(const ReadableString &a, const ReadableString &b, TAIL... tail) {
- return file_combinePaths(file_combinePaths(a, b), tail...);
- }
- // Path-syntax: Depends on pathSyntax argument.
- // Post-condition: Returns true iff path starts from a root, according to the path syntax.
- // Implicit drives on Windows using \ are treated as roots because we know that there is nothing above them.
- // 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.
- bool file_hasRoot(const ReadableString &path, bool treatHomeFolderAsRoot, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // Path-syntax: Depends on pathSyntax argument.
- // Returns true iff path is a root without any files nor folder names following.
- // Does not check if it actually exists, so use file_getEntryType on the actual folders and files for verifying existence.
- bool file_isRoot(const ReadableString &path, bool treatHomeFolderAsRoot, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // DSR_MAIN_CALLER is a convenient wrapper for getting input arguments as a list of portable Unicode strings.
- // The actual main function gets placed in DSR_MAIN_CALLER, which calls the given function.
- // Example:
- // DSR_MAIN_CALLER(dsrMain)
- // void dsrMain(List<String> args) {
- // printText("Input arguments:\n");
- // for (int a = 0; a < args.length(); a++) {
- // printText(" args[", a, "] = ", args[a], "\n");
- // }
- // }
- #ifdef USE_MICROSOFT_WINDOWS
- #define DSR_MAIN_CALLER(MAIN_NAME) \
- void MAIN_NAME(dsr::List<dsr::String> args); \
- int main() { \
- dsr::heap_startingApplication(); \
- MAIN_NAME(dsr::file_impl_getInputArguments()); \
- dsr::heap_terminatingApplication(); \
- return 0; \
- }
- #else
- #define DSR_MAIN_CALLER(MAIN_NAME) \
- void MAIN_NAME(dsr::List<dsr::String> args); \
- int main(int argc, char **argv) { \
- dsr::heap_startingApplication(); \
- MAIN_NAME(dsr::file_impl_convertInputArguments(argc, (void**)argv)); \
- dsr::heap_terminatingApplication(); \
- return 0; \
- }
- #endif
- // Helper functions have to be exposed for the macro handle your input arguments.
- // Do not call these yourself.
- List<String> file_impl_convertInputArguments(int argn, void **argv);
- List<String> file_impl_getInputArguments();
- // Path-syntax: According to the local computer.
- // Post-condition: Returns the current path, from where the application was called and relative paths start.
- String file_getCurrentPath();
- // Path-syntax: According to the local computer.
- // Side-effects: Sets the current path to file_optimizePath(path).
- // Post-condition: Returns Returns true on success and false on failure.
- bool file_setCurrentPath(const ReadableString &path);
- // Path-syntax: According to the local computer.
- // Post-condition: Returns the application's folder path, from where the application is stored.
- // If not implemented and allowFallback is true, the current path is returned instead as a qualified guess instead of raising an exception.
- String file_getApplicationFolder(bool allowFallback = true);
- // Path-syntax: This trivial operation should work the same independent of operating system.
- // Otherwise you just have to add a new argument after upgrading the static library.
- // 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.
- ReadableString file_getPathlessName(const ReadableString &path);
- // Path-syntax: This trivial operation should work the same independent of operating system.
- // Post-condition: Returns the filename's extension, or U"" if there is none.
- // 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.
- // Use file_getEntryType instead if you want to know if it's a file or folder.
- ReadableString file_getExtension(const String& filename);
- // Path-syntax: This trivial operation should work the same independent of operating system.
- // Post-condition: Returns filename without any extension, which is the original input if there is no extension.
- // Use to remove a file's type before appending a new extension.
- ReadableString file_getExtensionless(const String& filename);
- // Path-syntax: This trivial operation should work the same independent of operating system.
- // Post-condition: Returns true iff path has an extension, even if it's just an empty dot at the end that file_getExtension would not detect.
- // Useful to check if you need to add an extension or if it already exists in a full filename.
- bool file_hasExtension(const String& path);
- // Quickly gets the relative parent folder by removing the last entry from the string or appending .. at the end.
- // Path-syntax: Depends on pathSyntax argument.
- // This pure syntax function getting the parent folder does not access the system in any way.
- // Does not guarantee that the resulting path is usable on the system.
- // It allows using ~ as the root, for writing paths compatible across different user accounts pointing to different but corresponding files.
- // Going outside of a relative start will add .. to the path.
- // Depending on which current directory the result is applied to, the absolute path may end up as a root followed by multiple .. going nowhere.
- // Going outside of the absolute root returns U"?" as an error code.
- String file_getRelativeParentFolder(const ReadableString &path, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // Gets the canonical parent folder using the current directory.
- // This function for getting the parent folder treats path relative to the current directory and expands the result into an absolute path.
- // 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.
- // Path-syntax: According to the local computer.
- // Pre-conditions:
- // 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.
- // ~ 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.
- // Post-condition: Returns the absolute parent to the given path, or U"?" if trying to leave the root or use a tilde home alias.
- String file_getAbsoluteParentFolder(const ReadableString &path);
- // A theoretical version of file_getAbsoluteParentFolder for evaluation on a theoretical system without actually calling file_getCurrentPath or running on the given system.
- // Path-syntax: Depends on pathSyntax argument.
- // Post-condition: Returns the absolute parent to the given path, or U"?" if trying to leave the root or use a tilde home alias.
- String file_getTheoreticalAbsoluteParentFolder(const ReadableString &path, const ReadableString ¤tPath, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // Gets the canonical absolute version of the path.
- // Current directory is expanded, but not user accounts.
- // Path-syntax: According to the local computer.
- // Post-condition: Returns an absolute version of the path.
- String file_getAbsolutePath(const ReadableString &path);
- // A theoretical version of file_getAbsolutePath for evaluation on a theoretical system without actually calling file_getCurrentPath or running on the given system.
- // Current directory is expanded, but not user accounts.
- // Path-syntax: Depends on pathSyntax argument.
- // Post-condition: Returns an absolute version of the path.
- String file_getTheoreticalAbsolutePath(const ReadableString &path, const ReadableString ¤tPath, PathSyntax pathSyntax IMPLICIT_PATH_SYNTAX);
- // Path-syntax: According to the local computer.
- // Pre-condition: filename must refer to a file so that file_getEntryType(filename) == EntryType::File.
- // Post-condition: Returns a structure with information about the file at file_optimizePath(filename), or -1 if no such file exists.
- int64_t file_getFileSize(const ReadableString& filename);
- // Entry types distinguish between files folders and other things in the file system.
- enum class EntryType { NotFound, UnhandledType, File, Folder, SymbolicLink };
- String& string_toStreamIndented(String& target, const EntryType& source, const ReadableString& indentation);
- // Path-syntax: According to the local computer.
- // Post-condition: Returns what the file_optimizePath(path) points to in the filesystem.
- // Different comparisons on the result can be used to check if something exists.
- // Use file_getEntryType(filename) == EntryType::File to check if a file exists.
- // Use file_getEntryType(folderPath) == EntryType::Folder to check if a folder exists.
- // Use file_getEntryType(path) != EntryType::NotFound to check if the path leads to anything.
- EntryType file_getEntryType(const ReadableString &path);
- // Path-syntax: According to the local computer.
- // Side-effects: Calls action with the entry's path, name and type for everything detected in folderPath.
- // entryPath equals file_combinePaths(folderPath, entryName), and is used for recursive calls when entryType == EntryType::Folder.
- // entryName equals file_getPathlessName(entryPath).
- // entryType equals file_getEntryType(entryPath).
- // Post-condition: Returns true iff the folder could be found.
- bool file_getFolderContent(const ReadableString& folderPath, std::function<void(const ReadableString& entryPath, const ReadableString& entryName, EntryType entryType)> action);
- // Path-syntax: According to the local computer.
- // Access permissions: Default settings according to the local operating system, either inherited from the parent folder or no specific restrictions.
- // Pre-condition: The parent of path must already exist, because only one folder is created.
- // Side-effects: Creates a folder at path.
- // Post-condition: Returns true iff the operation was successful.
- bool file_createFolder(const ReadableString &path);
- // Path-syntax: According to the local computer.
- // Pre-condition: The folder at path must be empty, so any recursion must be done manually.
- // Otherwise you might accidentally erase "C:\myFolder\importantDocuments" from giving C:\myFolder \junk instead of "C:\myFolder\junk" as command line arguments.
- // Better to implement your own recursive search that confirms for each file and folder that they are no longer needed, for such a dangerous operation.
- // Side-effects: Removes the folder at path.
- // Post-condition: Returns true iff the operation was successful.
- bool file_removeEmptyFolder(const ReadableString& path);
- // Path-syntax: According to the local computer.
- // Pre-condition: The file at path must exist.
- // Side-effects: Removes the file at path. If the same file exists at multiple paths in the system, only the link to the file will be removed.
- // Post-condition: Returns true iff the operation was successful.
- bool file_removeFile(const ReadableString& filename);
- // The status of a program started using file_execute.
- enum class DsrProcessStatus {
- NotStarted, // The handle was default initialized or the result of a failed call to process_execute.
- Running, // The process is still running.
- Crashed, // The process has crashed and might not have done the task you asked for.
- Completed // The process has terminated successfully, so you may now check if it has written any files for you.
- };
- // A reference counted handle to a process, so that multiple callers can read the status at any time.
- struct DsrProcessImpl;
- using DsrProcess = Handle<DsrProcessImpl>;
- // Post-condition: Returns the status of process.
- DsrProcessStatus process_getStatus(const DsrProcess &process);
- // Path-syntax: According to the local computer.
- // Pre-condition: The executable at path must exist and have execution rights.
- // Side-effects: Starts the program at programPath, with programPath given again as argv[0] and arguments to argv[1...] to the program's main function.
- // If mustWork is true, then failure will throw an error.
- // Post-condition: Returns a DsrProcess handle to the started process.
- // On failure to start, the handle is empty and process_getStatus will then return DsrProcessStatus::NotStarted from it.
- DsrProcess process_execute(const ReadableString& programPath, List<String> arguments, bool mustWork = true);
- }
- #endif
|