metaforce/Runtime/CDvdFile.cpp

153 lines
4.6 KiB
C++
Raw Normal View History

#include "Runtime/CDvdFile.hpp"
#include "Runtime/CDvdRequest.hpp"
#include "Runtime/CStopwatch.hpp"
2016-03-06 19:12:32 -08:00
2021-04-10 01:42:06 -07:00
namespace metaforce {
2016-03-06 19:12:32 -08:00
hecl::ProjectPath CDvdFile::m_DvdRoot;
2019-03-09 00:58:27 -08:00
std::unordered_map<std::string, std::string> CDvdFile::m_caseInsensitiveMap;
2016-03-06 19:12:32 -08:00
2018-12-07 21:30:43 -08:00
class CFileDvdRequest : public IDvdRequest {
std::shared_ptr<athena::io::FileReader> m_reader;
void* m_buf;
u32 m_len;
ESeekOrigin m_whence;
int m_offset;
std::atomic_bool m_cancel = {false};
std::atomic_bool m_complete = {false};
std::function<void(u32)> m_callback;
2016-03-06 19:12:32 -08:00
public:
2020-04-15 06:42:44 -07:00
~CFileDvdRequest() override { CFileDvdRequest::PostCancelRequest(); }
2016-03-06 19:12:32 -08:00
void WaitUntilComplete() override {
2018-12-07 21:30:43 -08:00
while (!m_complete.load() && !m_cancel.load()) {
std::unique_lock lk{CDvdFile::m_WaitMutex};
2016-03-06 19:12:32 -08:00
}
2018-12-07 21:30:43 -08:00
}
bool IsComplete() override { return m_complete.load(); }
void PostCancelRequest() override {
if (m_complete.load() || m_cancel.load()) {
return;
}
std::unique_lock waitlk{CDvdFile::m_WaitMutex};
2018-12-07 21:30:43 -08:00
m_cancel.store(true);
}
2016-03-06 19:12:32 -08:00
2020-04-15 06:42:44 -07:00
[[nodiscard]] EMediaType GetMediaType() const override { return EMediaType::File; }
2016-03-06 19:12:32 -08:00
2018-12-07 21:30:43 -08:00
CFileDvdRequest(CDvdFile& file, void* buf, u32 len, ESeekOrigin whence, int off, std::function<void(u32)>&& cb)
: m_reader(file.m_reader), m_buf(buf), m_len(len), m_whence(whence), m_offset(off), m_callback(std::move(cb)) {}
2016-03-06 19:12:32 -08:00
2018-12-07 21:30:43 -08:00
void DoRequest() {
2020-04-15 06:42:44 -07:00
if (m_cancel.load()) {
2018-12-07 21:30:43 -08:00
return;
2020-04-15 06:42:44 -07:00
}
2018-12-07 21:30:43 -08:00
u32 readLen;
if (m_whence == ESeekOrigin::Cur && m_offset == 0) {
readLen = m_reader->readBytesToBuf(m_buf, m_len);
} else {
m_reader->seek(m_offset, athena::SeekOrigin(m_whence));
readLen = m_reader->readBytesToBuf(m_buf, m_len);
2016-03-06 19:12:32 -08:00
}
2020-04-15 06:42:44 -07:00
if (m_callback) {
2018-12-07 21:30:43 -08:00
m_callback(readLen);
2020-04-15 06:42:44 -07:00
}
2018-12-07 21:30:43 -08:00
m_complete.store(true);
}
2016-03-06 19:12:32 -08:00
};
std::thread CDvdFile::m_WorkerThread;
std::mutex CDvdFile::m_WorkerMutex;
std::condition_variable CDvdFile::m_WorkerCV;
std::mutex CDvdFile::m_WaitMutex;
2018-06-01 17:03:31 -07:00
std::atomic_bool CDvdFile::m_WorkerRun = {false};
2016-03-06 19:12:32 -08:00
std::vector<std::shared_ptr<IDvdRequest>> CDvdFile::m_RequestQueue;
2018-12-07 21:30:43 -08:00
void CDvdFile::WorkerProc() {
logvisor::RegisterThreadName("CDvdFile");
while (m_WorkerRun.load()) {
std::unique_lock lk{m_WorkerMutex};
while (!m_RequestQueue.empty()) {
2018-12-07 21:30:43 -08:00
std::vector<std::shared_ptr<IDvdRequest>> swapQueue;
swapQueue.swap(m_RequestQueue);
2018-12-07 21:30:43 -08:00
lk.unlock();
std::unique_lock waitlk{m_WaitMutex};
2018-12-07 21:30:43 -08:00
for (std::shared_ptr<IDvdRequest>& req : swapQueue) {
2020-04-15 06:42:44 -07:00
auto& concreteReq = static_cast<CFileDvdRequest&>(*req);
2018-12-07 21:30:43 -08:00
concreteReq.DoRequest();
}
waitlk.unlock();
swapQueue.clear();
lk.lock();
2016-03-06 19:12:32 -08:00
}
2020-04-15 06:42:44 -07:00
if (!m_WorkerRun.load()) {
2018-12-07 21:30:43 -08:00
break;
2020-04-15 06:42:44 -07:00
}
2018-12-07 21:30:43 -08:00
m_WorkerCV.wait(lk);
}
2016-03-06 19:12:32 -08:00
}
2018-12-07 21:30:43 -08:00
std::shared_ptr<IDvdRequest> CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off,
std::function<void(u32)>&& cb) {
std::shared_ptr<IDvdRequest> ret = std::make_shared<CFileDvdRequest>(*this, buf, len, whence, off, std::move(cb));
std::unique_lock lk{m_WorkerMutex};
2018-12-07 21:30:43 -08:00
m_RequestQueue.emplace_back(ret);
lk.unlock();
m_WorkerCV.notify_one();
return ret;
2016-03-06 19:12:32 -08:00
}
2019-03-09 00:58:27 -08:00
hecl::ProjectPath CDvdFile::ResolvePath(std::string_view path) {
auto start = path.begin();
2020-04-15 06:42:44 -07:00
while (*start == '/') {
++start;
}
2019-03-09 00:58:27 -08:00
std::string lowerChStr(start, path.end());
std::transform(lowerChStr.begin(), lowerChStr.end(), lowerChStr.begin(), ::tolower);
auto search = m_caseInsensitiveMap.find(lowerChStr);
2020-04-15 06:42:44 -07:00
if (search == m_caseInsensitiveMap.end()) {
2019-03-09 00:58:27 -08:00
return {};
2020-04-15 06:42:44 -07:00
}
2019-03-09 00:58:27 -08:00
return hecl::ProjectPath(m_DvdRoot, search->second);
}
void CDvdFile::RecursiveBuildCaseInsensitiveMap(const hecl::ProjectPath& path, std::string::size_type prefixLen) {
for (const auto& p : path.enumerateDir()) {
if (p.m_isDir) {
RecursiveBuildCaseInsensitiveMap(hecl::ProjectPath(path, p.m_name), prefixLen);
} else {
hecl::ProjectPath ch(path, p.m_name);
std::string chStr(ch.getAbsolutePathUTF8().begin() + prefixLen, ch.getAbsolutePathUTF8().end());
std::string lowerChStr(chStr);
std::transform(lowerChStr.begin(), lowerChStr.end(), lowerChStr.begin(), ::tolower);
m_caseInsensitiveMap[lowerChStr] = chStr;
}
}
}
2018-12-07 21:30:43 -08:00
void CDvdFile::Initialize(const hecl::ProjectPath& path) {
m_DvdRoot = path;
2019-03-09 00:58:27 -08:00
RecursiveBuildCaseInsensitiveMap(path, path.getAbsolutePathUTF8().length() + 1);
2020-04-15 06:42:44 -07:00
if (m_WorkerRun.load()) {
2018-12-07 21:30:43 -08:00
return;
2020-04-15 06:42:44 -07:00
}
2018-12-07 21:30:43 -08:00
m_WorkerRun.store(true);
m_WorkerThread = std::thread(WorkerProc);
2016-03-06 19:12:32 -08:00
}
2018-12-07 21:30:43 -08:00
void CDvdFile::Shutdown() {
2020-04-15 06:42:44 -07:00
if (!m_WorkerRun.load()) {
2018-12-07 21:30:43 -08:00
return;
2020-04-15 06:42:44 -07:00
}
2018-12-07 21:30:43 -08:00
m_WorkerRun.store(false);
m_WorkerCV.notify_one();
2020-04-15 06:42:44 -07:00
if (m_WorkerThread.joinable()) {
2018-12-07 21:30:43 -08:00
m_WorkerThread.join();
2020-04-15 06:42:44 -07:00
}
2018-12-07 21:30:43 -08:00
m_RequestQueue.clear();
2016-03-06 19:12:32 -08:00
}
2021-04-10 01:42:06 -07:00
} // namespace metaforce