CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/FileLoaders/LocalFileLoader.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <cstdio>1819#include "ppsspp_config.h"2021#include "Common/Data/Encoding/Utf8.h"22#include "Common/Log.h"23#include "Common/File/FileUtil.h"24#include "Common/File/DirListing.h"25#include "Core/FileLoaders/LocalFileLoader.h"2627#if PPSSPP_PLATFORM(ANDROID)28#include "android/jni/app-android.h"29#endif3031#ifdef _WIN3232#include "Common/CommonWindows.h"33#if PPSSPP_PLATFORM(UWP)34#include <fileapifromapp.h>35#endif36#else37#include <fcntl.h>38#endif3940#ifdef HAVE_LIBRETRO_VFS41#include <streams/file_stream.h>42#endif4344#if !defined(_WIN32) && !defined(HAVE_LIBRETRO_VFS)4546void LocalFileLoader::DetectSizeFd() {47#if PPSSPP_PLATFORM(ANDROID) || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64)48off64_t off = lseek64(fd_, 0, SEEK_END);49filesize_ = off;50lseek64(fd_, 0, SEEK_SET);51#else52off_t off = lseek(fd_, 0, SEEK_END);53filesize_ = off;54lseek(fd_, 0, SEEK_SET);55#endif56}57#endif5859LocalFileLoader::LocalFileLoader(const Path &filename)60: filesize_(0), filename_(filename) {61if (filename.empty()) {62ERROR_LOG(Log::FileSystem, "LocalFileLoader can't load empty filenames");63return;64}6566#if HAVE_LIBRETRO_VFS67isOpenedByFd_ = false;68handle_ = filestream_open(filename.c_str(), RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);69filestream_seek(handle_, 0, RETRO_VFS_SEEK_POSITION_END);70filesize_ = filestream_tell(handle_);71filestream_seek(handle_, 0, RETRO_VFS_SEEK_POSITION_START);72return;73#endif7475#if PPSSPP_PLATFORM(ANDROID) && !defined(HAVE_LIBRETRO_VFS)76if (filename.Type() == PathType::CONTENT_URI) {77int fd = Android_OpenContentUriFd(filename.ToString(), Android_OpenContentUriMode::READ);78VERBOSE_LOG(Log::System, "LocalFileLoader Fd %d for content URI: '%s'", fd, filename.c_str());79if (fd < 0) {80ERROR_LOG(Log::FileSystem, "LocalFileLoader failed to open content URI: '%s'", filename.c_str());81return;82}83fd_ = fd;84isOpenedByFd_ = true;85DetectSizeFd();86return;87}88#endif8990#if defined(HAVE_LIBRETRO_VFS)91// Nothing to do here...92#elif !defined(_WIN32)9394fd_ = open(filename.c_str(), O_RDONLY | O_CLOEXEC);95if (fd_ == -1) {96return;97}9899DetectSizeFd();100101#else // _WIN32102103const DWORD access = GENERIC_READ, share = FILE_SHARE_READ, mode = OPEN_EXISTING, flags = FILE_ATTRIBUTE_NORMAL;104#if PPSSPP_PLATFORM(UWP)105handle_ = CreateFile2FromAppW(filename.ToWString().c_str(), access, share, mode, nullptr);106#else107handle_ = CreateFile(filename.ToWString().c_str(), access, share, nullptr, mode, flags, nullptr);108#endif109if (handle_ == INVALID_HANDLE_VALUE) {110return;111}112LARGE_INTEGER end_offset;113const LARGE_INTEGER zero{};114if (SetFilePointerEx(handle_, zero, &end_offset, FILE_END) == 0) {115// Couldn't seek in the file. Close it and give up? This should never happen.116CloseHandle(handle_);117handle_ = INVALID_HANDLE_VALUE;118return;119}120filesize_ = end_offset.QuadPart;121SetFilePointerEx(handle_, zero, nullptr, FILE_BEGIN);122#endif // _WIN32123}124125LocalFileLoader::~LocalFileLoader() {126#if defined(HAVE_LIBRETRO_VFS)127filestream_close(handle_);128#elif !defined(_WIN32)129if (fd_ != -1) {130close(fd_);131}132#else133if (handle_ != INVALID_HANDLE_VALUE) {134CloseHandle(handle_);135}136#endif137}138139bool LocalFileLoader::Exists() {140// If we opened it for reading, it must exist. Done.141#if defined(HAVE_LIBRETRO_VFS)142return handle_ != 0;143144#elif !defined(_WIN32)145if (isOpenedByFd_) {146// As an optimization, if we already tried and failed, quickly return.147// This is used because Android Content URIs are so slow.148return fd_ != -1;149}150if (fd_ != -1)151return true;152#else153if (handle_ != INVALID_HANDLE_VALUE)154return true;155#endif156157File::FileInfo info;158if (File::GetFileInfo(filename_, &info)) {159return info.exists;160} else {161return false;162}163}164165bool LocalFileLoader::IsDirectory() {166File::FileInfo info;167if (File::GetFileInfo(filename_, &info)) {168return info.exists && info.isDirectory;169}170return false;171}172173s64 LocalFileLoader::FileSize() {174return filesize_;175}176177size_t LocalFileLoader::ReadAt(s64 absolutePos, size_t bytes, size_t count, void *data, Flags flags) {178if (bytes == 0)179return 0;180181if (filesize_ == 0) {182ERROR_LOG(Log::FileSystem, "ReadAt from 0-sized file: %s", filename_.c_str());183return 0;184}185186#if defined(HAVE_LIBRETRO_VFS)187std::lock_guard<std::mutex> guard(readLock_);188filestream_seek(handle_, absolutePos, RETRO_VFS_SEEK_POSITION_START);189return filestream_read(handle_, data, bytes * count) / bytes;190#elif PPSSPP_PLATFORM(SWITCH)191// Toolchain has no fancy IO API. We must lock.192std::lock_guard<std::mutex> guard(readLock_);193lseek(fd_, absolutePos, SEEK_SET);194return read(fd_, data, bytes * count) / bytes;195#elif PPSSPP_PLATFORM(ANDROID)196// pread64 doesn't appear to actually be 64-bit safe, though such ISOs are uncommon. See #10862.197if (absolutePos <= 0x7FFFFFFF) {198#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64199return pread64(fd_, data, bytes * count, absolutePos) / bytes;200#else201return pread(fd_, data, bytes * count, absolutePos) / bytes;202#endif203} else {204// Since pread64 doesn't change the file offset, it should be safe to avoid the lock in the common case.205std::lock_guard<std::mutex> guard(readLock_);206lseek64(fd_, absolutePos, SEEK_SET);207return read(fd_, data, bytes * count) / bytes;208}209#elif !defined(_WIN32)210#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS < 64211return pread64(fd_, data, bytes * count, absolutePos) / bytes;212#else213return pread(fd_, data, bytes * count, absolutePos) / bytes;214#endif215#else216DWORD read = -1;217OVERLAPPED offset = { 0 };218offset.Offset = (DWORD)(absolutePos & 0xffffffff);219offset.OffsetHigh = (DWORD)((absolutePos & 0xffffffff00000000) >> 32);220auto result = ReadFile(handle_, data, (DWORD)(bytes * count), &read, &offset);221return result == TRUE ? (size_t)read / bytes : -1;222#endif223}224225226