Fix checksum handling

This commit is contained in:
Phillip Stephens 2016-06-27 01:15:02 -07:00
parent 65ecd15219
commit 4cd0330e22
3 changed files with 56 additions and 21 deletions

View File

@ -220,8 +220,10 @@ class Card
void swapEndian(); void swapEndian();
void updateDirAndBat(); void updateDirAndBat();
void updateChecksum();
public: public:
Card(); Card();
Card(const Card& other);
Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr); Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr);
~Card(); ~Card();
@ -299,7 +301,7 @@ public:
* @param checksum * @param checksum
* @param checksumInv * @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__ #endif // __CARD_HPP__

View File

@ -52,6 +52,17 @@ Card::Card()
memset(__raw, 0xFF, BlockSize); 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) Card::Card(const SystemString& filename, const char* game, const char* maker)
: m_filename(filename) : 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 */ /* Close and reopen in read/write mode */
fclose(m_fileHandle); fclose(m_fileHandle);
m_fileHandle = nullptr;
m_fileHandle = Fopen(m_filename.c_str(), _S("r+")); 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); std::swap(m_currentBat, m_previousBat);
} }
void Card::updateChecksum()
{
swapEndian();
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw), 0xFE, &m_checksum, &m_checksumInv);
swapEndian();
}
std::unique_ptr<IFileHandle> Card::createFile(const char* filename, size_t size) std::unique_ptr<IFileHandle> Card::createFile(const char* filename, size_t size)
{ {
updateDirAndBat(); updateDirAndBat();
@ -379,7 +399,7 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
m_sizeMb = uint16_t(size); m_sizeMb = uint16_t(size);
m_maxBlock = m_sizeMb * MbitToBlocks; m_maxBlock = m_sizeMb * MbitToBlocks;
m_encoding = uint16_t(encoding); m_encoding = uint16_t(encoding);
calculateChecksum(reinterpret_cast<uint16_t*>(__raw), 0xFE, &m_checksum, &m_checksumInv); updateChecksum();
m_dir = Directory(); m_dir = Directory();
m_dirBackup = m_dir; m_dirBackup = m_dir;
m_bat = BlockAllocationTable(uint32_t(size) * MbitToBlocks); m_bat = BlockAllocationTable(uint32_t(size) * MbitToBlocks);
@ -389,7 +409,9 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
m_currentBat = &m_batBackup; m_currentBat = &m_batBackup;
m_previousBat = &m_bat; m_previousBat = &m_bat;
if (!m_fileHandle) if (m_fileHandle)
fclose(m_fileHandle);
m_fileHandle = Fopen(m_filename.c_str(), _S("wb")); m_fileHandle = Fopen(m_filename.c_str(), _S("wb"));
if (m_fileHandle) if (m_fileHandle)
@ -459,8 +481,10 @@ Card::operator bool() const
return false; return false;
uint16_t ckSum, ckSumInv; uint16_t ckSum, ckSumInv;
calculateChecksum(reinterpret_cast<const uint16_t*>(__raw), 0xFE, &ckSum, &ckSumInv); Card tmp = *this;
if (ckSum != m_checksum || ckSumInv != m_checksumInv) tmp.swapEndian();
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw), 0xFE, &ckSum, &ckSumInv);
if (SBig(ckSum) != m_checksum || SBig(ckSumInv) != m_checksumInv)
return false; return false;
if (!m_dir.valid() && !m_dirBackup.valid()) if (!m_dir.valid() && !m_dirBackup.valid())
return false; return false;
@ -514,14 +538,18 @@ void BlockAllocationTable::swapEndian()
void BlockAllocationTable::updateChecksum() void BlockAllocationTable::updateChecksum()
{ {
calculateChecksum(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv); swapEndian();
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
swapEndian();
} }
bool BlockAllocationTable::valid() const bool BlockAllocationTable::valid() const
{ {
uint16_t ckSum, ckSumInv; uint16_t ckSum, ckSumInv;
calculateChecksum(reinterpret_cast<const uint16_t*>(__raw + 4), 0xFFE, &ckSum, &ckSumInv); BlockAllocationTable tmp = *this;
return (ckSum == m_checksum && ckSumInv == m_checksumInv); tmp.swapEndian();
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw + 4), 0xFFE, &ckSum, &ckSumInv);
return (SBig(ckSum) == m_checksum && SBig(ckSumInv) == m_checksumInv);
} }
BlockAllocationTable::BlockAllocationTable(uint32_t blockCount) BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
@ -615,14 +643,18 @@ void Directory::swapEndian()
void Directory::updateChecksum() void Directory::updateChecksum()
{ {
calculateChecksum(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv); swapEndian();
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv);
swapEndian();
} }
bool Directory::valid() const bool Directory::valid() const
{ {
uint16_t ckSum, ckSumInv; uint16_t ckSum, ckSumInv;
calculateChecksum(reinterpret_cast<const uint16_t*>(__raw), 0xFFE, &ckSum, &ckSumInv); Directory tmp = *this;
return (ckSum == m_checksum && ckSumInv == m_checksumInv); tmp.swapEndian();
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw), 0xFFE, &ckSum, &ckSumInv);
return (SBig(ckSum) == m_checksum && SBig(ckSumInv) == m_checksumInv);
} }
Directory::Directory() Directory::Directory()
@ -681,17 +713,18 @@ File* Directory::getFile(const char* game, const char* maker, const char* filena
return nullptr; 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; *checksum = 0;
*checksumInv = 0; *checksumInv = 0;
for (size_t i = 0; i < len; ++i) for (size_t i = 0; i < len; ++i)
{ {
*checksum += data[i]; *checksum += SBig(data[i]);
*checksumInv += data[i] ^ 0xFFFF; *checksumInv += SBig(uint16_t(data[i] ^ 0xFFFF));
} }
*checksum = *checksum;
*checksumInv = *checksumInv; *checksum = SBig(*checksum);
*checksumInv = SBig(*checksumInv);
if (*checksum == 0xFFFF) if (*checksum == 0xFFFF)
*checksum = 0; *checksum = 0;
if (*checksumInv == 0xFFFF) if (*checksumInv == 0xFFFF)

View File

@ -6,13 +6,13 @@ int main()
kabufuda::Card mc{_S("test.USA.raw"), "GM8E", "01"}; kabufuda::Card mc{_S("test.USA.raw"), "GM8E", "01"};
if (!mc) if (!mc)
mc.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card2043Mb); mc.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card2043Mb);
std::unique_ptr<kabufuda::IFileHandle> f = mc.openFile("MetroidPrime A"); std::unique_ptr<kabufuda::IFileHandle> f = mc.openFile("MetroidPrime B");
if (!f) if (!f)
f = mc.createFile("MetroidPrime A", kabufuda::BlockSize); f = mc.createFile("MetroidPrime B", kabufuda::BlockSize);
if (f) if (f)
{ {
const char* test = "Metroid Prime A is Cool"; const char* test = "Metroid Prime B is Cool";
size_t len = strlen(test); size_t len = strlen(test);
uint8_t data[kabufuda::BlockSize] = {}; uint8_t data[kabufuda::BlockSize] = {};
mc.write(f, data, kabufuda::BlockSize); mc.write(f, data, kabufuda::BlockSize);
@ -24,7 +24,7 @@ int main()
mc.seek(f, -2, kabufuda::SeekOrigin::Current); mc.seek(f, -2, kabufuda::SeekOrigin::Current);
mc.read(f, &derp, 2); mc.read(f, &derp, 2);
std::cout << derp << std::endl; std::cout << derp << std::endl;
//mc.deleteFile(f); mc.deleteFile(f);
} }
return 0; return 0;
} }