memoserv/subprojects/memcard/src/block.cpp
King_DuckZ 4c655850de Committing old changes.
I'm not sure what this is, I think it's just adding a new
MemoryCard::content_info() method. There might be unwanted
debug stuff included in this commit too.
2020-03-19 19:48:28 +01:00

139 lines
4 KiB
C++

#include "memcard/block.hpp"
#include "memcard/memorycard.hpp"
#include "shiftjis_to_utf8.hpp"
#include <cassert>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string_view>
#define FLOAT_PALETTE_CONV
namespace mc {
namespace {
#if defined(FLOAT_PALETTE_CONV)
uint8_t _5bit_to_8bit(int n) {
return static_cast<uint8_t>(static_cast<float>(n) / 0x1F * 255.0f + 0.5f);
}
#endif
std::vector<uint8_t> extract_palette (const uint8_t* b, const uint8_t* e) {
std::vector<uint8_t> retval;
retval.reserve(16 * 4);
{
if (e - b < 96)
throw std::runtime_error("Not enough data to advance and extract an icon palette");
b += 96;
}
int entries_left = 16;
while (b != e and entries_left) {
--entries_left;
const auto lo = *b;
++b;
if (b == e)
throw std::runtime_error("Not enough data to extract an icon palette entry of 2 bytes");
const auto hi = *b;
++b;
#if defined(FLOAT_PALETTE_CONV)
const uint16_t col = (hi << 8) | lo;
const uint8_t red = _5bit_to_8bit(col & 0x1F);
const uint8_t green = _5bit_to_8bit((col & 0x3E0) >> 5);
const uint8_t blue = _5bit_to_8bit((col & 0x7C00) >> 10);
const uint8_t black_flag = (col & 0x8000) >> 15;
#else
const uint8_t red = (lo & 0x1F) << 3;
const uint8_t green = ((hi & 0x3) << 6) | ((lo & 0xE0) >> 2);
const uint8_t blue = ((hi & 0x7C) << 1);
const uint8_t black_flag = (hi & 0x80) >> 7;
#endif
const uint8_t alpha = (blue | green | red | black_flag ? 0xFF : 0x00);
//std::cout << "RGBA: " << std::setw(3) << (int)red << '\t' << (int)green << '\t' << (int)blue << '\t' << (int)alpha << '\t' << (int)black_flag << std::setw(0) << '\n';
retval.push_back(blue);
retval.push_back(green);
retval.push_back(red);
retval.push_back(alpha);
}
if (entries_left)
throw std::runtime_error("Not enough entries in the icon palette");
return retval;
}
} //unnamed namespace
template <bool Const>
BasicBlock<Const>::BasicBlock (data_type* beg) :
m_icon_palette(extract_palette(beg, beg + size())),
m_begin(beg)
{
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<unsigned char*>(&use_byte));
std::clog << "Use byte for block " << title() << " (" << title().size() << ')' <<
": 0x" << std::hex << use_byte << std::dec << '\n';
}
}
template <bool Const>
BasicBlock<Const>::~BasicBlock() = default;
template <bool Const>
bool BasicBlock<Const>::has_magic() const {
const constexpr uint16_t magic = ('S' << 8) | 'C'; //0x5343 "SC"
return magic == static_cast<uint16_t>((m_begin[0] << 8) | m_begin[1]);
}
template <bool Const>
IconDisplayFlag BasicBlock<Const>::icon_display_flag() const {
const uint8_t val = m_begin[2];
return static_cast<IconDisplayFlag>(val);
}
template <bool Const>
int BasicBlock<Const>::block_count() const {
return m_begin[3];
}
template <bool Const>
std::string BasicBlock<Const>::title() const {
char mem[64 + 1];
std::strncpy(mem, reinterpret_cast<const char*>(m_begin + 4), sizeof(mem) / sizeof(mem[0]));
std::string_view temp(mem, std::strlen(mem));
auto name = full_to_halfwidth_ascii(shiftjis_to_utf8(temp));
//trim spaces at the front
{
const auto pos = name.find_first_not_of(' ');
const auto non_space_it = (pos == name.npos ? name.end() : name.begin() + pos);
name.erase(name.begin(), non_space_it);
}
//trim spaces at the end
{
auto non_space_it = std::find_if(name.rbegin(), name.rend(), [](char c){return c != ' ';});
name.resize(name.size() - (non_space_it - name.rbegin()));
}
//remove repeated spaces
{
std::size_t start = 0;
while ((start = name.find(' ', start)) != name.npos) {
const std::size_t end = name.find_first_not_of(' ', start);
name.erase(start + 1, end - start - 1);
++start;
};
}
return name;
}
template class BasicBlock<true>;
template class BasicBlock<false>;
} //namespace mc