diff options
Diffstat (limited to 'src/lib/formats/fs_prodos.cpp')
-rw-r--r-- | src/lib/formats/fs_prodos.cpp | 158 |
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>;; |