diff --git a/src/cli/memcard.cpp b/src/cli/memcard.cpp index f0f5d9f..2ce5ab3 100644 --- a/src/cli/memcard.cpp +++ b/src/cli/memcard.cpp @@ -22,8 +22,10 @@ void print_blocks (const std::string& mc_path) { std::cout << "Block " << std::setfill(' ') << std::setw(2) << blk.index() << ": \"" << blk.title() << '"'; if (blk.block_count() > 1) { - std::cout << " [" << blk.block_count() << ']'; + std::cout << " (x" << blk.block_count() << ')'; } + std::cout << " [" << to_char(blk.country_code()) << ']'; + std::cout << ' ' << blk.product_code(); std::cout << '\n'; } } diff --git a/subprojects/memcard/include/memcard/block.hpp b/subprojects/memcard/include/memcard/block.hpp index 55bfee2..8ad2015 100644 --- a/subprojects/memcard/include/memcard/block.hpp +++ b/subprojects/memcard/include/memcard/block.hpp @@ -2,6 +2,7 @@ #include "memcard/frame.hpp" #include "memcard/frame_iterator.hpp" +#include "memcard/country_code.hpp" #include #include #include @@ -20,15 +21,16 @@ enum class IconDisplayFlag { template class BasicBlock { - using data_type = typename std::conditional::type; public: + using data_type = typename std::conditional::type; typedef FrameIterator iterator; typedef FrameIterator const_iterator; static const constexpr std::size_t FrameCount = 64; static const constexpr std::size_t TOCBlockIndex = 0; - BasicBlock (data_type* beg, std::size_t index); + BasicBlock (data_type* blk, std::size_t index); + BasicBlock (data_type* blk, BasicFrame toc_entry, std::size_t index); ~BasicBlock(); iterator begin(); @@ -52,8 +54,14 @@ public: int block_count() const; std::size_t index() const { return m_index; } std::string title() const; + std::size_t available_blocks() const; + uint16_t link_order() const; + CountryCode country_code() const; + std::string product_code() const; + bool has_pocket_station_content() const; private: + BasicFrame m_toc_entry; std::size_t m_index; data_type* m_begin; }; diff --git a/subprojects/memcard/include/memcard/country_code.hpp b/subprojects/memcard/include/memcard/country_code.hpp new file mode 100644 index 0000000..e687751 --- /dev/null +++ b/subprojects/memcard/include/memcard/country_code.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace mc::psx { +enum class CountryCode : uint16_t { + Japan = 'B' | ('I' << 8), + America = 'B' | ('A' << 8), + Europe = 'B' | ('E' << 8), + Unknown = 0 +}; + +std::string to_string (CountryCode code); +char to_char (CountryCode code); +uint16_t to_uint16 (CountryCode code); +CountryCode to_country_code (uint16_t code); +} //namespace mc::psx diff --git a/subprojects/memcard/include/memcard/frame.hpp b/subprojects/memcard/include/memcard/frame.hpp index 1b183e2..a00153b 100644 --- a/subprojects/memcard/include/memcard/frame.hpp +++ b/subprojects/memcard/include/memcard/frame.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace mc::psx { template @@ -29,11 +30,27 @@ public: data_type* data() { return m_data; } const data_type* data() const { return m_data; } + template + T extract (std::size_t offset) const; + private: + void extract (std::size_t offset, std::size_t sz, uint8_t* out); + std::size_t m_index; data_type* m_data; }; +template +inline T read_as (const BasicFrame& frame, std::size_t offset) { + T retval; + std::copy( + frame.begin() + offset, + frame.begin() + offset + sizeof(T), + reinterpret_cast(&retval) + ); + return retval; +} + using Frame = BasicFrame; using ConstFrame = BasicFrame; } //namespace mc::psx diff --git a/subprojects/memcard/meson.build b/subprojects/memcard/meson.build index 7e0a403..61fc4b6 100644 --- a/subprojects/memcard/meson.build +++ b/subprojects/memcard/meson.build @@ -15,6 +15,7 @@ memcard = shared_library('memcard', 'src/make_memory_card.cpp', 'src/part_iterator.cpp', 'src/frame.cpp', + 'src/country_code.cpp', install: true, include_directories: [private_incl, library_incl], ) diff --git a/subprojects/memcard/src/block.cpp b/subprojects/memcard/src/block.cpp index 6fa2aa5..97a7a9b 100644 --- a/subprojects/memcard/src/block.cpp +++ b/subprojects/memcard/src/block.cpp @@ -12,6 +12,8 @@ namespace mc::psx { namespace { + uint8_t g_dummy_data[Frame::size()] = {0}; + #if defined(FLOAT_PALETTE_CONV) uint8_t _5bit_to_8bit(int n) { return static_cast(static_cast(n) / 0x1F * 255.0f + 0.5f); @@ -68,20 +70,18 @@ namespace { } //unnamed namespace template -BasicBlock::BasicBlock (data_type* beg, std::size_t index) : +BasicBlock::BasicBlock (data_type* blk, std::size_t index) : + BasicBlock(blk, BasicFrame(g_dummy_data, 0), index) +{ +} + +template +BasicBlock::BasicBlock (data_type* blk, BasicFrame toc_entry, std::size_t index) : + m_toc_entry(toc_entry), m_index(index), - m_begin(beg) + m_begin(blk) { assert(m_begin); - - if (has_magic()) { - uint32_t use_byte; - static_assert(sizeof(use_byte) == 4, "Wrong type size"); - const constexpr int offs = 0x84; - std::copy(m_begin + offs, m_begin + offs + 4, reinterpret_cast(&use_byte)); - //std::clog << "Use byte for block " << title() << " (" << title().size() << ')' << - // ": 0x" << std::hex << use_byte << std::dec << '\n'; - } } template @@ -183,6 +183,34 @@ std::string BasicBlock::title() const { return name; } +template +std::size_t BasicBlock::available_blocks() const { + return m_toc_entry.data()[0]; +} + +template +uint16_t BasicBlock::link_order() const { + return read_as(m_toc_entry, 0x08); +} + +template +CountryCode BasicBlock::country_code() const { + const auto cc = read_as(m_toc_entry, 0x0A); + return to_country_code(cc); +} + +template +std::string BasicBlock::product_code() const { + std::string retval{reinterpret_cast(m_toc_entry.data() + 0x0C), 10}; + retval[4] = '-'; + return retval; +} + +template +bool BasicBlock::has_pocket_station_content() const { + return (m_toc_entry.data()[0x0C + 4] == 'P'); +} + template class BasicBlock; template class BasicBlock; } //namespace mc::psx diff --git a/subprojects/memcard/src/content_info.cpp b/subprojects/memcard/src/content_info.cpp index 2142ebd..211d85d 100644 --- a/subprojects/memcard/src/content_info.cpp +++ b/subprojects/memcard/src/content_info.cpp @@ -4,16 +4,6 @@ namespace mc::psx { namespace { - template - T read_as (const ConstFrame& frame, std::size_t offset) { - T retval; - std::copy( - frame.begin() + offset, - frame.begin() + offset + sizeof(T), - reinterpret_cast(&retval) - ); - return retval; - } } //unnamed namespace ContentInfo::ContentInfo (const ConstFrame& frame) : diff --git a/subprojects/memcard/src/country_code.cpp b/subprojects/memcard/src/country_code.cpp new file mode 100644 index 0000000..4e15a18 --- /dev/null +++ b/subprojects/memcard/src/country_code.cpp @@ -0,0 +1,34 @@ +#include "memcard/country_code.hpp" + +namespace mc::psx { +std::string to_string (CountryCode code) { + switch (code) { + case CountryCode::Japan: return "Japan"; + case CountryCode::America: return "America"; + case CountryCode::Europe: return "Europe"; + default: return "Unknown"; + }; +} + +char to_char (CountryCode code) { + switch (code) { + case CountryCode::Japan: return 'J'; + case CountryCode::America: return 'U'; + case CountryCode::Europe: return 'E'; + default: return 'X'; + }; +} + +uint16_t to_uint16 (CountryCode code) { + return static_cast(code); +} + +CountryCode to_country_code (uint16_t code) { + switch (code) { + case static_cast(CountryCode::Japan): return CountryCode::Japan; + case static_cast(CountryCode::America): return CountryCode::America; + case static_cast(CountryCode::Europe): return CountryCode::Europe; + default: return CountryCode::Unknown; + } +} +} //namespace mc::psx diff --git a/subprojects/memcard/src/memorycard.cpp b/subprojects/memcard/src/memorycard.cpp index 586109a..9643d55 100644 --- a/subprojects/memcard/src/memorycard.cpp +++ b/subprojects/memcard/src/memorycard.cpp @@ -7,6 +7,17 @@ namespace mc::psx { namespace { const constexpr std::size_t MemoryCardSize = 8192 * 16; + + template + BasicBlock make_block_for_index (typename BasicBlock::data_type* data, std::size_t index) { + const auto retptr = data + index * Block::size() * Frame::size(); + if (index > 0) { + return {retptr, BasicFrame(data + index * Frame::size(), index), index}; + } + else { + return {data + index, index}; + } + } } //unnamed namespace MemoryCard::MemoryCard() : @@ -63,11 +74,11 @@ auto MemoryCard::end() const -> const_iterator { } Block MemoryCard::block_at_index(std::size_t index) { - return Block(m_data.data() + index * Block::size() * Frame::size(), index); + return make_block_for_index(m_data.data(), index); } ConstBlock MemoryCard::block_at_index(std::size_t index) const { - return ConstBlock(m_data.data() + index * Block::size() * Frame::size(), index); + return make_block_for_index(m_data.data(), index); } std::vector block_group (const MemoryCard& mc, std::size_t index) {