mirror of https://github.com/AxioDL/kabufuda.git
Various fixes, integrity checks, and preparation to include in URDE
This commit is contained in:
parent
98b10f9641
commit
65ecd15219
|
@ -1,12 +1,21 @@
|
||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(kabufuda)
|
project(kabufuda)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wno-multichar -fno-exceptions")
|
|
||||||
|
if(NOT TARGET urde)
|
||||||
|
if(NOT MSVC)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
include_directories(include)
|
include_directories(include)
|
||||||
|
set(KABUFUDA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE PATH "kabufuda include path" FORCE)
|
||||||
|
|
||||||
add_library(kabufuda STATIC
|
add_library(kabufuda STATIC
|
||||||
include/Card.hpp src/Card.cpp
|
include/kabufuda/Card.hpp lib/Card.cpp
|
||||||
include/Util.hpp src/Util.cpp
|
include/kabufuda/Util.hpp lib/Util.cpp
|
||||||
include/SRAM.hpp src/SRAM.cpp
|
include/kabufuda/SRAM.hpp lib/SRAM.cpp
|
||||||
include/WideStringConvert.hpp src/WideStringConvert.cpp)
|
include/kabufuda/WideStringConvert.hpp lib/WideStringConvert.cpp)
|
||||||
|
|
||||||
add_subdirectory(test)
|
if (NOT TARGET urde)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
|
@ -95,7 +95,7 @@ class File
|
||||||
uint8_t __raw[0x40];
|
uint8_t __raw[0x40];
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pop()
|
#pragma pack(pop)
|
||||||
void swapEndian();
|
void swapEndian();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -108,7 +108,7 @@ public:
|
||||||
class IFileHandle
|
class IFileHandle
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IFileHandle() {}
|
virtual ~IFileHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockAllocationTable
|
class BlockAllocationTable
|
||||||
|
@ -128,10 +128,11 @@ class BlockAllocationTable
|
||||||
};
|
};
|
||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
#pragma pop()
|
#pragma pack(pop)
|
||||||
|
|
||||||
void swapEndian();
|
void swapEndian();
|
||||||
void updateChecksum();
|
void updateChecksum();
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks));
|
explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks));
|
||||||
|
@ -160,10 +161,11 @@ class Directory
|
||||||
};
|
};
|
||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
#pragma pop()
|
#pragma pack(pop)
|
||||||
|
|
||||||
void swapEndian();
|
void swapEndian();
|
||||||
void updateChecksum();
|
void updateChecksum();
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Directory();
|
Directory();
|
||||||
|
@ -199,7 +201,7 @@ class Card
|
||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pop()
|
#pragma pack(pop)
|
||||||
|
|
||||||
SystemString m_filename;
|
SystemString m_filename;
|
||||||
FILE* m_fileHandle = nullptr;
|
FILE* m_fileHandle = nullptr;
|
||||||
|
@ -237,7 +239,7 @@ public:
|
||||||
void deleteFile(const std::unique_ptr<IFileHandle>& fh);
|
void deleteFile(const std::unique_ptr<IFileHandle>& fh);
|
||||||
void write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t size);
|
void write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t size);
|
||||||
void read(const std::unique_ptr<IFileHandle>& fh, void* dst, size_t size);
|
void read(const std::unique_ptr<IFileHandle>& fh, void* dst, size_t size);
|
||||||
void seek(const std::unique_ptr<IFileHandle>& fh, uint32_t pos, SeekOrigin whence);
|
void seek(const std::unique_ptr<IFileHandle>& fh, int32_t pos, SeekOrigin whence);
|
||||||
/**
|
/**
|
||||||
* @brief Sets the current game, if not null any openFile requests will only return files that match this game
|
* @brief Sets the current game, if not null any openFile requests will only return files that match this game
|
||||||
* @param game The target game id, e.g "GM8E"
|
* @param game The target game id, e.g "GM8E"
|
||||||
|
@ -287,7 +289,7 @@ public:
|
||||||
|
|
||||||
void commit();
|
void commit();
|
||||||
|
|
||||||
operator bool() const { return m_fileHandle != nullptr; }
|
operator bool() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -297,7 +299,7 @@ public:
|
||||||
* @param checksum
|
* @param checksum
|
||||||
* @param checksumInv
|
* @param checksumInv
|
||||||
*/
|
*/
|
||||||
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
void calculateChecksum(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __CARD_HPP__
|
#endif // __CARD_HPP__
|
|
@ -1,5 +1,5 @@
|
||||||
#include "Card.hpp"
|
#include "kabufuda/Card.hpp"
|
||||||
#include "SRAM.hpp"
|
#include "kabufuda/SRAM.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -8,13 +8,17 @@
|
||||||
namespace kabufuda
|
namespace kabufuda
|
||||||
{
|
{
|
||||||
|
|
||||||
|
IFileHandle::~IFileHandle()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
class FileHandle : public IFileHandle
|
class FileHandle : public IFileHandle
|
||||||
{
|
{
|
||||||
friend class Card;
|
friend class Card;
|
||||||
const char* game;
|
const char* game;
|
||||||
const char* maker;
|
const char* maker;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
uint32_t offset =0;
|
int32_t offset =0;
|
||||||
public:
|
public:
|
||||||
FileHandle() = default;
|
FileHandle() = default;
|
||||||
FileHandle(const char* game, const char* maker, const char* filename)
|
FileHandle(const char* game, const char* maker, const char* filename)
|
||||||
|
@ -22,8 +26,13 @@ public:
|
||||||
maker(maker),
|
maker(maker),
|
||||||
filename(filename)
|
filename(filename)
|
||||||
{}
|
{}
|
||||||
|
virtual ~FileHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FileHandle::~FileHandle()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
void Card::swapEndian()
|
void Card::swapEndian()
|
||||||
{
|
{
|
||||||
m_formatTime = SBig(m_formatTime);
|
m_formatTime = SBig(m_formatTime);
|
||||||
|
@ -62,6 +71,22 @@ Card::Card(const SystemString& filename, const char* game, const char* maker)
|
||||||
fread(m_dirBackup.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_dirBackup.__raw, 1, BlockSize, m_fileHandle);
|
||||||
fread(m_bat.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_bat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
fread(m_batBackup.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_batBackup.__raw, 1, BlockSize, m_fileHandle);
|
||||||
|
|
||||||
|
m_dir.swapEndian();
|
||||||
|
m_dirBackup.swapEndian();
|
||||||
|
m_bat.swapEndian();
|
||||||
|
m_batBackup.swapEndian();
|
||||||
|
|
||||||
|
/* Check for data integrity, restoring valid data in case of corruption if possible */
|
||||||
|
if (!m_dir.valid() && m_dirBackup.valid())
|
||||||
|
m_dir = m_dirBackup;
|
||||||
|
else if (!m_dirBackup.valid() && m_dir.valid())
|
||||||
|
m_dirBackup = m_dir;
|
||||||
|
if (!m_bat.valid() && m_batBackup.valid())
|
||||||
|
m_bat = m_batBackup;
|
||||||
|
else if (!m_batBackup.valid() && m_bat.valid())
|
||||||
|
m_batBackup = m_bat;
|
||||||
|
|
||||||
if (m_dir.m_updateCounter > m_dirBackup.m_updateCounter)
|
if (m_dir.m_updateCounter > m_dirBackup.m_updateCounter)
|
||||||
{
|
{
|
||||||
m_currentDir = &m_dir;
|
m_currentDir = &m_dir;
|
||||||
|
@ -83,10 +108,7 @@ Card::Card(const SystemString& filename, const char* game, const char* maker)
|
||||||
m_currentBat = &m_batBackup;
|
m_currentBat = &m_batBackup;
|
||||||
m_previousBat = &m_bat;
|
m_previousBat = &m_bat;
|
||||||
}
|
}
|
||||||
m_currentDir->swapEndian();
|
|
||||||
m_previousDir->swapEndian();
|
|
||||||
m_currentBat->swapEndian();
|
|
||||||
m_previousBat->swapEndian();
|
|
||||||
/* Close and reopen in read/write mode */
|
/* Close and reopen in read/write mode */
|
||||||
fclose(m_fileHandle);
|
fclose(m_fileHandle);
|
||||||
m_fileHandle = Fopen(m_filename.c_str(), _S("r+"));
|
m_fileHandle = Fopen(m_filename.c_str(), _S("r+"));
|
||||||
|
@ -113,46 +135,26 @@ void Card::updateDirAndBat()
|
||||||
{
|
{
|
||||||
Directory updateDir = *m_currentDir;
|
Directory updateDir = *m_currentDir;
|
||||||
updateDir.m_updateCounter++;
|
updateDir.m_updateCounter++;
|
||||||
|
|
||||||
*m_previousDir = updateDir;
|
*m_previousDir = updateDir;
|
||||||
if (m_previousDir == &m_dir)
|
std::swap(m_currentDir, m_previousDir);
|
||||||
{
|
|
||||||
m_currentDir = &m_dir;
|
|
||||||
m_previousDir = &m_dirBackup;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_currentDir = &m_dirBackup;
|
|
||||||
m_previousDir = &m_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockAllocationTable updateBat = *m_currentBat;
|
BlockAllocationTable updateBat = *m_currentBat;
|
||||||
updateBat.m_updateCounter++;
|
updateBat.m_updateCounter++;
|
||||||
|
|
||||||
*m_previousBat = updateBat;
|
*m_previousBat = updateBat;
|
||||||
if (m_previousBat == &m_bat)
|
std::swap(m_currentBat, m_previousBat);
|
||||||
{
|
|
||||||
m_currentBat = &m_bat;
|
|
||||||
m_previousBat = &m_batBackup;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_currentBat = &m_batBackup;
|
|
||||||
m_previousBat = &m_bat;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
File* f = m_currentDir->getFirstFreeFile(m_game, m_maker, filename);
|
File* f = m_currentDir->getFirstFreeFile(m_game, m_maker, filename);
|
||||||
uint16_t block = m_currentBat->allocateBlocks(size / BlockSize, m_maxBlock);
|
uint16_t block = m_currentBat->allocateBlocks(uint16_t(size / BlockSize), m_maxBlock);
|
||||||
if (f && block != 0xFFFF)
|
if (f && block != 0xFFFF)
|
||||||
{
|
{
|
||||||
f->m_modifiedTime = getGCTime();
|
f->m_modifiedTime = uint32_t(getGCTime());
|
||||||
f->m_firstBlock = block;
|
f->m_firstBlock = block;
|
||||||
f->m_blockCount = size / BlockSize;
|
f->m_blockCount = uint16_t(size / BlockSize);
|
||||||
|
|
||||||
updateDirAndBat();
|
|
||||||
|
|
||||||
return std::unique_ptr<FileHandle>(new FileHandle(m_game, m_maker, filename));
|
return std::unique_ptr<FileHandle>(new FileHandle(m_game, m_maker, filename));
|
||||||
}
|
}
|
||||||
|
@ -161,6 +163,7 @@ std::unique_ptr<IFileHandle> Card::createFile(const char* filename, size_t size)
|
||||||
|
|
||||||
void Card::deleteFile(const std::unique_ptr<IFileHandle> &fh)
|
void Card::deleteFile(const std::unique_ptr<IFileHandle> &fh)
|
||||||
{
|
{
|
||||||
|
updateDirAndBat();
|
||||||
if (!fh)
|
if (!fh)
|
||||||
return;
|
return;
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
|
@ -175,7 +178,6 @@ void Card::deleteFile(const std::unique_ptr<IFileHandle> &fh)
|
||||||
}
|
}
|
||||||
*m_currentDir->getFile(f->game, f->maker, f->filename) = File();
|
*m_currentDir->getFile(f->game, f->maker, f->filename) = File();
|
||||||
|
|
||||||
updateDirAndBat();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t size)
|
void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t size)
|
||||||
|
@ -187,11 +189,14 @@ void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t
|
||||||
{
|
{
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
File* file = m_currentDir->getFile(f->game, f->maker, f->filename);
|
File* file = m_currentDir->getFile(f->game, f->maker, f->filename);
|
||||||
|
if (!file)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Block handling is a little different from cache handling,
|
/* Block handling is a little different from cache handling,
|
||||||
* since each block can be in an arbitrary location we must
|
* since each block can be in an arbitrary location we must
|
||||||
* first find our starting block.
|
* first find our starting block.
|
||||||
*/
|
*/
|
||||||
const uint16_t blockId = (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_currentBat->getNextBlock(block);
|
||||||
|
@ -199,13 +204,13 @@ void Card::write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t
|
||||||
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;
|
||||||
uint32_t blockOffset = f->offset % BlockSize;
|
uint32_t blockOffset = f->offset % BlockSize;
|
||||||
uint32_t rem = size;
|
size_t rem = size;
|
||||||
while (rem)
|
while (rem)
|
||||||
{
|
{
|
||||||
if (curBlock == 0xFFFF)
|
if (curBlock == 0xFFFF)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t cacheSize = rem;
|
size_t cacheSize = rem;
|
||||||
if (cacheSize + blockOffset > BlockSize)
|
if (cacheSize + blockOffset > BlockSize)
|
||||||
cacheSize = BlockSize - blockOffset;
|
cacheSize = BlockSize - blockOffset;
|
||||||
uint32_t offset = (curBlock * BlockSize) + blockOffset;
|
uint32_t offset = (curBlock * BlockSize) + blockOffset;
|
||||||
|
@ -233,11 +238,13 @@ void Card::read(const std::unique_ptr<IFileHandle> &fh, void *dst, size_t size)
|
||||||
{
|
{
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
File* file = m_currentDir->getFile(f->game, f->maker, f->filename);
|
File* file = m_currentDir->getFile(f->game, f->maker, f->filename);
|
||||||
|
if (!file)
|
||||||
|
return;
|
||||||
/* Block handling is a little different from cache handling,
|
/* Block handling is a little different from cache handling,
|
||||||
* since each block can be in an arbitrary location we must
|
* since each block can be in an arbitrary location we must
|
||||||
* first find our starting block.
|
* first find our starting block.
|
||||||
*/
|
*/
|
||||||
const uint16_t blockId = (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_currentBat->getNextBlock(block);
|
||||||
|
@ -245,13 +252,13 @@ void Card::read(const std::unique_ptr<IFileHandle> &fh, void *dst, size_t size)
|
||||||
uint8_t* tmpBuf = reinterpret_cast<uint8_t*>(dst);
|
uint8_t* tmpBuf = reinterpret_cast<uint8_t*>(dst);
|
||||||
uint16_t curBlock = block;
|
uint16_t curBlock = block;
|
||||||
uint32_t blockOffset = f->offset % BlockSize;
|
uint32_t blockOffset = f->offset % BlockSize;
|
||||||
uint32_t rem = size;
|
size_t rem = size;
|
||||||
while (rem)
|
while (rem)
|
||||||
{
|
{
|
||||||
if (curBlock == 0xFFFF)
|
if (curBlock == 0xFFFF)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t cacheSize = rem;
|
size_t cacheSize = rem;
|
||||||
if (cacheSize + blockOffset > BlockSize)
|
if (cacheSize + blockOffset > BlockSize)
|
||||||
cacheSize = BlockSize - blockOffset;
|
cacheSize = BlockSize - blockOffset;
|
||||||
uint32_t offset = (curBlock * BlockSize) + blockOffset;
|
uint32_t offset = (curBlock * BlockSize) + blockOffset;
|
||||||
|
@ -270,14 +277,16 @@ void Card::read(const std::unique_ptr<IFileHandle> &fh, void *dst, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::seek(const std::unique_ptr<IFileHandle> &fh, uint32_t pos, SeekOrigin whence)
|
void Card::seek(const std::unique_ptr<IFileHandle> &fh, int32_t pos, SeekOrigin whence)
|
||||||
{
|
{
|
||||||
if (!fh)
|
if (!fh)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
File* file = m_currentDir->getFile(f->game, f->maker, f->filename);
|
File* file = m_currentDir->getFile(f->game, f->maker, f->filename);
|
||||||
uint32_t oldOff = f->offset;
|
if (!file)
|
||||||
|
return;
|
||||||
|
|
||||||
switch(whence)
|
switch(whence)
|
||||||
{
|
{
|
||||||
case SeekOrigin::Begin:
|
case SeekOrigin::Begin:
|
||||||
|
@ -287,7 +296,7 @@ void Card::seek(const std::unique_ptr<IFileHandle> &fh, uint32_t pos, SeekOrigin
|
||||||
f->offset += pos;
|
f->offset += pos;
|
||||||
break;
|
break;
|
||||||
case SeekOrigin::End:
|
case SeekOrigin::End:
|
||||||
f->offset = (file->m_blockCount * BlockSize) - pos;
|
f->offset = int32_t(file->m_blockCount * BlockSize) - pos;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,7 +348,7 @@ void Card::getSerial(uint32_t *s0, uint32_t *s1)
|
||||||
{
|
{
|
||||||
uint32_t serial[8];
|
uint32_t serial[8];
|
||||||
for (uint32_t i = 0; i < 8; i++)
|
for (uint32_t i = 0; i < 8; i++)
|
||||||
memcpy(&serial[i], ((uint8_t*)m_serial + (i * 4)), 4);
|
memcpy(&serial[i], reinterpret_cast<uint8_t*>(m_serial + (i * 4)), 4);
|
||||||
*s0 = serial[0] ^ serial[2] ^ serial[4] ^ serial[6];
|
*s0 = serial[0] ^ serial[2] ^ serial[4] ^ serial[6];
|
||||||
*s1 = serial[1] ^ serial[3] ^ serial[5] ^ serial[7];
|
*s1 = serial[1] ^ serial[3] ^ serial[5] ^ serial[7];
|
||||||
}
|
}
|
||||||
|
@ -357,24 +366,28 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
|
||||||
m_formatTime = rand;
|
m_formatTime = rand;
|
||||||
for (int i = 0; i < 12; i++)
|
for (int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
rand = (((rand * (uint64_t)0x41c64e6d) + (uint64_t)0x3039) >> 16);
|
rand = (((rand * uint64_t(0x41c64e6d)) + uint64_t(0x3039)) >> 16);
|
||||||
m_serial[i] = (uint8_t)(g_SRAM.flash_id[uint32_t(id)][i] + (uint32_t)rand);
|
m_serial[i] = uint8_t(g_SRAM.flash_id[uint32_t(id)][i] + uint32_t(rand));
|
||||||
rand = (((rand * (uint64_t)0x41c64e6d) + (uint64_t)0x3039) >> 16);
|
rand = (((rand * uint64_t(0x41c64e6d)) + uint64_t(0x3039)) >> 16);
|
||||||
rand &= (uint64_t)0x7fffULL;
|
rand &= uint64_t(0x7fffULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sramBias = SBig(g_SRAM.counter_bias);
|
m_sramBias = int32_t(SBig(g_SRAM.counter_bias));
|
||||||
m_sramLanguage = SBig(g_SRAM.lang);
|
m_sramLanguage = uint32_t(SBig(g_SRAM.lang));
|
||||||
m_unknown = 0; /* 1 works for slot A, 0 both */
|
m_unknown = 0; /* 1 works for slot A, 0 both */
|
||||||
m_deviceId = 0;
|
m_deviceId = 0;
|
||||||
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((uint16_t*)__raw, 0xFE, &m_checksum, &m_checksumInv);
|
calculateChecksum(reinterpret_cast<uint16_t*>(__raw), 0xFE, &m_checksum, &m_checksumInv);
|
||||||
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);
|
||||||
m_batBackup = m_bat;
|
m_batBackup = m_bat;
|
||||||
|
m_currentDir = &m_dirBackup;
|
||||||
|
m_previousDir = &m_dir;
|
||||||
|
m_currentBat = &m_batBackup;
|
||||||
|
m_previousBat = &m_bat;
|
||||||
|
|
||||||
if (!m_fileHandle)
|
if (!m_fileHandle)
|
||||||
m_fileHandle = Fopen(m_filename.c_str(), _S("wb"));
|
m_fileHandle = Fopen(m_filename.c_str(), _S("wb"));
|
||||||
|
@ -409,7 +422,7 @@ uint32_t Card::getSizeMbitFromFile(const SystemString& filename)
|
||||||
{
|
{
|
||||||
Sstat stat;
|
Sstat stat;
|
||||||
Stat(filename.c_str(), &stat);
|
Stat(filename.c_str(), &stat);
|
||||||
return (stat.st_size / BlockSize) / MbitToBlocks;
|
return uint32_t(stat.st_size / BlockSize) / MbitToBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::commit()
|
void Card::commit()
|
||||||
|
@ -421,21 +434,42 @@ void Card::commit()
|
||||||
swapEndian();
|
swapEndian();
|
||||||
fwrite(__raw, 1, BlockSize, m_fileHandle);
|
fwrite(__raw, 1, BlockSize, m_fileHandle);
|
||||||
swapEndian();
|
swapEndian();
|
||||||
Directory tmpDir = *m_currentDir;
|
Directory tmpDir = m_dir;
|
||||||
|
tmpDir.updateChecksum();
|
||||||
tmpDir.swapEndian();
|
tmpDir.swapEndian();
|
||||||
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
tmpDir = *m_previousDir;
|
tmpDir = m_dirBackup;
|
||||||
|
tmpDir.updateChecksum();
|
||||||
tmpDir.swapEndian();
|
tmpDir.swapEndian();
|
||||||
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpDir.__raw, 1, BlockSize, m_fileHandle);
|
||||||
BlockAllocationTable tmpBat = *m_currentBat;
|
BlockAllocationTable tmpBat = m_bat;
|
||||||
|
tmpBat.updateChecksum();
|
||||||
tmpBat.swapEndian();
|
tmpBat.swapEndian();
|
||||||
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
tmpBat = *m_previousBat;
|
tmpBat = m_batBackup;
|
||||||
|
tmpBat.updateChecksum();
|
||||||
tmpBat.swapEndian();
|
tmpBat.swapEndian();
|
||||||
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
fwrite(tmpBat.__raw, 1, BlockSize, m_fileHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Card::operator bool() const
|
||||||
|
{
|
||||||
|
if (m_fileHandle == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint16_t ckSum, ckSumInv;
|
||||||
|
calculateChecksum(reinterpret_cast<const uint16_t*>(__raw), 0xFE, &ckSum, &ckSumInv);
|
||||||
|
if (ckSum != m_checksum || ckSumInv != m_checksumInv)
|
||||||
|
return false;
|
||||||
|
if (!m_dir.valid() && !m_dirBackup.valid())
|
||||||
|
return false;
|
||||||
|
if (!m_bat.valid() && !m_batBackup.valid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
File::File(char data[])
|
File::File(char data[])
|
||||||
{
|
{
|
||||||
memcpy(__raw, data, 0x40);
|
memcpy(__raw, data, 0x40);
|
||||||
|
@ -483,10 +517,17 @@ void BlockAllocationTable::updateChecksum()
|
||||||
calculateChecksum(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
calculateChecksum(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::BlockAllocationTable(uint32_t blockCount)
|
BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
|
||||||
{
|
{
|
||||||
memset(__raw, 0, BlockSize);
|
memset(__raw, 0, BlockSize);
|
||||||
m_freeBlocks = blockCount - FSTBlocks;
|
m_freeBlocks = uint16_t(blockCount - FSTBlocks);
|
||||||
m_lastAllocated = 4;
|
m_lastAllocated = 4;
|
||||||
updateChecksum();
|
updateChecksum();
|
||||||
}
|
}
|
||||||
|
@ -577,6 +618,13 @@ void Directory::updateChecksum()
|
||||||
calculateChecksum(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv);
|
calculateChecksum(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::Directory()
|
Directory::Directory()
|
||||||
{
|
{
|
||||||
memset(__raw, 0xFF, BlockSize);
|
memset(__raw, 0xFF, BlockSize);
|
||||||
|
@ -633,7 +681,7 @@ File* Directory::getFile(const char* game, const char* maker, const char* filena
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv)
|
void calculateChecksum(const uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv)
|
||||||
{
|
{
|
||||||
*checksum = 0;
|
*checksum = 0;
|
||||||
*checksumInv = 0;
|
*checksumInv = 0;
|
||||||
|
@ -649,5 +697,4 @@ void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t*
|
||||||
if (*checksumInv == 0xFFFF)
|
if (*checksumInv == 0xFFFF)
|
||||||
*checksumInv = 0;
|
*checksumInv = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
#include "SRAM.hpp"
|
#include "kabufuda/SRAM.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
#include "Util.hpp"
|
#include "kabufuda/Util.hpp"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda
|
|
@ -1,4 +1,4 @@
|
||||||
#include "WideStringConvert.hpp"
|
#include "kabufuda/WideStringConvert.hpp"
|
||||||
#include "utf8proc.h"
|
#include "utf8proc.h"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda
|
|
@ -1,26 +1,30 @@
|
||||||
#include "Card.hpp"
|
#include "kabufuda/Card.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main()
|
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 B");
|
std::unique_ptr<kabufuda::IFileHandle> f = mc.openFile("MetroidPrime A");
|
||||||
if (!f)
|
if (!f)
|
||||||
f = mc.createFile("MetroidPrime B", kabufuda::BlockSize);
|
f = mc.createFile("MetroidPrime A", kabufuda::BlockSize);
|
||||||
|
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
const char* test = "Metroid Prime A is Cool";
|
const char* test = "Metroid Prime A is Cool";
|
||||||
size_t len = strlen(test);
|
size_t len = strlen(test);
|
||||||
|
uint8_t data[kabufuda::BlockSize] = {};
|
||||||
|
mc.write(f, data, kabufuda::BlockSize);
|
||||||
|
mc.seek(f, 0, kabufuda::SeekOrigin::Begin);
|
||||||
mc.write(f, test, len + 1);
|
mc.write(f, test, len + 1);
|
||||||
uint16_t derp = 1234;
|
uint16_t derp = 1234;
|
||||||
|
mc.seek(f, 1, kabufuda::SeekOrigin::End);
|
||||||
mc.write(f, &derp, 2);
|
mc.write(f, &derp, 2);
|
||||||
mc.seek(f, -4, 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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue