3232
3333#include " Common/Assert.h"
3434
35+ #ifdef __LIBRETRO__
36+ #include " DolphinLibretro/Common/File.h"
37+ #endif
38+
3539namespace File
3640{
3741DirectIOFile::DirectIOFile () = default ;
@@ -79,6 +83,17 @@ bool DirectIOFile::Open(const std::string& path, AccessMode access_mode, OpenMod
7983 if (access_mode == AccessMode::Read && open_mode == OpenMode::Truncate)
8084 return false ;
8185
86+ #ifdef __LIBRETRO__
87+ if (Libretro::File::HasVFS ())
88+ {
89+ // used in Duplicate() later
90+ m_path = path;
91+
92+ return Libretro::File::Open (path, access_mode, open_mode,
93+ m_vfs_handle, m_mode, m_hints, m_current_offset);
94+ }
95+ #endif
96+
8297#if defined(_WIN32)
8398 DWORD desired_access = GENERIC_READ | GENERIC_WRITE;
8499 if (access_mode == AccessMode::Read)
@@ -168,6 +183,15 @@ bool DirectIOFile::Close()
168183
169184 m_current_offset = 0 ;
170185
186+ #ifdef __LIBRETRO__
187+ if (Libretro::File::HasVFS ())
188+ {
189+ int result = Libretro::File::Close (m_vfs_handle);
190+ m_vfs_handle = nullptr ;
191+ return result == 0 ;
192+ }
193+ #endif
194+
171195#if defined(_WIN32)
172196 return CloseHandle (std::exchange (m_handle, INVALID_HANDLE_VALUE)) != 0 ;
173197#else
@@ -177,6 +201,11 @@ bool DirectIOFile::Close()
177201
178202bool DirectIOFile::IsOpen () const
179203{
204+ #ifdef __LIBRETRO__
205+ if (Libretro::File::HasVFS ())
206+ return m_vfs_handle != nullptr ;
207+ #endif
208+
180209#if defined(_WIN32)
181210 return m_handle != INVALID_HANDLE_VALUE;
182211#else
@@ -216,6 +245,17 @@ static bool OverlappedTransfer(HANDLE handle, u64 offset, auto* data_ptr, u64 si
216245
217246bool DirectIOFile::OffsetRead (u64 offset, u8 * out_ptr, u64 size)
218247{
248+ #ifdef __LIBRETRO__
249+ if (Libretro::File::HasVFS ())
250+ {
251+ if (Libretro::File::Seek (m_vfs_handle, offset, SEEK_SET) < 0 )
252+ return false ;
253+
254+ int64_t bytes_read = Libretro::File::ReadBytes (m_vfs_handle, out_ptr, size);
255+ return bytes_read == static_cast <int64_t >(size);
256+ }
257+ #endif
258+
219259#if defined(_WIN32)
220260 return OverlappedTransfer<ReadFile>(m_handle, offset, out_ptr, size);
221261#else
@@ -225,6 +265,17 @@ bool DirectIOFile::OffsetRead(u64 offset, u8* out_ptr, u64 size)
225265
226266bool DirectIOFile::OffsetWrite (u64 offset, const u8 * in_ptr, u64 size)
227267{
268+ #ifdef __LIBRETRO__
269+ if (Libretro::File::HasVFS ())
270+ {
271+ if (Libretro::File::Seek (m_vfs_handle, offset, SEEK_SET) < 0 )
272+ return false ;
273+
274+ int64_t bytes_written = Libretro::File::WriteBytes (m_vfs_handle, in_ptr, size);
275+ return bytes_written == static_cast <int64_t >(size);
276+ }
277+ #endif
278+
228279#if defined(_WIN32)
229280 return OverlappedTransfer<WriteFile>(m_handle, offset, in_ptr, size);
230281#else
@@ -234,6 +285,11 @@ bool DirectIOFile::OffsetWrite(u64 offset, const u8* in_ptr, u64 size)
234285
235286u64 DirectIOFile::GetSize () const
236287{
288+ #ifdef __LIBRETRO__
289+ if (Libretro::File::HasVFS ())
290+ return Libretro::File::GetSize (m_vfs_handle);
291+ #endif
292+
237293#if defined(_WIN32)
238294 LARGE_INTEGER result{};
239295 if (GetFileSizeEx (m_handle, &result) != 0 )
@@ -275,6 +331,11 @@ bool DirectIOFile::Seek(s64 offset, SeekOrigin origin)
275331
276332bool DirectIOFile::Flush ()
277333{
334+ #ifdef __LIBRETRO__
335+ if (Libretro::File::HasVFS ())
336+ return Libretro::File::Flush (m_vfs_handle) == 0 ;
337+ #endif
338+
278339#if defined(_WIN32)
279340 return FlushFileBuffers (m_handle) != 0 ;
280341#else
@@ -284,6 +345,16 @@ bool DirectIOFile::Flush()
284345
285346void DirectIOFile::Swap (DirectIOFile& other)
286347{
348+ #ifdef __LIBRETRO__
349+ if (Libretro::File::HasVFS ())
350+ {
351+ std::swap (m_vfs_handle, other.m_vfs_handle );
352+ std::swap (m_path, other.m_path );
353+ std::swap (m_mode, other.m_mode );
354+ std::swap (m_hints, other.m_hints );
355+ }
356+ #endif
357+
287358#if defined(_WIN32)
288359 std::swap (m_handle, other.m_handle );
289360#else
@@ -299,6 +370,30 @@ DirectIOFile DirectIOFile::Duplicate() const
299370 if (!IsOpen ())
300371 return result;
301372
373+ #ifdef __LIBRETRO__
374+ if (Libretro::File::HasVFS ())
375+ {
376+ // We need to reopen the file, since VFS handles cannot be duplicated.
377+ result.m_vfs_handle = Libretro::File::Open (
378+ m_path, m_mode, m_hints);
379+
380+ if (result.m_vfs_handle )
381+ {
382+ result.m_path = m_path;
383+ result.m_mode = m_mode;
384+ result.m_hints = m_hints;
385+
386+ // Restore offset if possible
387+ Libretro::File::Seek (
388+ result.m_vfs_handle ,
389+ m_current_offset,
390+ SEEK_SET);
391+ result.m_current_offset = m_current_offset;
392+ }
393+ return result;
394+ }
395+ #endif
396+
302397#if defined(_WIN32)
303398 const auto current_process = GetCurrentProcess ();
304399 if (DuplicateHandle (current_process, m_handle, current_process, &result.m_handle , 0 , FALSE ,
@@ -319,6 +414,11 @@ DirectIOFile DirectIOFile::Duplicate() const
319414
320415bool Resize (DirectIOFile& file, u64 size)
321416{
417+ #ifdef __LIBRETRO__
418+ if (Libretro::File::HasVFS ())
419+ return Libretro::File::Truncate (file.m_vfs_handle , size) == 0 ;
420+ #endif
421+
322422#if defined(_WIN32)
323423 // This operation is not "atomic", but it's the only thing we're using the file pointer for.
324424 // Concurrent `Resize` would need some external synchronization to prevent race regardless.
@@ -333,6 +433,11 @@ bool Resize(DirectIOFile& file, u64 size)
333433bool Rename (DirectIOFile& file, const std::string& source_path [[maybe_unused]],
334434 const std::string& destination_path)
335435{
436+ #ifdef __LIBRETRO__
437+ if (Libretro::File::HasVFS ())
438+ return file.IsOpen () && Libretro::File::Rename (source_path, destination_path);
439+ #endif
440+
336441#if defined(_WIN32)
337442 const auto dest_name = UTF8ToWString (destination_path);
338443 const auto dest_name_byte_size = DWORD (dest_name.size () * sizeof (WCHAR));
@@ -354,6 +459,11 @@ bool Rename(DirectIOFile& file, const std::string& source_path [[maybe_unused]],
354459
355460bool Delete (DirectIOFile& file, const std::string& filename)
356461{
462+ #ifdef __LIBRETRO__
463+ if (Libretro::File::HasVFS ())
464+ return file.IsOpen () && Libretro::File::Delete (filename);
465+ #endif
466+
357467#if defined(_WIN32)
358468 FILE_DISPOSITION_INFO info{.DeleteFile = TRUE };
359469 return SetFileInformationByHandle (file.GetHandle (), FileDispositionInfo, &info, sizeof (info)) !=
0 commit comments