mirror of
https://github.com/holub/mame
synced 2025-06-05 12:26:35 +03:00
Filesystem code refactoring (#11570)
- Separate fs::block_t and fs::filesystem_t to a new source file and header - Remove inclusion of flopimg.h from fsmgr.h
This commit is contained in:
parent
7edf0aa2ab
commit
d8f1b27939
@ -75,6 +75,8 @@ project "formats"
|
||||
|
||||
MAME_DIR .. "src/lib/formats/fsmgr.h",
|
||||
MAME_DIR .. "src/lib/formats/fsmgr.cpp",
|
||||
MAME_DIR .. "src/lib/formats/fsblk.h",
|
||||
MAME_DIR .. "src/lib/formats/fsblk.cpp",
|
||||
MAME_DIR .. "src/lib/formats/fsblk_vec.h",
|
||||
MAME_DIR .. "src/lib/formats/fsblk_vec.cpp",
|
||||
MAME_DIR .. "src/lib/formats/fs_unformatted.h",
|
||||
|
@ -12,10 +12,13 @@
|
||||
|
||||
#include "fs_cbmdos.h"
|
||||
#include "d64_dsk.h"
|
||||
#include "fsblk.h"
|
||||
|
||||
#include "corestr.h"
|
||||
#include "strformat.h"
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
@ -13,10 +13,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "fsmgr.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs {
|
||||
|
||||
|
@ -15,10 +15,13 @@
|
||||
|
||||
#include "fs_coco_os9.h"
|
||||
#include "coco_rawdsk.h"
|
||||
#include "fsblk.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
#include "strformat.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
||||
using namespace fs;
|
||||
|
||||
|
@ -14,8 +14,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsmgr.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs {
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "fs_coco_rsdos.h"
|
||||
#include "coco_rawdsk.h"
|
||||
#include "fsblk.h"
|
||||
|
||||
#include "util/strformat.h"
|
||||
|
||||
#include <bitset>
|
||||
|
@ -14,8 +14,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsmgr.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs {
|
||||
|
||||
|
@ -141,10 +141,13 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "fs_fat.h"
|
||||
#include "fsblk.h"
|
||||
#include "pc_dsk.h"
|
||||
|
||||
#include "strformat.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
using namespace fs;
|
||||
|
||||
const fs::pc_fat_image fs::PC_FAT;
|
||||
|
@ -14,11 +14,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsmgr.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs {
|
||||
|
||||
using u8 = uint8_t;
|
||||
|
||||
// ======================> fat_image
|
||||
|
||||
class fat_image : public manager_t {
|
||||
|
@ -59,8 +59,11 @@
|
||||
*********************************************************************/
|
||||
|
||||
#include "fs_hp98x5.h"
|
||||
#include "fsblk.h"
|
||||
#include "hpi_dsk.h"
|
||||
|
||||
#include "strformat.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
|
||||
|
@ -9,16 +9,20 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "fs_hplif.h"
|
||||
#include "fsblk.h"
|
||||
#include "hp300_dsk.h"
|
||||
|
||||
#include "corestr.h"
|
||||
#include "osdcomm.h"
|
||||
#include "strformat.h"
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <iostream>
|
||||
|
||||
namespace fs {
|
||||
const hplif_image HPLIF;
|
||||
};
|
||||
|
@ -13,10 +13,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "fsmgr.h"
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs {
|
||||
|
||||
@ -39,7 +36,6 @@ namespace fs {
|
||||
virtual std::vector<meta_description> file_meta_description() const override;
|
||||
};
|
||||
|
||||
|
||||
extern const hplif_image HPLIF;
|
||||
|
||||
} // namespace fs
|
||||
|
@ -9,6 +9,7 @@
|
||||
*********************************************************************/
|
||||
|
||||
#include "fs_isis.h"
|
||||
#include "fsblk.h"
|
||||
#include "img_dsk.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
|
@ -4,6 +4,7 @@
|
||||
// Management of Oric Jasmin floppy images
|
||||
|
||||
#include "fs_oric_jasmin.h"
|
||||
#include "fsblk.h"
|
||||
#include "oric_dsk.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "fs_prodos.h"
|
||||
#include "ap_dsk35.h"
|
||||
#include "fsblk.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
#include "strformat.h"
|
||||
|
@ -4,6 +4,8 @@
|
||||
// Creation of unformatted floppy images
|
||||
|
||||
#include "fs_unformatted.h"
|
||||
#include "flopimg.h"
|
||||
#include "fsblk.h"
|
||||
|
||||
namespace fs {
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
#include "fsmgr.h"
|
||||
|
||||
class floppy_image;
|
||||
|
||||
namespace fs {
|
||||
|
||||
class unformatted_image : public manager_t {
|
||||
|
@ -4,6 +4,7 @@
|
||||
// Management of VTech images
|
||||
|
||||
#include "fs_vtech.h"
|
||||
#include "fsblk.h"
|
||||
#include "vt_dsk.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
|
254
src/lib/formats/fsblk.cpp
Normal file
254
src/lib/formats/fsblk.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
|
||||
// Filesystem operations on mounted image blocks
|
||||
|
||||
#include "fsblk.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
#include "strformat.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fs {
|
||||
|
||||
void refcounted_inner::ref()
|
||||
{
|
||||
m_ref ++;
|
||||
}
|
||||
|
||||
void refcounted_inner::ref_weak()
|
||||
{
|
||||
m_weak_ref ++;
|
||||
}
|
||||
|
||||
bool refcounted_inner::unref()
|
||||
{
|
||||
m_ref --;
|
||||
if(m_ref == 0) {
|
||||
if(m_weak_ref)
|
||||
drop_weak_references();
|
||||
else
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool refcounted_inner::unref_weak()
|
||||
{
|
||||
m_weak_ref --;
|
||||
if(m_weak_ref == 0 && m_ref == 0) {
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fsblk_t::set_block_size(u32 block_size)
|
||||
{
|
||||
m_block_size = block_size;
|
||||
}
|
||||
|
||||
u8 *fsblk_t::iblock_t::offset(const char *function, u32 off, u32 size)
|
||||
{
|
||||
if(off + size > m_size)
|
||||
throw std::out_of_range(util::string_format("block_t::%s out-of-block access, offset=%d, size=%d, block size=%d", function, off, size, m_size));
|
||||
return data() + off;
|
||||
}
|
||||
|
||||
const u8 *fsblk_t::iblock_t::rooffset(const char *function, u32 off, u32 size)
|
||||
{
|
||||
if(off + size > m_size)
|
||||
throw std::out_of_range(util::string_format("block_t::%s out-of-block read access, offset=%d, size=%d, block size=%d\n", function, off, size, m_size));
|
||||
return rodata() + off;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::copy(u32 offset, const u8 *src, u32 size)
|
||||
{
|
||||
memcpy(m_object->offset("copy", offset, size), src, size);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::fill(u32 offset, u8 data, u32 size)
|
||||
{
|
||||
memset(m_object->offset("fill", offset, size), data, size);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::fill(u8 data)
|
||||
{
|
||||
memset(m_object->data(), data, m_object->size());
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::wstr(u32 offset, std::string_view str)
|
||||
{
|
||||
memcpy(m_object->offset("wstr", offset, str.size()), str.data(), str.size());
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w8(u32 offset, u8 data)
|
||||
{
|
||||
m_object->offset("w8", offset, 1)[0] = data;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w16b(u32 offset, u16 data)
|
||||
{
|
||||
put_u16be(m_object->offset("w16b", offset, 2), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w24b(u32 offset, u32 data)
|
||||
{
|
||||
put_u24be(m_object->offset("w24b", offset, 3), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w32b(u32 offset, u32 data)
|
||||
{
|
||||
put_u32be(m_object->offset("w32b", offset, 4), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w16l(u32 offset, u16 data)
|
||||
{
|
||||
put_u16le(m_object->offset("w16l", offset, 2), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w24l(u32 offset, u32 data)
|
||||
{
|
||||
put_u24le(m_object->offset("w24l", offset, 3), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w32l(u32 offset, u32 data)
|
||||
{
|
||||
put_u32le(m_object->offset("w32l", offset, 4), data);
|
||||
}
|
||||
|
||||
std::string_view fsblk_t::block_t::rstr(u32 offset, u32 size) const
|
||||
{
|
||||
const u8 *d = m_object->rooffset("rstr", offset, size);
|
||||
return std::string_view(reinterpret_cast<const char *>(d), size);
|
||||
}
|
||||
|
||||
u8 fsblk_t::block_t::r8(u32 offset) const
|
||||
{
|
||||
return m_object->offset("r8", offset, 1)[0];
|
||||
}
|
||||
|
||||
u16 fsblk_t::block_t::r16b(u32 offset) const
|
||||
{
|
||||
return get_u16be(m_object->offset("r16b", offset, 2));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r24b(u32 offset) const
|
||||
{
|
||||
return get_u24be(m_object->offset("r24b", offset, 3));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r32b(u32 offset) const
|
||||
{
|
||||
return get_u32be(m_object->offset("r32b", offset, 4));
|
||||
}
|
||||
|
||||
u16 fsblk_t::block_t::r16l(u32 offset) const
|
||||
{
|
||||
return get_u16le(m_object->offset("r16l", offset, 2));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r24l(u32 offset) const
|
||||
{
|
||||
return get_u24le(m_object->offset("r24l", offset, 3));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r32l(u32 offset) const
|
||||
{
|
||||
return get_u32le(m_object->offset("r32l", offset, 4));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void filesystem_t::wstr(u8 *p, std::string_view str)
|
||||
{
|
||||
memcpy(p, str.data(), str.size());
|
||||
}
|
||||
|
||||
std::string_view filesystem_t::rstr(const u8 *p, u32 size)
|
||||
{
|
||||
return std::string_view(reinterpret_cast<const char *>(p), size);
|
||||
}
|
||||
|
||||
std::string_view filesystem_t::trim_end_spaces(std::string_view str)
|
||||
{
|
||||
const auto i = str.find_last_not_of(' ');
|
||||
return str.substr(0, (std::string::npos != i) ? (i + 1) : 0);
|
||||
}
|
||||
|
||||
meta_data filesystem_t::volume_metadata()
|
||||
{
|
||||
return meta_data();
|
||||
}
|
||||
|
||||
err_t filesystem_t::volume_metadata_change(const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, meta_data> filesystem_t::metadata(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, meta_data());
|
||||
}
|
||||
|
||||
err_t filesystem_t::metadata_change(const std::vector<std::string> &path, const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, std::vector<dir_entry>> filesystem_t::directory_contents(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, std::vector<dir_entry>());
|
||||
}
|
||||
|
||||
err_t filesystem_t::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::remove(const std::vector<std::string> &path)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::dir_create(const std::vector<std::string> &path, const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::file_create(const std::vector<std::string> &path, const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, std::vector<u8>> filesystem_t::file_read(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>());
|
||||
}
|
||||
|
||||
err_t filesystem_t::file_write(const std::vector<std::string> &path, const std::vector<u8> &data)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, std::vector<u8>> filesystem_t::file_rsrc_read(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>());
|
||||
}
|
||||
|
||||
err_t filesystem_t::file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::format(const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
} // namespace fs
|
276
src/lib/formats/fsblk.h
Normal file
276
src/lib/formats/fsblk.h
Normal file
@ -0,0 +1,276 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
|
||||
// Filesystem operations on mounted image blocks
|
||||
|
||||
#ifndef MAME_FORMATS_FSBLK_H
|
||||
#define MAME_FORMATS_FSBLK_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fsmeta.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fs {
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
enum err_t {
|
||||
ERR_OK = 0,
|
||||
ERR_UNSUPPORTED,
|
||||
ERR_INVALID,
|
||||
ERR_NOT_FOUND,
|
||||
ERR_NOT_EMPTY,
|
||||
ERR_NO_SPACE,
|
||||
};
|
||||
|
||||
template<typename T> class refcounted_outer {
|
||||
public:
|
||||
refcounted_outer(bool weak) : m_object(nullptr), m_is_weak_ref(weak) {}
|
||||
refcounted_outer(T *object, bool weak) : m_object(object), m_is_weak_ref(weak) {
|
||||
ref();
|
||||
}
|
||||
|
||||
refcounted_outer(const refcounted_outer &cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
}
|
||||
|
||||
refcounted_outer(refcounted_outer &&cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_object = nullptr;
|
||||
}
|
||||
|
||||
~refcounted_outer() {
|
||||
unref();
|
||||
}
|
||||
|
||||
refcounted_outer<T> &operator =(T *dir) {
|
||||
if(m_object != dir) {
|
||||
unref();
|
||||
m_object = dir;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
refcounted_outer<T> &operator =(const refcounted_outer<T> &cref) {
|
||||
if(m_object != cref.m_object) {
|
||||
unref();
|
||||
m_object = cref.m_object;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
refcounted_outer<T> &operator =(refcounted_outer<T> &&cref) {
|
||||
if(m_object != cref.m_object) {
|
||||
unref();
|
||||
m_object = cref.m_object;
|
||||
ref();
|
||||
} else if(m_is_weak_ref != cref.m_is_weak_ref) {
|
||||
ref();
|
||||
cref.unref();
|
||||
m_object = cref.m_object; // In case the object got deleted (when going from strong ref to weak on the last strong)
|
||||
}
|
||||
cref.m_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return m_object != nullptr; }
|
||||
|
||||
protected:
|
||||
T *m_object;
|
||||
bool m_is_weak_ref;
|
||||
|
||||
private:
|
||||
void ref() {
|
||||
if(m_object) {
|
||||
if(m_is_weak_ref)
|
||||
m_object->ref_weak();
|
||||
else
|
||||
m_object->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref() {
|
||||
if(m_object) {
|
||||
bool del = m_is_weak_ref ? m_object->unref_weak() : m_object->unref();
|
||||
if(del)
|
||||
m_object = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class refcounted_inner {
|
||||
public:
|
||||
refcounted_inner() : m_ref(0), m_weak_ref(0) {}
|
||||
virtual ~refcounted_inner() = default;
|
||||
|
||||
void ref();
|
||||
void ref_weak();
|
||||
bool unref();
|
||||
bool unref_weak();
|
||||
|
||||
virtual void drop_weak_references() = 0;
|
||||
|
||||
public:
|
||||
u32 m_ref, m_weak_ref;
|
||||
};
|
||||
|
||||
enum class dir_entry_type {
|
||||
dir,
|
||||
file,
|
||||
};
|
||||
|
||||
struct dir_entry {
|
||||
std::string m_name;
|
||||
dir_entry_type m_type;
|
||||
meta_data m_meta;
|
||||
|
||||
dir_entry(dir_entry_type type, const meta_data &meta) : m_name(meta.get_string(meta_name::name)), m_type(type), m_meta(std::move(meta)) {}
|
||||
};
|
||||
|
||||
class fsblk_t {
|
||||
protected:
|
||||
class iblock_t : public refcounted_inner {
|
||||
public:
|
||||
iblock_t(u32 size) : refcounted_inner(), m_size(size) {}
|
||||
virtual ~iblock_t() = default;
|
||||
|
||||
u32 size() const { return m_size; }
|
||||
|
||||
virtual const u8 *rodata() = 0;
|
||||
virtual u8 *data() = 0;
|
||||
u8 *offset(const char *function, u32 off, u32 size);
|
||||
const u8 *rooffset(const char *function, u32 off, u32 size);
|
||||
|
||||
protected:
|
||||
u32 m_size;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
class block_t : public refcounted_outer<iblock_t> {
|
||||
public:
|
||||
block_t(bool weak = false) : refcounted_outer<iblock_t>(weak) {}
|
||||
block_t(iblock_t *block, bool weak = true) : refcounted_outer(block, weak) {}
|
||||
virtual ~block_t() = default;
|
||||
|
||||
block_t strong() { return block_t(m_object, false); }
|
||||
block_t weak() { return block_t(m_object, true); }
|
||||
|
||||
u32 size() const { return m_object->size(); }
|
||||
|
||||
const u8 *rodata() const { return m_object->rodata(); }
|
||||
u8 *data() { return m_object->data(); }
|
||||
|
||||
void copy(u32 offset, const u8 *src, u32 size);
|
||||
void fill( u8 data);
|
||||
void fill(u32 offset, u8 data, u32 size);
|
||||
void wstr(u32 offset, std::string_view str);
|
||||
void w8( u32 offset, u8 data);
|
||||
void w16b(u32 offset, u16 data);
|
||||
void w24b(u32 offset, u32 data);
|
||||
void w32b(u32 offset, u32 data);
|
||||
void w16l(u32 offset, u16 data);
|
||||
void w24l(u32 offset, u32 data);
|
||||
void w32l(u32 offset, u32 data);
|
||||
|
||||
std::string_view rstr(u32 offset, u32 size) const;
|
||||
u8 r8( u32 offset) const;
|
||||
u16 r16b(u32 offset) const;
|
||||
u32 r24b(u32 offset) const;
|
||||
u32 r32b(u32 offset) const;
|
||||
u16 r16l(u32 offset) const;
|
||||
u32 r24l(u32 offset) const;
|
||||
u32 r32l(u32 offset) const;
|
||||
};
|
||||
|
||||
fsblk_t() : m_block_size(0) {}
|
||||
virtual ~fsblk_t() = default;
|
||||
|
||||
virtual void set_block_size(u32 block_size);
|
||||
virtual u32 block_count() const = 0;
|
||||
virtual block_t get(u32 id) = 0;
|
||||
virtual void fill(u8 data) = 0;
|
||||
|
||||
protected:
|
||||
u32 m_block_size;
|
||||
};
|
||||
|
||||
|
||||
class filesystem_t {
|
||||
public:
|
||||
virtual ~filesystem_t() = default;
|
||||
|
||||
// Get the metadata for the volume
|
||||
virtual meta_data volume_metadata();
|
||||
|
||||
// Change the metadata for the volume
|
||||
virtual err_t volume_metadata_change(const meta_data &meta);
|
||||
|
||||
// Get the metadata for a file or a directory. Empty path targets the root directory
|
||||
virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path);
|
||||
|
||||
// Change the metadata for a file or a directory. Empty path targets the root directory
|
||||
virtual err_t metadata_change(const std::vector<std::string> &path, const meta_data &meta);
|
||||
|
||||
// Get the contents of a directory, empty path targets the root directory
|
||||
virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path);
|
||||
|
||||
// Rename a file or a directory. In contrast to metadata_change, this can move the object
|
||||
// between directories
|
||||
virtual err_t rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath);
|
||||
|
||||
// Remove a file or a directory. Directories must be empty (e.g. it's not recursive)
|
||||
virtual err_t remove(const std::vector<std::string> &path);
|
||||
|
||||
// Create a directory, path designates where the directory must be, directory name is in meta
|
||||
virtual err_t dir_create(const std::vector<std::string> &path, const meta_data &meta);
|
||||
|
||||
// Create an empty file, path designates where the file must be, file name is in meta
|
||||
virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta);
|
||||
|
||||
// Read the contents of a file
|
||||
virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path);
|
||||
|
||||
// Replace the contents of a file, the file must already exist
|
||||
virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data);
|
||||
|
||||
// Read the resource fork of a file on systems that handle those
|
||||
virtual std::pair<err_t, std::vector<u8>> file_rsrc_read(const std::vector<std::string> &path);
|
||||
|
||||
// Replace the resource fork of a file, the file must already exist
|
||||
virtual err_t file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data);
|
||||
|
||||
// Format an image, provide the volume metadata
|
||||
virtual err_t format(const meta_data &meta);
|
||||
|
||||
static void wstr(u8 *p, std::string_view str);
|
||||
|
||||
static std::string_view rstr(const u8 *p, u32 size);
|
||||
|
||||
static std::string_view trim_end_spaces(std::string_view str);
|
||||
|
||||
protected:
|
||||
filesystem_t(fsblk_t &blockdev, u32 size) : m_blockdev(blockdev) {
|
||||
m_blockdev.set_block_size(size);
|
||||
}
|
||||
|
||||
fsblk_t &m_blockdev;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
||||
#endif
|
@ -3,7 +3,7 @@
|
||||
|
||||
// Block device on vector<uint8_t>
|
||||
|
||||
#include "fsmgr.h"
|
||||
#include "fsblk.h"
|
||||
|
||||
namespace fs {
|
||||
|
||||
|
@ -6,49 +6,10 @@
|
||||
// Currently limited to floppies and creation of preformatted images
|
||||
|
||||
#include "fsmgr.h"
|
||||
|
||||
#include "multibyte.h"
|
||||
#include "strformat.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include "flopimg.h"
|
||||
|
||||
namespace fs {
|
||||
|
||||
void refcounted_inner::ref()
|
||||
{
|
||||
m_ref ++;
|
||||
}
|
||||
|
||||
void refcounted_inner::ref_weak()
|
||||
{
|
||||
m_weak_ref ++;
|
||||
}
|
||||
|
||||
bool refcounted_inner::unref()
|
||||
{
|
||||
m_ref --;
|
||||
if(m_ref == 0) {
|
||||
if(m_weak_ref)
|
||||
drop_weak_references();
|
||||
else
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool refcounted_inner::unref_weak()
|
||||
{
|
||||
m_weak_ref --;
|
||||
if(m_weak_ref == 0 && m_ref == 0) {
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void manager_t::enumerate_f(floppy_enumerator &fe) const
|
||||
{
|
||||
}
|
||||
@ -104,209 +65,6 @@ char manager_t::directory_separator() const
|
||||
return 0; // Subdirectories not supported by default
|
||||
}
|
||||
|
||||
void fsblk_t::set_block_size(u32 block_size)
|
||||
{
|
||||
m_block_size = block_size;
|
||||
}
|
||||
|
||||
u8 *fsblk_t::iblock_t::offset(const char *function, u32 off, u32 size)
|
||||
{
|
||||
if(off + size > m_size)
|
||||
throw std::out_of_range(util::string_format("block_t::%s out-of-block access, offset=%d, size=%d, block size=%d", function, off, size, m_size));
|
||||
return data() + off;
|
||||
}
|
||||
|
||||
const u8 *fsblk_t::iblock_t::rooffset(const char *function, u32 off, u32 size)
|
||||
{
|
||||
if(off + size > m_size)
|
||||
throw std::out_of_range(util::string_format("block_t::%s out-of-block read access, offset=%d, size=%d, block size=%d\n", function, off, size, m_size));
|
||||
return rodata() + off;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::copy(u32 offset, const u8 *src, u32 size)
|
||||
{
|
||||
memcpy(m_object->offset("copy", offset, size), src, size);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::fill(u32 offset, u8 data, u32 size)
|
||||
{
|
||||
memset(m_object->offset("fill", offset, size), data, size);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::fill(u8 data)
|
||||
{
|
||||
memset(m_object->data(), data, m_object->size());
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::wstr(u32 offset, std::string_view str)
|
||||
{
|
||||
memcpy(m_object->offset("wstr", offset, str.size()), str.data(), str.size());
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w8(u32 offset, u8 data)
|
||||
{
|
||||
m_object->offset("w8", offset, 1)[0] = data;
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w16b(u32 offset, u16 data)
|
||||
{
|
||||
put_u16be(m_object->offset("w16b", offset, 2), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w24b(u32 offset, u32 data)
|
||||
{
|
||||
put_u24be(m_object->offset("w24b", offset, 3), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w32b(u32 offset, u32 data)
|
||||
{
|
||||
put_u32be(m_object->offset("w32b", offset, 4), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w16l(u32 offset, u16 data)
|
||||
{
|
||||
put_u16le(m_object->offset("w16l", offset, 2), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w24l(u32 offset, u32 data)
|
||||
{
|
||||
put_u24le(m_object->offset("w24l", offset, 3), data);
|
||||
}
|
||||
|
||||
void fsblk_t::block_t::w32l(u32 offset, u32 data)
|
||||
{
|
||||
put_u32le(m_object->offset("w32l", offset, 4), data);
|
||||
}
|
||||
|
||||
std::string_view fsblk_t::block_t::rstr(u32 offset, u32 size) const
|
||||
{
|
||||
const u8 *d = m_object->rooffset("rstr", offset, size);
|
||||
return std::string_view(reinterpret_cast<const char *>(d), size);
|
||||
}
|
||||
|
||||
u8 fsblk_t::block_t::r8(u32 offset) const
|
||||
{
|
||||
return m_object->offset("r8", offset, 1)[0];
|
||||
}
|
||||
|
||||
u16 fsblk_t::block_t::r16b(u32 offset) const
|
||||
{
|
||||
return get_u16be(m_object->offset("r16b", offset, 2));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r24b(u32 offset) const
|
||||
{
|
||||
return get_u24be(m_object->offset("r24b", offset, 3));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r32b(u32 offset) const
|
||||
{
|
||||
return get_u32be(m_object->offset("r32b", offset, 4));
|
||||
}
|
||||
|
||||
u16 fsblk_t::block_t::r16l(u32 offset) const
|
||||
{
|
||||
return get_u16le(m_object->offset("r16l", offset, 2));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r24l(u32 offset) const
|
||||
{
|
||||
return get_u24le(m_object->offset("r24l", offset, 3));
|
||||
}
|
||||
|
||||
u32 fsblk_t::block_t::r32l(u32 offset) const
|
||||
{
|
||||
return get_u32le(m_object->offset("r32l", offset, 4));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void filesystem_t::wstr(u8 *p, std::string_view str)
|
||||
{
|
||||
memcpy(p, str.data(), str.size());
|
||||
}
|
||||
|
||||
std::string_view filesystem_t::rstr(const u8 *p, u32 size)
|
||||
{
|
||||
return std::string_view(reinterpret_cast<const char *>(p), size);
|
||||
}
|
||||
|
||||
std::string_view filesystem_t::trim_end_spaces(std::string_view str)
|
||||
{
|
||||
const auto i = str.find_last_not_of(' ');
|
||||
return str.substr(0, (std::string::npos != i) ? (i + 1) : 0);
|
||||
}
|
||||
|
||||
meta_data filesystem_t::volume_metadata()
|
||||
{
|
||||
return meta_data();
|
||||
}
|
||||
|
||||
err_t filesystem_t::volume_metadata_change(const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, meta_data> filesystem_t::metadata(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, meta_data());
|
||||
}
|
||||
|
||||
err_t filesystem_t::metadata_change(const std::vector<std::string> &path, const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, std::vector<dir_entry>> filesystem_t::directory_contents(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, std::vector<dir_entry>());
|
||||
}
|
||||
|
||||
err_t filesystem_t::rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::remove(const std::vector<std::string> &path)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::dir_create(const std::vector<std::string> &path, const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::file_create(const std::vector<std::string> &path, const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, std::vector<u8>> filesystem_t::file_read(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>());
|
||||
}
|
||||
|
||||
err_t filesystem_t::file_write(const std::vector<std::string> &path, const std::vector<u8> &data)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::pair<err_t, std::vector<u8>> filesystem_t::file_rsrc_read(const std::vector<std::string> &path)
|
||||
{
|
||||
return std::make_pair(ERR_UNSUPPORTED, std::vector<u8>());
|
||||
}
|
||||
|
||||
err_t filesystem_t::file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
err_t filesystem_t::format(const meta_data &meta)
|
||||
{
|
||||
return ERR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
manager_t::floppy_enumerator::floppy_enumerator(u32 form_factor, const std::vector<u32> &variants)
|
||||
: m_form_factor(form_factor)
|
||||
, m_variants(variants)
|
||||
|
@ -8,266 +8,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "flopimg.h"
|
||||
#include "fsmeta.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class floppy_image_format_t;
|
||||
|
||||
namespace fs {
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
// declared in fsblk.h
|
||||
class filesystem_t;
|
||||
class fsblk_t;
|
||||
|
||||
using u32 = uint32_t;
|
||||
using u64 = uint64_t;
|
||||
|
||||
enum err_t {
|
||||
ERR_OK = 0,
|
||||
ERR_UNSUPPORTED,
|
||||
ERR_INVALID,
|
||||
ERR_NOT_FOUND,
|
||||
ERR_NOT_EMPTY,
|
||||
ERR_NO_SPACE,
|
||||
};
|
||||
|
||||
template<typename T> class refcounted_outer {
|
||||
public:
|
||||
refcounted_outer(bool weak) : m_object(nullptr), m_is_weak_ref(weak) {}
|
||||
refcounted_outer(T *object, bool weak) : m_object(object), m_is_weak_ref(weak) {
|
||||
ref();
|
||||
}
|
||||
|
||||
refcounted_outer(const refcounted_outer &cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
ref();
|
||||
}
|
||||
|
||||
refcounted_outer(refcounted_outer &&cref) {
|
||||
m_object = cref.m_object;
|
||||
m_is_weak_ref = cref.m_is_weak_ref;
|
||||
cref.m_object = nullptr;
|
||||
}
|
||||
|
||||
~refcounted_outer() {
|
||||
unref();
|
||||
}
|
||||
|
||||
refcounted_outer<T> &operator =(T *dir) {
|
||||
if(m_object != dir) {
|
||||
unref();
|
||||
m_object = dir;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
refcounted_outer<T> &operator =(const refcounted_outer<T> &cref) {
|
||||
if(m_object != cref.m_object) {
|
||||
unref();
|
||||
m_object = cref.m_object;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
refcounted_outer<T> &operator =(refcounted_outer<T> &&cref) {
|
||||
if(m_object != cref.m_object) {
|
||||
unref();
|
||||
m_object = cref.m_object;
|
||||
ref();
|
||||
} else if(m_is_weak_ref != cref.m_is_weak_ref) {
|
||||
ref();
|
||||
cref.unref();
|
||||
m_object = cref.m_object; // In case the object got deleted (when going from strong ref to weak on the last strong)
|
||||
}
|
||||
cref.m_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const { return m_object != nullptr; }
|
||||
|
||||
protected:
|
||||
T *m_object;
|
||||
bool m_is_weak_ref;
|
||||
|
||||
private:
|
||||
void ref() {
|
||||
if(m_object) {
|
||||
if(m_is_weak_ref)
|
||||
m_object->ref_weak();
|
||||
else
|
||||
m_object->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref() {
|
||||
if(m_object) {
|
||||
bool del = m_is_weak_ref ? m_object->unref_weak() : m_object->unref();
|
||||
if(del)
|
||||
m_object = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class refcounted_inner {
|
||||
public:
|
||||
refcounted_inner() : m_ref(0), m_weak_ref(0) {}
|
||||
virtual ~refcounted_inner() = default;
|
||||
|
||||
void ref();
|
||||
void ref_weak();
|
||||
bool unref();
|
||||
bool unref_weak();
|
||||
|
||||
virtual void drop_weak_references() = 0;
|
||||
|
||||
public:
|
||||
u32 m_ref, m_weak_ref;
|
||||
};
|
||||
|
||||
enum class dir_entry_type {
|
||||
dir,
|
||||
file,
|
||||
};
|
||||
|
||||
struct dir_entry {
|
||||
std::string m_name;
|
||||
dir_entry_type m_type;
|
||||
meta_data m_meta;
|
||||
|
||||
dir_entry(dir_entry_type type, const meta_data &meta) : m_name(meta.get_string(meta_name::name)), m_type(type), m_meta(std::move(meta)) {}
|
||||
};
|
||||
|
||||
class fsblk_t {
|
||||
protected:
|
||||
class iblock_t : public refcounted_inner {
|
||||
public:
|
||||
iblock_t(u32 size) : refcounted_inner(), m_size(size) {}
|
||||
virtual ~iblock_t() = default;
|
||||
|
||||
u32 size() const { return m_size; }
|
||||
|
||||
virtual const u8 *rodata() = 0;
|
||||
virtual u8 *data() = 0;
|
||||
u8 *offset(const char *function, u32 off, u32 size);
|
||||
const u8 *rooffset(const char *function, u32 off, u32 size);
|
||||
|
||||
protected:
|
||||
u32 m_size;
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
class block_t : public refcounted_outer<iblock_t> {
|
||||
public:
|
||||
block_t(bool weak = false) : refcounted_outer<iblock_t>(weak) {}
|
||||
block_t(iblock_t *block, bool weak = true) : refcounted_outer(block, weak) {}
|
||||
virtual ~block_t() = default;
|
||||
|
||||
block_t strong() { return block_t(m_object, false); }
|
||||
block_t weak() { return block_t(m_object, true); }
|
||||
|
||||
u32 size() const { return m_object->size(); }
|
||||
|
||||
const u8 *rodata() const { return m_object->rodata(); }
|
||||
u8 *data() { return m_object->data(); }
|
||||
|
||||
void copy(u32 offset, const u8 *src, u32 size);
|
||||
void fill( u8 data);
|
||||
void fill(u32 offset, u8 data, u32 size);
|
||||
void wstr(u32 offset, std::string_view str);
|
||||
void w8( u32 offset, u8 data);
|
||||
void w16b(u32 offset, u16 data);
|
||||
void w24b(u32 offset, u32 data);
|
||||
void w32b(u32 offset, u32 data);
|
||||
void w16l(u32 offset, u16 data);
|
||||
void w24l(u32 offset, u32 data);
|
||||
void w32l(u32 offset, u32 data);
|
||||
|
||||
std::string_view rstr(u32 offset, u32 size) const;
|
||||
u8 r8( u32 offset) const;
|
||||
u16 r16b(u32 offset) const;
|
||||
u32 r24b(u32 offset) const;
|
||||
u32 r32b(u32 offset) const;
|
||||
u16 r16l(u32 offset) const;
|
||||
u32 r24l(u32 offset) const;
|
||||
u32 r32l(u32 offset) const;
|
||||
};
|
||||
|
||||
fsblk_t() : m_block_size(0) {}
|
||||
virtual ~fsblk_t() = default;
|
||||
|
||||
virtual void set_block_size(u32 block_size);
|
||||
virtual u32 block_count() const = 0;
|
||||
virtual block_t get(u32 id) = 0;
|
||||
virtual void fill(u8 data) = 0;
|
||||
|
||||
protected:
|
||||
u32 m_block_size;
|
||||
};
|
||||
|
||||
|
||||
class filesystem_t {
|
||||
public:
|
||||
virtual ~filesystem_t() = default;
|
||||
|
||||
// Get the metadata for the volume
|
||||
virtual meta_data volume_metadata();
|
||||
|
||||
// Change the metadata for the volume
|
||||
virtual err_t volume_metadata_change(const meta_data &meta);
|
||||
|
||||
// Get the metadata for a file or a directory. Empty path targets the root directory
|
||||
virtual std::pair<err_t, meta_data> metadata(const std::vector<std::string> &path);
|
||||
|
||||
// Change the metadata for a file or a directory. Empty path targets the root directory
|
||||
virtual err_t metadata_change(const std::vector<std::string> &path, const meta_data &meta);
|
||||
|
||||
// Get the contents of a directory, empty path targets the root directory
|
||||
virtual std::pair<err_t, std::vector<dir_entry>> directory_contents(const std::vector<std::string> &path);
|
||||
|
||||
// Rename a file or a directory. In contrast to metadata_change, this can move the object
|
||||
// between directories
|
||||
virtual err_t rename(const std::vector<std::string> &opath, const std::vector<std::string> &npath);
|
||||
|
||||
// Remove a file or a directory. Directories must be empty (e.g. it's not recursive)
|
||||
virtual err_t remove(const std::vector<std::string> &path);
|
||||
|
||||
// Create a directory, path designates where the directory must be, directory name is in meta
|
||||
virtual err_t dir_create(const std::vector<std::string> &path, const meta_data &meta);
|
||||
|
||||
// Create an empty file, path designates where the file must be, file name is in meta
|
||||
virtual err_t file_create(const std::vector<std::string> &path, const meta_data &meta);
|
||||
|
||||
// Read the contents of a file
|
||||
virtual std::pair<err_t, std::vector<u8>> file_read(const std::vector<std::string> &path);
|
||||
|
||||
// Replace the contents of a file, the file must already exist
|
||||
virtual err_t file_write(const std::vector<std::string> &path, const std::vector<u8> &data);
|
||||
|
||||
// Read the resource fork of a file on systems that handle those
|
||||
virtual std::pair<err_t, std::vector<u8>> file_rsrc_read(const std::vector<std::string> &path);
|
||||
|
||||
// Replace the resource fork of a file, the file must already exist
|
||||
virtual err_t file_rsrc_write(const std::vector<std::string> &path, const std::vector<u8> &data);
|
||||
|
||||
// Format an image, provide the volume metadata
|
||||
virtual err_t format(const meta_data &meta);
|
||||
|
||||
static void wstr(u8 *p, std::string_view str);
|
||||
|
||||
static std::string_view rstr(const u8 *p, u32 size);
|
||||
|
||||
static std::string_view trim_end_spaces(std::string_view str);
|
||||
|
||||
protected:
|
||||
filesystem_t(fsblk_t &blockdev, u32 size) : m_blockdev(blockdev) {
|
||||
m_blockdev.set_block_size(size);
|
||||
}
|
||||
|
||||
fsblk_t &m_blockdev;
|
||||
};
|
||||
|
||||
class unformatted_floppy_creator;
|
||||
|
||||
class manager_t {
|
||||
public:
|
||||
@ -301,7 +55,6 @@ public:
|
||||
virtual void add(const manager_t *manager, const char *name, const char *description) = 0;
|
||||
};
|
||||
|
||||
|
||||
virtual ~manager_t() = default;
|
||||
|
||||
virtual const char *name() const = 0;
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "image_handler.h"
|
||||
|
||||
#include "formats/fsblk.h"
|
||||
|
||||
#include "corestr.h"
|
||||
#include "ioprocs.h"
|
||||
#include "path.h"
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "formats/flopimg.h"
|
||||
#include "formats/fsmgr.h"
|
||||
#include "harddisk.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user