mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
prodos: Add file and resource reading
This commit is contained in:
parent
9d4ffe837e
commit
94db317064
@ -67,6 +67,11 @@ bool fs_oric_jasmin::can_write() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_oric_jasmin::has_rsrc() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<fs_meta_description> fs_oric_jasmin::volume_meta_description() const
|
||||
{
|
||||
std::vector<fs_meta_description> res;
|
||||
@ -290,9 +295,9 @@ fs_meta_data fs_oric_jasmin::impl::file::metadata()
|
||||
res[fs_meta_name::name] = read_file_name(m_entry + 3);
|
||||
res[fs_meta_name::locked] = m_entry[2] == 'L';
|
||||
res[fs_meta_name::sequential] = m_entry[0xf] == 'S';
|
||||
res[fs_meta_name::size_in_blocks] = uint64_t(m_entry[0x10] | (m_entry[0x11] << 8));
|
||||
res[fs_meta_name::size_in_blocks] = r16l(m_entry + 0x10);
|
||||
|
||||
u16 ref = (m_entry[0] << 8) | m_entry[1];
|
||||
u16 ref = r16b(m_entry);
|
||||
auto dblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
res[fs_meta_name::loading_address] = uint64_t(dblk.r16l(2));
|
||||
res[fs_meta_name::length] = uint64_t(dblk.r16l(4));
|
||||
@ -351,7 +356,7 @@ std::vector<u8> fs_oric_jasmin::impl::file::read(u64 start, u64 length)
|
||||
std::pair<std::vector<u16>, u32> fs_oric_jasmin::impl::file::build_data_sector_table()
|
||||
{
|
||||
std::pair<std::vector<u16>, u32> res;
|
||||
u16 ref = (m_entry[0] << 8) | m_entry[1];
|
||||
u16 ref = r16b(m_entry);
|
||||
auto iblk = m_fs.m_blockdev.get(cs_to_block(ref));
|
||||
u32 length = iblk.r16l(4);
|
||||
while(m_fs.ref_valid(ref)) {
|
||||
@ -389,8 +394,8 @@ fs_meta_data fs_oric_jasmin::impl::system_file::metadata()
|
||||
res[fs_meta_name::name] = read_file_name(m_entry + 3);
|
||||
res[fs_meta_name::locked] = m_entry[2] == 'L';
|
||||
res[fs_meta_name::sequential] = m_entry[0xf] == 'S';
|
||||
res[fs_meta_name::size_in_blocks] = uint64_t(m_entry[0x10] | (m_entry[0x11] << 8));
|
||||
res[fs_meta_name::length] = uint64_t(0x3e00);
|
||||
res[fs_meta_name::size_in_blocks] = r16l(m_entry + 0x10);
|
||||
res[fs_meta_name::length] = 0x3e00;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ public:
|
||||
virtual bool can_format() const override;
|
||||
virtual bool can_read() const override;
|
||||
virtual bool can_write() const override;
|
||||
virtual bool has_rsrc() const override;
|
||||
|
||||
virtual std::vector<fs_meta_description> volume_meta_description() const override;
|
||||
virtual std::vector<fs_meta_description> file_meta_description() const override;
|
||||
|
@ -70,6 +70,11 @@ bool fs_prodos::can_write() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_prodos::has_rsrc() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
char fs_prodos::directory_separator() const
|
||||
{
|
||||
return '/';
|
||||
@ -333,12 +338,13 @@ filesystem_t::dir_t fs_prodos::impl::dir::dir_get(uint64_t key)
|
||||
if(type != 0xd)
|
||||
fatalerror("Unhandled directory type %x\n", type);
|
||||
|
||||
return new dir(m_fs, entry[17] | (entry[18] << 8), key);
|
||||
return new dir(m_fs, r16l(entry+0x11), key);
|
||||
}
|
||||
|
||||
fs_prodos::impl::file::file(impl &fs, const u8 *entry, u16 key) : m_fs(fs), m_key(key)
|
||||
{
|
||||
memcpy(m_entry, entry, 39);
|
||||
(void)m_key;
|
||||
}
|
||||
|
||||
void fs_prodos::impl::file::drop_weak_references()
|
||||
@ -348,31 +354,195 @@ void fs_prodos::impl::file::drop_weak_references()
|
||||
fs_meta_data fs_prodos::impl::file::metadata()
|
||||
{
|
||||
fs_meta_data res;
|
||||
std::string name;
|
||||
u8 type = m_entry[0];
|
||||
for(u8 i = 0; i != (type & 0xf); i++)
|
||||
name += char(m_entry[i+1]);
|
||||
u8 type = r8(m_entry);
|
||||
std::string name = rstr(m_entry+1, type & 0xf);
|
||||
type >>= 4;
|
||||
res[fs_meta_name::name] = name;
|
||||
if(type == 5) {
|
||||
auto rootblk = m_fs.m_blockdev.get(m_entry[0x11] | (m_entry[0x12] << 8));
|
||||
auto rootblk = m_fs.m_blockdev.get(r16l(m_entry+0x11));
|
||||
res[fs_meta_name::length] = rootblk.r24l(0x005);
|
||||
res[fs_meta_name::rsrc_length] = rootblk.r24l(0x105);
|
||||
|
||||
} else if((type >= 1 && type <= 3) || 1)
|
||||
res[fs_meta_name::length] = m_entry[0x15] | (m_entry[0x16] << 8) | (m_entry[0x17] << 16);
|
||||
} else if(type >= 1 && type <= 3)
|
||||
res[fs_meta_name::length] = r24l(m_entry + 0x15);
|
||||
|
||||
else
|
||||
fatalerror("fs_prodos::impl::file::metadata: Unhandled file type %d\n", type);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<uint16_t> fs_prodos::impl::file::get_file_blocks(uint8_t type, u16 block, u32 length)
|
||||
{
|
||||
u32 nb = (length+1)/512;
|
||||
std::vector<uint16_t> res;
|
||||
switch(type) {
|
||||
case 1:
|
||||
if(nb)
|
||||
res.push_back(block);
|
||||
break;
|
||||
|
||||
case 2: {
|
||||
auto iblk = m_fs.m_blockdev.get(block);
|
||||
if(nb > 255)
|
||||
nb = 255;
|
||||
for(u32 i=0; i != nb; i++)
|
||||
res.push_back(iblk.r8(i) | (iblk.r8(i | 0x100) << 8));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
auto mblk = m_fs.m_blockdev.get(block);
|
||||
for(u32 j=0; j < nb; j += 256) {
|
||||
u32 idx = j/256;
|
||||
auto iblk = m_fs.m_blockdev.get(mblk.r8(idx) | (mblk.r8(idx | 0x100) << 8));
|
||||
for(u32 i=0; i != 256 && res.size() != nb; i++)
|
||||
res.push_back(iblk.r8(i) | (iblk.r8(i | 0x100) << 8));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
fatalerror("fs_prodos::impl::file::get_file_blocks: unknown file type %d\n", type);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::pair<std::vector<uint16_t>, u32> fs_prodos::impl::file::data_blocks()
|
||||
{
|
||||
std::vector<uint16_t> blocks;
|
||||
|
||||
u8 type = r8(m_entry) >> 4;
|
||||
u32 length = 0;
|
||||
if(type >= 1 && type <= 3) {
|
||||
length = r24l(m_entry + 0x15);
|
||||
blocks = get_file_blocks(type, r16l(m_entry+0x11), length);
|
||||
|
||||
} else if(type == 5) {
|
||||
auto kblk = m_fs.m_blockdev.get(r16l(m_entry+0x11));
|
||||
length = kblk.r24l(0x005);
|
||||
blocks = get_file_blocks(kblk.r8(0x000), kblk.r16l(0x001), length);
|
||||
|
||||
} else
|
||||
fatalerror("fs_prodos::impl::file::data_blocks: Unhandled file type %d\n", type);
|
||||
|
||||
return std::make_pair(blocks, length);
|
||||
}
|
||||
|
||||
std::pair<std::vector<uint16_t>, u32> fs_prodos::impl::file::rsrc_blocks()
|
||||
{
|
||||
std::vector<uint16_t> blocks;
|
||||
|
||||
u8 type = r8(m_entry) >> 4;
|
||||
u32 length = 0;
|
||||
|
||||
if(type == 5) {
|
||||
auto kblk = m_fs.m_blockdev.get(r16l(m_entry+0x11));
|
||||
length = kblk.r24l(0x105);
|
||||
blocks = get_file_blocks(kblk.r8(0x100), kblk.r16l(0x101), length);
|
||||
|
||||
} else
|
||||
fatalerror("fs_prodos::impl::file::rsrc_blocks: Unhandled file type %d\n", type);
|
||||
|
||||
return std::make_pair(blocks, length);
|
||||
}
|
||||
|
||||
std::vector<u8> fs_prodos::impl::file::read_all()
|
||||
{
|
||||
abort();
|
||||
auto [blocks, length] = data_blocks();
|
||||
|
||||
std::vector<u8> data(length);
|
||||
u32 pos = 0;
|
||||
for(u16 block : blocks) {
|
||||
u32 npos = pos + 512;
|
||||
if(npos > length)
|
||||
npos = length;
|
||||
if(npos > pos) {
|
||||
auto dblk = m_fs.m_blockdev.get(block);
|
||||
memcpy(data.data() + pos, dblk.rodata(), npos - pos);
|
||||
} else
|
||||
break;
|
||||
pos = npos;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_prodos::impl::file::read(u64 start, u64 length)
|
||||
{
|
||||
abort();
|
||||
auto [blocks, rlength] = data_blocks();
|
||||
length += start;
|
||||
if(length > rlength)
|
||||
length = rlength;
|
||||
|
||||
if(rlength < start)
|
||||
return std::vector<u8>();
|
||||
|
||||
std::vector<u8> data(length - start);
|
||||
u32 pos = 0;
|
||||
for(u16 block : blocks) {
|
||||
u32 npos = pos + 512;
|
||||
if(npos > length)
|
||||
npos = length;
|
||||
if(npos > pos) {
|
||||
if(npos > start) {
|
||||
u32 off = pos < start ? start & 0xff : 0;
|
||||
auto dblk = m_fs.m_blockdev.get(block);
|
||||
memcpy(data.data() + pos + off - start, dblk.rodata() + off, npos - pos - off);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
pos = npos;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_prodos::impl::file::rsrc_read_all()
|
||||
{
|
||||
auto [blocks, length] = rsrc_blocks();
|
||||
|
||||
std::vector<u8> data(length);
|
||||
u32 pos = 0;
|
||||
for(u16 block : blocks) {
|
||||
u32 npos = pos + 512;
|
||||
if(npos > length)
|
||||
npos = length;
|
||||
if(npos > pos) {
|
||||
auto dblk = m_fs.m_blockdev.get(block);
|
||||
memcpy(data.data() + pos, dblk.rodata(), npos - pos);
|
||||
} else
|
||||
break;
|
||||
pos = npos;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<u8> fs_prodos::impl::file::rsrc_read(u64 start, u64 length)
|
||||
{
|
||||
auto [blocks, rlength] = rsrc_blocks();
|
||||
length += start;
|
||||
if(length > rlength)
|
||||
length = rlength;
|
||||
|
||||
if(rlength < start)
|
||||
return std::vector<u8>();
|
||||
|
||||
std::vector<u8> data(length - start);
|
||||
u32 pos = 0;
|
||||
for(u16 block : blocks) {
|
||||
u32 npos = pos + 512;
|
||||
if(npos > length)
|
||||
npos = length;
|
||||
if(npos > pos) {
|
||||
if(npos > start) {
|
||||
u32 off = pos < start ? start & 0xff : 0;
|
||||
auto dblk = m_fs.m_blockdev.get(block);
|
||||
memcpy(data.data() + pos + off - start, dblk.rodata() + off, npos - pos - off);
|
||||
}
|
||||
} else
|
||||
break;
|
||||
pos = npos;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
const filesystem_manager_type FS_PRODOS = &filesystem_manager_creator<fs_prodos>;;
|
||||
|
@ -45,13 +45,17 @@ public:
|
||||
virtual fs_meta_data metadata() override;
|
||||
virtual std::vector<u8> read_all() override;
|
||||
virtual std::vector<u8> read(u64 start, u64 length) override;
|
||||
virtual std::vector<u8> rsrc_read_all() override;
|
||||
virtual std::vector<u8> rsrc_read(u64 start, u64 length) override;
|
||||
|
||||
private:
|
||||
impl &m_fs;
|
||||
u16 m_key;
|
||||
u8 m_entry[39];
|
||||
|
||||
std::vector<u16> build_block_table();
|
||||
std::vector<uint16_t> get_file_blocks(uint8_t type, u16 block, u32 length);
|
||||
std::pair<std::vector<uint16_t>, uint32_t> data_blocks();
|
||||
std::pair<std::vector<uint16_t>, uint32_t> rsrc_blocks();
|
||||
};
|
||||
|
||||
impl(fsblk_t &blockdev);
|
||||
@ -80,6 +84,7 @@ public:
|
||||
virtual bool can_format() const override;
|
||||
virtual bool can_read() const override;
|
||||
virtual bool can_write() const override;
|
||||
virtual bool has_rsrc() const override;
|
||||
virtual char directory_separator() const override;
|
||||
|
||||
virtual std::vector<fs_meta_description> volume_meta_description() const override;
|
||||
|
@ -116,4 +116,9 @@ bool fs_unformatted::can_write() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fs_unformatted::has_rsrc() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const filesystem_manager_type FS_UNFORMATTED = &filesystem_manager_creator<fs_unformatted>;
|
||||
|
@ -46,6 +46,7 @@ public:
|
||||
virtual bool can_format() const override;
|
||||
virtual bool can_read() const override;
|
||||
virtual bool can_write() const override;
|
||||
virtual bool has_rsrc() const override;
|
||||
};
|
||||
|
||||
extern const filesystem_manager_type FS_UNFORMATTED;
|
||||
|
@ -262,6 +262,123 @@ uint32_t fsblk_t::block_t::r32l(u32 offset)
|
||||
return blk[0] | (blk[1] << 8) | (blk[2] << 16) | (blk[3] << 24);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void filesystem_t::copy(uint8_t *p, const uint8_t *src, u32 size)
|
||||
{
|
||||
memcpy(p, src, size);
|
||||
}
|
||||
|
||||
void filesystem_t::fill(uint8_t *p, uint8_t data, u32 size)
|
||||
{
|
||||
memset(p, data, size);
|
||||
}
|
||||
|
||||
void filesystem_t::wstr(uint8_t *p, const std::string &str)
|
||||
{
|
||||
memcpy(p, str.data(), str.size());
|
||||
}
|
||||
|
||||
void filesystem_t::w8(uint8_t *p, uint8_t data)
|
||||
{
|
||||
p[0] = data;
|
||||
}
|
||||
|
||||
void filesystem_t::w16b(uint8_t *p, u16 data)
|
||||
{
|
||||
p[0] = data >> 8;
|
||||
p[1] = data;
|
||||
}
|
||||
|
||||
void filesystem_t::w24b(uint8_t *p, u32 data)
|
||||
{
|
||||
p[0] = data >> 16;
|
||||
p[1] = data >> 8;
|
||||
p[2] = data;
|
||||
}
|
||||
|
||||
void filesystem_t::w32b(uint8_t *p, u32 data)
|
||||
{
|
||||
p[0] = data >> 24;
|
||||
p[1] = data >> 16;
|
||||
p[2] = data >> 8;
|
||||
p[3] = data;
|
||||
}
|
||||
|
||||
void filesystem_t::w16l(uint8_t *p, u16 data)
|
||||
{
|
||||
p[0] = data;
|
||||
p[1] = data >> 8;
|
||||
}
|
||||
|
||||
void filesystem_t::w24l(uint8_t *p, u32 data)
|
||||
{
|
||||
p[0] = data;
|
||||
p[1] = data >> 8;
|
||||
p[2] = data >> 16;
|
||||
}
|
||||
|
||||
void filesystem_t::w32l(uint8_t *p, u32 data)
|
||||
{
|
||||
p[0] = data;
|
||||
p[1] = data >> 8;
|
||||
p[2] = data >> 16;
|
||||
p[3] = data >> 24;
|
||||
}
|
||||
|
||||
std::string filesystem_t::rstr(const uint8_t *p, u32 size)
|
||||
{
|
||||
std::string res;
|
||||
for(u32 i=0; i != size; i++)
|
||||
res += char(*p++);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t filesystem_t::r8(const uint8_t *p)
|
||||
{
|
||||
return p[0];
|
||||
}
|
||||
|
||||
uint16_t filesystem_t::r16b(const uint8_t *p)
|
||||
{
|
||||
return (p[0] << 8) | p[1];
|
||||
}
|
||||
|
||||
uint32_t filesystem_t::r24b(const uint8_t *p)
|
||||
{
|
||||
return (p[0] << 16) | (p[1] << 8) | p[2];
|
||||
}
|
||||
|
||||
uint32_t filesystem_t::r32b(const uint8_t *p)
|
||||
{
|
||||
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
}
|
||||
|
||||
uint16_t filesystem_t::r16l(const uint8_t *p)
|
||||
{
|
||||
return p[0] | (p[1] << 8);
|
||||
}
|
||||
|
||||
uint32_t filesystem_t::r24l(const uint8_t *p)
|
||||
{
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16);
|
||||
}
|
||||
|
||||
uint32_t filesystem_t::r32l(const uint8_t *p)
|
||||
{
|
||||
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||
}
|
||||
|
||||
std::vector<u8> filesystem_t::ifile_t::rsrc_read_all()
|
||||
{
|
||||
fatalerror("rsrc_read_all called on filesystem without resource forks\n");
|
||||
}
|
||||
|
||||
std::vector<u8> filesystem_t::ifile_t::rsrc_read(u64 start, u64 length)
|
||||
{
|
||||
fatalerror("rsrc_read called on filesystem without resource forks\n");
|
||||
}
|
||||
|
||||
const char *fs_meta_get_name(fs_meta_name name)
|
||||
{
|
||||
switch(name) {
|
||||
|
@ -281,6 +281,8 @@ protected:
|
||||
virtual fs_meta_data metadata() = 0;
|
||||
virtual std::vector<u8> read_all() = 0;
|
||||
virtual std::vector<u8> read(u64 start, u64 length) = 0;
|
||||
virtual std::vector<u8> rsrc_read_all();
|
||||
virtual std::vector<u8> rsrc_read(u64 start, u64 length);
|
||||
};
|
||||
|
||||
public:
|
||||
@ -312,6 +314,8 @@ public:
|
||||
|
||||
std::vector<u8> read_all() { return m_object->read_all(); }
|
||||
std::vector<u8> read(u32 start, u32 length) { return m_object->read(start, length); }
|
||||
std::vector<u8> rsrc_read_all() { return m_object->rsrc_read_all(); }
|
||||
std::vector<u8> rsrc_read(u32 start, u32 length) { return m_object->rsrc_read(start, length); }
|
||||
};
|
||||
|
||||
filesystem_t(fsblk_t &blockdev, u32 size) : m_blockdev(blockdev) {
|
||||
@ -324,6 +328,26 @@ public:
|
||||
virtual fs_meta_data metadata();
|
||||
virtual dir_t root();
|
||||
|
||||
static void copy(uint8_t *p, const uint8_t *src, uint32_t size);
|
||||
static void fill(uint8_t *p, uint8_t data, uint32_t size);
|
||||
static void wstr(uint8_t *p, const std::string &str);
|
||||
static void w8( uint8_t *p, uint8_t data);
|
||||
static void w16b(uint8_t *p, uint16_t data);
|
||||
static void w24b(uint8_t *p, uint32_t data);
|
||||
static void w32b(uint8_t *p, uint32_t data);
|
||||
static void w16l(uint8_t *p, uint16_t data);
|
||||
static void w24l(uint8_t *p, uint32_t data);
|
||||
static void w32l(uint8_t *p, uint32_t data);
|
||||
|
||||
static std::string rstr(const uint8_t *p, uint32_t size);
|
||||
static uint8_t r8( const uint8_t *p);
|
||||
static uint16_t r16b(const uint8_t *p);
|
||||
static uint32_t r24b(const uint8_t *p);
|
||||
static uint32_t r32b(const uint8_t *p);
|
||||
static uint16_t r16l(const uint8_t *p);
|
||||
static uint32_t r24l(const uint8_t *p);
|
||||
static uint32_t r32l(const uint8_t *p);
|
||||
|
||||
protected:
|
||||
fsblk_t &m_blockdev;
|
||||
};
|
||||
@ -361,6 +385,7 @@ public:
|
||||
virtual bool can_format() const = 0;
|
||||
virtual bool can_read() const = 0;
|
||||
virtual bool can_write() const = 0;
|
||||
virtual bool has_rsrc() const = 0;
|
||||
virtual char directory_separator() const;
|
||||
|
||||
bool has_subdirectories() const { return directory_separator() != 0; }
|
||||
|
@ -652,8 +652,6 @@ static int flopdir(int argc, char *argv[])
|
||||
|
||||
fsblk_vec_t blockdev(img);
|
||||
return generic_dir(fs->m_manager, blockdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Should use chd&friends instead, but one thing at a time
|
||||
@ -696,6 +694,118 @@ static int hddir(int argc, char *argv[])
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int generic_read(const filesystem_manager_t *fm, fsblk_t &blockdev, const char *srcpath, const char *dstpath)
|
||||
{
|
||||
auto load_fs = fm->mount(blockdev);
|
||||
|
||||
std::string opath = srcpath;
|
||||
std::vector<std::string> path;
|
||||
if(fm->has_subdirectories()) {
|
||||
std::string element;
|
||||
char sep = fm->directory_separator();
|
||||
for(char c : opath) {
|
||||
if(c == sep) {
|
||||
if(!element.empty()) {
|
||||
path.push_back(element);
|
||||
element.clear();
|
||||
}
|
||||
} else
|
||||
element += c;
|
||||
}
|
||||
if(!element.empty())
|
||||
path.push_back(element);
|
||||
|
||||
} else
|
||||
path.push_back(opath);
|
||||
|
||||
auto dir = load_fs->root();
|
||||
std::string apath;
|
||||
for(unsigned int i = 0; i < path.size() - 1; i++) {
|
||||
auto c = dir.contents();
|
||||
unsigned int j;
|
||||
for(j = 0; j != c.size(); j++)
|
||||
if(c[j].m_name == path[i])
|
||||
break;
|
||||
if(j == c.size()) {
|
||||
fprintf(stderr, "Error: directory %s%c%s not found\n", apath.c_str(), fm->directory_separator(), path[i].c_str());
|
||||
return 1;
|
||||
}
|
||||
if(c[j].m_type != fs_dir_entry_type::dir) {
|
||||
fprintf(stderr, "Error: %s%c%s is not a directory\n", apath.c_str(), fm->directory_separator(), path[i].c_str());
|
||||
return 1;
|
||||
}
|
||||
dir = dir.dir_get(c[j].m_key);
|
||||
apath += fm->directory_separator() + path[i];
|
||||
}
|
||||
|
||||
auto c = dir.contents();
|
||||
unsigned int j;
|
||||
for(j = 0; j != c.size(); j++)
|
||||
if(c[j].m_name == path.back())
|
||||
break;
|
||||
if(j == c.size()) {
|
||||
fprintf(stderr, "Error: file %s%c%s not found\n", apath.c_str(), fm->directory_separator(), path.back().c_str());
|
||||
return 1;
|
||||
}
|
||||
auto file = dir.file_get(c[j].m_key);
|
||||
auto meta = file.metadata();
|
||||
|
||||
if(meta.find(fs_meta_name::length) == meta.end()) {
|
||||
fprintf(stderr, "Error: %s%c%s is not a readable file\n", apath.c_str(), fm->directory_separator(), path.back().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto filedata = file.read_all();
|
||||
|
||||
char msg[4096];
|
||||
sprintf(msg, "Error opening %s for writing", dstpath);
|
||||
auto fo = fopen(dstpath, "wb");
|
||||
if (!fo) {
|
||||
perror(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fwrite(filedata.data(), filedata.size(), 1, fo);
|
||||
fclose(fo);
|
||||
|
||||
bool has_rsrc = fm->has_rsrc() && meta.find(fs_meta_name::rsrc_length) != meta.end();
|
||||
|
||||
if(has_rsrc) {
|
||||
const char *d = dstpath + strlen(dstpath);
|
||||
while(d != dstpath && d[-1] != '/')
|
||||
d--;
|
||||
std::string dpath(dstpath, d);
|
||||
dpath += "._";
|
||||
dpath += d;
|
||||
|
||||
sprintf(msg, "Error opening %s for writing", dstpath);
|
||||
auto fo = fopen(dpath.c_str(), "wb");
|
||||
if (!fo) {
|
||||
perror(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
filedata = file.rsrc_read_all();
|
||||
u8 head[0x2a];
|
||||
filesystem_t::w32b(head+0x00, 0x00051607); // Magic
|
||||
filesystem_t::w32b(head+0x04, 0x00020000); // Version
|
||||
filesystem_t::fill(head+0x08, 0, 16); // Filler
|
||||
filesystem_t::w16b(head+0x18, 1); // Number of entries
|
||||
filesystem_t::w32b(head+0x1a, 2); // Resource fork
|
||||
filesystem_t::w32b(head+0x22, 0x2a); // Offset in the file
|
||||
filesystem_t::w32b(head+0x26, filedata.size()); // Length
|
||||
|
||||
fwrite(head, 0x2a, 1, fo);
|
||||
fwrite(filedata.data(), filedata.size(), 1, fo);
|
||||
fclose(fo);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int flopread(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=7) {
|
||||
@ -747,66 +857,47 @@ static int flopread(int argc, char *argv[])
|
||||
delete iog;
|
||||
|
||||
fsblk_vec_t blockdev(img);
|
||||
auto load_fs = fs->m_manager->mount(blockdev);
|
||||
return generic_read(fs->m_manager, blockdev, argv[5], argv[6]);
|
||||
}
|
||||
|
||||
std::string opath = argv[5];
|
||||
std::vector<std::string> path;
|
||||
if(fs->m_manager->has_subdirectories()) {
|
||||
abort();
|
||||
|
||||
} else
|
||||
path.push_back(opath);
|
||||
// Should use chd&friends instead, but one thing at a time
|
||||
|
||||
auto dir = load_fs->root();
|
||||
std::string apath;
|
||||
for(unsigned int i = 0; i < path.size() - 1; i++) {
|
||||
auto c = dir.contents();
|
||||
unsigned int j;
|
||||
for(j = 0; j != c.size(); j++)
|
||||
if(c[j].m_name == path[i])
|
||||
break;
|
||||
if(j == c.size()) {
|
||||
fprintf(stderr, "Error: directory %s%c%s not found\n", apath.c_str(), fs->m_manager->directory_separator(), path[i].c_str());
|
||||
return 1;
|
||||
}
|
||||
if(c[j].m_type != fs_dir_entry_type::dir) {
|
||||
fprintf(stderr, "Error: %s%c%s is not a directory\n", apath.c_str(), fs->m_manager->directory_separator(), path[i].c_str());
|
||||
return 1;
|
||||
}
|
||||
dir = dir.dir_get(c[j].m_key);
|
||||
apath += fs->m_manager->directory_separator() + path[i];
|
||||
}
|
||||
|
||||
auto c = dir.contents();
|
||||
unsigned int j;
|
||||
for(j = 0; j != c.size(); j++)
|
||||
if(c[j].m_name == path.back())
|
||||
break;
|
||||
if(j == c.size()) {
|
||||
fprintf(stderr, "Error: file %s%c%s not found\n", apath.c_str(), fs->m_manager->directory_separator(), path.back().c_str());
|
||||
return 1;
|
||||
}
|
||||
auto file = dir.file_get(c[j].m_key);
|
||||
auto meta = file.metadata();
|
||||
|
||||
if(meta.find(fs_meta_name::length) == meta.end()) {
|
||||
fprintf(stderr, "Error: %s%c%s is not a readable file\n", apath.c_str(), fs->m_manager->directory_separator(), path.back().c_str());
|
||||
static int hdread(int argc, char *argv[])
|
||||
{
|
||||
if (argc!=6) {
|
||||
fprintf(stderr, "Incorrect number of arguments.\n\n");
|
||||
display_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto filedata = file.read_all();
|
||||
auto fs = find_fs_by_name(argv[2]);
|
||||
if(!fs) {
|
||||
fprintf(stderr, "Error: Filesystem '%s' unknown\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sprintf(msg, "Error opening %s for writing", argv[6]);
|
||||
auto fo = fopen(argv[6], "wb");
|
||||
if (!fo) {
|
||||
if(!fs->m_manager || !fs->m_manager->can_read()) {
|
||||
fprintf(stderr, "Error: Filesystem '%s' does not implement reading\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char msg[4096];
|
||||
sprintf(msg, "Error opening %s for reading", argv[3]);
|
||||
FILE *f = fopen(argv[3], "rb");
|
||||
if (!f) {
|
||||
perror(msg);
|
||||
return 1;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t size = ftell(f);
|
||||
rewind(f);
|
||||
std::vector<u8> img(size);
|
||||
fread(img.data(), size, 1, f);
|
||||
fclose(f);
|
||||
|
||||
fwrite(filedata.data(), filedata.size(), 1, fo);
|
||||
fclose(fo);
|
||||
|
||||
return 0;
|
||||
fsblk_vec_t blockdev(img);
|
||||
return generic_read(fs->m_manager, blockdev, argv[4], argv[5]);
|
||||
}
|
||||
|
||||
|
||||
@ -832,6 +923,8 @@ int CLIB_DECL main(int argc, char *argv[])
|
||||
return flopread(argc, argv);
|
||||
else if (!core_stricmp("hddir", argv[1]))
|
||||
return hddir(argc, argv);
|
||||
else if (!core_stricmp("hdread", argv[1]))
|
||||
return hdread(argc, argv);
|
||||
else {
|
||||
fprintf(stderr, "Unknown command '%s'\n\n", argv[1]);
|
||||
display_usage();
|
||||
|
Loading…
Reference in New Issue
Block a user