summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats
diff options
context:
space:
mode:
author Olivier Galibert <galibert@pobox.com>2021-05-11 21:21:56 +0200
committer Olivier Galibert <galibert@pobox.com>2021-05-11 21:52:25 +0200
commit94db317064735d4f0126676a827ce63787fb044e (patch)
tree151caf7aa82acf1c3cf3b5a3ed308c2180dab8dc /src/lib/formats
parent9d4ffe837e0eb5309cd5d828b660a46d7820d1d7 (diff)
prodos: Add file and resource reading
Diffstat (limited to 'src/lib/formats')
-rw-r--r--src/lib/formats/fs_oric_jasmin.cpp15
-rw-r--r--src/lib/formats/fs_oric_jasmin.h1
-rw-r--r--src/lib/formats/fs_prodos.cpp190
-rw-r--r--src/lib/formats/fs_prodos.h7
-rw-r--r--src/lib/formats/fs_unformatted.cpp5
-rw-r--r--src/lib/formats/fs_unformatted.h1
-rw-r--r--src/lib/formats/fsmgr.cpp117
-rw-r--r--src/lib/formats/fsmgr.h25
8 files changed, 345 insertions, 16 deletions
diff --git a/src/lib/formats/fs_oric_jasmin.cpp b/src/lib/formats/fs_oric_jasmin.cpp
index 3f4e0b04e14..fec9261364e 100644
--- a/src/lib/formats/fs_oric_jasmin.cpp
+++ b/src/lib/formats/fs_oric_jasmin.cpp
@@ -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;
}
diff --git a/src/lib/formats/fs_oric_jasmin.h b/src/lib/formats/fs_oric_jasmin.h
index 823dcc90538..a38fe2b6952 100644
--- a/src/lib/formats/fs_oric_jasmin.h
+++ b/src/lib/formats/fs_oric_jasmin.h
@@ -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;
diff --git a/src/lib/formats/fs_prodos.cpp b/src/lib/formats/fs_prodos.cpp
index 5a4d3e6edf5..1845f4eb853 100644
--- a/src/lib/formats/fs_prodos.cpp
+++ b/src/lib/formats/fs_prodos.cpp
@@ -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>;;
diff --git a/src/lib/formats/fs_prodos.h b/src/lib/formats/fs_prodos.h
index 2f33254842b..be83ab5cd03 100644
--- a/src/lib/formats/fs_prodos.h
+++ b/src/lib/formats/fs_prodos.h
@@ -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;
diff --git a/src/lib/formats/fs_unformatted.cpp b/src/lib/formats/fs_unformatted.cpp
index 573be8ac2b9..2dc927b70fd 100644
--- a/src/lib/formats/fs_unformatted.cpp
+++ b/src/lib/formats/fs_unformatted.cpp
@@ -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>;
diff --git a/src/lib/formats/fs_unformatted.h b/src/lib/formats/fs_unformatted.h
index ce472cafdb3..fe5ac68973d 100644
--- a/src/lib/formats/fs_unformatted.h
+++ b/src/lib/formats/fs_unformatted.h
@@ -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;
diff --git a/src/lib/formats/fsmgr.cpp b/src/lib/formats/fsmgr.cpp
index 2b15b1aeb93..ddf9e04869e 100644
--- a/src/lib/formats/fsmgr.cpp
+++ b/src/lib/formats/fsmgr.cpp
@@ -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) {
diff --git a/src/lib/formats/fsmgr.h b/src/lib/formats/fsmgr.h
index 6ca909e3bcd..ed3a553843e 100644
--- a/src/lib/formats/fsmgr.h
+++ b/src/lib/formats/fsmgr.h
@@ -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; }