mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-28 00:17:08 +01:00
61 lines
2.2 KiB
C++
61 lines
2.2 KiB
C++
#pragma once
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <stdexcept>
|
|
#ifdef _WIN32
|
|
#include <Windows.h>
|
|
#endif
|
|
|
|
namespace dingosdk {
|
|
// Bounded reads share delete access so a writer can rename the old document.
|
|
class SharedTextFile {
|
|
public:
|
|
explicit SharedTextFile(const std::filesystem::path& path)
|
|
#ifdef _WIN32
|
|
: handle_(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)) {
|
|
if (handle_ == INVALID_HANDLE_VALUE) throw std::runtime_error("Cannot open content document");
|
|
#else
|
|
: file_(path, std::ios::binary | std::ios::ate) {
|
|
if (!file_) throw std::runtime_error("Cannot open content document");
|
|
#endif
|
|
}
|
|
SharedTextFile(const SharedTextFile&) = delete;
|
|
SharedTextFile& operator=(const SharedTextFile&) = delete;
|
|
~SharedTextFile() {
|
|
#ifdef _WIN32
|
|
CloseHandle(handle_);
|
|
#endif
|
|
}
|
|
std::string read(std::size_t limit) {
|
|
#ifdef _WIN32
|
|
LARGE_INTEGER length{};
|
|
if (!GetFileSizeEx(handle_, &length) || length.QuadPart < 0 ||
|
|
static_cast<unsigned long long>(length.QuadPart) > limit || limit > MAXDWORD)
|
|
throw std::runtime_error("Content document exceeds its read bound");
|
|
std::string text(static_cast<std::size_t>(length.QuadPart), '\0');
|
|
DWORD got{};
|
|
if (!ReadFile(handle_, text.data(), static_cast<DWORD>(text.size()), &got, nullptr) || got != text.size())
|
|
throw std::runtime_error("Cannot finish content document read");
|
|
#else
|
|
const auto length = file_.tellg();
|
|
if (length < 0 || static_cast<std::uintmax_t>(length) > limit) throw std::runtime_error("Content document exceeds its read bound");
|
|
std::string text(static_cast<std::size_t>(length), '\0');
|
|
file_.seekg(0);
|
|
if (!file_.read(text.data(), static_cast<std::streamsize>(text.size()))) throw std::runtime_error("Cannot finish content document read");
|
|
#endif
|
|
return text;
|
|
}
|
|
private:
|
|
#ifdef _WIN32
|
|
HANDLE handle_;
|
|
#else
|
|
std::ifstream file_;
|
|
#endif
|
|
};
|
|
inline std::string read_shared_text(const std::filesystem::path& path, std::size_t limit) {
|
|
return SharedTextFile(path).read(limit);
|
|
}
|
|
}
|