Use the libretro VFS interface in libretro builds

This commit is contained in:
刘皓
2026-01-01 00:24:01 -05:00
parent a018cfc017
commit 5716cbd41d
30 changed files with 624 additions and 252 deletions
+13
View File
@@ -256,6 +256,7 @@ if(LIBRETRO)
if(NOT MSVC)
add_compile_options(-fPIC)
endif()
add_compile_definitions(HAVE_LIBRETRO_VFS)
endif()
if(ANDROID)
@@ -944,6 +945,10 @@ add_library(Common STATIC
Common/TimeUtil.h
)
if(LIBRETRO)
target_include_directories(Common PRIVATE libretro/libretro-common/include)
endif()
include_directories(Common)
setup_target_project(Common Common)
@@ -1685,6 +1690,10 @@ add_library(native STATIC
ext/jpge/jpge.h
)
if(LIBRETRO)
target_include_directories(native PRIVATE libretro/libretro-common/include)
endif()
if(LINUX AND NOT ANDROID)
set(RT_LIB rt)
endif()
@@ -2509,6 +2518,10 @@ add_library(${CoreLibName} ${CoreLinkType}
${CMAKE_CURRENT_BINARY_DIR}/git-version.cpp
)
if(LIBRETRO)
target_include_directories(${CoreLibName} PRIVATE libretro/libretro-common/include)
endif()
if(ANDROID)
set(CoreExtraLibs ${CoreExtraLibs} android)
if(X86_64)
+41 -13
View File
@@ -134,12 +134,7 @@ bool PNGHeaderPeek::IsValidPNGHeader() const {
}
bool pngSave(const Path &filename, const void *buffer, int w, int h, int bytesPerPixel) {
png_image png{};
png.version = PNG_IMAGE_VERSION;
png.format = bytesPerPixel == 3 ? PNG_FORMAT_RGB : PNG_FORMAT_RGBA;
png.width = w;
png.height = h;
const int row_stride = w * bytesPerPixel;
png_bytepp row_ptrs = nullptr;
FILE *fp = File::OpenCFile(filename, "wb");
if (!fp) {
@@ -147,16 +142,28 @@ bool pngSave(const Path &filename, const void *buffer, int w, int h, int bytesPe
return false;
}
int result = png_image_write_to_stdio(&png, fp, 0, buffer, row_stride, nullptr);
if (png.warning_or_error >= 2) {
ERROR_LOG(Log::IO, "Saving image to PNG produced errors.");
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, pngErrorHandler, pngWarningHandler);
if (png_ptr == nullptr) {
fclose(fp);
ERROR_LOG(Log::IO, "PNG encode failed.");
return false;
}
png_image_free(&png);
fclose(fp);
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) {
png_destroy_write_struct(&png_ptr, nullptr);
fclose(fp);
ERROR_LOG(Log::IO, "PNG encode failed.");
return false;
}
if (setjmp(png_jmpbuf(png_ptr))) {
if (row_ptrs != nullptr) {
png_free(png_ptr, row_ptrs);
}
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
if (!result) {
// Should we even do this?
File::Delete(filename);
@@ -164,5 +171,26 @@ bool pngSave(const Path &filename, const void *buffer, int w, int h, int bytesPe
return false;
}
png_set_write_fn(png_ptr, fp, [](png_structp png_ptr, png_bytep data, png_size_t size) {
if (fwrite(data, 1, size, (FILE *)png_get_io_ptr(png_ptr)) < size) {
png_error(png_ptr, "Failed to write to file.");
}
}, [](png_structp png_ptr) {
fflush((FILE *)png_get_io_ptr(png_ptr));
});
png_set_IHDR(png_ptr, info_ptr, w, h, 8, bytesPerPixel == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
row_ptrs = (png_bytepp)png_malloc(png_ptr, (png_alloc_size_t)h * (png_alloc_size_t)sizeof(png_bytep));
for (png_alloc_size_t i = 0; i < h; ++i) {
row_ptrs[i] = (png_bytep)buffer + (png_alloc_size_t)w * (png_alloc_size_t)bytesPerPixel * i;
}
png_set_rows(png_ptr, info_ptr, row_ptrs);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
png_free(png_ptr, row_ptrs);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return true;
}
+163 -53
View File
@@ -77,6 +77,10 @@
#endif // !PPSSPP_PLATFORM(IOS)
#endif // __APPLE__
#ifdef HAVE_LIBRETRO_VFS
#include <file/file_path.h>
#endif
#include "Common/Data/Encoding/Utf8.h"
#include <sys/stat.h>
@@ -105,11 +109,27 @@ constexpr bool LOG_IO = false;
#define DIR_SEP_CHRS "/"
#endif
#ifdef HAVE_LIBRETRO_VFS
retro_vfs_mkdir_t LibretroMkdirCallback = nullptr;
static int LibretroMkdir(const char *path) noexcept {
return LibretroMkdirCallback != nullptr ? LibretroMkdirCallback(path) : retro_vfs_mkdir_impl(path);
}
#endif
// This namespace has various generic functions related to files and paths.
// The code still needs a ton of cleanup.
// REMEMBER: strdup considered harmful!
namespace File {
#ifdef HAVE_LIBRETRO_VFS
void InitLibretroVFS(const struct retro_vfs_interface_info *vfs) noexcept {
filestream_vfs_init(vfs);
path_vfs_init(vfs);
LibretroMkdirCallback = vfs->required_interface_version >= 3 ? vfs->iface->mkdir : nullptr;
}
#endif
FILE *OpenCFile(const Path &path, const char *mode) {
if (LOG_IO) {
INFO_LOG(Log::IO, "OpenCFile %s, %s", path.c_str(), mode);
@@ -120,6 +140,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
switch (path.Type()) {
case PathType::NATIVE:
break;
#ifndef HAVE_LIBRETRO_VFS
case PathType::CONTENT_URI:
// We're gonna need some error codes..
if (!strcmp(mode, "r") || !strcmp(mode, "rb") || !strcmp(mode, "rt")) {
@@ -167,7 +188,7 @@ FILE *OpenCFile(const Path &path, const char *mode) {
FILE *f = fdopen(descriptor, fmode);
if (f && (!strcmp(mode, "at") || !strcmp(mode, "a"))) {
// Append mode - not sure we got a "true" append mode, so seek to the end.
fseek(f, 0, SEEK_END);
Fseek(f, 0, SEEK_END);
}
return f;
} else {
@@ -175,12 +196,29 @@ FILE *OpenCFile(const Path &path, const char *mode) {
return nullptr;
}
break;
#endif
default:
ERROR_LOG(Log::IO, "OpenCFile(%s): PathType not yet supported", path.c_str());
return nullptr;
}
#if defined(_WIN32) && defined(UNICODE)
#ifdef HAVE_LIBRETRO_VFS
if (!strcmp(mode, "r") || !strcmp(mode, "rb") || !strcmp(mode, "rt")) {
INFO_LOG(Log::IO, "OpenCFile(%s): Opening content file for read.", path.c_str());
return filestream_open(path.c_str(), RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
} else if (!strcmp(mode, "w") || !strcmp(mode, "wb") || !strcmp(mode, "wt") || !strcmp(mode, "at") || !strcmp(mode, "a")) {
INFO_LOG(Log::IO, "OpenCFile(%s): Opening content file for write.", path.c_str());
bool append = !strcmp(mode, "at") || !strcmp(mode, "a");
FILE *f = filestream_open(path.c_str(), append && Exists(path) ? RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (f != nullptr && append) {
Fseek(f, 0, SEEK_END);
}
return f;
} else {
ERROR_LOG(Log::IO, "OpenCFile(%s): Mode not yet supported: %s", path.c_str(), mode);
return nullptr;
}
#elif defined(_WIN32) && defined(UNICODE)
#if PPSSPP_PLATFORM(UWP) && !defined(__LIBRETRO__)
// We shouldn't use _wfopen here,
// this function is not allowed to read outside Local and Installation folders
@@ -438,7 +476,9 @@ bool Exists(const Path &path) {
return Android_FileExists(path.c_str());
}
#if defined(_WIN32)
#ifdef HAVE_LIBRETRO_VFS
return path_is_valid(path.c_str());
#elif defined(_WIN32)
// Make sure Windows will no longer handle critical errors, which means no annoying "No disk" dialog
#if !PPSSPP_PLATFORM(UWP)
@@ -488,7 +528,9 @@ bool IsDirectory(const Path &path) {
return false;
}
#if defined(_WIN32)
#ifdef HAVE_LIBRETRO_VFS
return path_is_directory(path.c_str());
#elif defined(_WIN32)
WIN32_FILE_ATTRIBUTE_DATA data{};
#if PPSSPP_PLATFORM(UWP)
if (!GetFileAttributesExFromAppW(path.ToWString().c_str(), GetFileExInfoStandard, &data) || data.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
@@ -543,7 +585,12 @@ bool Delete(const Path &filename) {
return false;
}
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
if (filestream_delete(filename.c_str()) != 0) {
WARN_LOG(Log::IO, "Delete: DeleteFile failed on %s", filename.c_str());
return false;
}
#elif defined(_WIN32)
#if PPSSPP_PLATFORM(UWP)
if (!DeleteFileFromAppW(filename.ToWString().c_str())) {
WARN_LOG(Log::IO, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg().c_str());
@@ -603,7 +650,17 @@ bool CreateDir(const Path &path) {
}
DEBUG_LOG(Log::IO, "CreateDir('%s')", path.c_str());
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
switch (LibretroMkdir(path.ToString().c_str())) {
case -2:
DEBUG_LOG(Log::IO, "CreateDir: mkdir failed on %s: already exists", path.c_str());
case 0:
return true;
default:
ERROR_LOG(Log::IO, "CreateDir: mkdir failed on %s", path.c_str());
return false;
}
#elif defined(_WIN32)
#if PPSSPP_PLATFORM(UWP)
if (CreateDirectoryFromAppW(path.ToWString().c_str(), NULL))
return true;
@@ -715,6 +772,13 @@ bool Rename(const Path &srcFilename, const Path &destFilename) {
INFO_LOG(Log::IO, "Rename: %s --> %s", srcFilename.c_str(), destFilename.c_str());
#ifdef HAVE_LIBRETRO_VFS
if (filestream_rename(srcFilename.c_str(), destFilename.c_str()) == 0)
return true;
ERROR_LOG(Log::IO, "Rename: failed %s --> %s",
srcFilename.c_str(), destFilename.c_str());
return false;
#else
#if defined(_WIN32) && defined(UNICODE)
#if PPSSPP_PLATFORM(UWP)
if (MoveFileFromAppW(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str()))
@@ -733,6 +797,7 @@ bool Rename(const Path &srcFilename, const Path &destFilename) {
ERROR_LOG(Log::IO, "Rename: failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg().c_str());
return false;
#endif
}
// copies file srcFilename to destFilename, returns true on success
@@ -762,7 +827,7 @@ bool Copy(const Path &srcFilename, const Path &destFilename) {
}
INFO_LOG(Log::IO, "Copy by OpenCFile: %s --> %s", srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
#if defined(_WIN32) && !defined(HAVE_LIBRETRO_VFS)
#if PPSSPP_PLATFORM(UWP)
if (CopyFileFromAppW(srcFilename.ToWString().c_str(), destFilename.ToWString().c_str(), FALSE))
return true;
@@ -906,7 +971,9 @@ uint64_t GetFileSize(const Path &filename) {
return false;
}
#if defined(_WIN32) && defined(UNICODE)
#ifdef HAVE_LIBRETRO_VFS
return path_get_size(filename.c_str());
#elif defined(_WIN32) && defined(UNICODE)
WIN32_FILE_ATTRIBUTE_DATA attr;
#if PPSSPP_PLATFORM(UWP)
if (!GetFileAttributesExFromAppW(filename.ToWString().c_str(), GetFileExInfoStandard, &attr))
@@ -939,45 +1006,19 @@ uint64_t GetFileSize(const Path &filename) {
}
uint64_t GetFileSize(FILE *f) {
// This will only support 64-bit when large file support is available.
// That won't be the case on some versions of Android, at least.
#if defined(__ANDROID__) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
int fd = fileno(f);
off64_t pos = lseek64(fd, 0, SEEK_CUR);
off64_t size = lseek64(fd, 0, SEEK_END);
if (size != pos && lseek64(fd, pos, SEEK_SET) != pos) {
uint64_t pos = Ftell(f);
if (Fseek(f, 0, SEEK_END) != 0) {
return 0;
}
uint64_t size = Ftell(f);
// Reset the seek position to where it was when we started.
if (size != pos && Fseek(f, pos, SEEK_SET) != 0) {
// Should error here.
return 0;
}
if (size == -1)
return 0;
return size;
#else
#ifdef _WIN32
uint64_t pos = _ftelli64(f);
#else
uint64_t pos = ftello(f);
#endif
if (fseek(f, 0, SEEK_END) != 0) {
return 0;
}
#ifdef _WIN32
uint64_t size = _ftelli64(f);
// Reset the seek position to where it was when we started.
if (size != pos && _fseeki64(f, pos, SEEK_SET) != 0) {
#else
uint64_t size = ftello(f);
// Reset the seek position to where it was when we started.
if (size != pos && fseeko(f, pos, SEEK_SET) != 0) {
#endif
// Should error here.
return 0;
}
if (size == -1)
return 0;
return size;
#endif
}
// creates an empty file filename, returns true on success
@@ -1017,6 +1058,12 @@ bool DeleteDir(const Path &path) {
return false;
}
#ifdef HAVE_LIBRETRO_VFS
if (filestream_delete(path.c_str()) == 0)
return true;
ERROR_LOG(Log::IO, "DeleteDir: %s", path.c_str());
return false;
#else
#ifdef _WIN32
#if PPSSPP_PLATFORM(UWP)
if (RemoveDirectoryFromAppW(path.ToWString().c_str()))
@@ -1032,6 +1079,7 @@ bool DeleteDir(const Path &path) {
ERROR_LOG(Log::IO, "DeleteDir: %s: %s", path.c_str(), GetLastErrorMsg().c_str());
return false;
#endif
}
// Deletes the given directory and anything under it. Returns true on success.
@@ -1164,6 +1212,64 @@ const Path &GetExeDirectory() {
return ExePath;
}
int Fseek(FILE *file, int64_t offset, int whence) {
#ifdef HAVE_LIBRETRO_VFS
switch (whence) {
default:
whence = RETRO_VFS_SEEK_POSITION_START;
break;
case SEEK_CUR:
whence = RETRO_VFS_SEEK_POSITION_CURRENT;
break;
case SEEK_END:
whence = RETRO_VFS_SEEK_POSITION_END;
break;
}
return filestream_seek(file, offset, whence) < 0 ? -1 : 0;
#elif defined(_WIN32)
return _fseeki64(file, offset, whence);
#elif defined(__ANDROID__) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
return lseek64(fileno(file), offset, whence) == -1 ? -1 : 0;
#else
return fseeko(file, offset, whence);
#endif
}
int64_t Fseektell(FILE *file, int64_t offset, int whence) {
#ifdef HAVE_LIBRETRO_VFS
switch (whence) {
default:
whence = RETRO_VFS_SEEK_POSITION_START;
break;
case SEEK_CUR:
whence = RETRO_VFS_SEEK_POSITION_CURRENT;
break;
case SEEK_END:
whence = RETRO_VFS_SEEK_POSITION_END;
break;
}
return filestream_seek(file, offset, whence) < 0 ? -1 : filestream_tell(file);
#elif defined(_WIN32)
return _fseeki64(file, offset, whence) != 0 ? -1 : _ftelli64(file);
#elif defined(__ANDROID__) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
return lseek64(fileno(file), offset, whence);
#else
return fseeko(file, offset, whence) != 0 ? -1 : ftello(file);
#endif
}
int64_t Ftell(FILE *file) {
#ifdef HAVE_LIBRETRO_VFS
return filestream_tell(file);
#elif defined(_WIN32)
return _ftelli64(file);
#elif defined(__ANDROID__) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)
return lseek64(fileno(file), 0, SEEK_CUR);
#else
return ftello(file);
#endif
}
IOFile::IOFile(const Path &filename, const char openmode[]) {
Open(filename, openmode);
@@ -1183,21 +1289,21 @@ bool IOFile::Open(const Path& filename, const char openmode[])
bool IOFile::Close()
{
if (!IsOpen() || 0 != std::fclose(m_file))
if (!IsOpen() || 0 != fclose(m_file))
m_good = false;
m_file = NULL;
return m_good;
}
std::FILE* IOFile::ReleaseHandle()
FILE* IOFile::ReleaseHandle()
{
std::FILE* const ret = m_file;
FILE* const ret = m_file;
m_file = NULL;
return ret;
}
void IOFile::SetHandle(std::FILE* file)
void IOFile::SetHandle(FILE* file)
{
Close();
Clear();
@@ -1214,7 +1320,7 @@ uint64_t IOFile::GetSize()
bool IOFile::Seek(int64_t off, int origin)
{
if (!IsOpen() || 0 != fseeko(m_file, off, origin))
if (!IsOpen() || 0 != Fseek(m_file, off, origin))
m_good = false;
return m_good;
@@ -1223,14 +1329,14 @@ bool IOFile::Seek(int64_t off, int origin)
uint64_t IOFile::Tell()
{
if (IsOpen())
return ftello(m_file);
return Ftell(m_file);
else
return -1;
}
bool IOFile::Flush()
{
if (!IsOpen() || 0 != std::fflush(m_file))
if (!IsOpen() || 0 != fflush(m_file))
m_good = false;
return m_good;
@@ -1239,7 +1345,9 @@ bool IOFile::Flush()
bool IOFile::Resize(uint64_t size)
{
if (!IsOpen() || 0 !=
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
filestream_truncate(m_file, size)
#elif defined(_WIN32)
// ector: _chsize sucks, not 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe
_chsize_s(_fileno(m_file), size)
@@ -1280,7 +1388,7 @@ bool ReadFileToStringOptions(bool textFile, bool allowShort, const Path &filenam
if (textFile) {
// totalRead doesn't take \r into account since they might be skipped in this mode.
// So let's just ask how far the cursor got.
totalRead = ftell(f);
totalRead = Ftell(f);
}
success = allowShort ? (totalRead <= len) : (totalRead == len);
}
@@ -1294,14 +1402,14 @@ uint8_t *ReadLocalFile(const Path &filename, size_t *size) {
*size = 0;
return nullptr;
}
fseek(file, 0, SEEK_END);
size_t f_size = ftell(file);
Fseek(file, 0, SEEK_END);
size_t f_size = Ftell(file);
if ((long)f_size < 0) {
*size = 0;
fclose(file);
return nullptr;
}
fseek(file, 0, SEEK_SET);
Fseek(file, 0, SEEK_SET);
// NOTE: If you find ~10 memory leaks from here, with very varying sizes, it might be the VFPU LUTs.
uint8_t *contents = new uint8_t[f_size + 1];
if (fread(contents, 1, f_size, file) != f_size) {
@@ -1349,6 +1457,7 @@ void ChangeMTime(const Path &path, time_t mtime) {
return;
}
#ifndef HAVE_LIBRETRO_VFS
#ifdef _WIN32
_utimbuf buf{};
buf.actime = mtime;
@@ -1360,6 +1469,7 @@ void ChangeMTime(const Path &path, time_t mtime) {
buf.modtime = mtime;
utime(path.c_str(), &buf);
#endif
#endif
}
bool IsProbablyInDownloadsFolder(const Path &filename) {
+27 -7
View File
@@ -17,7 +17,6 @@
#pragma once
#include <fstream>
#include <cstdio>
#include <string>
#include <string_view>
@@ -137,6 +136,19 @@ const Path &GetExeDirectory();
const Path GetCurDirectory();
// Portable version of fseek() that works with 64-bit offsets if supported by
// the operating system.
int Fseek(FILE *file, int64_t offset, int whence);
// Portable version of fseek() that works with 64-bit offsets if supported by
// the operating system, and returns the new offset from the start of the file
// or -1 if it failed.
int64_t Fseektell(FILE *file, int64_t offset, int whence);
// Portable version of ftell() that works with 64-bit offsets if supported by
// the operating system.
int64_t Ftell(FILE *file);
// simple wrapper for cstdlib file functions to
// hopefully will make error checking easier
// and make forgetting an fclose() harder
@@ -156,7 +168,7 @@ public:
template <typename T>
bool ReadArray(T* data, size_t length)
{
if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file))
if (!IsOpen() || length != fread(data, sizeof(T), length, m_file))
m_good = false;
return m_good;
@@ -165,7 +177,7 @@ public:
template <typename T>
bool WriteArray(const T* data, size_t length)
{
if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file))
if (!IsOpen() || length != fwrite(data, sizeof(T), length, m_file))
m_good = false;
return m_good;
@@ -187,11 +199,11 @@ public:
bool IsGood() const { return m_good; }
operator bool() const { return IsGood() && IsOpen(); }
std::FILE* ReleaseHandle();
FILE* ReleaseHandle();
std::FILE* GetHandle() { return m_file; }
FILE* GetHandle() { return m_file; }
void SetHandle(std::FILE* file);
void SetHandle(FILE* file);
bool Seek(int64_t off, int origin);
uint64_t Tell();
@@ -202,15 +214,23 @@ public:
// clear error state
void Clear() {
m_good = true;
#ifndef HAVE_LIBRETRO_VFS
#undef clearerr
std::clearerr(m_file);
#endif
}
private:
std::FILE *m_file = nullptr;
FILE *m_file = nullptr;
bool m_good = true;
};
#ifdef HAVE_LIBRETRO_VFS
// Call this on libretro core initialization with the libretro virtual file
// system interface.
void InitLibretroVFS(const struct retro_vfs_interface_info *vfs) noexcept;
#endif
// TODO: Refactor, this was moved from the old file_util.cpp.
// Whole-file reading/writing
+4
View File
@@ -5,6 +5,10 @@
#include <string>
#include <string_view>
#ifdef HAVE_LIBRETRO_VFS
#include "libretro/LibretroFileStreamTransforms.h"
#endif
#if defined(__APPLE__)
#if TARGET_OS_IPHONE
+4 -4
View File
@@ -77,9 +77,9 @@ VFSOpenFile *DirectoryReader::OpenFileForRead(VFSFileReference *vfsReference, si
if (!file) {
return nullptr;
}
fseek(file, 0, SEEK_END);
*size = ftell(file);
fseek(file, 0, SEEK_SET);
File::Fseek(file, 0, SEEK_END);
*size = File::Ftell(file);
File::Fseek(file, 0, SEEK_SET);
DirectoryReaderOpenFile *openFile = new DirectoryReaderOpenFile();
openFile->file = file;
return openFile;
@@ -87,7 +87,7 @@ VFSOpenFile *DirectoryReader::OpenFileForRead(VFSFileReference *vfsReference, si
void DirectoryReader::Rewind(VFSOpenFile *vfsOpenFile) {
DirectoryReaderOpenFile *openFile = (DirectoryReaderOpenFile *)vfsOpenFile;
fseek(openFile->file, 0, SEEK_SET);
File::Fseek(openFile->file, 0, SEEK_SET);
}
size_t DirectoryReader::Read(VFSOpenFile *vfsOpenFile, void *buffer, size_t length) {
+129 -39
View File
@@ -15,41 +15,146 @@
#include "Common/File/VFS/ZipFileReader.h"
#include "Common/StringUtils.h"
ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath, bool logErrors) {
int error = 0;
zip *zip_file;
if (zipFile.Type() == PathType::CONTENT_URI) {
int fd = File::OpenFD(zipFile, File::OPEN_READ);
if (!fd) {
if (logErrors) {
ERROR_LOG(Log::IO, "Failed to open FD for '%s' as zip file", zipFile.c_str());
ZipContainer::ZipContainer() noexcept : sourceData_ {{}, nullptr}, zip_(nullptr) {}
ZipContainer::ZipContainer(const Path &path) : sourceData_ {path, nullptr}, zip_(nullptr) {
zip_source_t *source = zip_source_function_create(SourceCallback, &sourceData_, nullptr);
if ((zip_ = zip_open_from_source(source, ZIP_RDONLY, nullptr)) == nullptr) {
zip_source_free(source);
}
}
ZipContainer::ZipContainer(ZipContainer &&other) noexcept : sourceData_(other.sourceData_), zip_(other.zip_) {
other.sourceData_.path.clear();
other.sourceData_.file = nullptr;
other.zip_ = nullptr;
}
ZipContainer &ZipContainer::operator=(ZipContainer &&other) noexcept {
sourceData_ = other.sourceData_;
zip_ = other.zip_;
other.sourceData_.path.clear();
other.sourceData_.file = nullptr;
other.zip_ = nullptr;
return *this;
}
ZipContainer::~ZipContainer() {
close();
}
void ZipContainer::close() noexcept {
if (zip_ != nullptr) {
zip_close(zip_);
zip_ = nullptr;
}
}
ZipContainer::operator zip_t *() const noexcept {
return zip_;
}
zip_int64_t ZipContainer::SourceCallback(void *userdata, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
SourceData &sourceData = *(SourceData *)userdata;
switch (cmd) {
case ZIP_SOURCE_SUPPORTS:
return zip_source_make_command_bitmap(
ZIP_SOURCE_SUPPORTS,
ZIP_SOURCE_OPEN,
ZIP_SOURCE_READ,
ZIP_SOURCE_CLOSE,
ZIP_SOURCE_STAT,
ZIP_SOURCE_ERROR,
ZIP_SOURCE_SEEK,
ZIP_SOURCE_TELL,
-1);
case ZIP_SOURCE_OPEN:
{
FILE *newFile = File::OpenCFile(sourceData.path, "rb");
if (newFile == nullptr) {
return -1;
}
sourceData.file = newFile;
return 0;
}
case ZIP_SOURCE_READ:
{
size_t n = fread(data, 1, len, sourceData.file);
return ferror(sourceData.file) ? -1 : n;
}
return nullptr;
}
zip_file = zip_fdopen(fd, 0, &error);
} else {
zip_file = zip_open(zipFile.c_str(), 0, &error);
}
if (!zip_file) {
if (logErrors) {
ERROR_LOG(Log::IO, "Failed to open %s as a zip file", zipFile.c_str());
}
return nullptr;
}
case ZIP_SOURCE_CLOSE:
fclose(sourceData.file);
sourceData.file = nullptr;
return 0;
case ZIP_SOURCE_STAT:
{
if (sourceData.file == nullptr) {
return -1;
}
int64_t pos = File::Ftell(sourceData.file);
if (pos == -1) {
return -1;
}
if (File::Fseek(sourceData.file, 0, SEEK_END) != 0) {
return -1;
}
int64_t size = File::Ftell(sourceData.file);
if (size != pos && File::Fseek(sourceData.file, pos, SEEK_SET) != 0) {
return -1;
}
zip_stat_t *stat = (zip_stat_t *)data;
zip_stat_init(stat);
stat->valid = ZIP_STAT_SIZE;
stat->size = size;
return 0;
}
case ZIP_SOURCE_ERROR:
return ZIP_ER_INTERNAL;
case ZIP_SOURCE_SEEK:
{
zip_source_args_seek_t *args = (zip_source_args_seek_t *)data;
if (args == nullptr) {
return -1;
}
return File::Fseek(sourceData.file, args->offset, args->whence) ? -1 : 0;
}
case ZIP_SOURCE_TELL:
return File::Ftell(sourceData.file);
default:
return -1;
}
}
ZipFileReader *ZipFileReader::Create(const Path &zipFile, const char *inZipPath, bool logErrors) {
// The inZipPath is supposed to be a folder, and internally in this class, we suffix
// folder paths with '/', matching how the zip library works.
std::string path = inZipPath;
if (!path.empty() && path.back() != '/') {
path.push_back('/');
}
return new ZipFileReader(zip_file, zipFile, path);
ZipContainer zip(zipFile);
if (zip == nullptr) {
if (logErrors) {
ERROR_LOG(Log::IO, "Failed to open %s as a zip file", zipFile.c_str());
}
return nullptr;
}
return new ZipFileReader(std::move(zip), zipFile, path);
}
ZipFileReader::~ZipFileReader() {
std::lock_guard<std::mutex> guard(lock_);
zip_close(zip_file_);
zip_file_.close();
}
uint8_t *ZipFileReader::ReadFile(const char *path, size_t *size) {
@@ -320,30 +425,17 @@ void ZipFileReader::CloseFile(VFSOpenFile *vfsOpenFile) {
}
bool ReadSingleFileFromZip(Path zipFile, const char *path, std::string *data, std::mutex *mutex) {
zip *zip = nullptr;
int error = 0;
if (zipFile.Type() == PathType::CONTENT_URI) {
int fd = File::OpenFD(zipFile, File::OPEN_READ);
if (!fd) {
return false;
}
zip = zip_fdopen(fd, 0, &error);
} else {
zip = zip_open(zipFile.c_str(), 0, &error);
}
if (!zip) {
ZipContainer zip(zipFile);
if (zip == nullptr) {
return false;
}
struct zip_stat zstat;
if (zip_stat(zip, path, ZIP_FL_NOCASE | ZIP_FL_UNCHANGED, &zstat) != 0) {
zip_close(zip);
return false;
}
zip_file *file = zip_fopen_index(zip, zstat.index, ZIP_FL_UNCHANGED);
if (!file) {
zip_close(zip);
return false;
}
if (mutex) {
@@ -356,13 +448,11 @@ bool ReadSingleFileFromZip(Path zipFile, const char *path, std::string *data, st
}
data->resize(0);
zip_fclose(file);
zip_close(zip);
return false;
}
if (mutex) {
mutex->unlock();
}
zip_fclose(file);
zip_close(zip);
return true;
}
+25 -2
View File
@@ -9,11 +9,34 @@
#include <mutex>
#include <set>
#include <string>
#include <utility>
#include "Common/File/VFS/VFS.h"
#include "Common/File/FileUtil.h"
#include "Common/File/Path.h"
class ZipContainer {
public:
ZipContainer() noexcept;
ZipContainer(const Path &path);
~ZipContainer();
ZipContainer(const ZipContainer &) = delete;
ZipContainer(ZipContainer &&) noexcept;
ZipContainer &operator=(const ZipContainer &) = delete;
ZipContainer &operator=(ZipContainer &&) noexcept;
void close() noexcept;
operator zip_t *() const noexcept;
private:
struct SourceData {
Path path;
FILE *file;
} sourceData_;
zip_t *zip_;
static zip_int64_t SourceCallback(void *userdata, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
};
class ZipFileReader : public VFSBackend {
public:
static ZipFileReader *Create(const Path &zipFile, const char *inZipPath, bool logErrors = true);
@@ -45,11 +68,11 @@ public:
}
private:
ZipFileReader(zip *zip_file, const Path &zipPath, const std::string &inZipPath) : zip_file_(zip_file), zipPath_(zipPath), inZipPath_(inZipPath) {}
ZipFileReader(ZipContainer &&zip, const Path &zipPath, const std::string &inZipPath) : zip_file_(std::move(zip)), zipPath_(zipPath), inZipPath_(inZipPath) {}
// Path has to be either an empty string, or a string ending with a /.
bool GetZipListings(const std::string &path, std::set<std::string> &files, std::set<std::string> &directories);
zip *zip_file_ = nullptr;
ZipContainer zip_file_;
std::mutex lock_;
std::string inZipPath_;
Path zipPath_;
+4
View File
@@ -382,6 +382,10 @@ void OutputDebugStringUTF8(const char *p) {
#endif
#ifdef HAVE_LIBRETRO_VFS
#undef fprintf
#endif
void LogManager::StdioLog(const LogMessage &message) {
#if PPSSPP_PLATFORM(ANDROID)
#ifndef LOG_APP_NAME
+2 -1
View File
@@ -20,6 +20,7 @@
#include "Common/Data/Convert/ColorConv.h"
#include "Common/Data/Encoding/Utf8.h"
#include "Common/File/FileUtil.h"
#include "Common/File/VFS/VFS.h"
#include "Common/Render/AtlasGen.h"
@@ -74,7 +75,7 @@ void Image::SaveZIM(const char *zim_name, int zim_format) {
for (int y = 0; y < height(); y++) {
memcpy(image_data + y * width() * 4, (dat.data() + y * w), width() * 4);
}
FILE *f = fopen(zim_name, "wb");
FILE *f = File::OpenCFile(Path(zim_name), "wb");
// SaveZIM takes ownership over image_data, there's no leak.
::SaveZIM(f, width(), height(), width() * 4, zim_format | ZIM_DITHER, image_data);
fclose(f);
+2 -1
View File
@@ -6,6 +6,7 @@
#include "Common/Data/Format/PNGLoad.h"
#include "Common/Log.h"
#include "Common/GPU/thin3d.h"
#include "Common/File/FileUtil.h"
#define ICON_CACHE_VERSION 1
#define MK_FOURCC(str) (str[0] | ((uint8_t)str[1] << 8) | ((uint8_t)str[2] << 16) | ((uint8_t)str[3] << 24))
@@ -88,7 +89,7 @@ bool IconCache::LoadFromFile(FILE *file) {
// Check if we already have the entry somehow.
if (cache_.find(key) != cache_.end()) {
// Seek past the data and go to the next entry.
fseek(file, entryHeader.dataLen, SEEK_CUR);
File::Fseek(file, entryHeader.dataLen, SEEK_CUR);
continue;
}
+2
View File
@@ -6,6 +6,8 @@
#include <mutex>
#include <cstdint>
#include "Common/File/Path.h"
class UIContext;
+70 -19
View File
@@ -36,6 +36,8 @@
#include "zlib.h"
#include "ext/armips/Core/Assembler.h"
#include "Common/CommonTypes.h"
#include "Common/Log.h"
#include "Common/File/FileUtil.h"
@@ -44,7 +46,6 @@
#include "Core/MemMap.h"
#include "Core/Config.h"
#include "Core/Debugger/SymbolMap.h"
#include "ext/armips/Core/Assembler.h"
SymbolMap *g_symbolMap;
@@ -228,30 +229,80 @@ bool SymbolMap::SaveSymbolMap(const Path &filename) const {
std::string data;
buf.TakeAll(&data);
FILE *file = File::OpenCFile(filename, "wb");
if (file == nullptr) {
return false;
}
if (g_Config.bCompressSymbols) {
// TODO: Wrap this in some nicer way.
gzFile f;
if (filename.Type() == PathType::CONTENT_URI) {
int fd = File::OpenFD(filename, File::OPEN_WRITE);
f = gzdopen(fd, "w9");
if (f == Z_NULL) {
File::CloseFD(fd);
return false;
}
} else {
f = gzopen(filename.c_str(), "w9");
if (f == Z_NULL) {
return false;
}
uInt out_size = 4096;
Bytef *out_data = (Bytef *)std::malloc(out_size);
if (out_data == nullptr) {
fclose(file);
return false;
}
gzwrite(f, data.data(), (unsigned int)data.size());
gzclose(f);
z_stream strm;
strm.zalloc = nullptr;
strm.zfree = nullptr;
strm.opaque = nullptr;
if (deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
std::free(out_data);
fclose(file);
return false;
}
strm.next_in = (Bytef *)data.data();
strm.avail_in = data.size();
strm.next_out = out_data;
strm.avail_out = out_size;
int flush = Z_NO_FLUSH;
for (;;) {
int status = deflate(&strm, flush);
switch (status) {
case Z_OK:
case Z_STREAM_END:
if (strm.avail_out != out_size) {
fwrite(out_data, 1, out_size - strm.avail_out, file);
}
break;
case Z_BUF_ERROR:
{
std::free(out_data);
uInt new_out_size = 2 * out_size;
if (new_out_size < out_size) {
deflateEnd(&strm);
fclose(file);
return false;
}
out_size = new_out_size;
out_data = (Bytef *)std::malloc(out_size);
if (out_data == nullptr) {
deflateEnd(&strm);
fclose(file);
return false;
}
}
break;
default:
deflateEnd(&strm);
std::free(out_data);
fclose(file);
return false;
}
if (status == Z_STREAM_END) {
break;
}
if (strm.avail_in == 0) {
flush = Z_FINISH;
}
strm.next_out = out_data;
strm.avail_out = out_size;
}
deflateEnd(&strm);
std::free(out_data);
} else {
// Just plain write it.
FILE *file = File::OpenCFile(filename, "wb");
fwrite(data.data(), 1, data.size(), file);
fclose(file);
}
fclose(file);
return true;
}
+7 -37
View File
@@ -37,11 +37,6 @@
#include <fileapifromapp.h>
#endif
#if PPSSPP_PLATFORM(SWITCH)
// Far from optimal, but I guess it works...
#define fseeko fseek
#endif
static const char * const CACHEFILE_MAGIC = "ppssppDC";
static const s64 SAFETY_FREE_DISK_SPACE = 768 * 1024 * 1024; // 768 MB
// Aim to allow this many files cached at once.
@@ -203,7 +198,7 @@ void DiskCachingFileLoaderCache::InitCache(const Path &filename) {
void DiskCachingFileLoaderCache::ShutdownCache() {
if (f_) {
bool failed = false;
if (fseek(f_, sizeof(FileHeader), SEEK_SET) != 0) {
if (File::Fseek(f_, sizeof(FileHeader), SEEK_SET) != 0) {
failed = true;
} else if (fwrite(&index_[0], sizeof(BlockInfo), indexCount_, f_) != indexCount_) {
failed = true;
@@ -460,19 +455,11 @@ bool DiskCachingFileLoaderCache::ReadBlockData(u8 *dest, BlockInfo &info, size_t
fflush(f_);
bool failed = false;
#ifdef __ANDROID__
if (lseek64(fd_, blockOffset, SEEK_SET) != blockOffset) {
failed = true;
} else if (read(fd_, dest + offset, size) != (ssize_t)size) {
failed = true;
}
#else
if (fseeko(f_, blockOffset, SEEK_SET) != 0) {
if (File::Fseek(f_, blockOffset, SEEK_SET) != 0) {
failed = true;
} else if (fread(dest + offset, size, 1, f_) != 1) {
failed = true;
}
#endif
if (failed) {
ERROR_LOG(Log::Loader, "Unable to read disk cache data entry.");
@@ -488,19 +475,11 @@ void DiskCachingFileLoaderCache::WriteBlockData(BlockInfo &info, const u8 *src)
s64 blockOffset = GetBlockOffset(info.block);
bool failed = false;
#ifdef __ANDROID__
if (lseek64(fd_, blockOffset, SEEK_SET) != blockOffset) {
failed = true;
} else if (write(fd_, src, blockSize_) != (ssize_t)blockSize_) {
failed = true;
}
#else
if (fseeko(f_, blockOffset, SEEK_SET) != 0) {
if (File::Fseek(f_, blockOffset, SEEK_SET) != 0) {
failed = true;
} else if (fwrite(src, blockSize_, 1, f_) != 1) {
failed = true;
}
#endif
if (failed) {
ERROR_LOG(Log::Loader, "Unable to write disk cache data entry.");
@@ -516,7 +495,7 @@ void DiskCachingFileLoaderCache::WriteIndexData(u32 indexPos, BlockInfo &info) {
u32 offset = (u32)sizeof(FileHeader) + indexPos * (u32)sizeof(BlockInfo);
bool failed = false;
if (fseek(f_, offset, SEEK_SET) != 0) {
if (File::Fseek(f_, offset, SEEK_SET) != 0) {
failed = true;
} else if (fwrite(&info, sizeof(BlockInfo), 1, f_) != 1) {
failed = true;
@@ -553,11 +532,6 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const Path &path) {
if (valid) {
f_ = fp;
#ifdef __ANDROID__
// Android NDK does not support 64-bit file I/O using C streams
fd_ = fileno(f_);
#endif
// Now let's load the index.
blockSize_ = header.blockSize;
maxBlocks_ = header.maxBlocks;
@@ -572,7 +546,7 @@ bool DiskCachingFileLoaderCache::LoadCacheFile(const Path &path) {
}
void DiskCachingFileLoaderCache::LoadCacheIndex() {
if (fseek(f_, sizeof(FileHeader), SEEK_SET) != 0) {
if (File::Fseek(f_, sizeof(FileHeader), SEEK_SET) != 0) {
CloseFileHandle();
return;
}
@@ -631,10 +605,6 @@ void DiskCachingFileLoaderCache::CreateCacheFile(const Path &path) {
ERROR_LOG(Log::Loader, "Could not create disk cache file");
return;
}
#ifdef __ANDROID__
// Android NDK does not support 64-bit file I/O using C streams
fd_ = fileno(f_);
#endif
blockSize_ = DEFAULT_BLOCK_SIZE;
@@ -677,7 +647,7 @@ bool DiskCachingFileLoaderCache::LockCacheFile(bool lockStatus) {
u32 offset = (u32)offsetof(FileHeader, flags);
bool failed = false;
if (fseek(f_, offset, SEEK_SET) != 0) {
if (File::Fseek(f_, offset, SEEK_SET) != 0) {
failed = true;
} else if (fread(&flags_, sizeof(u32), 1, f_) != 1) {
failed = true;
@@ -704,7 +674,7 @@ bool DiskCachingFileLoaderCache::LockCacheFile(bool lockStatus) {
flags_ &= ~FLAG_LOCKED;
}
if (fseek(f_, offset, SEEK_SET) != 0) {
if (File::Fseek(f_, offset, SEEK_SET) != 0) {
failed = true;
} else if (fwrite(&flags_, sizeof(u32), 1, f_) != 1) {
failed = true;
+12 -16
View File
@@ -62,15 +62,6 @@ LocalFileLoader::LocalFileLoader(const Path &filename)
return;
}
#if HAVE_LIBRETRO_VFS
isOpenedByFd_ = false;
handle_ = filestream_open(filename.c_str(), RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
filestream_seek(handle_, 0, RETRO_VFS_SEEK_POSITION_END);
filesize_ = filestream_tell(handle_);
filestream_seek(handle_, 0, RETRO_VFS_SEEK_POSITION_START);
return;
#endif
#if PPSSPP_PLATFORM(ANDROID) && !defined(HAVE_LIBRETRO_VFS)
if (filename.Type() == PathType::CONTENT_URI) {
int fd = Android_OpenContentUriFd(filename.ToString(), Android_OpenContentUriMode::READ);
@@ -87,7 +78,11 @@ LocalFileLoader::LocalFileLoader(const Path &filename)
#endif
#if defined(HAVE_LIBRETRO_VFS)
// Nothing to do here...
file_ = File::OpenCFile(filename, "rb");
if (file_ == nullptr) {
return;
}
filesize_ = File::GetFileSize(file_);
#elif !defined(_WIN32)
fd_ = open(filename.c_str(), O_RDONLY | O_CLOEXEC);
@@ -123,7 +118,9 @@ LocalFileLoader::LocalFileLoader(const Path &filename)
LocalFileLoader::~LocalFileLoader() {
#if defined(HAVE_LIBRETRO_VFS)
filestream_close(handle_);
if (file_ != nullptr) {
fclose(file_);
}
#elif !defined(_WIN32)
if (fd_ != -1) {
close(fd_);
@@ -138,8 +135,7 @@ LocalFileLoader::~LocalFileLoader() {
bool LocalFileLoader::Exists() {
// If we opened it for reading, it must exist. Done.
#if defined(HAVE_LIBRETRO_VFS)
return handle_ != 0;
return file_ != nullptr;
#elif !defined(_WIN32)
if (isOpenedByFd_) {
// As an optimization, if we already tried and failed, quickly return.
@@ -178,9 +174,9 @@ size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void
}
#if defined(HAVE_LIBRETRO_VFS)
std::lock_guard<std::mutex> guard(readLock_);
filestream_seek(handle_, absolutePos, RETRO_VFS_SEEK_POSITION_START);
return filestream_read(handle_, data, bytes * count) / bytes;
std::lock_guard<std::mutex> guard(readLock_);
File::Fseek(file_, absolutePos, SEEK_SET);
return fread(data, bytes, count, file_);
#elif PPSSPP_PLATFORM(SWITCH)
// Toolchain has no fancy IO API. We must lock.
std::lock_guard<std::mutex> guard(readLock_);
+4 -7
View File
@@ -24,15 +24,10 @@
#include "Common/StringUtils.h"
#include "Core/Loaders.h"
#ifdef _WIN32
#if defined(_WIN32) && !defined(HAVE_LIBRETRO_VFS)
typedef void *HANDLE;
#endif
#ifdef HAVE_LIBRETRO_VFS
#include <streams/file_stream.h>
typedef RFILE* HANDLE;
#endif
class LocalFileLoader : public FileLoader {
public:
LocalFileLoader(const Path &filename);
@@ -47,7 +42,9 @@ public:
size_t ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags = Flags::NONE) override;
private:
#if !defined(_WIN32) && !defined(HAVE_LIBRETRO_VFS)
#ifdef HAVE_LIBRETRO_VFS
FILE *file_;
#elif !defined(_WIN32)
void DetectSizeFd();
int fd_ = -1;
#else
+61 -9
View File
@@ -155,7 +155,28 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File
}
//TODO: tests, should append seek to end of file? seeking in a file opened for append?
#if PPSSPP_PLATFORM(WINDOWS)
#ifdef HAVE_LIBRETRO_VFS
int flags = 0;
if (access & FILEACCESS_READ && access & FILEACCESS_WRITE)
flags = RETRO_VFS_FILE_ACCESS_READ_WRITE;
else if (access & FILEACCESS_WRITE)
flags = RETRO_VFS_FILE_ACCESS_WRITE;
else if (access & FILEACCESS_READ && access & FILEACCESS_CREATE)
flags = RETRO_VFS_FILE_ACCESS_READ_WRITE;
else
flags = RETRO_VFS_FILE_ACCESS_READ;
bool success = false;
if (!(access & FILEACCESS_CREATE)) {
hFile = filestream_open(fullName.c_str(), flags & RETRO_VFS_FILE_ACCESS_WRITE ? flags | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : flags, RETRO_VFS_FILE_ACCESS_HINT_NONE);
success = hFile != nullptr;
} else if (!(access & FILEACCESS_EXCL)) {
hFile = filestream_open(fullName.c_str(), flags & RETRO_VFS_FILE_ACCESS_WRITE && File::Exists(fullName) ? flags | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : flags, RETRO_VFS_FILE_ACCESS_HINT_NONE);
success = hFile != nullptr;
} else if (!File::Exists(fullName)) {
hFile = filestream_open(fullName.c_str(), flags & RETRO_VFS_FILE_ACCESS_WRITE ? flags | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : flags, RETRO_VFS_FILE_ACCESS_HINT_NONE);
success = hFile != nullptr;
}
#elif PPSSPP_PLATFORM(WINDOWS)
// Convert parameters to Windows permissions and access
DWORD desired = 0;
DWORD sharemode = 0;
@@ -278,7 +299,19 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File
DEBUG_LOG(Log::FileSystem, "Case may have been incorrect, second try opening %s (%s)", fullName.c_str(), fileName.c_str());
// And try again with the correct case this time
#if PPSSPP_PLATFORM(UWP)
#ifdef HAVE_LIBRETRO_VFS
success = false;
if (!(access & FILEACCESS_CREATE)) {
hFile = filestream_open(fullName.c_str(), flags & RETRO_VFS_FILE_ACCESS_WRITE ? flags | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : flags, RETRO_VFS_FILE_ACCESS_HINT_NONE);
success = hFile != nullptr;
} else if (!(access & FILEACCESS_EXCL)) {
hFile = filestream_open(fullName.c_str(), flags & RETRO_VFS_FILE_ACCESS_WRITE && File::Exists(fullName) ? flags | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : flags, RETRO_VFS_FILE_ACCESS_HINT_NONE);
success = hFile != nullptr;
} else if (!File::Exists(fullName)) {
hFile = filestream_open(fullName.c_str(), flags & RETRO_VFS_FILE_ACCESS_WRITE ? flags | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING : flags, RETRO_VFS_FILE_ACCESS_HINT_NONE);
success = hFile != nullptr;
}
#elif PPSSPP_PLATFORM(UWP)
// Should never get here.
#elif PPSSPP_PLATFORM(WINDOWS)
// Unlikely to get here, heh.
@@ -291,7 +324,7 @@ bool DirectoryFileHandle::Open(const Path &basePath, std::string &fileName, File
}
}
#if !PPSSPP_PLATFORM(WINDOWS)
#if !PPSSPP_PLATFORM(WINDOWS) && !defined(HAVE_LIBRETRO_VFS)
if (success) {
// Reject directories, even if we succeed in opening them.
// TODO: Might want to do this stat first...
@@ -337,7 +370,9 @@ size_t DirectoryFileHandle::Read(u8* pointer, s64 size)
}
}
if (size > 0) {
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
bytesRead = fread(pointer, 1, size, hFile);
#elif defined(_WIN32)
::ReadFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesRead, 0);
#else
bytesRead = read(hFile, pointer, size);
@@ -351,7 +386,9 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
size_t bytesWritten = 0;
bool diskFull = false;
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
bytesWritten = fwrite(pointer, 1, size, hFile);
#elif defined(_WIN32)
BOOL success = ::WriteFile(hFile, (LPVOID)pointer, (DWORD)size, (LPDWORD)&bytesWritten, 0);
if (success == FALSE) {
DWORD err = GetLastError();
@@ -406,7 +443,15 @@ size_t DirectoryFileHandle::Seek(s32 position, FileMove type)
}
size_t result;
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
int moveMethod = 0;
switch (type) {
case FILEMOVE_BEGIN: moveMethod = SEEK_SET; break;
case FILEMOVE_CURRENT: moveMethod = SEEK_CUR; break;
case FILEMOVE_END: moveMethod = SEEK_END; break;
}
result = File::Fseektell(hFile, position, moveMethod);
#elif defined(_WIN32)
DWORD moveMethod = 0;
switch (type) {
case FILEMOVE_BEGIN: moveMethod = FILE_BEGIN; break;
@@ -434,7 +479,11 @@ size_t DirectoryFileHandle::Seek(s32 position, FileMove type)
void DirectoryFileHandle::Close() {
if (needsTrunc_ != -1) {
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
if (filestream_truncate(hFile, needsTrunc_) != 0) {
ERROR_LOG(Log::FileSystem, "Failed to truncate file to %d bytes", (int)needsTrunc_);
}
#elif defined(_WIN32)
Seek((s32)needsTrunc_, FILEMOVE_BEGIN);
if (SetEndOfFile(hFile) == 0) {
ERROR_LOG(Log::FileSystem, "Failed to truncate file to %d bytes", (int)needsTrunc_);
@@ -447,7 +496,10 @@ void DirectoryFileHandle::Close() {
#endif
}
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
if (hFile != nullptr)
fclose(hFile);
#elif defined(_WIN32)
if (hFile != (HANDLE)-1)
CloseHandle(hFile);
#else
@@ -598,7 +650,7 @@ int DirectoryFileSystem::OpenFile(std::string filename, FileAccess access, const
}
return err;
} else {
#ifdef _WIN32
#if defined(_WIN32) || defined(HAVE_LIBRETRO_VFS)
if (access & FILEACCESS_APPEND) {
entry.hFile.Seek(0, FILEMOVE_END);
}
+4 -2
View File
@@ -24,7 +24,7 @@
#include "Common/File/Path.h"
#include "Core/FileSystems/FileSystem.h"
#ifdef _WIN32
#if defined(_WIN32) && !defined(HAVE_LIBRETRO_VFS)
typedef void * HANDLE;
#endif
@@ -34,7 +34,9 @@ struct DirectoryFileHandle {
SKIP_REPLAY,
};
#ifdef _WIN32
#ifdef HAVE_LIBRETRO_VFS
FILE *hFile = nullptr;
#elif defined(_WIN32)
HANDLE hFile = (HANDLE)-1;
#else
int hFile = -1;
+8 -22
View File
@@ -319,39 +319,25 @@ bool UmdReplace(const Path &filepath, FileLoader **fileLoader, std::string &erro
}
// Close the return value with ZipClose (if non-null, of course).
struct zip *ZipOpenPath(const Path &fileName) {
int error = 0;
// Need to special case for content URI here, similar to OpenCFile.
struct zip *z;
#if PPSSPP_PLATFORM(ANDROID)
if (fileName.Type() == PathType::CONTENT_URI) {
int fd = File::OpenFD(fileName, File::OPEN_READ);
z = zip_fdopen(fd, 0, &error);
} else
#endif
{ // continuation of above else in the ifdef
z = zip_open(fileName.c_str(), 0, &error);
}
if (!z) {
ERROR_LOG(Log::HLE, "Failed to open ZIP file '%s', error code=%i", fileName.c_str(), error);
ZipContainer ZipOpenPath(const Path &fileName) {
ZipContainer z(fileName);
if (z == nullptr) {
ERROR_LOG(Log::HLE, "Failed to open ZIP file '%s'", fileName.c_str());
}
return z;
}
void ZipClose(struct zip *z) {
if (z)
zip_close(z);
void ZipClose(ZipContainer &z) {
z.close();
}
bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info) {
struct zip *z = ZipOpenPath(fileName);
ZipContainer z = ZipOpenPath(fileName);
if (!z) {
info->contents = ZipFileContents::UNKNOWN;
return false;
}
DetectZipFileContents(z, info);
zip_close(z);
return true;
}
@@ -408,7 +394,7 @@ static bool ZipExtractFileToMemory(struct zip *z, int fileIndex, std::string *da
}
}
void DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
void DetectZipFileContents(zip_t *z, ZipFileInfo *info) {
int numFiles = zip_get_num_files(z);
_dbg_assert_(numFiles >= 0);
+4 -8
View File
@@ -20,13 +20,9 @@
#include <string>
#include <memory>
#ifdef SHARED_LIBZIP
#include <zip.h>
#else
#include "ext/libzip/zip.h"
#endif
#include "Common/CommonTypes.h"
#include "Common/File/Path.h"
#include "Common/File/VFS/ZipFileReader.h"
enum class IdentifiedFileType {
ERROR_IDENTIFYING,
@@ -191,8 +187,8 @@ struct ZipFileInfo {
std::string contentName;
};
struct zip *ZipOpenPath(const Path &fileName);
void ZipClose(zip *z);
ZipContainer ZipOpenPath(const Path &fileName);
void ZipClose(ZipContainer &z);
bool DetectZipFileContents(const Path &fileName, ZipFileInfo *info);
void DetectZipFileContents(struct zip *z, ZipFileInfo *info);
void DetectZipFileContents(zip_t *z, ZipFileInfo *info);
+2 -2
View File
@@ -119,7 +119,7 @@ bool MIPSTracer::flush_to_file() {
}
INFO_LOG(Log::JIT, "Trace flushed, closing the file...");
std::fclose(output);
fclose(output);
clear();
return true;
@@ -144,7 +144,7 @@ void MIPSTracer::flush_block_to_file(const TraceBlockInfo& block_info) {
snprintf(buffer, sizeof(buffer), "0x%08x: ", addr);
MIPSDisAsm(storage.read_asm(index), addr, buffer + prefix_size, sizeof(buffer) - prefix_size, true);
std::fprintf(output, "%s\n", buffer);
fprintf(output, "%s\n", buffer);
}
}
+1 -1
View File
@@ -249,7 +249,7 @@ static void DiscHandler(const http::ServerRequest &request, const Path &filename
}
FILE *fp = File::OpenCFile(filename, "rb");
if (!fp || fseek(fp, begin, SEEK_SET) != 0) {
if (!fp || File::Fseek(fp, begin, SEEK_SET) != 0) {
request.WriteHttpResponseHeader("1.0", 500, -1, "text/plain");
request.Out()->Push("File access failed.");
if (fp) {
+2 -2
View File
@@ -659,7 +659,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa
NOTICE_LOG(Log::G3D, "Saved Vulkan pipeline cache (%d bytes).", (int)size);
}
size_t seekPosOnFailure = ftell(file);
int64_t seekPosOnFailure = File::Ftell(file);
bool failed = false;
bool writeFailed = false;
@@ -711,7 +711,7 @@ void PipelineManagerVulkan::SavePipelineCache(FILE *file, bool saveRawPipelineCa
ERROR_LOG(Log::G3D, "Failed to write pipeline cache, some shader was missing");
// Write a zero in the right place so it doesn't try to load the pipelines next time.
size = 0;
fseek(file, (long)seekPosOnFailure, SEEK_SET);
File::Fseek(file, seekPosOnFailure, SEEK_SET);
writeFailed = fwrite(&size, sizeof(size), 1, file) != 1;
if (writeFailed) {
ERROR_LOG(Log::G3D, "Failed to write pipeline cache, disk full?");
+2
View File
@@ -30,6 +30,8 @@
#include "GPU/Vulkan/VulkanQueueRunner.h"
#include "GPU/Vulkan/VulkanRenderManager.h"
#include "Common/File/FileUtil.h"
struct VKRGraphicsPipeline;
class VulkanRenderManager;
class VulkanContext;
+2 -2
View File
@@ -506,10 +506,10 @@ struct VulkanCacheHeader {
bool ShaderManagerVulkan::LoadCacheFlags(FILE *f, DrawEngineVulkan *drawEngine) {
VulkanCacheHeader header{};
long pos = ftell(f);
int64_t pos = File::Ftell(f);
bool success = fread(&header, sizeof(header), 1, f) == 1;
// We'll read it again later, this is just to check the flags.
success = success && fseek(f, pos, SEEK_SET) == 0;
success = success && File::Fseek(f, pos, SEEK_SET) == 0;
if (!success || header.magic != CACHE_HEADER_MAGIC) {
WARN_LOG(Log::G3D, "Shader cache magic mismatch");
return false;
+2
View File
@@ -32,6 +32,8 @@
#include "Common/Math/lin/matrix4x4.h"
#include "GPU/Common/ShaderUniforms.h"
#include "Common/File/FileUtil.h"
class VulkanContext;
class DrawEngineVulkan;
class VulkanPushPool;
+13
View File
@@ -12,6 +12,19 @@ if(WIN32)
LibretroD3D11Context.cpp)
endif()
set(LIBRETRO_SRCS ${LIBRETRO_SRCS}
libretro-common/compat/compat_posix_string.c
libretro-common/compat/fopen_utf8.c
libretro-common/compat/compat_strl.c
libretro-common/encodings/encoding_utf.c
libretro-common/file/file_path.c
libretro-common/file/file_path_io.c
libretro-common/streams/file_stream.c
libretro-common/streams/file_stream_transforms.c
libretro-common/string/stdstring.c
libretro-common/time/rtime.c
libretro-common/vfs/vfs_implementation.c)
include_directories(libretro)
add_library(ppsspp_libretro SHARED ${LIBRETRO_SRCS})
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <streams/file_stream_transforms.h>
#undef fopen
#undef fseek
#undef ftell
+2
View File
@@ -13,6 +13,8 @@
#include <libretro_vulkan.h>
#include <GPU/Vulkan/VulkanRenderManager.h>
#undef fflush
static VulkanContext *vk;
void vk_libretro_init(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr, const char **required_device_extensions, unsigned num_required_device_extensions, const char **required_device_layers, unsigned num_required_device_layers, const VkPhysicalDeviceFeatures *required_features);
+6 -5
View File
@@ -6,6 +6,7 @@
#include <vector>
#include <cstdlib>
#include <mutex>
#include <fstream>
#include "Common/CPUDetect.h"
#include "Common/Log.h"
@@ -401,11 +402,11 @@ void retro_set_environment(retro_environment_t cb)
update_display_cb.callback = set_variable_visibility;
environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK, &update_display_cb);
#ifdef HAVE_LIBRETRO_VFS
struct retro_vfs_interface_info vfs_iface_info { 1, nullptr };
if (cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface_info))
filestream_vfs_init(&vfs_iface_info);
#endif
#ifdef HAVE_LIBRETRO_VFS
struct retro_vfs_interface_info vfs_iface_info { 2, nullptr };
if (cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface_info))
File::InitLibretroVFS(&vfs_iface_info);
#endif
}
static int get_language_auto(void)