|
|
@@ -21,13 +21,15 @@
|
|
|
// 3. This notice may not be removed or altered from any source
|
|
|
// distribution.
|
|
|
|
|
|
+#include "fileAPI.h"
|
|
|
+#ifdef USE_MICROSOFT_WINDOWS
|
|
|
+ #include <windows.h>
|
|
|
+#else
|
|
|
+ #include <unistd.h>
|
|
|
+#endif
|
|
|
#include <fstream>
|
|
|
#include <cstdlib>
|
|
|
-#include "fileAPI.h"
|
|
|
#include "bufferAPI.h"
|
|
|
-#ifdef __cpp_lib_filesystem
|
|
|
- #include <filesystem>
|
|
|
-#endif
|
|
|
|
|
|
namespace dsr {
|
|
|
|
|
|
@@ -35,28 +37,54 @@ namespace dsr {
|
|
|
// * pathSeparator is the token used to separate folders in the system, expressed as a UTF-32 string literal.
|
|
|
// * accessFile is the function for opening a file using the UTF-32 filename, for reading or writing.
|
|
|
// The C API is used for access, because some C++ standard library implementations don't support wide strings for MS-Windows.
|
|
|
-#if defined(WIN32) || defined(_WIN32)
|
|
|
- #include <windows.h>
|
|
|
+#ifdef USE_MICROSOFT_WINDOWS
|
|
|
+ using NativeChar = wchar_t; // UTF-16
|
|
|
static const char32_t* pathSeparator = U"\\";
|
|
|
static const CharacterEncoding nativeEncoding = CharacterEncoding::BOM_UTF16LE;
|
|
|
#define FILE_ACCESS_FUNCTION _wfopen
|
|
|
#define FILE_ACCESS_SELECTION (write ? L"wb" : L"rb")
|
|
|
+ List<String> file_impl_getInputArguments() {
|
|
|
+ // Get a pointer to static memory with the command
|
|
|
+ LPWSTR cmd = GetCommandLineW();
|
|
|
+ // Split the arguments into an array of arguments
|
|
|
+ int argc = 0;
|
|
|
+ LPWSTR *argv = CommandLineToArgvW(cmd, &argc);
|
|
|
+ // Convert the arguments into dsr::List<dsr::String>
|
|
|
+ List<String> args = file_impl_convertInputArguments(argc, (void**)argv);
|
|
|
+ // Free the native list of arguments
|
|
|
+ LocalFree(argv);
|
|
|
+ return args;
|
|
|
+ }
|
|
|
#else
|
|
|
+ using NativeChar = char; // UTF-8
|
|
|
static const char32_t* pathSeparator = U"/";
|
|
|
static const CharacterEncoding nativeEncoding = CharacterEncoding::BOM_UTF8;
|
|
|
#define FILE_ACCESS_FUNCTION fopen
|
|
|
#define FILE_ACCESS_SELECTION (write ? "wb" : "rb")
|
|
|
+ List<String> file_impl_getInputArguments() { return List<String>(); }
|
|
|
#endif
|
|
|
|
|
|
+// Length of fixed size buffers.
|
|
|
+const int maxLength = 512;
|
|
|
+
|
|
|
static const NativeChar* toNativeString(const ReadableString &filename, Buffer &buffer) {
|
|
|
buffer = string_saveToMemory(filename, nativeEncoding, LineEncoding::CrLf, false, true);
|
|
|
return (const NativeChar*)buffer_dangerous_getUnsafeData(buffer);
|
|
|
}
|
|
|
|
|
|
-static String fromNativeString(NativeChar *text) {
|
|
|
+static String fromNativeString(const NativeChar *text) {
|
|
|
return string_dangerous_decodeFromData(text, nativeEncoding);
|
|
|
}
|
|
|
|
|
|
+List<String> file_impl_convertInputArguments(int argn, void **argv) {
|
|
|
+ List<String> result;
|
|
|
+ result.reserve(argn);
|
|
|
+ for (int a = 0; a < argn; a++) {
|
|
|
+ result.push(fromNativeString((NativeChar*)(argv[a])));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
static FILE* accessFile(const ReadableString &filename, bool write) {
|
|
|
Buffer buffer;
|
|
|
return FILE_ACCESS_FUNCTION(toNativeString(filename, buffer), FILE_ACCESS_SELECTION);
|
|
|
@@ -101,77 +129,97 @@ const char32_t* file_separator() {
|
|
|
return pathSeparator;
|
|
|
}
|
|
|
|
|
|
-ReadableString file_getPathlessName(const ReadableString &path) {
|
|
|
- int lastSeparator = -1;
|
|
|
+inline bool isSeparator(DsrChar c) {
|
|
|
+ return c == U'\\' || c == U'/';
|
|
|
+}
|
|
|
+
|
|
|
+// Returns the index of the last / or \ in path, or defaultIndex if none existed.
|
|
|
+static int64_t getLastSeparator(const ReadableString &path, int defaultIndex) {
|
|
|
for (int64_t i = string_length(path) - 1; i >= 0; i--) {
|
|
|
DsrChar c = path[i];
|
|
|
- if (c == U'\\' || c == U'/') {
|
|
|
- lastSeparator = i;
|
|
|
- break;
|
|
|
+ if (isSeparator(c)) {
|
|
|
+ return i;
|
|
|
}
|
|
|
}
|
|
|
- return string_after(path, lastSeparator);
|
|
|
+ return defaultIndex;
|
|
|
}
|
|
|
|
|
|
-List<String> file_convertInputArguments(int argn, NativeChar **argv) {
|
|
|
- List<String> result;
|
|
|
- result.reserve(argn);
|
|
|
- for (int a = 0; a < argn; a++) {
|
|
|
- result.push(fromNativeString(argv[a]));
|
|
|
- }
|
|
|
- return result;
|
|
|
+ReadableString file_getPathlessName(const ReadableString &path) {
|
|
|
+ return string_after(path, getLastSeparator(path, -1));
|
|
|
}
|
|
|
|
|
|
-#ifdef __cpp_lib_filesystem
|
|
|
+ReadableString file_getFolderPath(const ReadableString &path) {
|
|
|
+ return string_before(path, getLastSeparator(path, string_length(path)));
|
|
|
+}
|
|
|
|
|
|
-static String fromU32String(std::u32string text) {
|
|
|
- dsr::String result;
|
|
|
- string_reserve(result, text.length());
|
|
|
- int i = 0;
|
|
|
- while (true) {
|
|
|
- DsrChar c = text[i];
|
|
|
- if (c == '\0') {
|
|
|
- break;
|
|
|
- } else {
|
|
|
- string_appendChar(result, c);
|
|
|
- }
|
|
|
- i++;
|
|
|
- }
|
|
|
- return result;
|
|
|
+bool file_hasRoot(const ReadableString &path) {
|
|
|
+ #ifdef USE_MICROSOFT_WINDOWS
|
|
|
+ // If a colon is found, it is a root path.
|
|
|
+ return string_findFirst(path, U':') > -1;
|
|
|
+ #else
|
|
|
+ // If the path begins with a separator, it is the root folder in Posix systems.
|
|
|
+ return path[0] == U'/';
|
|
|
+ #endif
|
|
|
}
|
|
|
|
|
|
-#define FROM_PATH(CONTENT) fromU32String((CONTENT).generic_u32string())
|
|
|
+String file_getCurrentPath() {
|
|
|
+ #ifdef USE_MICROSOFT_WINDOWS
|
|
|
+ NativeChar resultBuffer[maxLength + 1] = {0};
|
|
|
+ GetCurrentDirectoryW(maxLength, resultBuffer);
|
|
|
+ return fromNativeString(resultBuffer);
|
|
|
+ #else
|
|
|
+ NativeChar resultBuffer[maxLength + 1] = {0};
|
|
|
+ getcwd(resultBuffer, maxLength);
|
|
|
+ return fromNativeString(resultBuffer);
|
|
|
+ #endif
|
|
|
+}
|
|
|
|
|
|
-// Macros for creating wrapper functions
|
|
|
-#define DEF_FUNC_VOID_TO_STRING(FUNC_NAME, CALL_NAME) String FUNC_NAME() { return FROM_PATH(CALL_NAME()); }
|
|
|
-#define DEF_FUNC_STRING_TO_STRING(FUNC_NAME, ARG_NAME, CALL_NAME) String FUNC_NAME(const ReadableString& ARG_NAME) { Buffer buffer; return FROM_PATH(CALL_NAME(toNativeString(ARG_NAME, buffer))); }
|
|
|
-#define DEF_FUNC_STRING_TO_OTHER(FUNC_NAME, RETURN_TYPE, ARG_NAME, CALL_NAME) RETURN_TYPE FUNC_NAME(const ReadableString& ARG_NAME) { Buffer buffer; return CALL_NAME(toNativeString(ARG_NAME, buffer)); }
|
|
|
+#ifdef USE_MICROSOFT_WINDOWS
|
|
|
+static String file_getApplicationFilePath() {
|
|
|
+ NativeChar resultBuffer[maxLength + 1] = {0};
|
|
|
+ GetModuleFileNameW(nullptr, resultBuffer, maxLength);
|
|
|
+ return fromNativeString(resultBuffer);
|
|
|
+}
|
|
|
+#endif
|
|
|
|
|
|
-// Wrapper function implementations
|
|
|
-DEF_FUNC_VOID_TO_STRING(file_getCurrentPath, std::filesystem::current_path)
|
|
|
-DEF_FUNC_STRING_TO_STRING(file_getAbsolutePath, path, std::filesystem::absolute)
|
|
|
-DEF_FUNC_STRING_TO_STRING(file_getCanonicalPath, path, std::filesystem::canonical)
|
|
|
-DEF_FUNC_STRING_TO_OTHER(file_exists, bool, path, std::filesystem::exists)
|
|
|
-DEF_FUNC_STRING_TO_OTHER(file_getSize, int64_t, path, std::filesystem::file_size)
|
|
|
-DEF_FUNC_STRING_TO_OTHER(file_remove, bool, path, std::filesystem::remove)
|
|
|
-DEF_FUNC_STRING_TO_OTHER(file_removeRecursively, bool, path, std::filesystem::remove_all)
|
|
|
-DEF_FUNC_STRING_TO_OTHER(file_createFolder, bool, path, std::filesystem::create_directory)
|
|
|
+String file_getApplicationFolder(bool allowFallback) {
|
|
|
+ #ifdef USE_MICROSOFT_WINDOWS
|
|
|
+ return file_getFolderPath(file_getApplicationFilePath());
|
|
|
+ #else
|
|
|
+ #ifdef USE_LINUX
|
|
|
+ // TODO: Implement using "/proc/self/exe" on Linux
|
|
|
+ // https://www.wikitechy.com/tutorials/linux/how-to-find-the-location-of-the-executable-in-c
|
|
|
+ NativeChar resultBuffer[maxLength + 1] = {0};
|
|
|
+ //"/proc/curproc/file" on FreeBSD, which is not yet supported
|
|
|
+ //"/proc/self/path/a.out" on Solaris, which is not yet supported
|
|
|
+ readlink("/proc/self/exe", resultBuffer, maxLength);
|
|
|
+ return file_getFolderPath(fromNativeString(resultBuffer));
|
|
|
+ #else
|
|
|
+ if (allowFallback) {
|
|
|
+ return file_getCurrentPath();
|
|
|
+ } else {
|
|
|
+ throwError("file_getApplicationFolder is not implemented!\n");
|
|
|
+ }
|
|
|
+ #endif
|
|
|
+ #endif
|
|
|
+}
|
|
|
|
|
|
-void file_getFolderContent(const ReadableString& folderPath, std::function<void(ReadableString, EntryType)> action) {
|
|
|
- Buffer buffer;
|
|
|
- for (auto const& entry : std::filesystem::directory_iterator{toNativeString(folderPath, buffer)}) {
|
|
|
- EntryType entryType = EntryType::Unknown;
|
|
|
- if (entry.is_directory()) {
|
|
|
- entryType = EntryType::Folder;
|
|
|
- } else if (entry.is_regular_file()) {
|
|
|
- entryType = EntryType::File;
|
|
|
- } else if (entry.is_symlink()) {
|
|
|
- entryType = EntryType::SymbolicLink;
|
|
|
- }
|
|
|
- action(FROM_PATH(entry.path()), entryType);
|
|
|
+String file_combinePaths(const ReadableString &a, const ReadableString &b) {
|
|
|
+ if (isSeparator(a[string_length(a) - 1])) {
|
|
|
+ // Already ending with a separator.
|
|
|
+ return string_combine(a, b);
|
|
|
+ } else {
|
|
|
+ // Combine using a separator.
|
|
|
+ return string_combine(a, pathSeparator, b);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-#endif
|
|
|
+String file_getAbsolutePath(const ReadableString &path) {
|
|
|
+ if (file_hasRoot(path)) {
|
|
|
+ return path;
|
|
|
+ } else {
|
|
|
+ return file_combinePaths(file_getCurrentPath(), path);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
}
|