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 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__

View File

@ -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<uint16_t*>(__raw), 0xFE, &m_checksum, &m_checksumInv);
swapEndian();
}
std::unique_ptr<IFileHandle> 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<uint16_t*>(__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<const uint16_t*>(__raw), 0xFE, &ckSum, &ckSumInv);
if (ckSum != m_checksum || ckSumInv != m_checksumInv)
Card tmp = *this;
tmp.swapEndian();
calculateChecksumBE(reinterpret_cast<const uint16_t*>(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<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
{
uint16_t ckSum, ckSumInv;
calculateChecksum(reinterpret_cast<const uint16_t*>(__raw + 4), 0xFFE, &ckSum, &ckSumInv);
return (ckSum == m_checksum && ckSumInv == m_checksumInv);
BlockAllocationTable tmp = *this;
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)
@ -615,14 +643,18 @@ void Directory::swapEndian()
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
{
uint16_t ckSum, ckSumInv;
calculateChecksum(reinterpret_cast<const uint16_t*>(__raw), 0xFFE, &ckSum, &ckSumInv);
return (ckSum == m_checksum && ckSumInv == m_checksumInv);
Directory tmp = *this;
tmp.swapEndian();
calculateChecksumBE(reinterpret_cast<const uint16_t*>(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)

View File

@ -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<kabufuda::IFileHandle> f = mc.openFile("MetroidPrime A");
std::unique_ptr<kabufuda::IFileHandle> 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;
}