mirror of
https://github.com/AxioDL/kabufuda.git
synced 2025-05-13 10:51:20 +00:00
Checksum and Card copy fixes
This commit is contained in:
parent
3121f67f4d
commit
b5f5104877
@ -30,7 +30,7 @@ class BlockAllocationTable
|
|||||||
public:
|
public:
|
||||||
explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks));
|
explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks));
|
||||||
BlockAllocationTable(uint8_t data[BlockSize]);
|
BlockAllocationTable(uint8_t data[BlockSize]);
|
||||||
~BlockAllocationTable();
|
~BlockAllocationTable() = default;
|
||||||
|
|
||||||
uint16_t getNextBlock(uint16_t block) const;
|
uint16_t getNextBlock(uint16_t block) const;
|
||||||
uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const;
|
uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const;
|
||||||
|
@ -124,14 +124,10 @@ class Card
|
|||||||
|
|
||||||
SystemString m_filename;
|
SystemString m_filename;
|
||||||
FILE* m_fileHandle = nullptr;
|
FILE* m_fileHandle = nullptr;
|
||||||
Directory m_dir;
|
Directory m_dirs[2];
|
||||||
Directory m_dirBackup;
|
BlockAllocationTable m_bats[2];
|
||||||
Directory* m_currentDir;
|
uint8_t m_currentDir;
|
||||||
Directory* m_previousDir;
|
uint8_t m_currentBat;
|
||||||
BlockAllocationTable m_bat;
|
|
||||||
BlockAllocationTable m_batBackup;
|
|
||||||
BlockAllocationTable* m_currentBat;
|
|
||||||
BlockAllocationTable* m_previousBat;
|
|
||||||
|
|
||||||
uint16_t m_maxBlock;
|
uint16_t m_maxBlock;
|
||||||
char m_game[5] = {'\0'};
|
char m_game[5] = {'\0'};
|
||||||
@ -149,7 +145,11 @@ public:
|
|||||||
* @brief Card
|
* @brief Card
|
||||||
* @param other
|
* @param other
|
||||||
*/
|
*/
|
||||||
Card(const Card& other);
|
Card(const Card& other) = delete;
|
||||||
|
Card& operator=(const Card& other) = delete;
|
||||||
|
Card(Card&& other) = default;
|
||||||
|
Card& operator=(Card&& other) = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Card
|
* @brief Card
|
||||||
* @param filepath
|
* @param filepath
|
||||||
|
@ -29,9 +29,7 @@ class Directory
|
|||||||
public:
|
public:
|
||||||
Directory();
|
Directory();
|
||||||
Directory(uint8_t data[BlockSize]);
|
Directory(uint8_t data[BlockSize]);
|
||||||
Directory(const Directory& other);
|
~Directory() = default;
|
||||||
void operator=(const Directory& other);
|
|
||||||
~Directory();
|
|
||||||
|
|
||||||
bool hasFreeFile() const;
|
bool hasFreeFile() const;
|
||||||
int32_t numFreeFiles() const;
|
int32_t numFreeFiles() const;
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
File();
|
File();
|
||||||
File(char data[0x40]);
|
File(char data[0x40]);
|
||||||
File(const char* filename);
|
File(const char* filename);
|
||||||
~File() {}
|
~File() = default;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,6 +358,7 @@ static inline int Stat(const SystemChar* path, Sstat* statOut)
|
|||||||
* @param checksumInv
|
* @param checksumInv
|
||||||
*/
|
*/
|
||||||
void calculateChecksumBE(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);
|
||||||
|
void calculateChecksumLE(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __KABU_UTIL_HPP__
|
#endif // __KABU_UTIL_HPP__
|
||||||
|
@ -16,18 +16,14 @@ void BlockAllocationTable::swapEndian()
|
|||||||
|
|
||||||
void BlockAllocationTable::updateChecksum()
|
void BlockAllocationTable::updateChecksum()
|
||||||
{
|
{
|
||||||
swapEndian();
|
calculateChecksumLE(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
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;
|
||||||
BlockAllocationTable tmp = *this;
|
calculateChecksumLE(reinterpret_cast<const uint16_t*>(__raw + 4), 0xFFE, &ckSum, &ckSumInv);
|
||||||
tmp.swapEndian();
|
return (ckSum == m_checksum && ckSumInv == m_checksumInv);
|
||||||
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)
|
||||||
@ -38,8 +34,6 @@ BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
|
|||||||
updateChecksum();
|
updateChecksum();
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAllocationTable::~BlockAllocationTable() {}
|
|
||||||
|
|
||||||
uint16_t BlockAllocationTable::getNextBlock(uint16_t block) const
|
uint16_t BlockAllocationTable::getNextBlock(uint16_t block) const
|
||||||
{
|
{
|
||||||
if ((block < FSTBlocks) || (block > (BATSize - FSTBlocks)))
|
if ((block < FSTBlocks) || (block > (BATSize - FSTBlocks)))
|
||||||
|
@ -41,17 +41,6 @@ void Card::_swapEndian()
|
|||||||
|
|
||||||
Card::Card() { memset(__raw, 0xFF, BlockSize); }
|
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)
|
Card::Card(const SystemString& filename, const char* game, const char* maker) : m_filename(filename)
|
||||||
{
|
{
|
||||||
memset(__raw, 0xFF, BlockSize);
|
memset(__raw, 0xFF, BlockSize);
|
||||||
@ -66,47 +55,35 @@ Card::Card(const SystemString& filename, const char* game, const char* maker) :
|
|||||||
fread(__raw, 1, BlockSize, m_fileHandle);
|
fread(__raw, 1, BlockSize, m_fileHandle);
|
||||||
m_maxBlock = m_sizeMb * MbitToBlocks;
|
m_maxBlock = m_sizeMb * MbitToBlocks;
|
||||||
_swapEndian();
|
_swapEndian();
|
||||||
fread(m_dir.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_dirs[0].__raw, 1, BlockSize, m_fileHandle);
|
||||||
fread(m_dirBackup.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_dirs[1].__raw, 1, BlockSize, m_fileHandle);
|
||||||
fread(m_bat.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_bats[0].__raw, 1, BlockSize, m_fileHandle);
|
||||||
fread(m_batBackup.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_bats[1].__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
|
||||||
m_dir.swapEndian();
|
m_dirs[0].swapEndian();
|
||||||
m_dirBackup.swapEndian();
|
m_dirs[1].swapEndian();
|
||||||
m_bat.swapEndian();
|
m_bats[0].swapEndian();
|
||||||
m_batBackup.swapEndian();
|
m_bats[1].swapEndian();
|
||||||
|
|
||||||
/* Check for data integrity, restoring valid data in case of corruption if possible */
|
/* Check for data integrity, restoring valid data in case of corruption if possible */
|
||||||
if (!m_dir.valid() && m_dirBackup.valid())
|
if (!m_dirs[0].valid() && m_dirs[1].valid())
|
||||||
m_dir = m_dirBackup;
|
m_dirs[0] = m_dirs[1];
|
||||||
else if (!m_dirBackup.valid() && m_dir.valid())
|
else if (!m_dirs[1].valid() && m_dirs[0].valid())
|
||||||
m_dirBackup = m_dir;
|
m_dirs[1] = m_dirs[0];
|
||||||
if (!m_bat.valid() && m_batBackup.valid())
|
if (!m_bats[0].valid() && m_bats[1].valid())
|
||||||
m_bat = m_batBackup;
|
m_bats[0] = m_bats[1];
|
||||||
else if (!m_batBackup.valid() && m_bat.valid())
|
else if (!m_bats[1].valid() && m_bats[0].valid())
|
||||||
m_batBackup = m_bat;
|
m_bats[1] = m_bats[0];
|
||||||
|
|
||||||
if (m_dir.m_updateCounter > m_dirBackup.m_updateCounter)
|
if (m_dirs[0].m_updateCounter > m_dirs[1].m_updateCounter)
|
||||||
{
|
m_currentDir = 0;
|
||||||
m_currentDir = &m_dir;
|
|
||||||
m_previousDir = &m_dirBackup;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
m_currentDir = 1;
|
||||||
m_currentDir = &m_dirBackup;
|
|
||||||
m_previousDir = &m_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_bat.m_updateCounter > m_batBackup.m_updateCounter)
|
if (m_bats[0].m_updateCounter > m_bats[1].m_updateCounter)
|
||||||
{
|
m_currentBat = 0;
|
||||||
m_currentBat = &m_bat;
|
|
||||||
m_previousBat = &m_batBackup;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
m_currentBat = 1;
|
||||||
m_currentBat = &m_batBackup;
|
|
||||||
m_previousBat = &m_bat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Close and reopen in read/write mode */
|
/* Close and reopen in read/write mode */
|
||||||
fclose(m_fileHandle);
|
fclose(m_fileHandle);
|
||||||
@ -126,10 +103,10 @@ Card::~Card()
|
|||||||
ECardResult Card::openFile(const char* filename, std::unique_ptr<IFileHandle>& handleOut)
|
ECardResult Card::openFile(const char* filename, std::unique_ptr<IFileHandle>& handleOut)
|
||||||
{
|
{
|
||||||
handleOut.reset();
|
handleOut.reset();
|
||||||
File* f = m_currentDir->getFile(m_game, m_maker, filename);
|
File* f = m_dirs[m_currentDir].getFile(m_game, m_maker, filename);
|
||||||
if (!f || f->m_game[0] == 0xFF)
|
if (!f || f->m_game[0] == 0xFF)
|
||||||
return ECardResult::NOFILE;
|
return ECardResult::NOFILE;
|
||||||
int32_t idx = m_currentDir->indexForFile(f);
|
int32_t idx = m_dirs[m_currentDir].indexForFile(f);
|
||||||
if (idx != -1)
|
if (idx != -1)
|
||||||
{
|
{
|
||||||
handleOut = std::make_unique<FileHandle>(idx);
|
handleOut = std::make_unique<FileHandle>(idx);
|
||||||
@ -141,7 +118,7 @@ ECardResult Card::openFile(const char* filename, std::unique_ptr<IFileHandle>& h
|
|||||||
ECardResult Card::openFile(uint32_t fileno, std::unique_ptr<IFileHandle>& handleOut)
|
ECardResult Card::openFile(uint32_t fileno, std::unique_ptr<IFileHandle>& handleOut)
|
||||||
{
|
{
|
||||||
handleOut.reset();
|
handleOut.reset();
|
||||||
File* f = m_currentDir->getFile(fileno);
|
File* f = m_dirs[m_currentDir].getFile(fileno);
|
||||||
if (!f || f->m_game[0] == 0xFF)
|
if (!f || f->m_game[0] == 0xFF)
|
||||||
return ECardResult::NOFILE;
|
return ECardResult::NOFILE;
|
||||||
handleOut = std::make_unique<FileHandle>(fileno);
|
handleOut = std::make_unique<FileHandle>(fileno);
|
||||||
@ -150,22 +127,20 @@ ECardResult Card::openFile(uint32_t fileno, std::unique_ptr<IFileHandle>& handle
|
|||||||
|
|
||||||
void Card::_updateDirAndBat()
|
void Card::_updateDirAndBat()
|
||||||
{
|
{
|
||||||
Directory updateDir = *m_currentDir;
|
Directory updateDir = m_dirs[m_currentDir];
|
||||||
updateDir.m_updateCounter++;
|
updateDir.m_updateCounter++;
|
||||||
*m_previousDir = updateDir;
|
m_dirs[!m_currentDir] = updateDir;
|
||||||
std::swap(m_currentDir, m_previousDir);
|
m_currentDir = !m_currentDir;
|
||||||
|
|
||||||
BlockAllocationTable updateBat = *m_currentBat;
|
BlockAllocationTable updateBat = m_bats[m_currentBat];
|
||||||
updateBat.m_updateCounter++;
|
updateBat.m_updateCounter++;
|
||||||
*m_previousBat = updateBat;
|
m_bats[!m_currentBat] = updateBat;
|
||||||
std::swap(m_currentBat, m_previousBat);
|
m_currentBat = !m_currentBat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::_updateChecksum()
|
void Card::_updateChecksum()
|
||||||
{
|
{
|
||||||
_swapEndian();
|
calculateChecksumLE(reinterpret_cast<uint16_t*>(__raw), 0xFE, &m_checksum, &m_checksumInv);
|
||||||
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw), 0xFE, &m_checksum, &m_checksumInv);
|
|
||||||
_swapEndian();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
File* Card::_fileFromHandle(const std::unique_ptr<IFileHandle>& fh) const
|
File* Card::_fileFromHandle(const std::unique_ptr<IFileHandle>& fh) const
|
||||||
@ -177,7 +152,7 @@ File* Card::_fileFromHandle(const std::unique_ptr<IFileHandle>& fh) const
|
|||||||
if (!handle)
|
if (!handle)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
File* file = m_currentDir->getFile(handle->idx);
|
File* file = const_cast<Directory&>(m_dirs[m_currentDir]).getFile(handle->idx);
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,24 +165,24 @@ ECardResult Card::createFile(const char* filename, size_t size,
|
|||||||
return ECardResult::FATAL_ERROR;
|
return ECardResult::FATAL_ERROR;
|
||||||
if (strlen(filename) > 32)
|
if (strlen(filename) > 32)
|
||||||
return ECardResult::NAMETOOLONG;
|
return ECardResult::NAMETOOLONG;
|
||||||
if (m_currentDir->getFile(m_game, m_maker, filename))
|
if (m_dirs[m_currentDir].getFile(m_game, m_maker, filename))
|
||||||
return ECardResult::EXIST;
|
return ECardResult::EXIST;
|
||||||
uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize;
|
uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize;
|
||||||
if (neededBlocks > m_currentBat->numFreeBlocks())
|
if (neededBlocks > m_bats[m_currentBat].numFreeBlocks())
|
||||||
return ECardResult::INSSPACE;
|
return ECardResult::INSSPACE;
|
||||||
if (!m_currentDir->hasFreeFile())
|
if (!m_dirs[m_currentDir].hasFreeFile())
|
||||||
return ECardResult::NOENT;
|
return ECardResult::NOENT;
|
||||||
|
|
||||||
_updateDirAndBat();
|
_updateDirAndBat();
|
||||||
File* f = m_currentDir->getFirstFreeFile(m_game, m_maker, filename);
|
File* f = m_dirs[m_currentDir].getFirstFreeFile(m_game, m_maker, filename);
|
||||||
uint16_t block = m_currentBat->allocateBlocks(neededBlocks, m_maxBlock - FSTBlocks);
|
uint16_t block = m_bats[m_currentBat].allocateBlocks(neededBlocks, m_maxBlock - FSTBlocks);
|
||||||
if (f && block != 0xFFFF)
|
if (f && block != 0xFFFF)
|
||||||
{
|
{
|
||||||
f->m_modifiedTime = uint32_t(getGCTime());
|
f->m_modifiedTime = uint32_t(getGCTime());
|
||||||
f->m_firstBlock = block;
|
f->m_firstBlock = block;
|
||||||
f->m_blockCount = neededBlocks;
|
f->m_blockCount = neededBlocks;
|
||||||
|
|
||||||
handleOut = std::make_unique<FileHandle>(m_currentDir->indexForFile(f));
|
handleOut = std::make_unique<FileHandle>(m_dirs[m_currentDir].indexForFile(f));
|
||||||
return ECardResult::READY;
|
return ECardResult::READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,9 +191,9 @@ ECardResult Card::createFile(const char* filename, size_t size,
|
|||||||
|
|
||||||
std::unique_ptr<IFileHandle> Card::firstFile()
|
std::unique_ptr<IFileHandle> Card::firstFile()
|
||||||
{
|
{
|
||||||
File* f = m_currentDir->getFirstNonFreeFile(0, m_game, m_maker);
|
File* f = m_dirs[m_currentDir].getFirstNonFreeFile(0, m_game, m_maker);
|
||||||
if (f)
|
if (f)
|
||||||
return std::make_unique<FileHandle>(m_currentDir->indexForFile(f));
|
return std::make_unique<FileHandle>(m_dirs[m_currentDir].indexForFile(f));
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -229,10 +204,10 @@ std::unique_ptr<IFileHandle> Card::nextFile(const std::unique_ptr<IFileHandle>&
|
|||||||
if (!handle)
|
if (!handle)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
File* next = m_currentDir->getFirstNonFreeFile(handle->idx + 1, m_game, m_maker);
|
File* next = m_dirs[m_currentDir].getFirstNonFreeFile(handle->idx + 1, m_game, m_maker);
|
||||||
if (!next)
|
if (!next)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::make_unique<FileHandle>(m_currentDir->indexForFile(next));
|
return std::make_unique<FileHandle>(m_dirs[m_currentDir].indexForFile(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Card::getFilename(const std::unique_ptr<IFileHandle>& fh)
|
const char* Card::getFilename(const std::unique_ptr<IFileHandle>& fh)
|
||||||
@ -249,8 +224,8 @@ void Card::_deleteFile(File& f)
|
|||||||
while (block != 0xFFFF)
|
while (block != 0xFFFF)
|
||||||
{
|
{
|
||||||
/* TODO: add a fragmentation check */
|
/* TODO: add a fragmentation check */
|
||||||
uint16_t nextBlock = m_currentBat->getNextBlock(block);
|
uint16_t nextBlock = m_bats[m_currentBat].getNextBlock(block);
|
||||||
m_currentBat->clear(block, 1);
|
m_bats[m_currentBat].clear(block, 1);
|
||||||
block = nextBlock;
|
block = nextBlock;
|
||||||
}
|
}
|
||||||
f = File();
|
f = File();
|
||||||
@ -262,13 +237,13 @@ void Card::deleteFile(const std::unique_ptr<IFileHandle>& fh)
|
|||||||
if (!fh)
|
if (!fh)
|
||||||
return;
|
return;
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
_deleteFile(*m_currentDir->getFile(f->idx));
|
_deleteFile(*m_dirs[m_currentDir].getFile(f->idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
ECardResult Card::deleteFile(const char* filename)
|
ECardResult Card::deleteFile(const char* filename)
|
||||||
{
|
{
|
||||||
_updateDirAndBat();
|
_updateDirAndBat();
|
||||||
File* f = m_currentDir->getFile(m_game, m_maker, filename);
|
File* f = m_dirs[m_currentDir].getFile(m_game, m_maker, filename);
|
||||||
if (!f)
|
if (!f)
|
||||||
return ECardResult::NOFILE;
|
return ECardResult::NOFILE;
|
||||||
|
|
||||||
@ -279,7 +254,7 @@ ECardResult Card::deleteFile(const char* filename)
|
|||||||
ECardResult Card::deleteFile(uint32_t fileno)
|
ECardResult Card::deleteFile(uint32_t fileno)
|
||||||
{
|
{
|
||||||
_updateDirAndBat();
|
_updateDirAndBat();
|
||||||
File* f = m_currentDir->getFile(fileno);
|
File* f = m_dirs[m_currentDir].getFile(fileno);
|
||||||
if (!f)
|
if (!f)
|
||||||
return ECardResult::NOFILE;
|
return ECardResult::NOFILE;
|
||||||
|
|
||||||
@ -293,7 +268,7 @@ ECardResult Card::renameFile(const char* oldName, const char* newName)
|
|||||||
return ECardResult::NAMETOOLONG;
|
return ECardResult::NAMETOOLONG;
|
||||||
|
|
||||||
_updateDirAndBat();
|
_updateDirAndBat();
|
||||||
File* f = m_currentDir->getFile(m_game, m_maker, oldName);
|
File* f = m_dirs[m_currentDir].getFile(m_game, m_maker, oldName);
|
||||||
if (!f)
|
if (!f)
|
||||||
return ECardResult::NOFILE;
|
return ECardResult::NOFILE;
|
||||||
|
|
||||||
@ -309,7 +284,7 @@ void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t
|
|||||||
if (m_fileHandle)
|
if (m_fileHandle)
|
||||||
{
|
{
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
File* file = m_currentDir->getFile(f->idx);
|
File* file = m_dirs[m_currentDir].getFile(f->idx);
|
||||||
if (!file)
|
if (!file)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -320,7 +295,7 @@ void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t
|
|||||||
const uint16_t blockId = uint16_t(f->offset / BlockSize);
|
const uint16_t blockId = uint16_t(f->offset / BlockSize);
|
||||||
uint16_t block = file->m_firstBlock;
|
uint16_t block = file->m_firstBlock;
|
||||||
for (uint16_t i = 0; i < blockId; i++)
|
for (uint16_t i = 0; i < blockId; i++)
|
||||||
block = m_currentBat->getNextBlock(block);
|
block = m_bats[m_currentBat].getNextBlock(block);
|
||||||
|
|
||||||
const uint8_t* tmpBuf = reinterpret_cast<const uint8_t*>(buf);
|
const uint8_t* tmpBuf = reinterpret_cast<const uint8_t*>(buf);
|
||||||
uint16_t curBlock = block;
|
uint16_t curBlock = block;
|
||||||
@ -342,7 +317,7 @@ void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t
|
|||||||
blockOffset += cacheSize;
|
blockOffset += cacheSize;
|
||||||
if (blockOffset >= BlockSize)
|
if (blockOffset >= BlockSize)
|
||||||
{
|
{
|
||||||
curBlock = m_currentBat->getNextBlock(curBlock);
|
curBlock = m_bats[m_currentBat].getNextBlock(curBlock);
|
||||||
blockOffset = 0;
|
blockOffset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,7 +333,7 @@ void Card::read(const std::unique_ptr<IFileHandle>& fh, void* dst, size_t size)
|
|||||||
if (m_fileHandle)
|
if (m_fileHandle)
|
||||||
{
|
{
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
File* file = m_currentDir->getFile(f->idx);
|
File* file = m_dirs[m_currentDir].getFile(f->idx);
|
||||||
if (!file)
|
if (!file)
|
||||||
return;
|
return;
|
||||||
/* Block handling is a little different from cache handling,
|
/* Block handling is a little different from cache handling,
|
||||||
@ -368,7 +343,7 @@ void Card::read(const std::unique_ptr<IFileHandle>& fh, void* dst, size_t size)
|
|||||||
const uint16_t blockId = uint16_t(f->offset / BlockSize);
|
const uint16_t blockId = uint16_t(f->offset / BlockSize);
|
||||||
uint16_t block = file->m_firstBlock;
|
uint16_t block = file->m_firstBlock;
|
||||||
for (uint16_t i = 0; i < blockId; i++)
|
for (uint16_t i = 0; i < blockId; i++)
|
||||||
block = m_currentBat->getNextBlock(block);
|
block = m_bats[m_currentBat].getNextBlock(block);
|
||||||
|
|
||||||
uint8_t* tmpBuf = reinterpret_cast<uint8_t*>(dst);
|
uint8_t* tmpBuf = reinterpret_cast<uint8_t*>(dst);
|
||||||
uint16_t curBlock = block;
|
uint16_t curBlock = block;
|
||||||
@ -390,7 +365,7 @@ void Card::read(const std::unique_ptr<IFileHandle>& fh, void* dst, size_t size)
|
|||||||
blockOffset += cacheSize;
|
blockOffset += cacheSize;
|
||||||
if (blockOffset >= BlockSize)
|
if (blockOffset >= BlockSize)
|
||||||
{
|
{
|
||||||
curBlock = m_currentBat->getNextBlock(curBlock);
|
curBlock = m_bats[m_currentBat].getNextBlock(curBlock);
|
||||||
blockOffset = 0;
|
blockOffset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,7 +379,7 @@ void Card::seek(const std::unique_ptr<IFileHandle>& fh, int32_t pos, SeekOrigin
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
File* file = m_currentDir->getFile(f->idx);
|
File* file = m_dirs[m_currentDir].getFile(f->idx);
|
||||||
if (!file)
|
if (!file)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -848,8 +823,8 @@ void Card::getChecksum(uint16_t& checksum, uint16_t& inverse)
|
|||||||
|
|
||||||
void Card::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed)
|
void Card::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed)
|
||||||
{
|
{
|
||||||
bytesNotUsed = m_currentBat->numFreeBlocks() * 0x2000;
|
bytesNotUsed = m_bats[m_currentBat].numFreeBlocks() * 0x2000;
|
||||||
filesNotUsed = m_currentDir->numFreeFiles();
|
filesNotUsed = m_dirs[m_currentDir].numFreeFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::format(ECardSlot id, ECardSize size, EEncoding encoding)
|
void Card::format(ECardSlot id, ECardSize size, EEncoding encoding)
|
||||||
@ -873,14 +848,12 @@ void Card::format(ECardSlot id, ECardSize size, EEncoding encoding)
|
|||||||
m_maxBlock = m_sizeMb * MbitToBlocks;
|
m_maxBlock = m_sizeMb * MbitToBlocks;
|
||||||
m_encoding = uint16_t(encoding);
|
m_encoding = uint16_t(encoding);
|
||||||
_updateChecksum();
|
_updateChecksum();
|
||||||
m_dir = Directory();
|
m_dirs[0] = Directory();
|
||||||
m_dirBackup = m_dir;
|
m_dirs[1] = m_dirs[0];
|
||||||
m_bat = BlockAllocationTable(uint32_t(size) * MbitToBlocks);
|
m_bats[0] = BlockAllocationTable(uint32_t(size) * MbitToBlocks);
|
||||||
m_batBackup = m_bat;
|
m_bats[1] = m_bats[0];
|
||||||
m_currentDir = &m_dirBackup;
|
m_currentDir = 1;
|
||||||
m_previousDir = &m_dir;
|
m_currentBat = 1;
|
||||||
m_currentBat = &m_batBackup;
|
|
||||||
m_previousBat = &m_bat;
|
|
||||||
|
|
||||||
if (m_fileHandle)
|
if (m_fileHandle)
|
||||||
fclose(m_fileHandle);
|
fclose(m_fileHandle);
|
||||||
@ -892,16 +865,16 @@ void Card::format(ECardSlot id, ECardSize size, EEncoding encoding)
|
|||||||
_swapEndian();
|
_swapEndian();
|
||||||
fwrite(__raw, 1, BlockSize, m_fileHandle);
|
fwrite(__raw, 1, BlockSize, m_fileHandle);
|
||||||
_swapEndian();
|
_swapEndian();
|
||||||
Directory tmpDir = m_dir;
|
Directory tmpDir = m_dirs[0];
|
||||||
tmpDir.swapEndian();
|
tmpDir.swapEndian();
|
||||||
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
tmpDir = m_dirBackup;
|
tmpDir = m_dirs[1];
|
||||||
tmpDir.swapEndian();
|
tmpDir.swapEndian();
|
||||||
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
BlockAllocationTable tmpBat = m_bat;
|
BlockAllocationTable tmpBat = m_bats[0];
|
||||||
tmpBat.swapEndian();
|
tmpBat.swapEndian();
|
||||||
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
tmpBat = m_batBackup;
|
tmpBat = m_bats[1];
|
||||||
tmpBat.swapEndian();
|
tmpBat.swapEndian();
|
||||||
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
uint32_t dataLen = ((uint32_t(size) * MbitToBlocks) - 5) * BlockSize;
|
uint32_t dataLen = ((uint32_t(size) * MbitToBlocks) - 5) * BlockSize;
|
||||||
@ -930,19 +903,19 @@ void Card::commit()
|
|||||||
_swapEndian();
|
_swapEndian();
|
||||||
fwrite(__raw, 1, BlockSize, m_fileHandle);
|
fwrite(__raw, 1, BlockSize, m_fileHandle);
|
||||||
_swapEndian();
|
_swapEndian();
|
||||||
Directory tmpDir = m_dir;
|
Directory tmpDir = m_dirs[0];
|
||||||
tmpDir.updateChecksum();
|
tmpDir.updateChecksum();
|
||||||
tmpDir.swapEndian();
|
tmpDir.swapEndian();
|
||||||
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
tmpDir = m_dirBackup;
|
tmpDir = m_dirs[1];
|
||||||
tmpDir.updateChecksum();
|
tmpDir.updateChecksum();
|
||||||
tmpDir.swapEndian();
|
tmpDir.swapEndian();
|
||||||
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
BlockAllocationTable tmpBat = m_bat;
|
BlockAllocationTable tmpBat = m_bats[0];
|
||||||
tmpBat.updateChecksum();
|
tmpBat.updateChecksum();
|
||||||
tmpBat.swapEndian();
|
tmpBat.swapEndian();
|
||||||
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
tmpBat = m_batBackup;
|
tmpBat = m_bats[1];
|
||||||
tmpBat.updateChecksum();
|
tmpBat.updateChecksum();
|
||||||
tmpBat.swapEndian();
|
tmpBat.swapEndian();
|
||||||
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
@ -955,14 +928,12 @@ ECardResult Card::getError() const
|
|||||||
return ECardResult::NOCARD;
|
return ECardResult::NOCARD;
|
||||||
|
|
||||||
uint16_t ckSum, ckSumInv;
|
uint16_t ckSum, ckSumInv;
|
||||||
Card tmp = *this;
|
calculateChecksumLE(reinterpret_cast<const uint16_t*>(__raw), 0xFE, &ckSum, &ckSumInv);
|
||||||
tmp._swapEndian();
|
if (ckSum != m_checksum || ckSumInv != m_checksumInv)
|
||||||
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw), 0xFE, &ckSum, &ckSumInv);
|
|
||||||
if (SBig(ckSum) != m_checksum || SBig(ckSumInv) != m_checksumInv)
|
|
||||||
return ECardResult::BROKEN;
|
return ECardResult::BROKEN;
|
||||||
if (!m_dir.valid() && !m_dirBackup.valid())
|
if (!m_dirs[0].valid() && !m_dirs[1].valid())
|
||||||
return ECardResult::BROKEN;
|
return ECardResult::BROKEN;
|
||||||
if (!m_bat.valid() && !m_batBackup.valid())
|
if (!m_bats[0].valid() && !m_bats[1].valid())
|
||||||
return ECardResult::BROKEN;
|
return ECardResult::BROKEN;
|
||||||
|
|
||||||
return ECardResult::READY;
|
return ECardResult::READY;
|
||||||
|
@ -15,18 +15,14 @@ void Directory::swapEndian()
|
|||||||
|
|
||||||
void Directory::updateChecksum()
|
void Directory::updateChecksum()
|
||||||
{
|
{
|
||||||
swapEndian();
|
calculateChecksumLE(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
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;
|
||||||
Directory tmp = *this;
|
calculateChecksumLE(reinterpret_cast<const uint16_t*>(__raw), 0xFFE, &ckSum, &ckSumInv);
|
||||||
tmp.swapEndian();
|
return (ckSum == m_checksum && ckSumInv == m_checksumInv);
|
||||||
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw), 0xFFE, &ckSum, &ckSumInv);
|
|
||||||
return (SBig(ckSum) == m_checksum && SBig(ckSumInv) == m_checksumInv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::Directory()
|
Directory::Directory()
|
||||||
@ -38,12 +34,6 @@ Directory::Directory()
|
|||||||
|
|
||||||
Directory::Directory(uint8_t data[]) { memcpy(__raw, data, BlockSize); }
|
Directory::Directory(uint8_t data[]) { memcpy(__raw, data, BlockSize); }
|
||||||
|
|
||||||
Directory::Directory(const Directory& other) { memcpy(__raw, other.__raw, BlockSize); }
|
|
||||||
|
|
||||||
void Directory::operator=(const Directory& other) { memcpy(__raw, other.__raw, BlockSize); }
|
|
||||||
|
|
||||||
Directory::~Directory() {}
|
|
||||||
|
|
||||||
bool Directory::hasFreeFile() const
|
bool Directory::hasFreeFile() const
|
||||||
{
|
{
|
||||||
for (uint16_t i = 0; i < 127; i++)
|
for (uint16_t i = 0; i < 127; i++)
|
||||||
|
@ -41,4 +41,20 @@ void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, u
|
|||||||
if (*checksumInv == 0xFFFF)
|
if (*checksumInv == 0xFFFF)
|
||||||
*checksumInv = 0;
|
*checksumInv = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void calculateChecksumLE(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 += uint16_t(data[i] ^ 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*checksum == 0xFFFF)
|
||||||
|
*checksum = 0;
|
||||||
|
if (*checksumInv == 0xFFFF)
|
||||||
|
*checksumInv = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user