diff options
author | Jesse Talavera-Greenberg <jesse@jesse.tg> | 2023-08-18 16:50:57 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-18 22:50:57 +0200 |
commit | ee5567708630441d8d3210e81d6e03d028fb7bbd (patch) | |
tree | ab92234123b16ec414d6c0da9bb0716c1b798229 /src/Platform.h | |
parent | f454eba3c3243b095f0e6b9ddde3e68b095c5d8d (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.h | 261 |
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 |