mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-07-11 01:25:07 +02:00
Use the libretro VFS interface in libretro builds
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <mutex>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Common/File/Path.h"
|
||||
|
||||
|
||||
class UIContext;
|
||||
|
||||
|
||||
+70
-19
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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?");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <streams/file_stream_transforms.h>
|
||||
#undef fopen
|
||||
#undef fseek
|
||||
#undef ftell
|
||||
@@ -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,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)
|
||||
|
||||
Reference in New Issue
Block a user