summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/formats/fs_prodos.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/formats/fs_prodos.cpp')
-rw-r--r--src/lib/formats/fs_prodos.cpp158
1 files changed, 148 insertions, 10 deletions
diff --git a/src/lib/formats/fs_prodos.cpp b/src/lib/formats/fs_prodos.cpp
index f6923e587c8..5a4d3e6edf5 100644
--- a/src/lib/formats/fs_prodos.cpp
+++ b/src/lib/formats/fs_prodos.cpp
@@ -91,12 +91,28 @@ std::vector<fs_meta_description> fs_prodos::volume_meta_description() const
std::vector<fs_meta_description> fs_prodos::file_meta_description() const
{
std::vector<fs_meta_description> res;
+ res.emplace_back(fs_meta_description(fs_meta_name::name, fs_meta_type::string, "Empty file", false, [](const fs_meta &m) { return m.as_string().size() <= 15; }, "File name, up to 15 characters"));
+ res.emplace_back(fs_meta_description(fs_meta_name::length, fs_meta_type::number, 0, true, nullptr, "Size of the file in bytes"));
+ res.emplace_back(fs_meta_description(fs_meta_name::rsrc_length, fs_meta_type::number, 0, true, nullptr, "Size of the resource fork in bytes"));
+ res.emplace_back(fs_meta_description(fs_meta_name::os_version, fs_meta_type::number, 5, false, [](const fs_meta &m) { return m.as_number() <= 255; }, "Creator OS version"));
+ res.emplace_back(fs_meta_description(fs_meta_name::os_minimum_version, fs_meta_type::number, 5, false, [](const fs_meta &m) { return m.as_number() <= 255; }, "Minimum OS version"));
+
+ auto now = util::arbitrary_datetime::now();
+ res.emplace_back(fs_meta_description(fs_meta_name::creation_date, fs_meta_type::date, now, false, nullptr, "Creation time"));
+ res.emplace_back(fs_meta_description(fs_meta_name::modification_date, fs_meta_type::date, now, false, nullptr, "Modification time"));
return res;
}
std::vector<fs_meta_description> fs_prodos::directory_meta_description() const
{
std::vector<fs_meta_description> res;
+ res.emplace_back(fs_meta_description(fs_meta_name::name, fs_meta_type::string, "Empty directory", false, [](const fs_meta &m) { return m.as_string().size() <= 15; }, "Directory name, up to 15 characters"));
+ res.emplace_back(fs_meta_description(fs_meta_name::os_version, fs_meta_type::number, 5, false, [](const fs_meta &m) { return m.as_number() <= 255; }, "Creator OS version"));
+ res.emplace_back(fs_meta_description(fs_meta_name::os_minimum_version, fs_meta_type::number, 5, false, [](const fs_meta &m) { return m.as_number() <= 255; }, "Minimum OS version"));
+
+ auto now = util::arbitrary_datetime::now();
+ res.emplace_back(fs_meta_description(fs_meta_name::creation_date, fs_meta_type::date, now, false, nullptr, "Creation time"));
+ res.emplace_back(fs_meta_description(fs_meta_name::modification_date, fs_meta_type::date, now, false, nullptr, "Modification time"));
return res;
}
@@ -201,7 +217,7 @@ fs_meta_data fs_prodos::impl::metadata()
filesystem_t::dir_t fs_prodos::impl::root()
{
if(!m_root)
- m_root = new root_dir(*this);
+ m_root = new dir(*this, 2);
return m_root.strong();
}
@@ -211,30 +227,152 @@ void fs_prodos::impl::drop_root_ref()
}
-void fs_prodos::impl::root_dir::drop_weak_references()
+void fs_prodos::impl::dir::drop_weak_references()
{
- m_fs.drop_root_ref();
+ if(m_base_block == 2)
+ m_fs.drop_root_ref();
}
-fs_meta_data fs_prodos::impl::root_dir::metadata()
+fs_meta_data fs_prodos::impl::dir::metadata()
{
- return fs_meta_data();
+ fs_meta_data res;
+ if(m_base_block == 2)
+ return res;
+
+ auto bdir = m_fs.m_blockdev.get(m_base_block);
+ int len = bdir.r8(0x04) & 0xf;
+ res[fs_meta_name::name] = bdir.rstr(0x05, len);
+ res[fs_meta_name::os_version] = uint64_t(bdir.r8(0x20));
+ res[fs_meta_name::os_minimum_version] = uint64_t(bdir.r8(0x21));
+ res[fs_meta_name::creation_date] = prodos_to_dt(bdir.r32l(0x1c));
+ res[fs_meta_name::modification_date] = prodos_to_dt(bdir.r32l(0x16));
+ return res;
}
-std::vector<fs_dir_entry> fs_prodos::impl::root_dir::contents()
+std::vector<fs_dir_entry> fs_prodos::impl::dir::contents()
{
std::vector<fs_dir_entry> res;
+
+ u16 block = m_base_block;
+ u32 off = 39 + 4;
+ u32 id = 1;
+ do {
+ auto blk = m_fs.m_blockdev.get(block);
+ while(off < 511) {
+ u8 type = blk.r8(off);
+ auto name = blk.rstr(off+1, type & 0xf);
+ type >>= 4;
+ if(type == 0xd)
+ res.emplace_back(fs_dir_entry(name, fs_dir_entry_type::dir, id));
+ else if(type != 0)
+ res.emplace_back(fs_dir_entry(name, fs_dir_entry_type::file, id));
+ off += 39;
+ id ++;
+ }
+ block = blk.r16l(2);
+ if(block >= m_fs.m_blockdev.block_count())
+ break;
+ off = 4;
+ } while(block);
+ return res;
+}
+
+std::pair<fsblk_t::block_t, const u8 *> fs_prodos::impl::dir::get_entry_ro(uint64_t key)
+{
+ std::pair<fsblk_t::block_t, const u8 *> res;
+ res.first = m_fs.m_blockdev.get(m_base_block);
+ while(key >= 13) {
+ key -= 13;
+ u16 block = res.first.r16l(2);
+ if(!block || block >= m_fs.m_blockdev.block_count()) {
+ res.first = nullptr;
+ res.second = nullptr;
+ return res;
+ }
+ res.first = m_fs.m_blockdev.get(block);
+ }
+ res.second = res.first.rodata() + 4 + 39 * key;
+ return res;
+}
+
+std::pair<fsblk_t::block_t, u8 *> fs_prodos::impl::dir::get_entry(uint64_t key)
+{
+ std::pair<fsblk_t::block_t, u8 *> res;
+ res.first = m_fs.m_blockdev.get(m_base_block);
+ while(key > 13) {
+ key -= 13;
+ u16 block = res.first.r16l(2);
+ if(!block || block >= m_fs.m_blockdev.block_count()) {
+ res.first = nullptr;
+ res.second = nullptr;
+ return res;
+ }
+ res.first = m_fs.m_blockdev.get(block);
+ }
+ res.second = res.first.data() + 4 + 39 * key;
+ return res;
+}
+
+filesystem_t::file_t fs_prodos::impl::dir::file_get(uint64_t key)
+{
+ auto [blk, entry] = get_entry_ro(key);
+ if(!blk)
+ fatalerror("Out-of-range key on file_get\n");
+ u8 type = entry[0] >> 4;
+ if(type == 0 || type == 4 || type > 5)
+ fatalerror("Unhandled file type %x\n", type);
+ return new file(m_fs, entry, key);
+}
+
+filesystem_t::dir_t fs_prodos::impl::dir::dir_get(uint64_t key)
+{
+ auto [blk, entry] = get_entry_ro(key);
+ if(!blk)
+ fatalerror("Out-of-range key on dir_get\n");
+ u8 type = entry[0] >> 4;
+ if(type != 0xd)
+ fatalerror("Unhandled directory type %x\n", type);
+
+ return new dir(m_fs, entry[17] | (entry[18] << 8), 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 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]);
+ 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));
+ 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);
+
return res;
}
-filesystem_t::file_t fs_prodos::impl::root_dir::file_get(uint64_t key)
+std::vector<u8> fs_prodos::impl::file::read_all()
{
- return nullptr;
+ abort();
}
-filesystem_t::dir_t fs_prodos::impl::root_dir::dir_get(uint64_t key)
+std::vector<u8> fs_prodos::impl::file::read(u64 start, u64 length)
{
- return nullptr;
+ abort();
}
const filesystem_manager_type FS_PRODOS = &filesystem_manager_creator<fs_prodos>;;