diff --git a/scripts/src/formats.lua b/scripts/src/formats.lua index 132a33ec2ce..0fc21bb1941 100644 --- a/scripts/src/formats.lua +++ b/scripts/src/formats.lua @@ -1091,6 +1091,18 @@ if opt_tool(FORMATS, "HTI_TAP") then } end +-------------------------------------------------- +-- +--@src/lib/formats/hp_ipc_dsk.h,FORMATS["HP300_DSK"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "HP300_DSK") then + files { + MAME_DIR.. "src/lib/formats/hp300_dsk.cpp", + MAME_DIR.. "src/lib/formats/hp300_dsk.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/hpi_dsk.h,FORMATS["HPI_DSK"] = true @@ -2172,6 +2184,18 @@ if opt_tool(FORMATS, "FS_FAT") then } end +-------------------------------------------------- +-- +--@src/lib/formats/fs_hplif.h,FORMATS["FS_HPLIF"] = true +-------------------------------------------------- + +if opt_tool(FORMATS, "FS_HPLIF") then + files { + MAME_DIR.. "src/lib/formats/fs_hplif.cpp", + MAME_DIR.. "src/lib/formats/fs_hplif.h", + } +end + -------------------------------------------------- -- --@src/lib/formats/fs_oric_jasmin.h,FORMATS["FS_ORIC_JASMIN"] = true diff --git a/src/lib/formats/all.cpp b/src/lib/formats/all.cpp index 98acf68d677..b8d0089f3f9 100644 --- a/src/lib/formats/all.cpp +++ b/src/lib/formats/all.cpp @@ -336,6 +336,10 @@ #include "hti_tape.h" #endif +#ifdef HAS_FORMATS_HP300_DSK +#include "hp300_dsk.h" +#endif + #ifdef HAS_FORMATS_HPI_DSK #include "hpi_dsk.h" #endif @@ -720,6 +724,10 @@ #include "fs_fat.h" #endif +#ifdef HAS_FORMATS_FS_HPLIF +#include "fs_hplif.h" +#endif + #ifdef HAS_FORMATS_FS_ISIS #include "fs_isis.h" #endif @@ -867,12 +875,18 @@ void mame_formats_full_list(mame_formats_enumerator &en) #ifdef HAS_FORMATS_APOLLO_DSK en.add(FLOPPY_APOLLO_FORMAT); // apollo_dsk.h #endif +#ifdef HAS_FORMATS_HP300_DSK + en.add(FLOPPY_HP300_FORMAT); // hp300_dsk.h +#endif #ifdef HAS_FORMATS_HP_IPC_DSK en.add(FLOPPY_HP_IPC_FORMAT); // hp_ipc_dsk.h #endif #ifdef HAS_FORMATS_HPI_DSK en.add(FLOPPY_HPI_FORMAT); // hpi_dsk.h #endif +#ifdef HAS_FORMATS_FS_HPLIF + en.add(fs::HPLIF); // fs_lif.h +#endif en.category("Applix"); #ifdef HAS_FORMATS_APPLIX_DSK diff --git a/src/lib/formats/fs_hplif.cpp b/src/lib/formats/fs_hplif.cpp new file mode 100644 index 00000000000..018c4ba5e21 --- /dev/null +++ b/src/lib/formats/fs_hplif.cpp @@ -0,0 +1,494 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle +/*************************************************************************** + + fs_hplif.cpp + + Management of HP LIF images + +***************************************************************************/ + +#include "fs_hplif.h" +#include "hp300_dsk.h" +#include "corestr.h" +#include "osdcomm.h" +#include "strformat.h" + +#include +#include +#include +#include +#include +namespace fs { + const hplif_image HPLIF; +}; + +using namespace fs; + +namespace { + +class impl : public filesystem_t { +public: + + struct hplif_time { + u8 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + }; + + struct hplif_dirent + { + char m_file_name[10]; + u16 m_file_type; + u32 m_starting_sector; + u32 m_sector_count; + hplif_time m_time; + u16 m_volume_number; + u32 m_general_purpose; + }; + + class block_iterator + { + public: + block_iterator(const impl &fs, u32 first_sector, u32 sector_count); + bool next(); + const void *data() const; + const std::array &dirent_data() const; + u8 size() const; + + private: + const impl & m_fs; + fsblk_t::block_t m_block; + u8 m_sector; + u32 m_sector_count; + }; + + impl(fsblk_t &blockdev); + virtual ~impl() = default; + + virtual meta_data volume_metadata() override; + virtual std::pair metadata(const std::vector &path) override; + virtual std::pair> directory_contents(const std::vector &path) override; + virtual std::pair> file_read(const std::vector &path) override; + +private: + fsblk_t::block_t read_sector(u32 starting_sector) const; + std::optional dirent_from_path(const std::vector &path) const; + void iterate_directory_entries(const std::function &callback) const; + util::arbitrary_datetime decode_datetime(const hplif_time *time) const; + meta_data metadata_from_dirent(const hplif_dirent &dirent) const; + err_t format(const meta_data &meta) override; +}; + +// methods +std::string_view strtrimright_hplif(std::string_view str); +template std::string_view strtrimright_hplif(const char (&str)[N]); + +} // anonymous namespace + + +//------------------------------------------------- +// name +//------------------------------------------------- + +const char *fs::hplif_image::name() const +{ + return "hplif"; +} + + +//------------------------------------------------- +// description +//------------------------------------------------- + +const char *fs::hplif_image::description() const +{ + return "HPLIF"; +} + + +//------------------------------------------------- +// enumerate_f +//------------------------------------------------- + +void fs::hplif_image::enumerate_f(floppy_enumerator &fe) const +{ + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 630784, "hp_lif_9121_format_1", "HP 9212 LIF 3.5\" dual-sided double density Format 1"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 709632, "hp_lif_9121_format_2", "HP 9121 LIF 3.5\" dual-sided double density Format 2"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 788480, "hp_lif_9121_format_3", "HP 9121 LIF 3.5\" dual-sided double density Format 3"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::SSDD, 286720, "hp_lif_9121_format_4", "HP 9121 LIF 3.5\" single-sided double density Format 4"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSDD, 737280, "hp_lif_9121_format_16", "HP 9121 LIF 3.5\" dual-sided double density Format 16"); + + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSHD, 1261568, "hp_lif_9122_format_014", "HP 9122 LIF 3.5\" dual-sided high density Format 0, 1, 4"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSHD, 1419264, "hp_lif_9122_format_2", "HP 9122 LIF 3.5\" dual-sided high density Format 2"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSHD, 1576960, "hp_lif_9122_format_3", "HP 9122 LIF 3.5\" dual-sided high density Format 3"); + fe.add(FLOPPY_HP300_FORMAT, floppy_image::FF_35, floppy_image::DSHD, 1474560, "hp_lif_9122_format_16" , "HP 9122 LIF 3.5\" dual-sided high density Format 16"); +} + + +//------------------------------------------------- +// can_format +//------------------------------------------------- + +bool fs::hplif_image::can_format() const +{ + return true; +} + + +//------------------------------------------------- +// can_read +//------------------------------------------------- + +bool fs::hplif_image::can_read() const +{ + return true; +} + + +//------------------------------------------------- +// can_write +//------------------------------------------------- + +bool fs::hplif_image::can_write() const +{ + return false; +} + + +//------------------------------------------------- +// has_rsrc +//------------------------------------------------- + +bool fs::hplif_image::has_rsrc() const +{ + return false; +} + + +//------------------------------------------------- +// volume_meta_description +//------------------------------------------------- + +std::vector fs::hplif_image::volume_meta_description() const +{ + std::vector results; + results.emplace_back(meta_name::name, "", false, [](const meta_value &m) { return m.as_string().size() <= 6; }, "Volume name, up to 6 characters"); + results.emplace_back(meta_name::creation_date, 0, true, nullptr, "Time of creation"); + return results; +} + + +//------------------------------------------------- +// file_meta_description +//------------------------------------------------- + +std::vector fs::hplif_image::file_meta_description() const +{ + std::vector results; + results.emplace_back(meta_name::name, "", false, [](const meta_value &m) { return m.as_string().size() <= 10; }, "File name, up to 10 characters"); + results.emplace_back(meta_name::file_type, "", true, nullptr, "Type of the file"); + results.emplace_back(meta_name::length, 0, true, nullptr, "Size of the file in bytes"); + results.emplace_back(meta_name::modification_date, 0, true, nullptr, "Time of last modification"); + return results; +} + + +//------------------------------------------------- +// mount +//------------------------------------------------- + +std::unique_ptr fs::hplif_image::mount(fsblk_t &blockdev) const +{ + return std::make_unique(blockdev); +} + + +//------------------------------------------------- +// strtrimright_cbm +//------------------------------------------------- + +namespace { + +std::string_view strtrimright_hplif(std::string_view str) +{ + return strtrimright(str, [](char c) { return c != (char)0x20; }); +} + + +//------------------------------------------------- +// strtrimright_cbm +//------------------------------------------------- + +template +std::string_view strtrimright_hplif(const char (&str)[N]) +{ + std::string_view sv(str, std::size(str)); + return strtrimright_hplif(sv); +} + + +//------------------------------------------------- +// impl ctor +//------------------------------------------------- + +impl::impl(fsblk_t &blockdev) + : filesystem_t(blockdev, 256) +{ +} + + +//------------------------------------------------- +// impl::volume_metadata +//------------------------------------------------- + +meta_data impl::volume_metadata() +{ + auto block = read_sector(0); + std::string_view disk_name = std::string_view((const char *) block.rodata() + 2, 6); + + meta_data results; + results.set(meta_name::name, strtrimright_hplif(disk_name)); + results.set(meta_name::creation_date, decode_datetime(reinterpret_cast(block.rodata() + 36))); + return results; +} + + +//------------------------------------------------- +// impl::metadata +//------------------------------------------------- + +std::pair impl::metadata(const std::vector &path) +{ + std::optional dirent = dirent_from_path(path); + if (!dirent) + return std::make_pair(ERR_NOT_FOUND, meta_data()); + + return std::make_pair(ERR_OK, metadata_from_dirent(*dirent)); +} + + +//------------------------------------------------- +// impl::directory_contents +//------------------------------------------------- + +std::pair> impl::directory_contents(const std::vector &path) +{ + std::vector results; + auto callback = [this, &results](const hplif_dirent &ent) + { + results.emplace_back(dir_entry_type::file, metadata_from_dirent(ent)); + return false; + }; + iterate_directory_entries(callback); + return std::make_pair(ERR_OK, std::move(results)); +} + + +//------------------------------------------------- +// impl::file_read +//------------------------------------------------- + +std::pair> impl::file_read(const std::vector &path) +{ + // find the file + std::optional dirent = dirent_from_path(path); + if (!dirent) + return std::make_pair(ERR_NOT_FOUND, std::vector()); + + // and get the data + u32 sector_count = big_endianize_int32(dirent->m_sector_count); + hplif_dirent hdr = dirent.value(); + std::vector result; + result.insert(result.end(), + reinterpret_cast(&hdr), + reinterpret_cast(&hdr) + 32); + result.reserve(sector_count * 256 + 32); + block_iterator iter(*this, big_endianize_int32(dirent->m_starting_sector), sector_count); + while (iter.next()) + result.insert(result.end(), (const u8 *)iter.data(), (const u8 *)iter.data() + 256); + + return std::make_pair(ERR_OK, std::move(result)); +} + + +//------------------------------------------------- +// impl::read_sector +//------------------------------------------------- + +fsblk_t::block_t impl::read_sector(u32 sector) const +{ + return m_blockdev.get(sector); +} + + +//------------------------------------------------- +// impl::dirent_from_path +//------------------------------------------------- + +std::optional impl::dirent_from_path(const std::vector &path) const +{ + if (path.size() != 1) + return { }; + std::string_view path_part = path[0]; + + std::optional result; + auto callback = [&result, path_part](const hplif_dirent &dirent) + { + bool found = strtrimright_hplif(dirent.m_file_name) == path_part; + if (found) + result = dirent; + return found; + }; + iterate_directory_entries(callback); + return result; +} + + +//------------------------------------------------- +// impl::iterate_directory_entries +//------------------------------------------------- + +void impl::iterate_directory_entries(const std::function &callback) const +{ + fsblk_t::block_t block = m_blockdev.get(0); + block_iterator iter(*this, block.r32b(8), block.r32b(16)); + + if (block.r16b(0) != 0x8000) + { + return; + } + + while (iter.next()) + { + for (const hplif_dirent &ent : iter.dirent_data()) + { + if (ent.m_file_type == 0xffff) + { + return; + } + + if (ent.m_file_type != 0x0000) + { + if (callback(ent)) + return; + } + } + } +} + +//------------------------------------------------- +// impl::decode_datetime +//------------------------------------------------- + +util::arbitrary_datetime impl::decode_datetime(const hplif_time *time) const +{ + util::arbitrary_datetime result; + memset(&result, 0, sizeof(result)); + + result.year = bcd_2_dec(time->year) + 1900; + result.month = bcd_2_dec(time->month); + result.day_of_month = bcd_2_dec(time->day); + result.hour = bcd_2_dec(time->hour); + result.minute = bcd_2_dec(time->minute); + result.second = bcd_2_dec(time->second); + return result; +} + +//------------------------------------------------- +// impl::metadata_from_dirent +//------------------------------------------------- + +meta_data impl::metadata_from_dirent(const hplif_dirent &dirent) const +{ + std::string file_type = util::string_format("0x%04X", big_endianize_int16(dirent.m_file_type)); + + // build the metadata and return it + meta_data result; + result.set(meta_name::name, strtrimright_hplif(dirent.m_file_name)); + result.set(meta_name::file_type, std::move(file_type)); + result.set(meta_name::length, big_endianize_int32(dirent.m_sector_count) * 256); + result.set(meta_name::modification_date, decode_datetime(&dirent.m_time)); + return result; +} + + +//------------------------------------------------- +// impl::block_iterator ctor +//------------------------------------------------- + +impl::block_iterator::block_iterator(const impl &fs, u32 starting_sector, u32 sector_count) + : m_fs(fs) + , m_sector(starting_sector) + , m_sector_count(sector_count) +{ +} + + +//------------------------------------------------- +// impl::block_iterator::next +//------------------------------------------------- + +bool impl::block_iterator::next() +{ + bool result; + if (m_sector_count != 0x00) + { + m_block = m_fs.read_sector(m_sector++); + m_sector_count--; + result = true; + } + else + { + // the iterator has already completed + result = false; + } + return result; +} + + +//------------------------------------------------- +// impl::block_iterator::data +//------------------------------------------------- + +const void *impl::block_iterator::data() const +{ + return m_block.rodata(); +} + +//------------------------------------------------- +// impl::format +//------------------------------------------------- + +err_t impl::format(const meta_data &meta) +{ + std::string volume_name = meta.get_string(meta_name::name, "B9826 "); + fsblk_t::block_t block = m_blockdev.get(0); + + if (volume_name.size() < 6) + volume_name.insert(volume_name.end(), 6 - volume_name.size(), ' '); + if (volume_name.size() > 6) + volume_name.resize(6); + + block.w16b(0, 0x8000); // LIF magic + block.wstr(2, volume_name); + block.w32b(8, 2); // directory start + block.w16b(12, 0x1000); // LIF identifier + block.w32b(16, 14); // directory size + block.w16b(20, 1); // LIF version + return ERR_OK; +} + +//------------------------------------------------- +// impl::block_iterator::dirent_data +//------------------------------------------------- + +const std::array &impl::block_iterator::dirent_data() const +{ + return *reinterpret_cast *>(m_block.rodata()); +} + +} // anonymous namespace diff --git a/src/lib/formats/fs_hplif.h b/src/lib/formats/fs_hplif.h new file mode 100644 index 00000000000..57d151db26c --- /dev/null +++ b/src/lib/formats/fs_hplif.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:Nathan Woods +/*************************************************************************** + + fs_hplif.h + + Management of CBM (Commodore) DOS disk images + +***************************************************************************/ + +#ifndef MAME_FORMATS_FS_HPLIF_H +#define MAME_FORMATS_FS_HPLIF_H + +#pragma once + + +#include "fsmgr.h" +#include +#include + +namespace fs { + + class hplif_image : public manager_t { + public: + hplif_image() = default; + + virtual const char *name() const override; + virtual const char *description() const override; + + virtual void enumerate_f(floppy_enumerator &fe) const override; + virtual std::unique_ptr mount(fsblk_t &blockdev) const override; + + 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 volume_meta_description() const override; + virtual std::vector file_meta_description() const override; + }; + + + extern const hplif_image HPLIF; + +} // namespace fs + +#endif // #define MAME_FORMATS_FS_HPLIF_H diff --git a/src/lib/formats/hp300_dsk.cpp b/src/lib/formats/hp300_dsk.cpp new file mode 100644 index 00000000000..99f9ac033ee --- /dev/null +++ b/src/lib/formats/hp300_dsk.cpp @@ -0,0 +1,48 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle +/********************************************************************* + + formats/hp300_dsk.c + + HP 9000/300 disk format + +*********************************************************************/ + +#include "formats/hp300_dsk.h" + +hp300_format::hp300_format() : wd177x_format(formats) +{ +} + +const char *hp300_format::name() const +{ + return "hp300"; +} + +const char *hp300_format::description() const +{ + return "HP 9000/300 disk image"; +} + +const char *hp300_format::extensions() const +{ + return "img"; +} + +const hp300_format::format hp300_format::formats[] = { + // HP 9121S, 9121D or 9133A + { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 16, 77, 2, 256, {}, 1, {}, 50, 22, 54 }, // FORMAT 0,1 + { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 9, 77, 2, 512, {}, 1, {}, 50, 22, 89 }, // FORMAT 2 + { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 5, 77, 2, 1024, {}, 1, {}, 50, 22, 108 }, // FORMAT 3 + { floppy_image::FF_35, floppy_image::DSSD, floppy_image::MFM, 2000, 16, 70, 1, 256, {}, 1, {}, 32, 22, 46 }, // FORMAT 4 + { floppy_image::FF_35, floppy_image::DSDD, floppy_image::MFM, 2000, 9, 80, 2, 512, {}, 1, {}, 146, 22, 81 }, // FORMAT 16 + // HP9122C/D, 9123D, 9133D/H/L or 9153A/B + { floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, 2000, 32, 77, 2, 256, {}, 1, {}, 50, 22, 59 }, // FORMAT 0,1,4 + { floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, 2000, 18, 77, 2, 512, {}, 1, {}, 50, 22, 97 }, // FORMAT 2 + { floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, 2000, 10, 77, 2, 1024, {}, 1, {}, 50, 22, 123 }, // FORMAT 3 + { floppy_image::FF_35, floppy_image::DSHD, floppy_image::MFM, 2000, 18, 80, 2, 512, {}, 1, {}, 146, 22, 98 }, // FORMAT 16 + {} +}; + +const hp300_format FLOPPY_HP300_FORMAT; + diff --git a/src/lib/formats/hp300_dsk.h b/src/lib/formats/hp300_dsk.h new file mode 100644 index 00000000000..b86cd1bc72b --- /dev/null +++ b/src/lib/formats/hp300_dsk.h @@ -0,0 +1,32 @@ +// license:BSD-3-Clause +// copyright-holders:Sven Schnelle +/********************************************************************* + + formats/hp300_dsk.h + + HP9000/300 disk format + +*********************************************************************/ +#ifndef MAME_FORMATS_HP300_DSK_H +#define MAME_FORMATS_HP300_DSK_H + +#pragma once + +#include "wd177x_dsk.h" + +class hp300_format : public wd177x_format +{ +public: + hp300_format(); + + virtual const char *name() const override; + virtual const char *description() const override; + virtual const char *extensions() const override; + +private: + static const format formats[]; +}; + +extern const hp300_format FLOPPY_HP300_FORMAT; + +#endif // MAME_FORMATS_HP300_DSK_H