From a64c85a3f5641581a19ef52a5c7898ec3cb71754 Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Sun, 31 Jan 2021 20:04:51 -0500 Subject: Abstracted some of the sprite dumper functionality out --- tools/sprite_dumper/common.h | 139 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 tools/sprite_dumper/common.h (limited to 'tools/sprite_dumper/common.h') diff --git a/tools/sprite_dumper/common.h b/tools/sprite_dumper/common.h new file mode 100644 index 0000000..dca5de9 --- /dev/null +++ b/tools/sprite_dumper/common.h @@ -0,0 +1,139 @@ +#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); + + memcpy(result.data() + bPos, result.data() + bPos - o - 1, n); + bPos += n; + 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_; +}; + +#endif /* end of include guard: COMMON_H_04DD2B2A */ -- cgit 1.4.1