#ifndef COMMON_H_04DD2B2A #define COMMON_H_04DD2B2A #include #include #include #include class BufferView { public: BufferView(const std::vector& buffer) : data_(&buffer) {} int ReadNextByte() { int o2r = offset_; offset_++; return ReadByte(o2r); } int ReadByte(int addr) const { return static_cast((*data_)[addr]); } int ReadNextTwoBytes() { int o2r = offset_; offset_+=2; return ReadTwoBytes(o2r); } int ReadTwoBytes(int addr) const { return static_cast((*data_)[addr]) | (static_cast((*data_)[addr + 1]) << 8); } int ReadNextFourBytes() { int o2r = offset_; offset_+=4; return ReadFourBytes(o2r); } unsigned long ReadFourBytes(int addr) const { return static_cast((*data_)[addr]) | (static_cast((*data_)[addr + 1]) << 8) | (static_cast((*data_)[addr + 2]) << 16) | (static_cast((*data_)[addr + 3]) << 24); } void Seek(int offset) { offset_ = offset; } void SeekAdd(int delta) { offset_ += delta; } std::vector Decompress(int addr) { int start = addr; Seek(addr); if (ReadNextByte() != 0x10) { throw std::domain_error("No LZ77 signature"); } int length = ReadNextByte(); length += (ReadNextByte() << 8); length += (ReadNextByte() << 16); std::vector result(length, 0); int bPos = 0; while (bPos < length) { unsigned char ch = ReadNextByte(); for (int i=0;i<8;i++) { switch ((ch >> (7-i)) & 1) { case 0: { if (bPos >= length) break; result[bPos++] = ReadNextByte(); break; } case 1: { int t = (ReadNextByte() << 8); t += ReadNextByte(); int n = ((t >> 12) & 0xF) + 3; // num of bytes to copy int o = (t & 0xFFF); for (int j=0; j= length) break; result[bPos] = result[bPos - o - 1]; bPos++; } break; } default: break; } } } return result; } private: const std::vector* data_; int offset_ = 0; }; class Rom { public: explicit Rom(std::string_view filename) { std::ifstream romfile(filename.data(), std::ios::binary); if (!romfile.is_open()) { throw std::invalid_argument("Could not find ROM file: " + std::string(filename)); } romfile.seekg(0, romfile.end); int length = romfile.tellg(); romfile.seekg(0, romfile.beg); if (length != 0x2000000) { throw std::invalid_argument("Incorrect ROM length"); } data_ = std::vector(length, 0); romfile.read(data_.data(), length); const char header[] = {'M','O','T','H','E','R','3',0,0,0,0,0,'A','3','U','J'}; std::string headerTest; for (int i = 0xA0; i < 0xB0; i++) { if (data_.at(i) != header[i-0xA0]) { std::cout << i << std::endl; throw std::invalid_argument("Invalid ROM header"); } } } const std::vector& data() const { return data_; } BufferView buffer() const { return {data_}; } private: std::vector data_; }; class Palette { public: Palette() = default; Palette(BufferView m3, const int addr) { for (int i=0; i<16; i++) { unsigned short ch = m3.ReadTwoBytes(addr + (i << 1)); int r = (ch & 0x1F); int g = ((ch >> 5) & 0x1F); int b = ((ch >> 10) & 0x1F); colors_.push_back(Magick::ColorRGB((r << 3)/256.0, (g << 3)/256.0, (b << 3)/256.0)); } } explicit Palette(std::vector colors) : colors_(colors) {} const std::vector& Colors() const { return colors_; } private: std::vector colors_; }; #endif /* end of include guard: COMMON_H_04DD2B2A */