mirror of
https://github.com/AxioDL/kabufuda.git
synced 2025-05-13 10:51:20 +00:00
Changes to support CMemoryCardSys integration
This commit is contained in:
parent
31029767c8
commit
223ea9a56e
@ -36,6 +36,7 @@ public:
|
|||||||
uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const;
|
uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const;
|
||||||
bool clear(uint16_t first, uint16_t count);
|
bool clear(uint16_t first, uint16_t count);
|
||||||
uint16_t allocateBlocks(uint16_t count, uint16_t maxBlocks);
|
uint16_t allocateBlocks(uint16_t count, uint16_t maxBlocks);
|
||||||
|
uint16_t numFreeBlocks() const { return m_freeBlocks; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif // __KABU_BLOCKALLOCATIONATABLE_HPP__
|
#endif // __KABU_BLOCKALLOCATIONATABLE_HPP__
|
||||||
|
@ -10,15 +10,94 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#define CARD_FILENAME_MAX 32
|
||||||
|
#define CARD_ICON_MAX 8
|
||||||
|
#undef NOFILE
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda
|
||||||
{
|
{
|
||||||
|
|
||||||
class IFileHandle
|
class IFileHandle
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
uint32_t idx;
|
||||||
|
IFileHandle() = default;
|
||||||
|
IFileHandle(uint32_t idx) : idx(idx) {}
|
||||||
public:
|
public:
|
||||||
|
uint32_t getFileNo() const { return idx; }
|
||||||
virtual ~IFileHandle();
|
virtual ~IFileHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ECardResult
|
||||||
|
{
|
||||||
|
CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */
|
||||||
|
FATAL_ERROR = -128,
|
||||||
|
ENCODING = -13,
|
||||||
|
NAMETOOLONG = -12,
|
||||||
|
INSSPACE = -9,
|
||||||
|
NOENT = -8,
|
||||||
|
EXIST = -7,
|
||||||
|
BROKEN = -6,
|
||||||
|
IOERROR = -5,
|
||||||
|
NOFILE = -4,
|
||||||
|
NOCARD = -3,
|
||||||
|
WRONGDEVICE = -2,
|
||||||
|
BUSY = -1,
|
||||||
|
READY = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProbeResults
|
||||||
|
{
|
||||||
|
ECardResult x0_error;
|
||||||
|
uint32_t x4_cardSize; /* in megabits */
|
||||||
|
uint32_t x8_sectorSize; /* in bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CardStat
|
||||||
|
{
|
||||||
|
/* read-only (Set by CARDGetStatus) */
|
||||||
|
char x0_fileName[CARD_FILENAME_MAX];
|
||||||
|
uint32_t x20_length;
|
||||||
|
uint32_t x24_time; /* seconds since 01/01/2000 midnight */
|
||||||
|
uint8_t x28_gameName[4];
|
||||||
|
uint8_t x2c_company[2];
|
||||||
|
|
||||||
|
/* read/write (Set by CARDGetStatus/CARDSetStatus) */
|
||||||
|
uint8_t x2e_bannerFormat;
|
||||||
|
uint8_t x2f___padding;
|
||||||
|
uint32_t x30_iconAddr; /* offset to the banner, bannerTlut, icon, iconTlut data set. */
|
||||||
|
uint16_t x34_iconFormat;
|
||||||
|
uint16_t x36_iconSpeed;
|
||||||
|
uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */
|
||||||
|
|
||||||
|
/* read-only (Set by CARDGetStatus) */
|
||||||
|
uint32_t x3c_offsetBanner;
|
||||||
|
uint32_t x40_offsetBannerTlut;
|
||||||
|
uint32_t x44_offsetIcon[CARD_ICON_MAX];
|
||||||
|
uint32_t x64_offsetIconTlut;
|
||||||
|
uint32_t x68_offsetData;
|
||||||
|
|
||||||
|
uint32_t GetFileLength() const { return x20_length; }
|
||||||
|
uint32_t GetTime() const { return x24_time; }
|
||||||
|
EImageFormat GetBannerFormat() const { return EImageFormat(x2e_bannerFormat & 0x3); }
|
||||||
|
void SetBannerFormat(EImageFormat fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | uint8_t(fmt); }
|
||||||
|
EImageFormat GetIconFormat(int idx) const { return EImageFormat((x34_iconFormat >> (idx * 2)) & 0x3); }
|
||||||
|
void SetIconFormat(EImageFormat fmt, int idx)
|
||||||
|
{
|
||||||
|
x34_iconFormat &= ~(0x3 << (idx * 2));
|
||||||
|
x34_iconFormat |= uint16_t(fmt) << (idx * 2);
|
||||||
|
}
|
||||||
|
void SetIconSpeed(EAnimationSpeed sp, int idx)
|
||||||
|
{
|
||||||
|
x36_iconSpeed &= ~(0x3 << (idx * 2));
|
||||||
|
x36_iconSpeed |= uint16_t(sp) << (idx * 2);
|
||||||
|
}
|
||||||
|
uint32_t GetIconAddr() const { return x30_iconAddr; }
|
||||||
|
void SetIconAddr(uint32_t addr) { x30_iconAddr = addr; }
|
||||||
|
uint32_t GetCommentAddr() const { return x38_commentAddr; }
|
||||||
|
void SetCommentAddr(uint32_t addr) { x38_commentAddr = addr; }
|
||||||
|
};
|
||||||
|
|
||||||
class Card
|
class Card
|
||||||
{
|
{
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
@ -62,6 +141,7 @@ class Card
|
|||||||
void _updateDirAndBat();
|
void _updateDirAndBat();
|
||||||
void _updateChecksum();
|
void _updateChecksum();
|
||||||
File* _fileFromHandle(const std::unique_ptr<IFileHandle>& fh) const;
|
File* _fileFromHandle(const std::unique_ptr<IFileHandle>& fh) const;
|
||||||
|
void _deleteFile(File& f);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Card();
|
Card();
|
||||||
@ -85,12 +165,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::unique_ptr<IFileHandle> openFile(const char* filename);
|
std::unique_ptr<IFileHandle> openFile(const char* filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief openFile
|
||||||
|
* @param fileno
|
||||||
|
*/
|
||||||
|
std::unique_ptr<IFileHandle> openFile(uint32_t fileno);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief createFile
|
* @brief createFile
|
||||||
* @param filename
|
* @param filename
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<IFileHandle> createFile(const char* filename, size_t size);
|
ECardResult createFile(const char* filename, size_t size, std::unique_ptr<IFileHandle>& handleOut);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief firstFile
|
* @brief firstFile
|
||||||
@ -104,18 +190,39 @@ public:
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<IFileHandle> nextFile(const std::unique_ptr<IFileHandle>& cur);
|
std::unique_ptr<IFileHandle> nextFile(const std::unique_ptr<IFileHandle>& cur);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief getFilename
|
* @brief getFilename
|
||||||
* @param fh
|
* @param fh
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
const char* getFilename(const std::unique_ptr<IFileHandle>& fh);
|
const char* getFilename(const std::unique_ptr<IFileHandle>& fh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief deleteFile
|
* @brief deleteFile
|
||||||
* @param fh
|
* @param fh
|
||||||
*/
|
*/
|
||||||
void deleteFile(const std::unique_ptr<IFileHandle>& fh);
|
void deleteFile(const std::unique_ptr<IFileHandle>& fh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deleteFile
|
||||||
|
* @param filename
|
||||||
|
*/
|
||||||
|
ECardResult deleteFile(const char* filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief deleteFile
|
||||||
|
* @param fileno
|
||||||
|
*/
|
||||||
|
ECardResult deleteFile(uint32_t fileno);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief renameFile
|
||||||
|
* @param oldName
|
||||||
|
* @param newName
|
||||||
|
*/
|
||||||
|
ECardResult renameFile(const char* oldName, const char* newName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief write
|
* @brief write
|
||||||
* @param fh
|
* @param fh
|
||||||
@ -344,21 +451,27 @@ public:
|
|||||||
* @param checksum The checksum of the system header
|
* @param checksum The checksum of the system header
|
||||||
* @param inverse The inverser checksum of the system header
|
* @param inverse The inverser checksum of the system header
|
||||||
*/
|
*/
|
||||||
void getChecksum(uint16_t* checksum, uint16_t* inverse);
|
void getChecksum(uint16_t& checksum, uint16_t& inverse);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the available storage and directory space
|
||||||
|
* @param bytesNotUsed Number of free bytes out
|
||||||
|
* @param filesNotUsed Number of free files out
|
||||||
|
*/
|
||||||
|
void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Formats the memory card and assigns a new serial
|
* @brief Formats the memory card and assigns a new serial
|
||||||
* @param size The desired size of the file @sa ECardSize
|
* @param size The desired size of the file @sa ECardSize
|
||||||
* @param encoding The desired encoding @sa EEncoding
|
* @param encoding The desired encoding @sa EEncoding
|
||||||
*/
|
*/
|
||||||
void format(EDeviceId deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII);
|
void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the size of the file in Megabits from a file on disk, useful for determining filesize ahead of
|
* @brief Returns basic stats about a card image without opening a handle
|
||||||
* time.
|
* @return ProbeResults structure
|
||||||
* @return Size of file in Megabits
|
|
||||||
*/
|
*/
|
||||||
static uint32_t getSizeMbitFromFile(const SystemString& filename);
|
static ProbeResults probeCardFile(const SystemString& filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes any changes to the Card instance immediately to disk. <br />
|
* @brief Writes any changes to the Card instance immediately to disk. <br />
|
||||||
@ -366,7 +479,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void commit();
|
void commit();
|
||||||
|
|
||||||
operator bool() const;
|
/**
|
||||||
|
* @brief Gets card-scope error state
|
||||||
|
* @return READY, BROKEN, or NOCARD
|
||||||
|
*/
|
||||||
|
ECardResult getError() const;
|
||||||
|
|
||||||
|
operator bool() const { return getError() == ECardResult::READY; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,9 +54,9 @@ enum class SeekOrigin
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The EDeviceId enum
|
* @brief The ECardSlot enum
|
||||||
*/
|
*/
|
||||||
enum class EDeviceId : uint16_t
|
enum class ECardSlot : uint16_t
|
||||||
{
|
{
|
||||||
SlotA,
|
SlotA,
|
||||||
SlotB
|
SlotB
|
||||||
|
@ -33,6 +33,8 @@ public:
|
|||||||
void operator=(const Directory& other);
|
void operator=(const Directory& other);
|
||||||
~Directory();
|
~Directory();
|
||||||
|
|
||||||
|
bool hasFreeFile() const;
|
||||||
|
int32_t numFreeFiles() const;
|
||||||
File* getFirstFreeFile(const char* game, const char* maker, const char* filename);
|
File* getFirstFreeFile(const char* game, const char* maker, const char* filename);
|
||||||
File* getFirstNonFreeFile(uint32_t start, const char* game, const char* maker);
|
File* getFirstNonFreeFile(uint32_t start, const char* game, const char* maker);
|
||||||
File* getFile(const char* game, const char* maker, const char* filename);
|
File* getFile(const char* game, const char* maker, const char* filename);
|
||||||
|
@ -127,7 +127,9 @@ static inline double SBig(double val)
|
|||||||
int64_t ival = bswap64(*((int64_t*)(&val)));
|
int64_t ival = bswap64(*((int64_t*)(&val)));
|
||||||
return *((double*)(&ival));
|
return *((double*)(&ival));
|
||||||
}
|
}
|
||||||
|
#ifndef SBIG
|
||||||
#define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
|
#define SBIG(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline int16_t SLittle(int16_t val) { return val; }
|
static inline int16_t SLittle(int16_t val) { return val; }
|
||||||
static inline uint16_t SLittle(uint16_t val) { return val; }
|
static inline uint16_t SLittle(uint16_t val) { return val; }
|
||||||
@ -137,7 +139,9 @@ static inline int64_t SLittle(int64_t val) { return val; }
|
|||||||
static inline uint64_t SLittle(uint64_t val) { return val; }
|
static inline uint64_t SLittle(uint64_t val) { return val; }
|
||||||
static inline float SLittle(float val) { return val; }
|
static inline float SLittle(float val) { return val; }
|
||||||
static inline double SLittle(double val) { return val; }
|
static inline double SLittle(double val) { return val; }
|
||||||
|
#ifndef SLITTLE
|
||||||
#define SLITTLE(q) (q)
|
#define SLITTLE(q) (q)
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
static inline int16_t SLittle(int16_t val) { return bswap16(val); }
|
static inline int16_t SLittle(int16_t val) { return bswap16(val); }
|
||||||
static inline uint16_t SLittle(uint16_t val) { return bswap16(val); }
|
static inline uint16_t SLittle(uint16_t val) { return bswap16(val); }
|
||||||
@ -155,7 +159,9 @@ static inline double SLittle(double val)
|
|||||||
int64_t ival = bswap64(*((int64_t*)(&val)));
|
int64_t ival = bswap64(*((int64_t*)(&val)));
|
||||||
return *((double*)(&ival));
|
return *((double*)(&ival));
|
||||||
}
|
}
|
||||||
|
#ifndef SLITTLE
|
||||||
#define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
|
#define SLITTLE(q) (((q)&0x000000FF) << 24 | ((q)&0x0000FF00) << 8 | ((q)&0x00FF0000) >> 8 | ((q)&0xFF000000) >> 24)
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline int16_t SBig(int16_t val) { return val; }
|
static inline int16_t SBig(int16_t val) { return val; }
|
||||||
static inline uint16_t SBig(uint16_t val) { return val; }
|
static inline uint16_t SBig(uint16_t val) { return val; }
|
||||||
@ -165,8 +171,10 @@ static inline int64_t SBig(int64_t val) { return val; }
|
|||||||
static inline uint64_t SBig(uint64_t val) { return val; }
|
static inline uint64_t SBig(uint64_t val) { return val; }
|
||||||
static inline float SBig(float val) { return val; }
|
static inline float SBig(float val) { return val; }
|
||||||
static inline double SBig(double val) { return val; }
|
static inline double SBig(double val) { return val; }
|
||||||
|
#ifndef SBIG
|
||||||
#define SBIG(q) (q)
|
#define SBIG(q) (q)
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if CARD_UCS2
|
#if CARD_UCS2
|
||||||
typedef wchar_t SystemChar;
|
typedef wchar_t SystemChar;
|
||||||
|
@ -43,7 +43,7 @@ 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)))
|
||||||
return 0;
|
return 0xFFFF;
|
||||||
|
|
||||||
return m_map[block - FSTBlocks];
|
return m_map[block - FSTBlocks];
|
||||||
}
|
}
|
||||||
|
@ -8,17 +8,18 @@
|
|||||||
namespace kabufuda
|
namespace kabufuda
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#define ROUND_UP_8192(val) (((val) + 8191) & ~8191)
|
||||||
|
|
||||||
IFileHandle::~IFileHandle() {}
|
IFileHandle::~IFileHandle() {}
|
||||||
|
|
||||||
class FileHandle : public IFileHandle
|
class FileHandle : public IFileHandle
|
||||||
{
|
{
|
||||||
friend class Card;
|
friend class Card;
|
||||||
uint32_t idx;
|
|
||||||
int32_t offset = 0;
|
int32_t offset = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FileHandle() = default;
|
FileHandle() = default;
|
||||||
FileHandle(uint32_t idx) : idx(idx) {}
|
FileHandle(uint32_t idx) : IFileHandle(idx) {}
|
||||||
virtual ~FileHandle();
|
virtual ~FileHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -109,7 +110,6 @@ 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);
|
rewind(m_fileHandle);
|
||||||
}
|
}
|
||||||
@ -129,12 +129,18 @@ std::unique_ptr<IFileHandle> Card::openFile(const char* filename)
|
|||||||
int32_t idx = m_currentDir->indexForFile(f);
|
int32_t idx = m_currentDir->indexForFile(f);
|
||||||
if (f && idx != -1)
|
if (f && idx != -1)
|
||||||
{
|
{
|
||||||
|
return std::make_unique<FileHandle>(idx);
|
||||||
return std::unique_ptr<IFileHandle>(new FileHandle(idx));
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<IFileHandle> Card::openFile(uint32_t fileno)
|
||||||
|
{
|
||||||
|
if (fileno >= 127)
|
||||||
|
return nullptr;
|
||||||
|
return std::make_unique<FileHandle>(fileno);
|
||||||
|
}
|
||||||
|
|
||||||
void Card::_updateDirAndBat()
|
void Card::_updateDirAndBat()
|
||||||
{
|
{
|
||||||
Directory updateDir = *m_currentDir;
|
Directory updateDir = *m_currentDir;
|
||||||
@ -168,27 +174,40 @@ File* Card::_fileFromHandle(const std::unique_ptr<IFileHandle>& fh) const
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<IFileHandle> Card::createFile(const char* filename, size_t size)
|
ECardResult Card::createFile(const char* filename, size_t size,
|
||||||
|
std::unique_ptr<IFileHandle>& handleOut)
|
||||||
{
|
{
|
||||||
|
if (strlen(filename) > 32)
|
||||||
|
return ECardResult::NAMETOOLONG;
|
||||||
|
if (m_currentDir->getFile(m_game, m_maker, filename))
|
||||||
|
return ECardResult::EXIST;
|
||||||
|
uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize;
|
||||||
|
if (neededBlocks > m_currentBat->numFreeBlocks())
|
||||||
|
return ECardResult::INSSPACE;
|
||||||
|
if (!m_currentDir->hasFreeFile())
|
||||||
|
return ECardResult::NOENT;
|
||||||
|
|
||||||
_updateDirAndBat();
|
_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(uint16_t(size / BlockSize), m_maxBlock);
|
uint16_t block = m_currentBat->allocateBlocks(neededBlocks, m_maxBlock);
|
||||||
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 = uint16_t(size / BlockSize);
|
f->m_blockCount = neededBlocks;
|
||||||
|
|
||||||
return std::unique_ptr<IFileHandle>(new FileHandle(m_currentDir->indexForFile(f)));
|
handleOut = std::make_unique<FileHandle>(m_currentDir->indexForFile(f));
|
||||||
|
return ECardResult::READY;
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
|
return ECardResult::FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
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_currentDir->getFirstNonFreeFile(0, m_game, m_maker);
|
||||||
if (f)
|
if (f)
|
||||||
return std::unique_ptr<IFileHandle>(new FileHandle(m_currentDir->indexForFile(f)));
|
return std::make_unique<FileHandle>(m_currentDir->indexForFile(f));
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -202,7 +221,7 @@ std::unique_ptr<IFileHandle> Card::nextFile(const std::unique_ptr<IFileHandle>&
|
|||||||
File* next = m_currentDir->getFirstNonFreeFile(handle->idx + 1, m_game, m_maker);
|
File* next = m_currentDir->getFirstNonFreeFile(handle->idx + 1, m_game, m_maker);
|
||||||
if (!next)
|
if (!next)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return std::unique_ptr<IFileHandle>(new FileHandle(m_currentDir->indexForFile(next)));
|
return std::make_unique<FileHandle>(m_currentDir->indexForFile(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Card::getFilename(const std::unique_ptr<IFileHandle>& fh)
|
const char* Card::getFilename(const std::unique_ptr<IFileHandle>& fh)
|
||||||
@ -213,14 +232,9 @@ const char* Card::getFilename(const std::unique_ptr<IFileHandle>& fh)
|
|||||||
return f->m_filename;
|
return f->m_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::deleteFile(const std::unique_ptr<IFileHandle>& fh)
|
void Card::_deleteFile(File& f)
|
||||||
{
|
{
|
||||||
_updateDirAndBat();
|
uint16_t block = f.m_firstBlock;
|
||||||
if (!fh)
|
|
||||||
return;
|
|
||||||
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
|
||||||
uint16_t block = m_currentDir->getFile(f->idx)->m_firstBlock;
|
|
||||||
|
|
||||||
while (block != 0xFFFF)
|
while (block != 0xFFFF)
|
||||||
{
|
{
|
||||||
/* TODO: add a fragmentation check */
|
/* TODO: add a fragmentation check */
|
||||||
@ -228,7 +242,52 @@ void Card::deleteFile(const std::unique_ptr<IFileHandle>& fh)
|
|||||||
m_currentBat->clear(block, 1);
|
m_currentBat->clear(block, 1);
|
||||||
block = nextBlock;
|
block = nextBlock;
|
||||||
}
|
}
|
||||||
*m_currentDir->getFile(f->idx) = File();
|
f = File();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Card::deleteFile(const std::unique_ptr<IFileHandle>& fh)
|
||||||
|
{
|
||||||
|
_updateDirAndBat();
|
||||||
|
if (!fh)
|
||||||
|
return;
|
||||||
|
FileHandle* f = dynamic_cast<FileHandle*>(fh.get());
|
||||||
|
_deleteFile(*m_currentDir->getFile(f->idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
ECardResult Card::deleteFile(const char* filename)
|
||||||
|
{
|
||||||
|
_updateDirAndBat();
|
||||||
|
File* f = m_currentDir->getFile(m_game, m_maker, filename);
|
||||||
|
if (!f)
|
||||||
|
return ECardResult::NOFILE;
|
||||||
|
|
||||||
|
_deleteFile(*f);
|
||||||
|
return ECardResult::READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ECardResult Card::deleteFile(uint32_t fileno)
|
||||||
|
{
|
||||||
|
_updateDirAndBat();
|
||||||
|
File* f = m_currentDir->getFile(fileno);
|
||||||
|
if (!f)
|
||||||
|
return ECardResult::NOFILE;
|
||||||
|
|
||||||
|
_deleteFile(*f);
|
||||||
|
return ECardResult::READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ECardResult Card::renameFile(const char* oldName, const char* newName)
|
||||||
|
{
|
||||||
|
if (strlen(newName) > 32)
|
||||||
|
return ECardResult::NAMETOOLONG;
|
||||||
|
|
||||||
|
_updateDirAndBat();
|
||||||
|
File* f = m_currentDir->getFile(m_game, m_maker, oldName);
|
||||||
|
if (!f)
|
||||||
|
return ECardResult::NOFILE;
|
||||||
|
|
||||||
|
strncpy(f->m_filename, newName, 32);
|
||||||
|
return ECardResult::READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@ -564,7 +623,8 @@ bool Card::copyFileTo(const std::unique_ptr<IFileHandle>& fh, Card& dest)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Try to allocate a new file */
|
/* Try to allocate a new file */
|
||||||
std::unique_ptr<IFileHandle> tmpHandle = dest.createFile(toCopy->m_filename, toCopy->m_blockCount * BlockSize);
|
std::unique_ptr<IFileHandle> tmpHandle;
|
||||||
|
dest.createFile(toCopy->m_filename, toCopy->m_blockCount * BlockSize, tmpHandle);
|
||||||
if (!tmpHandle)
|
if (!tmpHandle)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -656,13 +716,19 @@ void Card::getSerial(uint64_t& serial)
|
|||||||
_swapEndian();
|
_swapEndian();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::getChecksum(uint16_t* checksum, uint16_t* inverse)
|
void Card::getChecksum(uint16_t& checksum, uint16_t& inverse)
|
||||||
{
|
{
|
||||||
*checksum = m_checksum;
|
checksum = m_checksum;
|
||||||
*inverse = m_checksumInv;
|
inverse = m_checksumInv;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
|
void Card::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed)
|
||||||
|
{
|
||||||
|
bytesNotUsed = m_currentBat->numFreeBlocks() * 0x2000;
|
||||||
|
filesNotUsed = m_currentDir->numFreeFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Card::format(ECardSlot id, ECardSize size, EEncoding encoding)
|
||||||
{
|
{
|
||||||
memset(__raw, 0xFF, BlockSize);
|
memset(__raw, 0xFF, BlockSize);
|
||||||
uint64_t rand = uint64_t(getGCTime());
|
uint64_t rand = uint64_t(getGCTime());
|
||||||
@ -723,11 +789,12 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Card::getSizeMbitFromFile(const SystemString& filename)
|
ProbeResults Card::probeCardFile(const SystemString& filename)
|
||||||
{
|
{
|
||||||
Sstat stat;
|
Sstat stat;
|
||||||
Stat(filename.c_str(), &stat);
|
if (Stat(filename.c_str(), &stat))
|
||||||
return uint32_t(stat.st_size / BlockSize) / MbitToBlocks;
|
return { ECardResult::NOCARD, 0, 0 };
|
||||||
|
return { ECardResult::READY, uint32_t(stat.st_size / BlockSize) / MbitToBlocks, 0x2000 };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::commit()
|
void Card::commit()
|
||||||
@ -758,22 +825,22 @@ void Card::commit()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Card::operator bool() const
|
ECardResult Card::getError() const
|
||||||
{
|
{
|
||||||
if (m_fileHandle == nullptr)
|
if (m_fileHandle == nullptr)
|
||||||
return false;
|
return ECardResult::NOCARD;
|
||||||
|
|
||||||
uint16_t ckSum, ckSumInv;
|
uint16_t ckSum, ckSumInv;
|
||||||
Card tmp = *this;
|
Card tmp = *this;
|
||||||
tmp._swapEndian();
|
tmp._swapEndian();
|
||||||
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw), 0xFE, &ckSum, &ckSumInv);
|
calculateChecksumBE(reinterpret_cast<const uint16_t*>(tmp.__raw), 0xFE, &ckSum, &ckSumInv);
|
||||||
if (SBig(ckSum) != m_checksum || SBig(ckSumInv) != m_checksumInv)
|
if (SBig(ckSum) != m_checksum || SBig(ckSumInv) != m_checksumInv)
|
||||||
return false;
|
return ECardResult::BROKEN;
|
||||||
if (!m_dir.valid() && !m_dirBackup.valid())
|
if (!m_dir.valid() && !m_dirBackup.valid())
|
||||||
return false;
|
return ECardResult::BROKEN;
|
||||||
if (!m_bat.valid() && !m_batBackup.valid())
|
if (!m_bat.valid() && !m_batBackup.valid())
|
||||||
return false;
|
return ECardResult::BROKEN;
|
||||||
|
|
||||||
return true;
|
return ECardResult::READY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,23 @@ void Directory::operator=(const Directory& other) { memcpy(__raw, other.__raw, B
|
|||||||
|
|
||||||
Directory::~Directory() {}
|
Directory::~Directory() {}
|
||||||
|
|
||||||
|
bool Directory::hasFreeFile() const
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0; i < 127; i++)
|
||||||
|
if (m_files[i].m_game[0] == 0xFF)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Directory::numFreeFiles() const
|
||||||
|
{
|
||||||
|
int32_t ret = 0;
|
||||||
|
for (uint16_t i = 0; i < 127; i++)
|
||||||
|
if (m_files[i].m_game[0] == 0xFF)
|
||||||
|
++ret;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
File* Directory::getFirstFreeFile(const char* game, const char* maker, const char* filename)
|
File* Directory::getFirstFreeFile(const char* game, const char* maker, const char* filename)
|
||||||
{
|
{
|
||||||
for (uint16_t i = 0; i < 127; i++)
|
for (uint16_t i = 0; i < 127; i++)
|
||||||
|
@ -5,18 +5,18 @@ 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::ECardSlot::SlotA, kabufuda::ECardSize::Card2043Mb);
|
||||||
uint64_t a = 0;
|
uint64_t a = 0;
|
||||||
mc.getSerial(a);
|
mc.getSerial(a);
|
||||||
|
|
||||||
kabufuda::Card mc2{_S("test2.USA.raw"), "GM8E", "01"};
|
kabufuda::Card mc2{_S("test2.USA.raw"), "GM8E", "01"};
|
||||||
if (!mc2)
|
if (!mc2)
|
||||||
mc2.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card2043Mb);
|
mc2.format(kabufuda::ECardSlot::SlotA, kabufuda::ECardSize::Card2043Mb);
|
||||||
|
|
||||||
std::unique_ptr<kabufuda::IFileHandle> f = mc.openFile("MetroidPrime A");
|
std::unique_ptr<kabufuda::IFileHandle> f = mc.openFile("MetroidPrime A");
|
||||||
if (!f)
|
if (!f)
|
||||||
{
|
{
|
||||||
f = mc.createFile("MetroidPrime A", kabufuda::BlockSize);
|
mc.createFile("MetroidPrime A", kabufuda::BlockSize, f);
|
||||||
mc.setPublic(f, true);
|
mc.setPublic(f, true);
|
||||||
mc.setCanCopy(f, true);
|
mc.setCanCopy(f, true);
|
||||||
mc.setCanMove(f, true);
|
mc.setCanMove(f, true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user