mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-10-24 08:05:42 +00:00
94 lines
3.3 KiB
C++
94 lines
3.3 KiB
C++
#pragma once
|
|
#include "YBaseLib/ByteStream.h"
|
|
#include "types.h"
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class HDDImage
|
|
{
|
|
public:
|
|
using SectorIndex = u32;
|
|
|
|
static constexpr u32 InvalidSectorNumber = UINT32_C(0xFFFFFFFF);
|
|
static constexpr u32 DefaultSectorSize = 4096;
|
|
|
|
static std::unique_ptr<HDDImage> Create(const char* filename, u64 size_in_bytes, u32 sector_size = DefaultSectorSize);
|
|
static std::unique_ptr<HDDImage> Open(const char* filename, u32 sector_size = DefaultSectorSize);
|
|
|
|
~HDDImage();
|
|
|
|
const u64 GetImageSize() const { return m_image_size; }
|
|
const u32 GetSectorSize() const { return m_sector_size; }
|
|
const u32 GetSectorCount() const { return m_sector_count; }
|
|
|
|
void Read(void* buffer, u64 offset, u32 size);
|
|
void Write(const void* buffer, u64 offset, u32 size);
|
|
|
|
/// Erases the current replay log, and replaces it with the log from the specified stream.
|
|
bool LoadState(ByteStream* stream);
|
|
|
|
/// Copies the current state of the replay log to the specified stream, so it can be restored later.
|
|
bool SaveState(ByteStream* stream);
|
|
|
|
/// Flushes any buffered sectors to the backing file/log.
|
|
void Flush();
|
|
|
|
/// Commits all changes made in the replay log to the base image.
|
|
void CommitLog();
|
|
|
|
/// Erases any changes made in the replay log, restoring the image to its base state.
|
|
void RevertLog();
|
|
|
|
private:
|
|
using LogSectorMap = std::vector<SectorIndex>;
|
|
struct SectorBuffer
|
|
{
|
|
std::unique_ptr<byte[]> data;
|
|
SectorIndex sector_number = InvalidSectorNumber;
|
|
bool in_log = false;
|
|
bool dirty = false;
|
|
};
|
|
|
|
HDDImage(const std::string filename, ByteStream* base_stream, ByteStream* log_stream, u64 size, u32 sector_size,
|
|
u32 sector_count, u32 version_number, LogSectorMap log_sector_map);
|
|
|
|
static ByteStream* CreateLogFile(const char* filename, bool truncate_existing, bool atomic_update, u64 image_size,
|
|
u32 sector_size, u32& num_sectors, u32 version_number, LogSectorMap& sector_map);
|
|
static ByteStream* OpenLogFile(const char* filename, u64 image_size, u32& sector_size, u32& num_sectors,
|
|
u32& version_number, LogSectorMap& sector_map);
|
|
|
|
// Returns the offset in the image (either log or base) for the specified sector.
|
|
u64 GetFileOffset(SectorIndex sector_index) const
|
|
{
|
|
return static_cast<u64>(sector_index) * static_cast<u64>(m_sector_size);
|
|
}
|
|
|
|
// Returns whether the specified sector is in the log (true), or in the base image (false).
|
|
bool IsSectorInLog(SectorIndex sector_index) const { return (m_log_sector_map[sector_index] != InvalidSectorNumber); }
|
|
|
|
// Currently, we only have one sector open. But we could change this in the future.
|
|
SectorBuffer& GetSector(SectorIndex sector_index);
|
|
|
|
void LoadSector(SectorBuffer& buf, SectorIndex sector_index);
|
|
void LoadSectorFromImage(SectorBuffer& buf, SectorIndex sector_index);
|
|
void LoadSectorFromLog(SectorBuffer& buf, SectorIndex sector_index);
|
|
void WriteSectorToLog(SectorBuffer& buf);
|
|
void ReleaseSector(SectorBuffer& buf);
|
|
void ReleaseAllSectors();
|
|
|
|
std::string m_filename;
|
|
|
|
ByteStream* m_base_stream;
|
|
ByteStream* m_log_stream;
|
|
|
|
u64 m_image_size;
|
|
u32 m_sector_size;
|
|
u32 m_sector_count;
|
|
u32 m_version_number;
|
|
|
|
LogSectorMap m_log_sector_map;
|
|
|
|
SectorBuffer m_current_sector;
|
|
};
|