mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
212 lines
5.6 KiB
C++
212 lines
5.6 KiB
C++
#include "lib/globals.h"
|
|
#include "lib/vfs/vfs.h"
|
|
#include "lib/config.pb.h"
|
|
#include "lib/utils.h"
|
|
#include <fmt/format.h>
|
|
|
|
/* A directory entry looks like:
|
|
*
|
|
* 00-09: ten byte filename FFFFFFFF.EE
|
|
* 0a-0b: word: start sector
|
|
* 0c-17: unknown
|
|
*/
|
|
|
|
class Smaky6Filesystem : public Filesystem
|
|
{
|
|
class Entry
|
|
{
|
|
public:
|
|
Entry(const Bytes& bytes)
|
|
{
|
|
ByteReader br(bytes);
|
|
br.seek(10);
|
|
startSector = br.read_le16();
|
|
endSector = br.read_le16();
|
|
}
|
|
|
|
public:
|
|
std::string filename;
|
|
std::string mode;
|
|
uint16_t startSector;
|
|
uint16_t endSector;
|
|
};
|
|
|
|
class SmakyDirent : public Dirent
|
|
{
|
|
public:
|
|
SmakyDirent(const Bytes& dbuf)
|
|
{
|
|
{
|
|
std::stringstream ss;
|
|
|
|
for (int i = 0; i <= 7; i++)
|
|
{
|
|
uint8_t c = dbuf[i] & 0x7f;
|
|
if (c == ' ')
|
|
break;
|
|
ss << (char)c;
|
|
}
|
|
for (int i = 8; i <= 9; i++)
|
|
{
|
|
uint8_t c = dbuf[i] & 0x7f;
|
|
if (c == ' ')
|
|
break;
|
|
if (i == 8)
|
|
ss << '.';
|
|
ss << (char)c;
|
|
}
|
|
filename = ss.str();
|
|
}
|
|
|
|
std::string metadataBytes;
|
|
{
|
|
std::stringstream ss;
|
|
|
|
for (int i = 10; i < 0x18; i++)
|
|
ss << fmt::format("{:02x} ", (uint8_t)dbuf[i]);
|
|
|
|
metadataBytes = ss.str();
|
|
}
|
|
|
|
ByteReader br(dbuf);
|
|
|
|
br.skip(10); /* filename */
|
|
startSector = br.read_le16();
|
|
endSector = br.read_le16();
|
|
br.skip(2); /* unknown */
|
|
lastSectorLength = br.read_le16();
|
|
|
|
file_type = TYPE_FILE;
|
|
length = (endSector - startSector - 1) * 256 + lastSectorLength;
|
|
|
|
path = {filename};
|
|
attributes[Filesystem::FILENAME] = filename;
|
|
attributes[Filesystem::LENGTH] = std::to_string(length);
|
|
attributes[Filesystem::FILE_TYPE] = "file";
|
|
attributes[Filesystem::MODE] = "";
|
|
attributes["smaky6.start_sector"] = std::to_string(startSector);
|
|
attributes["smaky6.end_sector"] = std::to_string(endSector);
|
|
attributes["smaky6.sectors"] =
|
|
std::to_string(endSector - startSector);
|
|
attributes["smaky6.metadata_bytes"] = metadataBytes;
|
|
}
|
|
|
|
public:
|
|
unsigned startSector;
|
|
unsigned endSector;
|
|
unsigned lastSectorLength;
|
|
};
|
|
|
|
friend class Directory;
|
|
class Directory
|
|
{
|
|
public:
|
|
Directory(Smaky6Filesystem* fs)
|
|
{
|
|
/* Read the directory. */
|
|
|
|
auto bytes = fs->getLogicalSector(0, 3);
|
|
ByteReader br(bytes);
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
{
|
|
auto dbuf = bytes.slice(i * 0x18, 0x18);
|
|
if (dbuf[0])
|
|
{
|
|
auto de = std::make_shared<SmakyDirent>(dbuf);
|
|
dirents.push_back(de);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<SmakyDirent> findFile(const std::string& filename)
|
|
{
|
|
for (auto& de : dirents)
|
|
if (de->filename == filename)
|
|
return de;
|
|
|
|
throw FileNotFoundException();
|
|
}
|
|
|
|
public:
|
|
std::vector<std::shared_ptr<SmakyDirent>> dirents;
|
|
};
|
|
|
|
public:
|
|
Smaky6Filesystem(
|
|
const Smaky6FsProto& config, std::shared_ptr<SectorInterface> sectors):
|
|
Filesystem(sectors),
|
|
_config(config)
|
|
{
|
|
}
|
|
|
|
uint32_t capabilities() const
|
|
{
|
|
return OP_LIST | OP_GETFILE | OP_GETFSDATA | OP_GETDIRENT;
|
|
}
|
|
|
|
FilesystemStatus check() override
|
|
{
|
|
return FS_OK;
|
|
}
|
|
|
|
std::map<std::string, std::string> getMetadata() override
|
|
{
|
|
Directory dir(this);
|
|
unsigned usedBlocks = 3;
|
|
for (auto& de : dir.dirents)
|
|
usedBlocks += (de->endSector - de->startSector);
|
|
|
|
std::map<std::string, std::string> attributes;
|
|
attributes[VOLUME_NAME] = "";
|
|
attributes[TOTAL_BLOCKS] = std::to_string(getLogicalSectorCount());
|
|
attributes[USED_BLOCKS] = std::to_string(usedBlocks);
|
|
attributes[BLOCK_SIZE] = std::to_string(getLogicalSectorSize(0, 0));
|
|
return attributes;
|
|
}
|
|
|
|
std::vector<std::shared_ptr<Dirent>> list(const Path& path) override
|
|
{
|
|
if (!path.empty())
|
|
throw FileNotFoundException();
|
|
|
|
Directory dir(this);
|
|
std::vector<std::shared_ptr<Dirent>> result;
|
|
for (auto& de : dir.dirents)
|
|
result.push_back(de);
|
|
return result;
|
|
}
|
|
|
|
std::shared_ptr<Dirent> getDirent(const Path& path) override
|
|
{
|
|
Directory dir(this);
|
|
if (path.size() != 1)
|
|
throw BadPathException();
|
|
|
|
return dir.findFile(path[0]);
|
|
}
|
|
|
|
Bytes getFile(const Path& path) override
|
|
{
|
|
if (path.size() != 1)
|
|
throw BadPathException(path);
|
|
|
|
Directory dir(this);
|
|
auto de = dir.findFile(path[0]);
|
|
|
|
Bytes data =
|
|
getLogicalSector(de->startSector, de->endSector - de->startSector);
|
|
data = data.slice(0, de->length);
|
|
return data;
|
|
}
|
|
|
|
private:
|
|
const Smaky6FsProto& _config;
|
|
};
|
|
|
|
std::unique_ptr<Filesystem> Filesystem::createSmaky6Filesystem(
|
|
const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors)
|
|
{
|
|
return std::make_unique<Smaky6Filesystem>(config.smaky6(), sectors);
|
|
}
|