From 4cd0330e22e89d4aefa00f153e23b0e8c932b05e Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Mon, 27 Jun 2016 01:15:02 -0700 Subject: [PATCH] Fix checksum handling --- include/kabufuda/Card.hpp | 4 ++- lib/Card.cpp | 65 +++++++++++++++++++++++++++++---------- test/main.cpp | 8 ++--- 3 files changed, 56 insertions(+), 21 deletions(-) diff --git a/include/kabufuda/Card.hpp b/include/kabufuda/Card.hpp index d918086..f2a5832 100644 --- a/include/kabufuda/Card.hpp +++ b/include/kabufuda/Card.hpp @@ -220,8 +220,10 @@ class Card void swapEndian(); void updateDirAndBat(); + void updateChecksum(); public: Card(); + Card(const Card& other); Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr); ~Card(); @@ -299,7 +301,7 @@ public: * @param checksum * @param checksumInv */ -void calculateChecksum(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv); +void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv); } #endif // __CARD_HPP__ diff --git a/lib/Card.cpp b/lib/Card.cpp index 152ddb5..d205db2 100644 --- a/lib/Card.cpp +++ b/lib/Card.cpp @@ -52,6 +52,17 @@ Card::Card() memset(__raw, 0xFF, BlockSize); } +Card::Card(const Card& other) +{ + memcpy(__raw, other.__raw, BlockSize); + m_dir = other.m_dir; + m_dirBackup = other.m_dirBackup; + m_bat = other.m_bat; + m_batBackup = other.m_batBackup; + memcpy(m_game, other.m_game, 4); + memcpy(m_maker, other.m_maker, 2); +} + Card::Card(const SystemString& filename, const char* game, const char* maker) : m_filename(filename) { @@ -111,7 +122,9 @@ Card::Card(const SystemString& filename, const char* game, const char* maker) /* Close and reopen in read/write mode */ fclose(m_fileHandle); + m_fileHandle = nullptr; m_fileHandle = Fopen(m_filename.c_str(), _S("r+")); + rewind(m_fileHandle); } } @@ -144,6 +157,13 @@ void Card::updateDirAndBat() std::swap(m_currentBat, m_previousBat); } +void Card::updateChecksum() +{ + swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw), 0xFE, &m_checksum, &m_checksumInv); + swapEndian(); +} + std::unique_ptr Card::createFile(const char* filename, size_t size) { updateDirAndBat(); @@ -379,7 +399,7 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding) m_sizeMb = uint16_t(size); m_maxBlock = m_sizeMb * MbitToBlocks; m_encoding = uint16_t(encoding); - calculateChecksum(reinterpret_cast(__raw), 0xFE, &m_checksum, &m_checksumInv); + updateChecksum(); m_dir = Directory(); m_dirBackup = m_dir; m_bat = BlockAllocationTable(uint32_t(size) * MbitToBlocks); @@ -389,8 +409,10 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding) m_currentBat = &m_batBackup; m_previousBat = &m_bat; - if (!m_fileHandle) - m_fileHandle = Fopen(m_filename.c_str(), _S("wb")); + if (m_fileHandle) + fclose(m_fileHandle); + + m_fileHandle = Fopen(m_filename.c_str(), _S("wb")); if (m_fileHandle) { @@ -459,8 +481,10 @@ Card::operator bool() const return false; uint16_t ckSum, ckSumInv; - calculateChecksum(reinterpret_cast(__raw), 0xFE, &ckSum, &ckSumInv); - if (ckSum != m_checksum || ckSumInv != m_checksumInv) + Card tmp = *this; + tmp.swapEndian(); + calculateChecksumBE(reinterpret_cast(tmp.__raw), 0xFE, &ckSum, &ckSumInv); + if (SBig(ckSum) != m_checksum || SBig(ckSumInv) != m_checksumInv) return false; if (!m_dir.valid() && !m_dirBackup.valid()) return false; @@ -514,14 +538,18 @@ void BlockAllocationTable::swapEndian() void BlockAllocationTable::updateChecksum() { - calculateChecksum(reinterpret_cast(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv); + swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv); + swapEndian(); } bool BlockAllocationTable::valid() const { uint16_t ckSum, ckSumInv; - calculateChecksum(reinterpret_cast(__raw + 4), 0xFFE, &ckSum, &ckSumInv); - return (ckSum == m_checksum && ckSumInv == m_checksumInv); + BlockAllocationTable tmp = *this; + tmp.swapEndian(); + calculateChecksumBE(reinterpret_cast(tmp.__raw + 4), 0xFFE, &ckSum, &ckSumInv); + return (SBig(ckSum) == m_checksum && SBig(ckSumInv) == m_checksumInv); } BlockAllocationTable::BlockAllocationTable(uint32_t blockCount) @@ -615,14 +643,18 @@ void Directory::swapEndian() void Directory::updateChecksum() { - calculateChecksum(reinterpret_cast(__raw), 0xFFE, &m_checksum, &m_checksumInv); + swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw), 0xFFE, &m_checksum, &m_checksumInv); + swapEndian(); } bool Directory::valid() const { uint16_t ckSum, ckSumInv; - calculateChecksum(reinterpret_cast(__raw), 0xFFE, &ckSum, &ckSumInv); - return (ckSum == m_checksum && ckSumInv == m_checksumInv); + Directory tmp = *this; + tmp.swapEndian(); + calculateChecksumBE(reinterpret_cast(tmp.__raw), 0xFFE, &ckSum, &ckSumInv); + return (SBig(ckSum) == m_checksum && SBig(ckSumInv) == m_checksumInv); } Directory::Directory() @@ -681,17 +713,18 @@ File* Directory::getFile(const char* game, const char* maker, const char* filena return nullptr; } -void calculateChecksum(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv) +void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv) { *checksum = 0; *checksumInv = 0; for (size_t i = 0; i < len; ++i) { - *checksum += data[i]; - *checksumInv += data[i] ^ 0xFFFF; + *checksum += SBig(data[i]); + *checksumInv += SBig(uint16_t(data[i] ^ 0xFFFF)); } - *checksum = *checksum; - *checksumInv = *checksumInv; + + *checksum = SBig(*checksum); + *checksumInv = SBig(*checksumInv); if (*checksum == 0xFFFF) *checksum = 0; if (*checksumInv == 0xFFFF) diff --git a/test/main.cpp b/test/main.cpp index e36d4ff..45fa1a9 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -6,13 +6,13 @@ int main() kabufuda::Card mc{_S("test.USA.raw"), "GM8E", "01"}; if (!mc) mc.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card2043Mb); - std::unique_ptr f = mc.openFile("MetroidPrime A"); + std::unique_ptr f = mc.openFile("MetroidPrime B"); if (!f) - f = mc.createFile("MetroidPrime A", kabufuda::BlockSize); + f = mc.createFile("MetroidPrime B", kabufuda::BlockSize); if (f) { - const char* test = "Metroid Prime A is Cool"; + const char* test = "Metroid Prime B is Cool"; size_t len = strlen(test); uint8_t data[kabufuda::BlockSize] = {}; mc.write(f, data, kabufuda::BlockSize); @@ -24,7 +24,7 @@ int main() mc.seek(f, -2, kabufuda::SeekOrigin::Current); mc.read(f, &derp, 2); std::cout << derp << std::endl; - //mc.deleteFile(f); + mc.deleteFile(f); } return 0; }