aboutsummaryrefslogtreecommitdiff
path: root/src/Platform.h
diff options
context:
space:
mode:
authorJesse Talavera-Greenberg <jesse@jesse.tg>2023-08-18 16:50:57 -0400
committerGitHub <noreply@github.com>2023-08-18 22:50:57 +0200
commitee5567708630441d8d3210e81d6e03d028fb7bbd (patch)
treeab92234123b16ec414d6c0da9bb0716c1b798229 /src/Platform.h
parentf454eba3c3243b095f0e6b9ddde3e68b095c5d8d (diff)
Assorted portability enhancements (#1800)
* Introduce some Platform calls for managing dynamic libraries * Add Platform::WriteFATSectors * Introduce some Platform calls for managing dynamic libraries * Add Platform::WriteFATSectors * Change includes of "../types.h" to "types.h" - Makes it easier to directly include these headers in downstream projects * Change an include of "../Wifi.h" to "Wifi.h" * Allow CommonFuncs.cpp to compile on Android * Tidy up some logging calls - Use Platform::Log in LAN_Socket.cpp - Soften some warnings to Debug logs (since they don't necessarily represent problems) * Add Platform::EnterGBAMode - Gracefully stop the emulator if trying to enter GBA mode * Soften some logs that most players won't care about * Soften some more logs * Introduce Platform wrappers for file operations * Fix pointer spacing * Fix more style nits * Log the errno when ftruncate fails * Fix FileSeek offset argument - With an s32 offset, we couldn't access files larger than 2GB * Revise Platform::StopEmu to address feedback - Remove Platform::EnterGBAMode in favor of adding a reason to Platform::StopEmu - Also rename Platform::StopEmu to Platform::SignalStop - Add an optional argument to NDS::Stop - Use the new argument everywhere that the console stops itself * Rename FileGetString to FileReadLine - It conveys the meaning better * Rename FileSeekOrigin::Set to Start - It conveys the meaning better * Change definition of FileGetString to FileReadLine - Oops, almost forgot it * Rename FlushFile to FileFlush - To remain consistent with the other File functions * Add a FileType usage * Fix line break in FileSeekOrigin * Document Platform::DeInit * Clarify that StopReason::Unknown doesn't always mean an error * Move and document FileType::HostFile * Remove Platform::OpenDataFile - Nothing currently uses it * Refactor Platform::OpenFile and Platform::OpenLocalFile to accept a FileMode enum instead of a string - The enum is converted to fopen flags under the hood - The file type is used to decide whether to add the "b" flag - Some helper functions are exposed for the benefit of consistent behavior among frontends - Equivalent behavior is maintained * Fix a tab that should be spaces * Use Windows' 64-bit implementations of fseek/ftell * Move Platform::IsBinaryFile to Platform.cpp - It could vary by frontend * Remove an unused FileType * Rename an enum constant * Document various Platform items * Use Platform::DynamicLibrary to load libandroid - And clean it up at the end * Fix a typo * Pass the correct filetype to FATStorage - Since it can be used for DSI NAND images or for SD cards * Remove Platform::FileType
Diffstat (limited to 'src/Platform.h')
-rw-r--r--src/Platform.h261
1 files changed, 224 insertions, 37 deletions
diff --git a/src/Platform.h b/src/Platform.h
index 59e7c02..91da4c1 100644
--- a/src/Platform.h
+++ b/src/Platform.h
@@ -28,12 +28,64 @@ namespace Platform
{
void Init(int argc, char** argv);
+
+/**
+ * Frees all resources that were allocated in \c Init
+ * or by any other \c Platform function.
+ */
void DeInit();
-void StopEmu();
+enum StopReason {
+ /**
+ * The emulator stopped for some unspecified reason.
+ * Not necessarily an error.
+ */
+ Unknown,
+
+ /**
+ * The emulator stopped due to an external call to \c NDS::Stop,
+ * most likely because the user stopped the game manually.
+ */
+ External,
+
+ /**
+ * The emulator stopped because it tried to enter GBA mode,
+ * which melonDS does not support.
+ */
+ GBAModeNotSupported,
+
+ /**
+ * The emulator stopped because of an error in the emulated console,
+ * not necessarily because of an error in melonDS.
+ */
+ BadExceptionRegion,
+
+ /**
+ * The emulated console shut itself down normally,
+ * likely because its system settings were adjusted
+ * or its "battery" ran out.
+ */
+ PowerOff,
+};
-// instance ID, for local multiplayer
+/**
+ * Signals to the frontend that no more frames should be requested.
+ * Frontends should not call this directly;
+ * use \c NDS::Stop instead.
+ */
+void SignalStop(StopReason reason);
+
+/**
+ * @returns The ID of the running melonDS instance if running in local multiplayer mode,
+ * or 0 if not.
+ */
int InstanceID();
+
+/**
+ * @returns A suffix that should be appended to all instance-specific paths
+ * if running in local multiplayer mode,
+ * or the empty string if not.
+ */
std::string InstanceFileSuffix();
// configuration values
@@ -82,6 +134,8 @@ enum ConfigEntry
Firm_Message,
Firm_MAC,
+ WifiSettingsPath,
+
AudioBitDepth,
DSi_FullBIOSBoot
@@ -92,43 +146,154 @@ bool GetConfigBool(ConfigEntry entry);
std::string GetConfigString(ConfigEntry entry);
bool GetConfigArray(ConfigEntry entry, void* data);
-// fopen() wrappers
-// * OpenFile():
-// simple fopen() wrapper that supports UTF8.
-// can be optionally restricted to only opening a file that already exists.
-// * OpenLocalFile():
-// opens files local to the emulator (melonDS.ini, BIOS, firmware, ...)
-// For Windows builds, or portable UNIX builds it checks, by order of priority:
-// * current working directory
-// * emulator directory (essentially where the melonDS executable is) if supported
-// * any platform-specific application data directories
-// in create mode, if the file doesn't exist, it will be created in the emulator
-// directory if supported, or in the current directory otherwise
-// For regular UNIX builds, the user's configuration directory is always used.
-// * OpenDataFile():
-// Opens a file that was installed alongside melonDS on UNIX systems in /usr/share, etc.
-// Looks in the user's data directory first, then the system's.
-// If on Windows or a portable UNIX build, this simply calls OpenLocalFile().
-
-FILE* OpenFile(const std::string& path, const std::string& mode, bool mustexist=false);
-FILE* OpenLocalFile(const std::string& path, const std::string& mode);
-FILE* OpenDataFile(const std::string& path);
-
-inline bool FileExists(const std::string& name)
-{
- FILE* f = OpenFile(name, "rb");
- if (!f) return false;
- fclose(f);
- return true;
-}
+/**
+ * Denotes how a file will be opened and accessed.
+ * Flags may or may not correspond to the operating system's file API.
+ */
+enum FileMode : unsigned {
+ None = 0,
+
+ /**
+ * Opens a file for reading.
+ * Either this or \c Write must be set.
+ * Similar to \c "r" in \c fopen.
+ */
+ Read = 0b00'00'01,
+
+ /**
+ * Opens a file for writing, creating it if it doesn't exist.
+ * Will truncate existing files unless \c Preserve is set.
+ * Either this or \c Read must be set.
+ * Similar to <tt>fopen</tt>'s \c "w" flag.
+ */
+ Write = 0b00'00'10,
+
+ /**
+ * Opens an existing file as-is without truncating it.
+ * The file may still be created unless \c NoCreate is set.
+ * @note This flag has no effect if \c Write is not set.
+ */
+ Preserve = 0b00'01'00,
+
+ /**
+ * Do not create the file if it doesn't exist.
+ * @note This flag has no effect if \c Write is not set.
+ */
+ NoCreate = 0b00'10'00,
+
+ /**
+ * Opens a file in text mode,
+ * rather than the default binary mode.
+ * Text-mode files may have their line endings converted
+ * to match the operating system,
+ * and may also be line-buffered.
+ */
+ Text = 0b01'00'00,
+
+ /**
+ * Opens a file for reading and writing.
+ * Equivalent to <tt>Read | Write</tt>.
+ */
+ ReadWrite = Read | Write,
+
+ /**
+ * Opens a file for reading and writing
+ * without truncating it or creating a new one.
+ * Equivalent to <tt>Read | Write | Preserve | NoCreate</tt>.
+ */
+ ReadWriteExisting = Read | Write | Preserve | NoCreate,
+
+ /**
+ * Opens a file for reading in text mode.
+ * Equivalent to <tt>Read | Text</tt>.
+ */
+ ReadText = Read | Text,
+
+ /**
+ * Opens a file for writing in text mode,
+ * creating it if it doesn't exist.
+ * Equivalent to <tt>Write | Text</tt>.
+ */
+ WriteText = Write | Text,
+};
-inline bool LocalFileExists(const std::string& name)
+/**
+ * Denotes the origin of a seek operation.
+ * Similar to \c fseek's \c SEEK_* constants.
+ */
+enum class FileSeekOrigin
{
- FILE* f = OpenLocalFile(name, "rb");
- if (!f) return false;
- fclose(f);
- return true;
-}
+ Start,
+ Current,
+ End,
+};
+
+/**
+ * Opaque handle for a file object.
+ * This can be implemented as a struct defined by the frontend,
+ * or as a simple pointer cast.
+ * The core will never look inside this struct,
+ * but frontends may do so freely.
+ */
+struct FileHandle;
+
+// Simple fopen() wrapper that supports UTF8.
+// Can be optionally restricted to only opening a file that already exists.
+FileHandle* OpenFile(const std::string& path, FileMode mode);
+
+// opens files local to the emulator (melonDS.ini, BIOS, firmware, ...)
+// For Windows builds, or portable UNIX builds it checks, by order of priority:
+// * current working directory
+// * emulator directory (essentially where the melonDS executable is) if supported
+// * any platform-specific application data directories
+// in create mode, if the file doesn't exist, it will be created in the emulator
+// directory if supported, or in the current directory otherwise
+// For regular UNIX builds, the user's configuration directory is always used.
+FileHandle* OpenLocalFile(const std::string& path, FileMode mode);
+
+/// Returns true if the given file exists.
+bool FileExists(const std::string& name);
+bool LocalFileExists(const std::string& name);
+
+/** Close a file opened with \c OpenFile.
+ * @returns \c true if the file was closed successfully, false otherwise.
+ * @post \c file is no longer valid and should not be used.
+ * The underlying object may still be allocated (e.g. if the frontend refcounts files),
+ * but that's an implementation detail.
+ * @see fclose
+ */
+bool CloseFile(FileHandle* file);
+
+/// @returns \c true if there is no more data left to read in this file,
+/// \c false if there is still data left to read or if there was an error.
+/// @see feof
+bool IsEndOfFile(FileHandle* file);
+
+/// @see fgets
+bool FileReadLine(char* str, int count, FileHandle* file);
+
+/// @see fseek
+bool FileSeek(FileHandle* file, s64 offset, FileSeekOrigin origin);
+
+/// @see rewind
+void FileRewind(FileHandle* file);
+
+/// @see fread
+u64 FileRead(void* data, u64 size, u64 count, FileHandle* file);
+
+/// @see fflush
+bool FileFlush(FileHandle* file);
+
+/// @see fwrite
+u64 FileWrite(const void* data, u64 size, u64 count, FileHandle* file);
+
+/// @see fprintf
+u64 FileWriteFormatted(FileHandle* file, const char* fmt, ...);
+
+/// @returns The length of the file in bytes, or 0 if there was an error.
+/// @note If this function checks the length by using \c fseek and \c ftell
+/// (or local equivalents), it must leave the stream position as it was found.
+u64 FileLength(FileHandle* file);
enum LogLevel
{
@@ -201,6 +366,28 @@ void Camera_Start(int num);
void Camera_Stop(int num);
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv);
+struct DynamicLibrary;
+
+/**
+ * @param lib The name of the library to load.
+ * @return A handle to the loaded library, or \c nullptr if the library could not be loaded.
+ */
+DynamicLibrary* DynamicLibrary_Load(const char* lib);
+
+/**
+ * Releases a loaded library.
+ * Pointers to functions in the library will be invalidated.
+ * @param lib The library to unload.
+ */
+void DynamicLibrary_Unload(DynamicLibrary* lib);
+
+/**
+ * Loads a function from a library.
+ * @param lib The library to load the function from.
+ * @param name The name of the function to load.
+ * @return A pointer to the loaded function, or \c nullptr if the function could not be loaded.
+ */
+void* DynamicLibrary_LoadFunction(DynamicLibrary* lib, const char* name);
}
#endif // PLATFORM_H