dolphin/Source/Core/Common/IOFile.cpp
LillyJadeKatrin 335cf4f2db Added CopyReader to BlobReader and all subclasses
A deep-copy method CopyReader has been added to BlobReader (virtual) and all of its subclasses (override). This should create a second BlobReader to open the same set of data but with an independent read pointer so that it doesn't interfere with any reads done on the original Reader.

As part of this, IOFile has added code to create a deep copy IOFile pointer onto the same file, with code based on the platform in question to find the file ID from the file pointer and open a new one. There has also been a small piece added to FileInfo to enable a deep copy, but its only subclass at this time already had a copy constructor so this was relatively minor.
2023-10-01 09:04:06 -04:00

182 lines
3.2 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Common/IOFile.h"
#include <cstddef>
#include <cstdio>
#include <string>
#ifdef _WIN32
#include <io.h>
#include "Common/CommonFuncs.h"
#include "Common/StringUtil.h"
#else
#include <unistd.h>
#endif
#ifdef ANDROID
#include <algorithm>
#include "jni/AndroidCommon/AndroidCommon.h"
#endif
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
namespace File
{
IOFile::IOFile() : m_file(nullptr), m_good(true)
{
}
IOFile::IOFile(std::FILE* file) : m_file(file), m_good(true)
{
}
IOFile::IOFile(const std::string& filename, const char openmode[], SharedAccess sh)
: m_file(nullptr), m_good(true)
{
Open(filename, openmode, sh);
}
IOFile::~IOFile()
{
Close();
}
IOFile::IOFile(IOFile&& other) noexcept : m_file(nullptr), m_good(true)
{
Swap(other);
}
IOFile& IOFile::operator=(IOFile&& other) noexcept
{
Swap(other);
return *this;
}
void IOFile::Swap(IOFile& other) noexcept
{
std::swap(m_file, other.m_file);
std::swap(m_good, other.m_good);
}
bool IOFile::Open(const std::string& filename, const char openmode[],
[[maybe_unused]] SharedAccess sh)
{
Close();
#ifdef _WIN32
if (sh == SharedAccess::Default)
{
m_good = _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()) == 0;
}
else if (sh == SharedAccess::Read)
{
m_file = _tfsopen(UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str(), SH_DENYWR);
m_good = m_file != nullptr;
}
#else
#ifdef ANDROID
if (IsPathAndroidContent(filename))
m_file = fdopen(OpenAndroidContent(filename, OpenModeToAndroid(openmode)), openmode);
else
#endif
m_file = std::fopen(filename.c_str(), openmode);
m_good = m_file != nullptr;
#endif
return m_good;
}
bool IOFile::Close()
{
if (!IsOpen() || 0 != std::fclose(m_file))
m_good = false;
m_file = nullptr;
return m_good;
}
IOFile IOFile::Duplicate(const char openmode[]) const
{
#ifdef _WIN32
return IOFile(_fdopen(_dup(_fileno(m_file)), openmode));
#else // _WIN32
return IOFile(fdopen(dup(fileno(m_file)), openmode));
#endif // _WIN32
}
void IOFile::SetHandle(std::FILE* file)
{
Close();
ClearError();
m_file = file;
}
u64 IOFile::GetSize() const
{
if (IsOpen())
return File::GetSize(m_file);
else
return 0;
}
bool IOFile::Seek(s64 offset, SeekOrigin origin)
{
int fseek_origin;
switch (origin)
{
case SeekOrigin::Begin:
fseek_origin = SEEK_SET;
break;
case SeekOrigin::Current:
fseek_origin = SEEK_CUR;
break;
case SeekOrigin::End:
fseek_origin = SEEK_END;
break;
default:
return false;
}
if (!IsOpen() || 0 != fseeko(m_file, offset, fseek_origin))
m_good = false;
return m_good;
}
u64 IOFile::Tell() const
{
if (IsOpen())
return ftello(m_file);
else
return UINT64_MAX;
}
bool IOFile::Flush()
{
if (!IsOpen() || 0 != std::fflush(m_file))
m_good = false;
return m_good;
}
bool IOFile::Resize(u64 size)
{
#ifdef _WIN32
if (!IsOpen() || 0 != _chsize_s(_fileno(m_file), size))
#else
// TODO: handle 64bit and growing
if (!IsOpen() || 0 != ftruncate(fileno(m_file), size))
#endif
m_good = false;
return m_good;
}
} // namespace File