mirror of https://github.com/AxioDL/kabufuda.git
New code style refactor
This commit is contained in:
parent
a1e2242691
commit
f126245eef
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
IndentWidth: 4
|
BasedOnStyle: LLVM
|
||||||
ColumnLimit: 120
|
ColumnLimit: 120
|
||||||
UseTab: Never
|
UseTab: Never
|
||||||
---
|
---
|
||||||
|
@ -8,7 +8,6 @@ DerivePointerAlignment: false
|
||||||
PointerAlignment: Left
|
PointerAlignment: Left
|
||||||
AlignAfterOpenBracket: Align
|
AlignAfterOpenBracket: Align
|
||||||
AlignConsecutiveAssignments: false
|
AlignConsecutiveAssignments: false
|
||||||
BreakBeforeBraces: Allman
|
|
||||||
IndentCaseLabels: false
|
IndentCaseLabels: false
|
||||||
AllowShortBlocksOnASingleLine: true
|
AllowShortBlocksOnASingleLine: true
|
||||||
AlignOperands: true
|
AlignOperands: true
|
||||||
|
@ -24,6 +23,6 @@ NamespaceIndentation: None
|
||||||
BinPackArguments: true
|
BinPackArguments: true
|
||||||
BinPackParameters: true
|
BinPackParameters: true
|
||||||
SortIncludes: false
|
SortIncludes: false
|
||||||
AccessModifierOffset: -4
|
AccessModifierOffset: -2
|
||||||
ConstructorInitializerIndentWidth: 0
|
ConstructorInitializerIndentWidth: 0
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
|
|
@ -11,40 +11,38 @@ using SizeReturn = DWORD;
|
||||||
#include "Util.hpp"
|
#include "Util.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
|
|
||||||
class AsyncIO
|
class AsyncIO {
|
||||||
{
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int m_fd = -1;
|
int m_fd = -1;
|
||||||
std::vector<std::pair<struct aiocb, SizeReturn>> m_queue;
|
std::vector<std::pair<struct aiocb, SizeReturn>> m_queue;
|
||||||
#else
|
#else
|
||||||
HANDLE m_fh = INVALID_HANDLE_VALUE;
|
HANDLE m_fh = INVALID_HANDLE_VALUE;
|
||||||
std::vector<std::pair<OVERLAPPED, SizeReturn>> m_queue;
|
std::vector<std::pair<OVERLAPPED, SizeReturn>> m_queue;
|
||||||
#endif
|
#endif
|
||||||
void _waitForOperation(size_t qIdx) const;
|
void _waitForOperation(size_t qIdx) const;
|
||||||
size_t m_maxBlock = 0;
|
size_t m_maxBlock = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AsyncIO() = default;
|
AsyncIO() = default;
|
||||||
AsyncIO(SystemStringView filename, bool truncate = false);
|
AsyncIO(SystemStringView filename, bool truncate = false);
|
||||||
~AsyncIO();
|
~AsyncIO();
|
||||||
AsyncIO(AsyncIO&& other);
|
AsyncIO(AsyncIO&& other);
|
||||||
AsyncIO& operator=(AsyncIO&& other);
|
AsyncIO& operator=(AsyncIO&& other);
|
||||||
AsyncIO(const AsyncIO* other) = delete;
|
AsyncIO(const AsyncIO* other) = delete;
|
||||||
AsyncIO& operator=(const AsyncIO& other) = delete;
|
AsyncIO& operator=(const AsyncIO& other) = delete;
|
||||||
void resizeQueue(size_t queueSz) { m_queue.resize(queueSz); }
|
void resizeQueue(size_t queueSz) { m_queue.resize(queueSz); }
|
||||||
bool asyncRead(size_t qIdx, void* buf, size_t length, off_t offset);
|
bool asyncRead(size_t qIdx, void* buf, size_t length, off_t offset);
|
||||||
bool asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset);
|
bool asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset);
|
||||||
ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const;
|
ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const;
|
||||||
ECardResult pollStatus() const;
|
ECardResult pollStatus() const;
|
||||||
void waitForCompletion() const;
|
void waitForCompletion() const;
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
operator bool() const { return m_fd != -1; }
|
operator bool() const { return m_fd != -1; }
|
||||||
#else
|
#else
|
||||||
operator bool() const { return m_fh != INVALID_HANDLE_VALUE; }
|
operator bool() const { return m_fh != INVALID_HANDLE_VALUE; }
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -2,39 +2,36 @@
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
class BlockAllocationTable {
|
||||||
class BlockAllocationTable
|
friend class Card;
|
||||||
{
|
|
||||||
friend class Card;
|
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
union {
|
union {
|
||||||
struct
|
struct {
|
||||||
{
|
uint16_t m_checksum;
|
||||||
uint16_t m_checksum;
|
uint16_t m_checksumInv;
|
||||||
uint16_t m_checksumInv;
|
uint16_t m_updateCounter;
|
||||||
uint16_t m_updateCounter;
|
uint16_t m_freeBlocks;
|
||||||
uint16_t m_freeBlocks;
|
uint16_t m_lastAllocated;
|
||||||
uint16_t m_lastAllocated;
|
uint16_t m_map[0xFFB];
|
||||||
uint16_t m_map[0xFFB];
|
|
||||||
};
|
|
||||||
uint8_t __raw[BlockSize];
|
|
||||||
};
|
};
|
||||||
|
uint8_t __raw[BlockSize];
|
||||||
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
void swapEndian();
|
void swapEndian();
|
||||||
void updateChecksum();
|
void updateChecksum();
|
||||||
bool valid() const;
|
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));
|
||||||
BlockAllocationTable(uint8_t data[BlockSize]);
|
BlockAllocationTable(uint8_t data[BlockSize]);
|
||||||
~BlockAllocationTable() = default;
|
~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;
|
||||||
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; }
|
uint16_t numFreeBlocks() const { return m_freeBlocks; }
|
||||||
};
|
};
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
|
@ -13,316 +13,309 @@
|
||||||
#define CARD_FILENAME_MAX 32
|
#define CARD_FILENAME_MAX 32
|
||||||
#define CARD_ICON_MAX 8
|
#define CARD_ICON_MAX 8
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
|
class FileHandle {
|
||||||
|
friend class Card;
|
||||||
|
uint32_t idx = -1;
|
||||||
|
int32_t offset = 0;
|
||||||
|
FileHandle(uint32_t idx) : idx(idx) {}
|
||||||
|
|
||||||
class FileHandle
|
|
||||||
{
|
|
||||||
friend class Card;
|
|
||||||
uint32_t idx = -1;
|
|
||||||
int32_t offset = 0;
|
|
||||||
FileHandle(uint32_t idx) : idx(idx) {}
|
|
||||||
public:
|
public:
|
||||||
FileHandle() = default;
|
FileHandle() = default;
|
||||||
uint32_t getFileNo() const { return idx; }
|
uint32_t getFileNo() const { return idx; }
|
||||||
operator bool() const { return getFileNo() != -1; }
|
operator bool() const { return getFileNo() != -1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProbeResults
|
struct ProbeResults {
|
||||||
{
|
ECardResult x0_error;
|
||||||
ECardResult x0_error;
|
uint32_t x4_cardSize; /* in megabits */
|
||||||
uint32_t x4_cardSize; /* in megabits */
|
uint32_t x8_sectorSize; /* in bytes */
|
||||||
uint32_t x8_sectorSize; /* in bytes */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CardStat
|
struct CardStat {
|
||||||
{
|
/* read-only (Set by Card::getStatus) */
|
||||||
/* read-only (Set by Card::getStatus) */
|
char x0_fileName[CARD_FILENAME_MAX];
|
||||||
char x0_fileName[CARD_FILENAME_MAX];
|
uint32_t x20_length;
|
||||||
uint32_t x20_length;
|
uint32_t x24_time; /* seconds since 01/01/2000 midnight */
|
||||||
uint32_t x24_time; /* seconds since 01/01/2000 midnight */
|
uint8_t x28_gameName[4];
|
||||||
uint8_t x28_gameName[4];
|
uint8_t x2c_company[2];
|
||||||
uint8_t x2c_company[2];
|
|
||||||
|
|
||||||
/* read/write (Set by Card::getStatus/Card::setStatus) */
|
/* read/write (Set by Card::getStatus/Card::setStatus) */
|
||||||
uint8_t x2e_bannerFormat;
|
uint8_t x2e_bannerFormat;
|
||||||
uint8_t x2f___padding;
|
uint8_t x2f___padding;
|
||||||
uint32_t x30_iconAddr; /* offset to the banner, bannerTlut, icon, iconTlut data set. */
|
uint32_t x30_iconAddr; /* offset to the banner, bannerTlut, icon, iconTlut data set. */
|
||||||
uint16_t x34_iconFormat;
|
uint16_t x34_iconFormat;
|
||||||
uint16_t x36_iconSpeed;
|
uint16_t x36_iconSpeed;
|
||||||
uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */
|
uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */
|
||||||
|
|
||||||
/* read-only (Set by Card::getStatus) */
|
/* read-only (Set by Card::getStatus) */
|
||||||
uint32_t x3c_offsetBanner;
|
uint32_t x3c_offsetBanner;
|
||||||
uint32_t x40_offsetBannerTlut;
|
uint32_t x40_offsetBannerTlut;
|
||||||
uint32_t x44_offsetIcon[CARD_ICON_MAX];
|
uint32_t x44_offsetIcon[CARD_ICON_MAX];
|
||||||
uint32_t x64_offsetIconTlut;
|
uint32_t x64_offsetIconTlut;
|
||||||
uint32_t x68_offsetData;
|
uint32_t x68_offsetData;
|
||||||
|
|
||||||
uint32_t GetFileLength() const { return x20_length; }
|
uint32_t GetFileLength() const { return x20_length; }
|
||||||
uint32_t GetTime() const { return x24_time; }
|
uint32_t GetTime() const { return x24_time; }
|
||||||
EImageFormat GetBannerFormat() const { return EImageFormat(x2e_bannerFormat & 0x3); }
|
EImageFormat GetBannerFormat() const { return EImageFormat(x2e_bannerFormat & 0x3); }
|
||||||
void SetBannerFormat(EImageFormat fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | uint8_t(fmt); }
|
void SetBannerFormat(EImageFormat fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | uint8_t(fmt); }
|
||||||
EImageFormat GetIconFormat(int idx) const { return EImageFormat((x34_iconFormat >> (idx * 2)) & 0x3); }
|
EImageFormat GetIconFormat(int idx) const { return EImageFormat((x34_iconFormat >> (idx * 2)) & 0x3); }
|
||||||
void SetIconFormat(EImageFormat fmt, int idx)
|
void SetIconFormat(EImageFormat fmt, int idx) {
|
||||||
{
|
x34_iconFormat &= ~(0x3 << (idx * 2));
|
||||||
x34_iconFormat &= ~(0x3 << (idx * 2));
|
x34_iconFormat |= uint16_t(fmt) << (idx * 2);
|
||||||
x34_iconFormat |= uint16_t(fmt) << (idx * 2);
|
}
|
||||||
}
|
void SetIconSpeed(EAnimationSpeed sp, int idx) {
|
||||||
void SetIconSpeed(EAnimationSpeed sp, int idx)
|
x36_iconSpeed &= ~(0x3 << (idx * 2));
|
||||||
{
|
x36_iconSpeed |= uint16_t(sp) << (idx * 2);
|
||||||
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 GetIconAddr() const { return x30_iconAddr; }
|
uint32_t GetCommentAddr() const { return x38_commentAddr; }
|
||||||
void SetIconAddr(uint32_t addr) { x30_iconAddr = addr; }
|
void SetCommentAddr(uint32_t addr) { x38_commentAddr = 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)
|
||||||
struct CardHeader
|
struct CardHeader {
|
||||||
{
|
uint8_t m_serial[12];
|
||||||
uint8_t m_serial[12];
|
uint64_t m_formatTime;
|
||||||
uint64_t m_formatTime;
|
int32_t m_sramBias;
|
||||||
int32_t m_sramBias;
|
uint32_t m_sramLanguage;
|
||||||
uint32_t m_sramLanguage;
|
uint32_t m_unknown;
|
||||||
uint32_t m_unknown;
|
uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */
|
||||||
uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */
|
uint16_t m_sizeMb;
|
||||||
uint16_t m_sizeMb;
|
uint16_t m_encoding;
|
||||||
uint16_t m_encoding;
|
uint8_t __padding[468];
|
||||||
uint8_t __padding[468];
|
uint16_t m_updateCounter;
|
||||||
uint16_t m_updateCounter;
|
uint16_t m_checksum;
|
||||||
uint16_t m_checksum;
|
uint16_t m_checksumInv;
|
||||||
uint16_t m_checksumInv;
|
void _swapEndian();
|
||||||
void _swapEndian();
|
};
|
||||||
};
|
union {
|
||||||
union {
|
CardHeader m_ch;
|
||||||
CardHeader m_ch;
|
uint8_t __raw[BlockSize];
|
||||||
uint8_t __raw[BlockSize];
|
};
|
||||||
};
|
CardHeader m_tmpCh;
|
||||||
CardHeader m_tmpCh;
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
SystemString m_filename;
|
SystemString m_filename;
|
||||||
AsyncIO m_fileHandle;
|
AsyncIO m_fileHandle;
|
||||||
Directory m_dirs[2];
|
Directory m_dirs[2];
|
||||||
BlockAllocationTable m_bats[2];
|
BlockAllocationTable m_bats[2];
|
||||||
Directory m_tmpDirs[2];
|
Directory m_tmpDirs[2];
|
||||||
BlockAllocationTable m_tmpBats[2];
|
BlockAllocationTable m_tmpBats[2];
|
||||||
uint8_t m_currentDir;
|
uint8_t m_currentDir;
|
||||||
uint8_t m_currentBat;
|
uint8_t m_currentBat;
|
||||||
|
|
||||||
uint16_t m_maxBlock;
|
uint16_t m_maxBlock;
|
||||||
char m_game[5] = {'\0'};
|
char m_game[5] = {'\0'};
|
||||||
char m_maker[3] = {'\0'};
|
char m_maker[3] = {'\0'};
|
||||||
|
|
||||||
void _updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat);
|
void _updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat);
|
||||||
void _updateChecksum();
|
void _updateChecksum();
|
||||||
File* _fileFromHandle(const FileHandle& fh) const;
|
File* _fileFromHandle(const FileHandle& fh) const;
|
||||||
void _deleteFile(File& f, BlockAllocationTable& bat);
|
void _deleteFile(File& f, BlockAllocationTable& bat);
|
||||||
|
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
bool m_opened = false;
|
bool m_opened = false;
|
||||||
ECardResult _pumpOpen();
|
ECardResult _pumpOpen();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Card();
|
Card();
|
||||||
/**
|
/**
|
||||||
* @brief Card
|
* @brief Card
|
||||||
* @param other
|
* @param other
|
||||||
*/
|
*/
|
||||||
Card(const Card& other) = delete;
|
Card(const Card& other) = delete;
|
||||||
Card& operator=(const Card& other) = delete;
|
Card& operator=(const Card& other) = delete;
|
||||||
Card(Card&& other);
|
Card(Card&& other);
|
||||||
Card& operator=(Card&& other);
|
Card& operator=(Card&& other);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Card
|
* @brief Card
|
||||||
* @param filepath
|
* @param filepath
|
||||||
* @param game
|
* @param game
|
||||||
* @param maker
|
* @param maker
|
||||||
*/
|
*/
|
||||||
Card(const char* game = nullptr, const char* maker = nullptr);
|
Card(const char* game = nullptr, const char* maker = nullptr);
|
||||||
~Card();
|
~Card();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief openFile
|
* @brief openFile
|
||||||
* @param filename
|
* @param filename
|
||||||
*/
|
*/
|
||||||
ECardResult openFile(const char* filename, FileHandle& handleOut);
|
ECardResult openFile(const char* filename, FileHandle& handleOut);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief openFile
|
* @brief openFile
|
||||||
* @param fileno
|
* @param fileno
|
||||||
*/
|
*/
|
||||||
ECardResult openFile(uint32_t fileno, FileHandle& handleOut);
|
ECardResult openFile(uint32_t fileno, FileHandle& handleOut);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief createFile
|
* @brief createFile
|
||||||
* @param filename
|
* @param filename
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut);
|
ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief closeFile
|
* @brief closeFile
|
||||||
* @param fh FileHandle to close
|
* @param fh FileHandle to close
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
ECardResult closeFile(FileHandle& fh);
|
ECardResult closeFile(FileHandle& fh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief firstFile
|
* @brief firstFile
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
FileHandle firstFile();
|
FileHandle firstFile();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief nextFile
|
* @brief nextFile
|
||||||
* @param cur
|
* @param cur
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
FileHandle nextFile(const FileHandle& cur);
|
FileHandle nextFile(const FileHandle& cur);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief getFilename
|
* @brief getFilename
|
||||||
* @param fh
|
* @param fh
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
const char* getFilename(const FileHandle& fh);
|
const char* getFilename(const FileHandle& fh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief deleteFile
|
* @brief deleteFile
|
||||||
* @param fh
|
* @param fh
|
||||||
*/
|
*/
|
||||||
void deleteFile(const FileHandle& fh);
|
void deleteFile(const FileHandle& fh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief deleteFile
|
* @brief deleteFile
|
||||||
* @param filename
|
* @param filename
|
||||||
*/
|
*/
|
||||||
ECardResult deleteFile(const char* filename);
|
ECardResult deleteFile(const char* filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief deleteFile
|
* @brief deleteFile
|
||||||
* @param fileno
|
* @param fileno
|
||||||
*/
|
*/
|
||||||
ECardResult deleteFile(uint32_t fileno);
|
ECardResult deleteFile(uint32_t fileno);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief renameFile
|
* @brief renameFile
|
||||||
* @param oldName
|
* @param oldName
|
||||||
* @param newName
|
* @param newName
|
||||||
*/
|
*/
|
||||||
ECardResult renameFile(const char* oldName, const char* newName);
|
ECardResult renameFile(const char* oldName, const char* newName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief write
|
* @brief write
|
||||||
* @param fh
|
* @param fh
|
||||||
* @param buf
|
* @param buf
|
||||||
* @param size
|
* @param size
|
||||||
*/
|
*/
|
||||||
ECardResult asyncWrite(FileHandle& fh, const void* buf, size_t size);
|
ECardResult asyncWrite(FileHandle& fh, const void* buf, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief read
|
* @brief read
|
||||||
* @param fh
|
* @param fh
|
||||||
* @param dst
|
* @param dst
|
||||||
* @param size
|
* @param size
|
||||||
*/
|
*/
|
||||||
ECardResult asyncRead(FileHandle& fh, void* dst, size_t size);
|
ECardResult asyncRead(FileHandle& fh, void* dst, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief seek
|
* @brief seek
|
||||||
* @param fh
|
* @param fh
|
||||||
* @param pos
|
* @param pos
|
||||||
* @param whence
|
* @param whence
|
||||||
*/
|
*/
|
||||||
void seek(FileHandle& fh, int32_t pos, SeekOrigin whence);
|
void seek(FileHandle& fh, int32_t pos, SeekOrigin whence);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the current offset of the specified file
|
* @brief Returns the current offset of the specified file
|
||||||
* @param fh The file to retrieve the offset from
|
* @param fh The file to retrieve the offset from
|
||||||
* @return The offset or -1 if an invalid handle is passed
|
* @return The offset or -1 if an invalid handle is passed
|
||||||
*/
|
*/
|
||||||
int32_t tell(const FileHandle& fh);
|
int32_t tell(const FileHandle& fh);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setPublic
|
* @brief setPublic
|
||||||
* @param fh
|
* @param fh
|
||||||
* @param pub
|
* @param pub
|
||||||
*/
|
*/
|
||||||
void setPublic(const FileHandle& fh, bool pub);
|
void setPublic(const FileHandle& fh, bool pub);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief isPublic
|
* @brief isPublic
|
||||||
* @param fh
|
* @param fh
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool isPublic(const FileHandle& fh) const;
|
bool isPublic(const FileHandle& fh) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setCanCopy
|
* @brief setCanCopy
|
||||||
* @param fh
|
* @param fh
|
||||||
* @param copy
|
* @param copy
|
||||||
*/
|
*/
|
||||||
void setCanCopy(const FileHandle& fh, bool copy) const;
|
void setCanCopy(const FileHandle& fh, bool copy) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief canCopy
|
* @brief canCopy
|
||||||
* @param fh
|
* @param fh
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool canCopy(const FileHandle& fh) const;
|
bool canCopy(const FileHandle& fh) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setCanMove
|
* @brief setCanMove
|
||||||
* @param fh
|
* @param fh
|
||||||
* @param move
|
* @param move
|
||||||
*/
|
*/
|
||||||
void setCanMove(const FileHandle& fh, bool move);
|
void setCanMove(const FileHandle& fh, bool move);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief canMove
|
* @brief canMove
|
||||||
* @param fh
|
* @param fh
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
bool canMove(const FileHandle& fh) const;
|
bool canMove(const FileHandle& fh) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief getStatus
|
* @brief getStatus
|
||||||
* @param fh Handle of requested file
|
* @param fh Handle of requested file
|
||||||
* @param statOut Structure to fill with file stat
|
* @param statOut Structure to fill with file stat
|
||||||
* @return NOFILE or READY
|
* @return NOFILE or READY
|
||||||
*/
|
*/
|
||||||
ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const;
|
ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief getStatus
|
* @brief getStatus
|
||||||
* @param fileNo Number of requested file
|
* @param fileNo Number of requested file
|
||||||
* @param statOut Structure to fill with file stat
|
* @param statOut Structure to fill with file stat
|
||||||
* @return NOFILE or READY
|
* @return NOFILE or READY
|
||||||
*/
|
*/
|
||||||
ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const;
|
ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setStatus
|
* @brief setStatus
|
||||||
* @param fh Handle of requested file
|
* @param fh Handle of requested file
|
||||||
* @param statOut Structure to access for file stat
|
* @param statOut Structure to access for file stat
|
||||||
* @return NOFILE or READY
|
* @return NOFILE or READY
|
||||||
*/
|
*/
|
||||||
ECardResult setStatus(const FileHandle& fh, const CardStat& stat);
|
ECardResult setStatus(const FileHandle& fh, const CardStat& stat);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief setStatus
|
* @brief setStatus
|
||||||
* @param fileNo Number of requested file
|
* @param fileNo Number of requested file
|
||||||
* @param statOut Structure to access for file stat
|
* @param statOut Structure to access for file stat
|
||||||
* @return NOFILE or READY
|
* @return NOFILE or READY
|
||||||
*/
|
*/
|
||||||
ECardResult setStatus(uint32_t fileNo, const CardStat& stat);
|
ECardResult setStatus(uint32_t fileNo, const CardStat& stat);
|
||||||
|
|
||||||
#if 0 // TODO: Async-friendly implementations
|
#if 0 // TODO: Async-friendly implementations
|
||||||
/**
|
/**
|
||||||
|
@ -342,98 +335,97 @@ public:
|
||||||
bool moveFileTo(FileHandle& fh, Card& dest);
|
bool moveFileTo(FileHandle& fh, Card& dest);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @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"
|
||||||
* @sa openFile
|
* @sa openFile
|
||||||
*/
|
*/
|
||||||
void setCurrentGame(const char* game);
|
void setCurrentGame(const char* game);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the currently selected game
|
* @brief Returns the currently selected game
|
||||||
* @return The selected game, or nullptr
|
* @return The selected game, or nullptr
|
||||||
*/
|
*/
|
||||||
const uint8_t* getCurrentGame() const;
|
const uint8_t* getCurrentGame() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the current maker, if not null any openFile requests will only return files that match this maker
|
* @brief Sets the current maker, if not null any openFile requests will only return files that match this maker
|
||||||
* @param maker The target maker id, e.g "01"
|
* @param maker The target maker id, e.g "01"
|
||||||
* @sa openFile
|
* @sa openFile
|
||||||
*/
|
*/
|
||||||
void setCurrentMaker(const char* maker);
|
void setCurrentMaker(const char* maker);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the currently selected maker
|
* @brief Returns the currently selected maker
|
||||||
* @return The selected maker, or nullptr
|
* @return The selected maker, or nullptr
|
||||||
*/
|
*/
|
||||||
const uint8_t* getCurrentMaker() const;
|
const uint8_t* getCurrentMaker() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves the format assigned serial
|
* @brief Retrieves the format assigned serial
|
||||||
* @param serial
|
* @param serial
|
||||||
*/
|
*/
|
||||||
void getSerial(uint64_t& serial);
|
void getSerial(uint64_t& serial);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Retrieves the checksum values of the Card system header
|
* @brief Retrieves the checksum values of the Card system header
|
||||||
* @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
|
* @brief Retrieves the available storage and directory space
|
||||||
* @param bytesNotUsed Number of free bytes out
|
* @param bytesNotUsed Number of free bytes out
|
||||||
* @param filesNotUsed Number of free files out
|
* @param filesNotUsed Number of free files out
|
||||||
*/
|
*/
|
||||||
void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed);
|
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(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII);
|
void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns basic stats about a card image without opening a handle
|
* @brief Returns basic stats about a card image without opening a handle
|
||||||
* @return ProbeResults structure
|
* @return ProbeResults structure
|
||||||
*/
|
*/
|
||||||
static ProbeResults probeCardFile(SystemStringView filename);
|
static ProbeResults probeCardFile(SystemStringView 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 />
|
||||||
* <b>Note:</b> <i>Under normal circumstances there is no need to call this function.</i>
|
* <b>Note:</b> <i>Under normal circumstances there is no need to call this function.</i>
|
||||||
*/
|
*/
|
||||||
void commit();
|
void commit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens card image (does nothing if currently open path matches)
|
* @brief Opens card image (does nothing if currently open path matches)
|
||||||
*/
|
*/
|
||||||
bool open(SystemStringView filepath);
|
bool open(SystemStringView filepath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Commits changes to disk and closes host file
|
* @brief Commits changes to disk and closes host file
|
||||||
*/
|
*/
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Access host filename of card
|
* @brief Access host filename of card
|
||||||
*/
|
*/
|
||||||
SystemStringView cardFilename() const { return m_filename; }
|
SystemStringView cardFilename() const { return m_filename; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets card-scope error state
|
* @brief Gets card-scope error state
|
||||||
* @return READY, BROKEN, or NOCARD
|
* @return READY, BROKEN, or NOCARD
|
||||||
*/
|
*/
|
||||||
ECardResult getError() const;
|
ECardResult getError() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Block caller until any asynchronous I/O operations have completed
|
* @brief Block caller until any asynchronous I/O operations have completed
|
||||||
*/
|
*/
|
||||||
void waitForCompletion() const;
|
void waitForCompletion() const;
|
||||||
|
|
||||||
operator bool() const { return getError() == ECardResult::READY; }
|
operator bool() const { return getError() == ECardResult::READY; }
|
||||||
};
|
};
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "Util.hpp"
|
#include "Util.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
uint32_t constexpr BlockSize = 0x2000;
|
uint32_t constexpr BlockSize = 0x2000;
|
||||||
uint32_t constexpr MaxFiles = 127;
|
uint32_t constexpr MaxFiles = 127;
|
||||||
uint32_t constexpr FSTBlocks = 5;
|
uint32_t constexpr FSTBlocks = 5;
|
||||||
|
@ -14,64 +13,50 @@ uint32_t constexpr BATSize = 0xFFB;
|
||||||
/**
|
/**
|
||||||
* @brief The EPermissions enum
|
* @brief The EPermissions enum
|
||||||
*/
|
*/
|
||||||
enum class EPermissions : uint8_t
|
enum class EPermissions : uint8_t {
|
||||||
{
|
Public = (1 << 2),
|
||||||
Public = (1 << 2),
|
NoCopy = (1 << 3),
|
||||||
NoCopy = (1 << 3),
|
NoMove = (1 << 4),
|
||||||
NoMove = (1 << 4),
|
Global = (1 << 5),
|
||||||
Global = (1 << 5),
|
Company = (1 << 6)
|
||||||
Company = (1 << 6)
|
|
||||||
};
|
};
|
||||||
ENABLE_BITWISE_ENUM(EPermissions)
|
ENABLE_BITWISE_ENUM(EPermissions)
|
||||||
|
|
||||||
enum class EImageFormat : uint8_t
|
enum class EImageFormat : uint8_t {
|
||||||
{
|
None,
|
||||||
None,
|
C8,
|
||||||
C8,
|
RGB5A3,
|
||||||
RGB5A3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EAnimationType
|
enum class EAnimationType {
|
||||||
{
|
Loop = 0,
|
||||||
Loop = 0,
|
Bounce = 2,
|
||||||
Bounce = 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class EAnimationSpeed
|
enum class EAnimationSpeed {
|
||||||
{
|
End,
|
||||||
End,
|
Fast,
|
||||||
Fast,
|
Middle,
|
||||||
Middle,
|
Slow,
|
||||||
Slow,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SeekOrigin
|
enum class SeekOrigin { Begin, Current, End };
|
||||||
{
|
|
||||||
Begin,
|
|
||||||
Current,
|
|
||||||
End
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ECardSlot enum
|
* @brief The ECardSlot enum
|
||||||
*/
|
*/
|
||||||
enum class ECardSlot : uint16_t
|
enum class ECardSlot : uint16_t { SlotA, SlotB };
|
||||||
{
|
|
||||||
SlotA,
|
|
||||||
SlotB
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ECardSize enum
|
* @brief The ECardSize enum
|
||||||
*/
|
*/
|
||||||
enum class ECardSize : uint16_t
|
enum class ECardSize : uint16_t {
|
||||||
{
|
Card59Mb = 0x04,
|
||||||
Card59Mb = 0x04,
|
Card123Mb = 0x08,
|
||||||
Card123Mb = 0x08,
|
Card251Mb = 0x10,
|
||||||
Card251Mb = 0x10,
|
Card507Mb = 0x20,
|
||||||
Card507Mb = 0x20,
|
Card1019Mb = 0x40,
|
||||||
Card1019Mb = 0x40,
|
Card2043Mb = 0x80
|
||||||
Card2043Mb = 0x80
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr uint32_t BannerWidth = 96;
|
static constexpr uint32_t BannerWidth = 96;
|
||||||
|
@ -82,10 +67,8 @@ static constexpr uint32_t IconHeight = 32;
|
||||||
/**
|
/**
|
||||||
* @brief The EEncoding enum
|
* @brief The EEncoding enum
|
||||||
*/
|
*/
|
||||||
enum class EEncoding : uint16_t
|
enum class EEncoding : uint16_t {
|
||||||
{
|
ASCII, /**< Standard ASCII Encoding */
|
||||||
ASCII, /**< Standard ASCII Encoding */
|
SJIS /**< SJIS Encoding for japanese */
|
||||||
SJIS /**< SJIS Encoding for japanese */
|
|
||||||
};
|
};
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -2,41 +2,37 @@
|
||||||
|
|
||||||
#include "File.hpp"
|
#include "File.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
class Directory {
|
||||||
class Directory
|
friend class Card;
|
||||||
{
|
|
||||||
friend class Card;
|
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
union {
|
union {
|
||||||
struct
|
struct {
|
||||||
{
|
File m_files[MaxFiles];
|
||||||
File m_files[MaxFiles];
|
uint8_t __padding[0x3a];
|
||||||
uint8_t __padding[0x3a];
|
uint16_t m_updateCounter;
|
||||||
uint16_t m_updateCounter;
|
uint16_t m_checksum;
|
||||||
uint16_t m_checksum;
|
uint16_t m_checksumInv;
|
||||||
uint16_t m_checksumInv;
|
|
||||||
};
|
|
||||||
uint8_t __raw[BlockSize];
|
|
||||||
};
|
};
|
||||||
|
uint8_t __raw[BlockSize];
|
||||||
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
void swapEndian();
|
void swapEndian();
|
||||||
void updateChecksum();
|
void updateChecksum();
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Directory();
|
Directory();
|
||||||
Directory(uint8_t data[BlockSize]);
|
Directory(uint8_t data[BlockSize]);
|
||||||
~Directory() = default;
|
~Directory() = default;
|
||||||
|
|
||||||
bool hasFreeFile() const;
|
bool hasFreeFile() const;
|
||||||
int32_t numFreeFiles() 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);
|
||||||
File* getFile(uint32_t idx);
|
File* getFile(uint32_t idx);
|
||||||
int32_t indexForFile(File* f);
|
int32_t indexForFile(File* f);
|
||||||
};
|
};
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -2,44 +2,40 @@
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
class File {
|
||||||
class File
|
friend class IFileHandle;
|
||||||
{
|
friend class Directory;
|
||||||
friend class IFileHandle;
|
friend class Card;
|
||||||
friend class Directory;
|
|
||||||
friend class Card;
|
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
union {
|
union {
|
||||||
struct
|
struct {
|
||||||
{
|
uint8_t m_game[4];
|
||||||
uint8_t m_game[4];
|
uint8_t m_maker[2];
|
||||||
uint8_t m_maker[2];
|
uint8_t m_reserved;
|
||||||
uint8_t m_reserved;
|
uint8_t m_bannerFlags;
|
||||||
uint8_t m_bannerFlags;
|
char m_filename[0x20];
|
||||||
char m_filename[0x20];
|
uint32_t m_modifiedTime;
|
||||||
uint32_t m_modifiedTime;
|
uint32_t m_iconAddress;
|
||||||
uint32_t m_iconAddress;
|
uint16_t m_iconFmt;
|
||||||
uint16_t m_iconFmt;
|
uint16_t m_animSpeed;
|
||||||
uint16_t m_animSpeed;
|
EPermissions m_permissions;
|
||||||
EPermissions m_permissions;
|
int8_t m_copyCounter;
|
||||||
int8_t m_copyCounter;
|
uint16_t m_firstBlock;
|
||||||
uint16_t m_firstBlock;
|
uint16_t m_blockCount;
|
||||||
uint16_t m_blockCount;
|
uint16_t m_reserved2;
|
||||||
uint16_t m_reserved2;
|
uint32_t m_commentAddr;
|
||||||
uint32_t m_commentAddr;
|
|
||||||
};
|
|
||||||
uint8_t __raw[0x40];
|
|
||||||
};
|
};
|
||||||
|
uint8_t __raw[0x40];
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
void swapEndian();
|
void swapEndian();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
File();
|
File();
|
||||||
File(char data[0x40]);
|
File(char data[0x40]);
|
||||||
File(const char* filename);
|
File(const char* filename);
|
||||||
~File() = default;
|
~File() = default;
|
||||||
};
|
};
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -25,50 +25,46 @@ must not be misrepresented as being the original software.
|
||||||
distribution.
|
distribution.
|
||||||
-------------------------------------------------------------*/
|
-------------------------------------------------------------*/
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
#pragma pack(push, 1)
|
||||||
#pragma pack(push,1)
|
union SRAMFlags {
|
||||||
union SRAMFlags
|
uint8_t Hex;
|
||||||
{
|
struct {
|
||||||
uint8_t Hex;
|
uint8_t : 2;
|
||||||
struct
|
uint8_t sound : 1; // Audio settings; 0 = Mono, 1 = Stereo
|
||||||
{
|
uint8_t initialized : 1; // if 0, displays prompt to set language on boot and asks user to set options and time/date
|
||||||
uint8_t : 2;
|
uint8_t : 2;
|
||||||
uint8_t sound : 1; // Audio settings; 0 = Mono, 1 = Stereo
|
uint8_t boot_menu : 1; // if 1, skips logo animation and boots into the system menu regardless of if there is a
|
||||||
uint8_t initialized : 1; // if 0, displays prompt to set language on boot and asks user to set options and time/date
|
// disc inserted
|
||||||
uint8_t : 2;
|
uint8_t progressive : 1; // if 1, automatically displays Progressive Scan prompt in games that support it
|
||||||
uint8_t boot_menu : 1; // if 1, skips logo animation and boots into the system menu regardless of if there is a disc inserted
|
};
|
||||||
uint8_t progressive : 1; // if 1, automatically displays Progressive Scan prompt in games that support it
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
union SRAM
|
union SRAM {
|
||||||
{
|
uint8_t p_SRAM[64];
|
||||||
uint8_t p_SRAM[64];
|
struct // Stored configuration value from the system SRAM area
|
||||||
struct // Stored configuration value from the system SRAM area
|
{
|
||||||
{
|
uint16_t checksum; // Holds the block checksum.
|
||||||
uint16_t checksum; // Holds the block checksum.
|
uint16_t checksum_inv; // Holds the inverse block checksum
|
||||||
uint16_t checksum_inv; // Holds the inverse block checksum
|
uint32_t ead0; // Unknown attribute
|
||||||
uint32_t ead0; // Unknown attribute
|
uint32_t ead1; // Unknown attribute
|
||||||
uint32_t ead1; // Unknown attribute
|
uint32_t counter_bias; // Bias value for the realtime clock
|
||||||
uint32_t counter_bias; // Bias value for the realtime clock
|
int8_t display_offsetH; // Pixel offset for the VI
|
||||||
int8_t display_offsetH; // Pixel offset for the VI
|
uint8_t ntd; // Unknown attribute
|
||||||
uint8_t ntd; // Unknown attribute
|
uint8_t lang; // Language of system
|
||||||
uint8_t lang; // Language of system
|
SRAMFlags flags; // Device and operations flag
|
||||||
SRAMFlags flags; // Device and operations flag
|
|
||||||
|
|
||||||
// Stored configuration value from the extended SRAM area
|
// Stored configuration value from the extended SRAM area
|
||||||
uint8_t flash_id[2][12]; // flash_id[2][12] 96bit memorycard unlock flash ID
|
uint8_t flash_id[2][12]; // flash_id[2][12] 96bit memorycard unlock flash ID
|
||||||
uint32_t wirelessKbd_id; // Device ID of last connected wireless keyboard
|
uint32_t wirelessKbd_id; // Device ID of last connected wireless keyboard
|
||||||
uint16_t wirelessPad_id[4]; // 16-bit device ID of last connected pad.
|
uint16_t wirelessPad_id[4]; // 16-bit device ID of last connected pad.
|
||||||
uint8_t dvderr_code; // last non-recoverable error from DVD interface
|
uint8_t dvderr_code; // last non-recoverable error from DVD interface
|
||||||
uint8_t __padding0; // reserved
|
uint8_t __padding0; // reserved
|
||||||
uint8_t flashID_chksum[2]; // 8-bit checksum of unlock flash ID
|
uint8_t flashID_chksum[2]; // 8-bit checksum of unlock flash ID
|
||||||
uint32_t __padding1; // padding
|
uint32_t __padding1; // padding
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
extern const SRAM g_SRAM;
|
extern const SRAM g_SRAM;
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -39,77 +39,68 @@
|
||||||
|
|
||||||
#ifndef ENABLE_BITWISE_ENUM
|
#ifndef ENABLE_BITWISE_ENUM
|
||||||
#define ENABLE_BITWISE_ENUM(type) \
|
#define ENABLE_BITWISE_ENUM(type) \
|
||||||
constexpr type operator|(type a, type b) \
|
constexpr type operator|(type a, type b) { \
|
||||||
{ \
|
using T = std::underlying_type_t<type>; \
|
||||||
using T = std::underlying_type_t<type>; \
|
return type(static_cast<T>(a) | static_cast<T>(b)); \
|
||||||
return type(static_cast<T>(a) | static_cast<T>(b)); \
|
} \
|
||||||
} \
|
constexpr type operator&(type a, type b) { \
|
||||||
constexpr type operator&(type a, type b) \
|
using T = std::underlying_type_t<type>; \
|
||||||
{ \
|
return type(static_cast<T>(a) & static_cast<T>(b)); \
|
||||||
using T = std::underlying_type_t<type>; \
|
} \
|
||||||
return type(static_cast<T>(a) & static_cast<T>(b)); \
|
inline type& operator|=(type& a, const type& b) { \
|
||||||
} \
|
using T = std::underlying_type_t<type>; \
|
||||||
inline type& operator|=(type& a, const type& b) \
|
a = type(static_cast<T>(a) | static_cast<T>(b)); \
|
||||||
{ \
|
return a; \
|
||||||
using T = std::underlying_type_t<type>; \
|
} \
|
||||||
a = type(static_cast<T>(a) | static_cast<T>(b)); \
|
inline type& operator&=(type& a, const type& b) { \
|
||||||
return a; \
|
using T = std::underlying_type_t<type>; \
|
||||||
} \
|
a = type(static_cast<T>(a) & static_cast<T>(b)); \
|
||||||
inline type& operator&=(type& a, const type& b) \
|
return a; \
|
||||||
{ \
|
} \
|
||||||
using T = std::underlying_type_t<type>; \
|
inline type operator~(const type& key) { \
|
||||||
a = type(static_cast<T>(a) & static_cast<T>(b)); \
|
using T = std::underlying_type_t<type>; \
|
||||||
return a; \
|
return type(~static_cast<T>(key)); \
|
||||||
} \
|
}
|
||||||
inline type operator~(const type& key) \
|
|
||||||
{ \
|
|
||||||
using T = std::underlying_type_t<type>; \
|
|
||||||
return type(~static_cast<T>(key)); \
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
|
|
||||||
/* Type-sensitive byte swappers */
|
/* Type-sensitive byte swappers */
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T bswap16(T val)
|
static inline T bswap16(T val) {
|
||||||
{
|
|
||||||
#if __GNUC__
|
#if __GNUC__
|
||||||
return __builtin_bswap16(val);
|
return __builtin_bswap16(val);
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
return _byteswap_ushort(val);
|
return _byteswap_ushort(val);
|
||||||
#else
|
#else
|
||||||
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T bswap32(T val)
|
static inline T bswap32(T val) {
|
||||||
{
|
|
||||||
#if __GNUC__
|
#if __GNUC__
|
||||||
return __builtin_bswap32(val);
|
return __builtin_bswap32(val);
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
return _byteswap_ulong(val);
|
return _byteswap_ulong(val);
|
||||||
#else
|
#else
|
||||||
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
||||||
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
||||||
return val;
|
return val;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static inline T bswap64(T val)
|
static inline T bswap64(T val) {
|
||||||
{
|
|
||||||
#if __GNUC__
|
#if __GNUC__
|
||||||
return __builtin_bswap64(val);
|
return __builtin_bswap64(val);
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
return _byteswap_uint64(val);
|
return _byteswap_uint64(val);
|
||||||
#else
|
#else
|
||||||
return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
|
return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) |
|
||||||
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
|
((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) |
|
||||||
((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
|
((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) |
|
||||||
((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
|
((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,15 +111,13 @@ static inline int32_t SBig(int32_t val) { return bswap32(val); }
|
||||||
static inline uint32_t SBig(uint32_t val) { return bswap32(val); }
|
static inline uint32_t SBig(uint32_t val) { return bswap32(val); }
|
||||||
static inline int64_t SBig(int64_t val) { return bswap64(val); }
|
static inline int64_t SBig(int64_t val) { return bswap64(val); }
|
||||||
static inline uint64_t SBig(uint64_t val) { return bswap64(val); }
|
static inline uint64_t SBig(uint64_t val) { return bswap64(val); }
|
||||||
static inline float SBig(float val)
|
static inline float SBig(float val) {
|
||||||
{
|
int32_t ival = bswap32(*((int32_t*)(&val)));
|
||||||
int32_t ival = bswap32(*((int32_t*)(&val)));
|
return *((float*)(&ival));
|
||||||
return *((float*)(&ival));
|
|
||||||
}
|
}
|
||||||
static inline double SBig(double val)
|
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
|
#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)
|
||||||
|
@ -152,15 +141,13 @@ static inline int32_t SLittle(int32_t val) { return bswap32(val); }
|
||||||
static inline uint32_t SLittle(uint32_t val) { return bswap32(val); }
|
static inline uint32_t SLittle(uint32_t val) { return bswap32(val); }
|
||||||
static inline int64_t SLittle(int64_t val) { return bswap64(val); }
|
static inline int64_t SLittle(int64_t val) { return bswap64(val); }
|
||||||
static inline uint64_t SLittle(uint64_t val) { return bswap64(val); }
|
static inline uint64_t SLittle(uint64_t val) { return bswap64(val); }
|
||||||
static inline float SLittle(float val)
|
static inline float SLittle(float val) {
|
||||||
{
|
int32_t ival = bswap32(*((int32_t*)(&val)));
|
||||||
int32_t ival = bswap32(*((int32_t*)(&val)));
|
return *((float*)(&ival));
|
||||||
return *((float*)(&ival));
|
|
||||||
}
|
}
|
||||||
static inline double SLittle(double val)
|
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
|
#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)
|
||||||
|
@ -186,28 +173,28 @@ typedef std::wstring SystemString;
|
||||||
typedef std::wstring_view SystemStringView;
|
typedef std::wstring_view SystemStringView;
|
||||||
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
|
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towlower); }
|
||||||
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
|
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), towupper); }
|
||||||
class SystemUTF8Conv
|
class SystemUTF8Conv {
|
||||||
{
|
std::string m_utf8;
|
||||||
std::string m_utf8;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {}
|
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {}
|
||||||
std::string_view str() const { return m_utf8; }
|
std::string_view str() const { return m_utf8; }
|
||||||
const char* c_str() const { return m_utf8.c_str(); }
|
const char* c_str() const { return m_utf8.c_str(); }
|
||||||
std::string operator+(std::string_view other) const { return m_utf8 + other.data(); }
|
std::string operator+(std::string_view other) const { return m_utf8 + other.data(); }
|
||||||
};
|
};
|
||||||
inline std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
inline std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
||||||
class SystemStringConv
|
class SystemStringConv {
|
||||||
{
|
std::wstring m_sys;
|
||||||
std::wstring m_sys;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {}
|
explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {}
|
||||||
SystemStringView sys_str() const { return m_sys; }
|
SystemStringView sys_str() const { return m_sys; }
|
||||||
const SystemChar* c_str() const { return m_sys.c_str(); }
|
const SystemChar* c_str() const { return m_sys.c_str(); }
|
||||||
std::wstring operator+(const std::wstring_view other) const { return m_sys + other.data(); }
|
std::wstring operator+(const std::wstring_view other) const { return m_sys + other.data(); }
|
||||||
};
|
};
|
||||||
inline std::wstring operator+(const std::wstring_view lhs, const SystemStringConv& rhs) { return std::wstring(lhs) + rhs.c_str(); }
|
inline std::wstring operator+(const std::wstring_view lhs, const SystemStringConv& rhs) {
|
||||||
|
return std::wstring(lhs) + rhs.c_str();
|
||||||
|
}
|
||||||
#ifndef _SYS_STR
|
#ifndef _SYS_STR
|
||||||
#define _SYS_STR(val) L##val
|
#define _SYS_STR(val) L##val
|
||||||
#endif
|
#endif
|
||||||
|
@ -219,28 +206,28 @@ typedef std::string SystemString;
|
||||||
typedef std::string_view SystemStringView;
|
typedef std::string_view SystemStringView;
|
||||||
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
|
static inline void ToLower(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), tolower); }
|
||||||
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
|
static inline void ToUpper(SystemString& str) { std::transform(str.begin(), str.end(), str.begin(), toupper); }
|
||||||
class SystemUTF8Conv
|
class SystemUTF8Conv {
|
||||||
{
|
std::string_view m_utf8;
|
||||||
std::string_view m_utf8;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
|
explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {}
|
||||||
std::string_view str() const { return m_utf8; }
|
std::string_view str() const { return m_utf8; }
|
||||||
const char* c_str() const { return m_utf8.data(); }
|
const char* c_str() const { return m_utf8.data(); }
|
||||||
std::string operator+(std::string_view other) const { return std::string(m_utf8) + other.data(); }
|
std::string operator+(std::string_view other) const { return std::string(m_utf8) + other.data(); }
|
||||||
};
|
};
|
||||||
inline std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
inline std::string operator+(std::string_view lhs, const SystemUTF8Conv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
||||||
class SystemStringConv
|
class SystemStringConv {
|
||||||
{
|
SystemStringView m_sys;
|
||||||
SystemStringView m_sys;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SystemStringConv(std::string_view str) : m_sys(str) {}
|
explicit SystemStringConv(std::string_view str) : m_sys(str) {}
|
||||||
SystemStringView sys_str() const { return m_sys; }
|
SystemStringView sys_str() const { return m_sys; }
|
||||||
const SystemChar* c_str() const { return m_sys.data(); }
|
const SystemChar* c_str() const { return m_sys.data(); }
|
||||||
std::string operator+(std::string_view other) const { return std::string(m_sys) + other.data(); }
|
std::string operator+(std::string_view other) const { return std::string(m_sys) + other.data(); }
|
||||||
};
|
};
|
||||||
inline std::string operator+(std::string_view lhs, const SystemStringConv& rhs) { return std::string(lhs) + rhs.c_str(); }
|
inline std::string operator+(std::string_view lhs, const SystemStringConv& rhs) {
|
||||||
|
return std::string(lhs) + rhs.c_str();
|
||||||
|
}
|
||||||
#ifndef _SYS_STR
|
#ifndef _SYS_STR
|
||||||
#define _SYS_STR(val) val
|
#define _SYS_STR(val) val
|
||||||
#endif
|
#endif
|
||||||
|
@ -250,28 +237,24 @@ typedef struct stat Sstat;
|
||||||
uint64_t getGCTime();
|
uint64_t getGCTime();
|
||||||
|
|
||||||
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
||||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
|
||||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline int Stat(const SystemChar* path, Sstat* statOut)
|
static inline int Stat(const SystemChar* path, Sstat* statOut) {
|
||||||
{
|
|
||||||
#if CARD_UCS2
|
#if CARD_UCS2
|
||||||
size_t pos;
|
size_t pos;
|
||||||
for (pos = 0; pos < 3 && path[pos] != L'\0'; ++pos)
|
for (pos = 0; pos < 3 && path[pos] != L'\0'; ++pos) {}
|
||||||
{
|
if (pos == 2 && path[1] == L':') {
|
||||||
}
|
SystemChar fixPath[4] = {path[0], L':', L'/', L'\0'};
|
||||||
if (pos == 2 && path[1] == L':')
|
return _wstat(fixPath, statOut);
|
||||||
{
|
}
|
||||||
SystemChar fixPath[4] = {path[0], L':', L'/', L'\0'};
|
return _wstat(path, statOut);
|
||||||
return _wstat(fixPath, statOut);
|
|
||||||
}
|
|
||||||
return _wstat(path, statOut);
|
|
||||||
#else
|
#else
|
||||||
return stat(path, statOut);
|
return stat(path, statOut);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,22 +269,20 @@ void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, u
|
||||||
|
|
||||||
#undef NOFILE
|
#undef NOFILE
|
||||||
|
|
||||||
enum class ECardResult
|
enum class ECardResult {
|
||||||
{
|
CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */
|
||||||
CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */
|
FATAL_ERROR = -128,
|
||||||
FATAL_ERROR = -128,
|
ENCODING = -13,
|
||||||
ENCODING = -13,
|
NAMETOOLONG = -12,
|
||||||
NAMETOOLONG = -12,
|
INSSPACE = -9,
|
||||||
INSSPACE = -9,
|
NOENT = -8,
|
||||||
NOENT = -8,
|
EXIST = -7,
|
||||||
EXIST = -7,
|
BROKEN = -6,
|
||||||
BROKEN = -6,
|
IOERROR = -5,
|
||||||
IOERROR = -5,
|
NOFILE = -4,
|
||||||
NOFILE = -4,
|
NOCARD = -3,
|
||||||
NOCARD = -3,
|
WRONGDEVICE = -2,
|
||||||
WRONGDEVICE = -2,
|
BUSY = -1,
|
||||||
BUSY = -1,
|
READY = 0
|
||||||
READY = 0
|
|
||||||
};
|
};
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
std::string WideToUTF8(std::wstring_view src);
|
std::string WideToUTF8(std::wstring_view src);
|
||||||
std::wstring UTF8ToWide(std::string_view src);
|
std::wstring UTF8ToWide(std::string_view src);
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
||||||
|
|
|
@ -8,5 +8,4 @@
|
||||||
#endif
|
#endif
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
|
|
||||||
void* memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen);
|
void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen);
|
||||||
|
|
||||||
|
|
|
@ -1,161 +1,141 @@
|
||||||
#include "kabufuda/AsyncIO.hpp"
|
#include "kabufuda/AsyncIO.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
|
|
||||||
AsyncIO::AsyncIO(SystemStringView filename, bool truncate)
|
AsyncIO::AsyncIO(SystemStringView filename, bool truncate) {
|
||||||
{
|
m_fd = open(filename.data(), O_RDWR | O_CREAT | (truncate ? O_TRUNC : 0));
|
||||||
m_fd = open(filename.data(), O_RDWR | O_CREAT | (truncate ? O_TRUNC : 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO::~AsyncIO()
|
AsyncIO::~AsyncIO() {
|
||||||
{
|
if (*this) {
|
||||||
if (*this)
|
aio_cancel(m_fd, nullptr);
|
||||||
{
|
close(m_fd);
|
||||||
aio_cancel(m_fd, nullptr);
|
}
|
||||||
close(m_fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO::AsyncIO(AsyncIO&& other)
|
AsyncIO::AsyncIO(AsyncIO&& other) {
|
||||||
{
|
m_fd = other.m_fd;
|
||||||
m_fd = other.m_fd;
|
other.m_fd = -1;
|
||||||
other.m_fd = -1;
|
m_queue = std::move(other.m_queue);
|
||||||
m_queue = std::move(other.m_queue);
|
m_maxBlock = other.m_maxBlock;
|
||||||
m_maxBlock = other.m_maxBlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO& AsyncIO::operator=(AsyncIO&& other)
|
AsyncIO& AsyncIO::operator=(AsyncIO&& other) {
|
||||||
{
|
if (*this) {
|
||||||
if (*this)
|
aio_cancel(m_fd, nullptr);
|
||||||
{
|
close(m_fd);
|
||||||
aio_cancel(m_fd, nullptr);
|
}
|
||||||
close(m_fd);
|
m_fd = other.m_fd;
|
||||||
}
|
other.m_fd = -1;
|
||||||
m_fd = other.m_fd;
|
m_queue = std::move(other.m_queue);
|
||||||
other.m_fd = -1;
|
m_maxBlock = other.m_maxBlock;
|
||||||
m_queue = std::move(other.m_queue);
|
return *this;
|
||||||
m_maxBlock = other.m_maxBlock;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncIO::_waitForOperation(size_t qIdx) const
|
void AsyncIO::_waitForOperation(size_t qIdx) const {
|
||||||
{
|
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
||||||
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
if (aio.first.aio_fildes == 0)
|
||||||
if (aio.first.aio_fildes == 0)
|
return;
|
||||||
return;
|
const struct aiocb* aiop = &aio.first;
|
||||||
const struct aiocb* aiop = &aio.first;
|
struct timespec ts = {2, 0};
|
||||||
struct timespec ts = {2, 0};
|
while (aio_suspend(&aiop, 1, &ts) && errno == EINTR) {}
|
||||||
while (aio_suspend(&aiop, 1, &ts) && errno == EINTR) {}
|
if (aio_error(&aio.first) != EINPROGRESS)
|
||||||
if (aio_error(&aio.first) != EINPROGRESS)
|
aio.second = aio_return(&aio.first);
|
||||||
aio.second = aio_return(&aio.first);
|
aio.first.aio_fildes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) {
|
||||||
|
struct aiocb& aio = m_queue[qIdx].first;
|
||||||
|
if (aio.aio_fildes) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
||||||
|
#endif
|
||||||
|
_waitForOperation(qIdx);
|
||||||
|
}
|
||||||
|
memset(&aio, 0, sizeof(struct aiocb));
|
||||||
|
aio.aio_fildes = m_fd;
|
||||||
|
aio.aio_offset = offset;
|
||||||
|
aio.aio_buf = buf;
|
||||||
|
aio.aio_nbytes = length;
|
||||||
|
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
||||||
|
return aio_read(&aio) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset) {
|
||||||
|
struct aiocb& aio = m_queue[qIdx].first;
|
||||||
|
if (aio.aio_fildes) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
||||||
|
#endif
|
||||||
|
_waitForOperation(qIdx);
|
||||||
|
}
|
||||||
|
memset(&aio, 0, sizeof(struct aiocb));
|
||||||
|
aio.aio_fildes = m_fd;
|
||||||
|
aio.aio_offset = offset;
|
||||||
|
aio.aio_buf = const_cast<void*>(buf);
|
||||||
|
aio.aio_nbytes = length;
|
||||||
|
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
||||||
|
return aio_write(&aio) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const {
|
||||||
|
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
||||||
|
if (aio.first.aio_fildes == 0) {
|
||||||
|
if (szRet)
|
||||||
|
*szRet = aio.second;
|
||||||
|
return ECardResult::READY;
|
||||||
|
}
|
||||||
|
switch (aio_error(&aio.first)) {
|
||||||
|
case 0:
|
||||||
|
aio.second = aio_return(&aio.first);
|
||||||
aio.first.aio_fildes = 0;
|
aio.first.aio_fildes = 0;
|
||||||
|
if (szRet)
|
||||||
|
*szRet = aio.second;
|
||||||
|
return ECardResult::READY;
|
||||||
|
case EINPROGRESS:
|
||||||
|
return ECardResult::BUSY;
|
||||||
|
default:
|
||||||
|
aio.second = aio_return(&aio.first);
|
||||||
|
aio.first.aio_fildes = 0;
|
||||||
|
if (szRet)
|
||||||
|
*szRet = aio.second;
|
||||||
|
return ECardResult::IOERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset)
|
ECardResult AsyncIO::pollStatus() const {
|
||||||
{
|
ECardResult result = ECardResult::READY;
|
||||||
struct aiocb& aio = m_queue[qIdx].first;
|
for (auto it = const_cast<AsyncIO*>(this)->m_queue.begin();
|
||||||
if (aio.aio_fildes)
|
it != const_cast<AsyncIO*>(this)->m_queue.begin() + m_maxBlock; ++it) {
|
||||||
{
|
auto& aio = *it;
|
||||||
#ifndef NDEBUG
|
|
||||||
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
|
||||||
#endif
|
|
||||||
_waitForOperation(qIdx);
|
|
||||||
}
|
|
||||||
memset(&aio, 0, sizeof(struct aiocb));
|
|
||||||
aio.aio_fildes = m_fd;
|
|
||||||
aio.aio_offset = offset;
|
|
||||||
aio.aio_buf = buf;
|
|
||||||
aio.aio_nbytes = length;
|
|
||||||
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
|
||||||
return aio_read(&aio) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset)
|
|
||||||
{
|
|
||||||
struct aiocb& aio = m_queue[qIdx].first;
|
|
||||||
if (aio.aio_fildes)
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
|
||||||
#endif
|
|
||||||
_waitForOperation(qIdx);
|
|
||||||
}
|
|
||||||
memset(&aio, 0, sizeof(struct aiocb));
|
|
||||||
aio.aio_fildes = m_fd;
|
|
||||||
aio.aio_offset = offset;
|
|
||||||
aio.aio_buf = const_cast<void*>(buf);
|
|
||||||
aio.aio_nbytes = length;
|
|
||||||
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
|
||||||
return aio_write(&aio) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const
|
|
||||||
{
|
|
||||||
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
|
||||||
if (aio.first.aio_fildes == 0)
|
if (aio.first.aio_fildes == 0)
|
||||||
{
|
continue;
|
||||||
if (szRet)
|
switch (aio_error(&aio.first)) {
|
||||||
*szRet = aio.second;
|
|
||||||
return ECardResult::READY;
|
|
||||||
}
|
|
||||||
switch (aio_error(&aio.first))
|
|
||||||
{
|
|
||||||
case 0:
|
case 0:
|
||||||
aio.second = aio_return(&aio.first);
|
aio.second = aio_return(&aio.first);
|
||||||
aio.first.aio_fildes = 0;
|
aio.first.aio_fildes = 0;
|
||||||
if (szRet)
|
break;
|
||||||
*szRet = aio.second;
|
|
||||||
return ECardResult::READY;
|
|
||||||
case EINPROGRESS:
|
case EINPROGRESS:
|
||||||
return ECardResult::BUSY;
|
if (result > ECardResult::BUSY)
|
||||||
|
result = ECardResult::BUSY;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
aio.second = aio_return(&aio.first);
|
aio.second = aio_return(&aio.first);
|
||||||
aio.first.aio_fildes = 0;
|
aio.first.aio_fildes = 0;
|
||||||
if (szRet)
|
if (result > ECardResult::IOERROR)
|
||||||
*szRet = aio.second;
|
result = ECardResult::IOERROR;
|
||||||
return ECardResult::IOERROR;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (result == ECardResult::READY)
|
||||||
ECardResult AsyncIO::pollStatus() const
|
|
||||||
{
|
|
||||||
ECardResult result = ECardResult::READY;
|
|
||||||
for (auto it = const_cast<AsyncIO*>(this)->m_queue.begin();
|
|
||||||
it != const_cast<AsyncIO*>(this)->m_queue.begin() + m_maxBlock;
|
|
||||||
++it)
|
|
||||||
{
|
|
||||||
auto& aio = *it;
|
|
||||||
if (aio.first.aio_fildes == 0)
|
|
||||||
continue;
|
|
||||||
switch (aio_error(&aio.first))
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
aio.second = aio_return(&aio.first);
|
|
||||||
aio.first.aio_fildes = 0;
|
|
||||||
break;
|
|
||||||
case EINPROGRESS:
|
|
||||||
if (result > ECardResult::BUSY)
|
|
||||||
result = ECardResult::BUSY;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
aio.second = aio_return(&aio.first);
|
|
||||||
aio.first.aio_fildes = 0;
|
|
||||||
if (result > ECardResult::IOERROR)
|
|
||||||
result = ECardResult::IOERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result == ECardResult::READY)
|
|
||||||
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncIO::waitForCompletion() const
|
|
||||||
{
|
|
||||||
for (size_t i=0 ; i<m_maxBlock ; ++i)
|
|
||||||
_waitForOperation(i);
|
|
||||||
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncIO::waitForCompletion() const {
|
||||||
|
for (size_t i = 0; i < m_maxBlock; ++i)
|
||||||
|
_waitForOperation(i);
|
||||||
|
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace kabufuda
|
||||||
|
|
|
@ -1,191 +1,153 @@
|
||||||
#include "kabufuda/AsyncIO.hpp"
|
#include "kabufuda/AsyncIO.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
|
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0)
|
static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) {
|
||||||
{
|
aio.Internal = 0;
|
||||||
aio.Internal = 0;
|
aio.InternalHigh = 0;
|
||||||
aio.InternalHigh = 0;
|
aio.Offset = offset;
|
||||||
aio.Offset = offset;
|
aio.OffsetHigh = 0;
|
||||||
aio.OffsetHigh = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO::AsyncIO(SystemStringView filename, bool truncate)
|
AsyncIO::AsyncIO(SystemStringView filename, bool truncate) {
|
||||||
{
|
|
||||||
#if WINDOWS_STORE
|
#if WINDOWS_STORE
|
||||||
CREATEFILE2_EXTENDED_PARAMETERS parms = {};
|
CREATEFILE2_EXTENDED_PARAMETERS parms = {};
|
||||||
parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
|
parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
|
||||||
parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||||
parms.dwFileFlags = FILE_FLAG_OVERLAPPED;
|
parms.dwFileFlags = FILE_FLAG_OVERLAPPED;
|
||||||
m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE,
|
m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms);
|
||||||
truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms);
|
|
||||||
#else
|
#else
|
||||||
m_fh = CreateFileW(filename.data(), GENERIC_READ | GENERIC_WRITE,
|
m_fh = CreateFileW(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
truncate ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
nullptr, truncate ? CREATE_ALWAYS : OPEN_ALWAYS,
|
|
||||||
FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO::~AsyncIO()
|
AsyncIO::~AsyncIO() {
|
||||||
{
|
if (*this) {
|
||||||
if (*this)
|
if (CancelIoEx(m_fh, nullptr))
|
||||||
{
|
waitForCompletion();
|
||||||
if (CancelIoEx(m_fh, nullptr))
|
CloseHandle(m_fh);
|
||||||
waitForCompletion();
|
}
|
||||||
CloseHandle(m_fh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO::AsyncIO(AsyncIO&& other)
|
AsyncIO::AsyncIO(AsyncIO&& other) {
|
||||||
{
|
m_fh = other.m_fh;
|
||||||
m_fh = other.m_fh;
|
other.m_fh = INVALID_HANDLE_VALUE;
|
||||||
other.m_fh = INVALID_HANDLE_VALUE;
|
m_queue = std::move(other.m_queue);
|
||||||
m_queue = std::move(other.m_queue);
|
m_maxBlock = other.m_maxBlock;
|
||||||
m_maxBlock = other.m_maxBlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncIO& AsyncIO::operator=(AsyncIO&& other)
|
AsyncIO& AsyncIO::operator=(AsyncIO&& other) {
|
||||||
{
|
if (*this) {
|
||||||
if (*this)
|
if (CancelIoEx(m_fh, nullptr))
|
||||||
{
|
waitForCompletion();
|
||||||
if (CancelIoEx(m_fh, nullptr))
|
CloseHandle(m_fh);
|
||||||
waitForCompletion();
|
}
|
||||||
CloseHandle(m_fh);
|
m_fh = other.m_fh;
|
||||||
}
|
other.m_fh = INVALID_HANDLE_VALUE;
|
||||||
m_fh = other.m_fh;
|
m_queue = std::move(other.m_queue);
|
||||||
other.m_fh = INVALID_HANDLE_VALUE;
|
m_maxBlock = other.m_maxBlock;
|
||||||
m_queue = std::move(other.m_queue);
|
return *this;
|
||||||
m_maxBlock = other.m_maxBlock;
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncIO::_waitForOperation(size_t qIdx) const
|
void AsyncIO::_waitForOperation(size_t qIdx) const {
|
||||||
{
|
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
||||||
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
if (aio.first.hEvent == 0)
|
||||||
if (aio.first.hEvent == 0)
|
return;
|
||||||
return;
|
GetOverlappedResult(m_fh, &aio.first, &aio.second, TRUE);
|
||||||
GetOverlappedResult(m_fh, &aio.first, &aio.second, TRUE);
|
CloseHandle(aio.first.hEvent);
|
||||||
|
aio.first.hEvent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset) {
|
||||||
|
OVERLAPPED& aio = m_queue[qIdx].first;
|
||||||
|
if (aio.hEvent) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
||||||
|
#endif
|
||||||
|
_waitForOperation(qIdx);
|
||||||
|
} else {
|
||||||
|
aio.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
}
|
||||||
|
ResetOverlapped(aio, DWORD(offset));
|
||||||
|
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
||||||
|
BOOL res = ReadFile(m_fh, buf, length, nullptr, &aio);
|
||||||
|
return res == TRUE || GetLastError() == ERROR_IO_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset) {
|
||||||
|
OVERLAPPED& aio = m_queue[qIdx].first;
|
||||||
|
if (aio.hEvent) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
||||||
|
#endif
|
||||||
|
_waitForOperation(qIdx);
|
||||||
|
} else {
|
||||||
|
aio.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||||
|
}
|
||||||
|
ResetOverlapped(aio, DWORD(offset));
|
||||||
|
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
||||||
|
BOOL res = WriteFile(m_fh, buf, length, nullptr, &aio);
|
||||||
|
return res == TRUE || GetLastError() == ERROR_IO_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const {
|
||||||
|
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
||||||
|
if (aio.first.hEvent == 0) {
|
||||||
|
if (szRet)
|
||||||
|
*szRet = aio.second;
|
||||||
|
return ECardResult::READY;
|
||||||
|
}
|
||||||
|
if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) {
|
||||||
CloseHandle(aio.first.hEvent);
|
CloseHandle(aio.first.hEvent);
|
||||||
aio.first.hEvent = 0;
|
aio.first.hEvent = 0;
|
||||||
|
if (szRet)
|
||||||
|
*szRet = aio.second;
|
||||||
|
return ECardResult::READY;
|
||||||
|
} else {
|
||||||
|
if (GetLastError() == ERROR_IO_INCOMPLETE) {
|
||||||
|
return ECardResult::BUSY;
|
||||||
|
} else {
|
||||||
|
_waitForOperation(qIdx);
|
||||||
|
return ECardResult::IOERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AsyncIO::asyncRead(size_t qIdx, void* buf, size_t length, off_t offset)
|
ECardResult AsyncIO::pollStatus() const {
|
||||||
{
|
ECardResult result = ECardResult::READY;
|
||||||
OVERLAPPED& aio = m_queue[qIdx].first;
|
for (auto it = const_cast<AsyncIO*>(this)->m_queue.begin();
|
||||||
if (aio.hEvent)
|
it != const_cast<AsyncIO*>(this)->m_queue.begin() + m_maxBlock; ++it) {
|
||||||
{
|
auto& aio = *it;
|
||||||
#ifndef NDEBUG
|
|
||||||
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
|
||||||
#endif
|
|
||||||
_waitForOperation(qIdx);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aio.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
|
||||||
}
|
|
||||||
ResetOverlapped(aio, DWORD(offset));
|
|
||||||
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
|
||||||
BOOL res = ReadFile(m_fh, buf, length, nullptr, &aio);
|
|
||||||
return res == TRUE || GetLastError() == ERROR_IO_PENDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AsyncIO::asyncWrite(size_t qIdx, const void* buf, size_t length, off_t offset)
|
|
||||||
{
|
|
||||||
OVERLAPPED& aio = m_queue[qIdx].first;
|
|
||||||
if (aio.hEvent)
|
|
||||||
{
|
|
||||||
#ifndef NDEBUG
|
|
||||||
fprintf(stderr, "WARNING: synchronous kabufuda fallback, check access polling\n");
|
|
||||||
#endif
|
|
||||||
_waitForOperation(qIdx);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
aio.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
|
||||||
}
|
|
||||||
ResetOverlapped(aio, DWORD(offset));
|
|
||||||
m_maxBlock = std::max(m_maxBlock, qIdx + 1);
|
|
||||||
BOOL res = WriteFile(m_fh, buf, length, nullptr, &aio);
|
|
||||||
return res == TRUE || GetLastError() == ERROR_IO_PENDING;
|
|
||||||
}
|
|
||||||
|
|
||||||
ECardResult AsyncIO::pollStatus(size_t qIdx, SizeReturn* szRet) const
|
|
||||||
{
|
|
||||||
auto& aio = const_cast<AsyncIO*>(this)->m_queue[qIdx];
|
|
||||||
if (aio.first.hEvent == 0)
|
if (aio.first.hEvent == 0)
|
||||||
{
|
continue;
|
||||||
if (szRet)
|
if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) {
|
||||||
*szRet = aio.second;
|
CloseHandle(aio.first.hEvent);
|
||||||
return ECardResult::READY;
|
aio.first.hEvent = 0;
|
||||||
|
} else {
|
||||||
|
if (GetLastError() == ERROR_IO_INCOMPLETE) {
|
||||||
|
if (result > ECardResult::BUSY)
|
||||||
|
result = ECardResult::BUSY;
|
||||||
|
} else {
|
||||||
|
_waitForOperation(it - m_queue.cbegin());
|
||||||
|
if (result > ECardResult::IOERROR)
|
||||||
|
result = ECardResult::IOERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE))
|
}
|
||||||
{
|
if (result == ECardResult::READY)
|
||||||
CloseHandle(aio.first.hEvent);
|
|
||||||
aio.first.hEvent = 0;
|
|
||||||
if (szRet)
|
|
||||||
*szRet = aio.second;
|
|
||||||
return ECardResult::READY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (GetLastError() == ERROR_IO_INCOMPLETE)
|
|
||||||
{
|
|
||||||
return ECardResult::BUSY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_waitForOperation(qIdx);
|
|
||||||
return ECardResult::IOERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ECardResult AsyncIO::pollStatus() const
|
|
||||||
{
|
|
||||||
ECardResult result = ECardResult::READY;
|
|
||||||
for (auto it = const_cast<AsyncIO*>(this)->m_queue.begin();
|
|
||||||
it != const_cast<AsyncIO*>(this)->m_queue.begin() + m_maxBlock;
|
|
||||||
++it)
|
|
||||||
{
|
|
||||||
auto& aio = *it;
|
|
||||||
if (aio.first.hEvent == 0)
|
|
||||||
continue;
|
|
||||||
if (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE))
|
|
||||||
{
|
|
||||||
CloseHandle(aio.first.hEvent);
|
|
||||||
aio.first.hEvent = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (GetLastError() == ERROR_IO_INCOMPLETE)
|
|
||||||
{
|
|
||||||
if (result > ECardResult::BUSY)
|
|
||||||
result = ECardResult::BUSY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_waitForOperation(it - m_queue.cbegin());
|
|
||||||
if (result > ECardResult::IOERROR)
|
|
||||||
result = ECardResult::IOERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result == ECardResult::READY)
|
|
||||||
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AsyncIO::waitForCompletion() const
|
|
||||||
{
|
|
||||||
for (size_t i=0 ; i<m_maxBlock ; ++i)
|
|
||||||
_waitForOperation(i);
|
|
||||||
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncIO::waitForCompletion() const {
|
||||||
|
for (size_t i = 0; i < m_maxBlock; ++i)
|
||||||
|
_waitForOperation(i);
|
||||||
|
const_cast<AsyncIO*>(this)->m_maxBlock = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace kabufuda
|
||||||
|
|
|
@ -2,112 +2,97 @@
|
||||||
#include "kabufuda/Util.hpp"
|
#include "kabufuda/Util.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
void BlockAllocationTable::swapEndian() {
|
||||||
void BlockAllocationTable::swapEndian()
|
m_checksum = SBig(m_checksum);
|
||||||
{
|
m_checksumInv = SBig(m_checksumInv);
|
||||||
m_checksum = SBig(m_checksum);
|
m_updateCounter = SBig(m_updateCounter);
|
||||||
m_checksumInv = SBig(m_checksumInv);
|
m_freeBlocks = SBig(m_freeBlocks);
|
||||||
m_updateCounter = SBig(m_updateCounter);
|
m_lastAllocated = SBig(m_lastAllocated);
|
||||||
m_freeBlocks = SBig(m_freeBlocks);
|
std::for_each(std::begin(m_map), std::end(m_map), [](uint16_t& val) { val = SBig(val); });
|
||||||
m_lastAllocated = SBig(m_lastAllocated);
|
|
||||||
std::for_each(std::begin(m_map), std::end(m_map), [](uint16_t& val) { val = SBig(val); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockAllocationTable::updateChecksum()
|
void BlockAllocationTable::updateChecksum() {
|
||||||
{
|
swapEndian();
|
||||||
swapEndian();
|
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
swapEndian();
|
||||||
swapEndian();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockAllocationTable::valid() const
|
bool BlockAllocationTable::valid() const {
|
||||||
{
|
uint16_t ckSum, ckSumInv;
|
||||||
uint16_t ckSum, ckSumInv;
|
const_cast<BlockAllocationTable&>(*this).swapEndian();
|
||||||
const_cast<BlockAllocationTable&>(*this).swapEndian();
|
calculateChecksumBE(reinterpret_cast<const uint16_t*>(__raw + 4), 0xFFE, &ckSum, &ckSumInv);
|
||||||
calculateChecksumBE(reinterpret_cast<const uint16_t*>(__raw + 4), 0xFFE, &ckSum, &ckSumInv);
|
bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv);
|
||||||
bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv);
|
const_cast<BlockAllocationTable&>(*this).swapEndian();
|
||||||
const_cast<BlockAllocationTable&>(*this).swapEndian();
|
return res;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
|
BlockAllocationTable::BlockAllocationTable(uint32_t blockCount) {
|
||||||
{
|
memset(__raw, 0, BlockSize);
|
||||||
memset(__raw, 0, BlockSize);
|
m_freeBlocks = uint16_t(blockCount - FSTBlocks);
|
||||||
m_freeBlocks = uint16_t(blockCount - FSTBlocks);
|
m_lastAllocated = 4;
|
||||||
m_lastAllocated = 4;
|
updateChecksum();
|
||||||
updateChecksum();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 0xFFFF;
|
|
||||||
|
|
||||||
return m_map[block - FSTBlocks];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t BlockAllocationTable::nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const
|
|
||||||
{
|
|
||||||
if (m_freeBlocks > 0)
|
|
||||||
{
|
|
||||||
maxBlock = std::min(maxBlock, uint16_t(BATSize));
|
|
||||||
for (uint16_t i = startingBlock; i < maxBlock; ++i)
|
|
||||||
if (m_map[i - FSTBlocks] == 0)
|
|
||||||
return i;
|
|
||||||
|
|
||||||
for (uint16_t i = FSTBlocks; i < startingBlock; ++i)
|
|
||||||
if (m_map[i - FSTBlocks] == 0)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0xFFFF;
|
return 0xFFFF;
|
||||||
|
|
||||||
|
return m_map[block - FSTBlocks];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockAllocationTable::clear(uint16_t first, uint16_t count)
|
uint16_t BlockAllocationTable::nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const {
|
||||||
{
|
if (m_freeBlocks > 0) {
|
||||||
std::vector<uint16_t> blocks;
|
maxBlock = std::min(maxBlock, uint16_t(BATSize));
|
||||||
while (first != 0xFFFF && first != 0)
|
for (uint16_t i = startingBlock; i < maxBlock; ++i)
|
||||||
{
|
if (m_map[i - FSTBlocks] == 0)
|
||||||
blocks.push_back(first);
|
return i;
|
||||||
first = getNextBlock(first);
|
|
||||||
|
for (uint16_t i = FSTBlocks; i < startingBlock; ++i)
|
||||||
|
if (m_map[i - FSTBlocks] == 0)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlockAllocationTable::clear(uint16_t first, uint16_t count) {
|
||||||
|
std::vector<uint16_t> blocks;
|
||||||
|
while (first != 0xFFFF && first != 0) {
|
||||||
|
blocks.push_back(first);
|
||||||
|
first = getNextBlock(first);
|
||||||
|
}
|
||||||
|
if (first > 0) {
|
||||||
|
size_t length = blocks.size();
|
||||||
|
if (length != count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; ++i)
|
||||||
|
m_map[blocks.at(i) - FSTBlocks] = 0;
|
||||||
|
m_freeBlocks += count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BlockAllocationTable::allocateBlocks(uint16_t count, uint16_t maxBlocks) {
|
||||||
|
uint16_t firstBlock = nextFreeBlock(maxBlocks - FSTBlocks, m_lastAllocated + 1);
|
||||||
|
uint16_t freeBlock = firstBlock;
|
||||||
|
if (freeBlock != 0xFFFF) {
|
||||||
|
uint16_t tmpCount = count;
|
||||||
|
while ((count--) > 0 && freeBlock != 0xFFFF) {
|
||||||
|
m_map[(freeBlock - FSTBlocks)] = 0xFFFF;
|
||||||
|
if (count != 0) {
|
||||||
|
m_map[(freeBlock - FSTBlocks)] = nextFreeBlock(maxBlocks - FSTBlocks, freeBlock + 1);
|
||||||
|
freeBlock = m_map[(freeBlock - FSTBlocks)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (first > 0)
|
if (freeBlock == 0xFFFF)
|
||||||
{
|
return 0xFFFF;
|
||||||
size_t length = blocks.size();
|
|
||||||
if (length != count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
m_lastAllocated = freeBlock;
|
||||||
m_map[blocks.at(i) - FSTBlocks] = 0;
|
m_freeBlocks -= tmpCount;
|
||||||
m_freeBlocks += count;
|
}
|
||||||
return true;
|
return firstBlock;
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t BlockAllocationTable::allocateBlocks(uint16_t count, uint16_t maxBlocks)
|
|
||||||
{
|
|
||||||
uint16_t firstBlock = nextFreeBlock(maxBlocks - FSTBlocks, m_lastAllocated + 1);
|
|
||||||
uint16_t freeBlock = firstBlock;
|
|
||||||
if (freeBlock != 0xFFFF)
|
|
||||||
{
|
|
||||||
uint16_t tmpCount = count;
|
|
||||||
while ((count--) > 0 && freeBlock != 0xFFFF)
|
|
||||||
{
|
|
||||||
m_map[(freeBlock - FSTBlocks)] = 0xFFFF;
|
|
||||||
if (count != 0)
|
|
||||||
{
|
|
||||||
m_map[(freeBlock - FSTBlocks)] = nextFreeBlock(maxBlocks - FSTBlocks, freeBlock + 1);
|
|
||||||
freeBlock = m_map[(freeBlock - FSTBlocks)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (freeBlock == 0xFFFF)
|
|
||||||
return 0xFFFF;
|
|
||||||
|
|
||||||
m_lastAllocated = freeBlock;
|
|
||||||
m_freeBlocks -= tmpCount;
|
|
||||||
}
|
|
||||||
return firstBlock;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace kabufuda
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,131 +2,111 @@
|
||||||
#include "kabufuda/Util.hpp"
|
#include "kabufuda/Util.hpp"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
void Directory::swapEndian() {
|
||||||
void Directory::swapEndian()
|
std::for_each(std::begin(m_files), std::end(m_files), [](File& f) { f.swapEndian(); });
|
||||||
{
|
|
||||||
std::for_each(std::begin(m_files), std::end(m_files), [](File& f) { f.swapEndian(); });
|
|
||||||
|
|
||||||
m_updateCounter = SBig(m_updateCounter);
|
m_updateCounter = SBig(m_updateCounter);
|
||||||
m_checksum = SBig(m_checksum);
|
m_checksum = SBig(m_checksum);
|
||||||
m_checksumInv = SBig(m_checksumInv);
|
m_checksumInv = SBig(m_checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Directory::updateChecksum()
|
void Directory::updateChecksum() {
|
||||||
{
|
swapEndian();
|
||||||
swapEndian();
|
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
calculateChecksumBE(reinterpret_cast<uint16_t*>(__raw), 0xFFE, &m_checksum, &m_checksumInv);
|
swapEndian();
|
||||||
swapEndian();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Directory::valid() const
|
bool Directory::valid() const {
|
||||||
{
|
uint16_t ckSum, ckSumInv;
|
||||||
uint16_t ckSum, ckSumInv;
|
const_cast<Directory&>(*this).swapEndian();
|
||||||
const_cast<Directory&>(*this).swapEndian();
|
calculateChecksumBE(reinterpret_cast<const uint16_t*>(__raw), 0xFFE, &ckSum, &ckSumInv);
|
||||||
calculateChecksumBE(reinterpret_cast<const uint16_t*>(__raw), 0xFFE, &ckSum, &ckSumInv);
|
bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv);
|
||||||
bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv);
|
const_cast<Directory&>(*this).swapEndian();
|
||||||
const_cast<Directory&>(*this).swapEndian();
|
return res;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::Directory()
|
Directory::Directory() {
|
||||||
{
|
memset(__raw, 0xFF, BlockSize);
|
||||||
memset(__raw, 0xFF, BlockSize);
|
m_updateCounter = 0;
|
||||||
m_updateCounter = 0;
|
updateChecksum();
|
||||||
updateChecksum();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::Directory(uint8_t data[]) { memcpy(__raw, data, BlockSize); }
|
Directory::Directory(uint8_t data[]) { memcpy(__raw, data, BlockSize); }
|
||||||
|
|
||||||
bool Directory::hasFreeFile() const
|
bool Directory::hasFreeFile() const {
|
||||||
{
|
for (uint16_t i = 0; i < 127; i++)
|
||||||
for (uint16_t i = 0; i < 127; i++)
|
if (m_files[i].m_game[0] == 0xFF)
|
||||||
if (m_files[i].m_game[0] == 0xFF)
|
return true;
|
||||||
return true;
|
return false;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Directory::numFreeFiles() const
|
int32_t Directory::numFreeFiles() const {
|
||||||
{
|
int32_t ret = 0;
|
||||||
int32_t ret = 0;
|
for (uint16_t i = 0; i < 127; i++)
|
||||||
for (uint16_t i = 0; i < 127; i++)
|
if (m_files[i].m_game[0] == 0xFF)
|
||||||
if (m_files[i].m_game[0] == 0xFF)
|
++ret;
|
||||||
++ret;
|
return 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++)
|
if (m_files[i].m_game[0] == 0xFF) {
|
||||||
{
|
File* ret = &m_files[i];
|
||||||
if (m_files[i].m_game[0] == 0xFF)
|
*ret = File(filename);
|
||||||
{
|
if (game && strlen(game) == 4)
|
||||||
File* ret = &m_files[i];
|
memcpy(ret->m_game, game, 4);
|
||||||
*ret = File(filename);
|
if (maker && strlen(maker) == 2)
|
||||||
if (game && strlen(game) == 4)
|
memcpy(ret->m_maker, maker, 2);
|
||||||
memcpy(ret->m_game, game, 4);
|
return ret;
|
||||||
if (maker && strlen(maker) == 2)
|
|
||||||
memcpy(ret->m_maker, maker, 2);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
File* Directory::getFirstNonFreeFile(uint32_t start, const char* game, const char* maker)
|
File* Directory::getFirstNonFreeFile(uint32_t start, const char* game, const char* maker) {
|
||||||
{
|
for (uint16_t i = start; i < 127; i++) {
|
||||||
for (uint16_t i = start; i < 127; i++)
|
if (m_files[i].m_game[0] != 0xFF) {
|
||||||
{
|
File* ret = &m_files[i];
|
||||||
if (m_files[i].m_game[0] != 0xFF)
|
if (game && std::strlen(game) == 4 && std::strncmp(reinterpret_cast<const char*>(ret->m_game), game, 4) != 0)
|
||||||
{
|
continue;
|
||||||
File* ret = &m_files[i];
|
if (maker && std::strlen(maker) == 2 && std::strncmp(reinterpret_cast<const char*>(ret->m_maker), maker, 2) != 0)
|
||||||
if (game && std::strlen(game) == 4 &&
|
continue;
|
||||||
std::strncmp(reinterpret_cast<const char*>(ret->m_game), game, 4) != 0)
|
return ret;
|
||||||
continue;
|
|
||||||
if (maker && std::strlen(maker) == 2 &&
|
|
||||||
std::strncmp(reinterpret_cast<const char*>(ret->m_maker), maker, 2) != 0)
|
|
||||||
continue;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
File* Directory::getFile(const char* game, const char* maker, const char* filename) {
|
||||||
|
for (uint16_t i = 0; i < 127; i++) {
|
||||||
|
if (game && strlen(game) == 4 && memcmp(m_files[i].m_game, game, 4))
|
||||||
|
continue;
|
||||||
|
if (maker && strlen(maker) == 2 && memcmp(m_files[i].m_maker, maker, 2))
|
||||||
|
continue;
|
||||||
|
if (!strcmp(m_files[i].m_filename, filename))
|
||||||
|
return &m_files[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
File* Directory::getFile(uint32_t idx) {
|
||||||
|
if (idx >= 127)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
return &m_files[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
File* Directory::getFile(const char* game, const char* maker, const char* filename)
|
int32_t Directory::indexForFile(File* f) {
|
||||||
{
|
if (!f)
|
||||||
for (uint16_t i = 0; i < 127; i++)
|
return -1;
|
||||||
{
|
|
||||||
if (game && strlen(game) == 4 && memcmp(m_files[i].m_game, game, 4))
|
|
||||||
continue;
|
|
||||||
if (maker && strlen(maker) == 2 && memcmp(m_files[i].m_maker, maker, 2))
|
|
||||||
continue;
|
|
||||||
if (!strcmp(m_files[i].m_filename, filename))
|
|
||||||
return &m_files[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
auto it = std::find_if(std::begin(m_files), std::end(m_files), [&f](const File& file) -> bool { return f == &file; });
|
||||||
}
|
if (it == std::end(m_files))
|
||||||
|
return -1;
|
||||||
File* Directory::getFile(uint32_t idx)
|
return it - std::begin(m_files);
|
||||||
{
|
|
||||||
if (idx >= 127)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return &m_files[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t Directory::indexForFile(File* f)
|
|
||||||
{
|
|
||||||
if (!f)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
auto it =
|
|
||||||
std::find_if(std::begin(m_files), std::end(m_files), [&f](const File& file) -> bool { return f == &file; });
|
|
||||||
if (it == std::end(m_files))
|
|
||||||
return -1;
|
|
||||||
return it - std::begin(m_files);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} // namespace kabufuda
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
#include "kabufuda/File.hpp"
|
#include "kabufuda/File.hpp"
|
||||||
#include "kabufuda/Util.hpp"
|
#include "kabufuda/Util.hpp"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
File::File() { memset(__raw, 0xFF, 0x40); }
|
File::File() { memset(__raw, 0xFF, 0x40); }
|
||||||
|
|
||||||
File::File(char data[]) { memcpy(__raw, data, 0x40); }
|
File::File(char data[]) { memcpy(__raw, data, 0x40); }
|
||||||
|
|
||||||
File::File(const char* filename)
|
File::File(const char* filename) {
|
||||||
{
|
memset(__raw, 0, 0x40);
|
||||||
memset(__raw, 0, 0x40);
|
memset(m_filename, 0, 32);
|
||||||
memset(m_filename, 0, 32);
|
strncpy(m_filename, filename, 32);
|
||||||
strncpy(m_filename, filename, 32);
|
|
||||||
}
|
|
||||||
void File::swapEndian()
|
|
||||||
{
|
|
||||||
m_modifiedTime = SBig(m_modifiedTime);
|
|
||||||
m_iconAddress = SBig(m_iconAddress);
|
|
||||||
m_iconFmt = SBig(m_iconFmt);
|
|
||||||
m_animSpeed = SBig(m_animSpeed);
|
|
||||||
m_firstBlock = SBig(m_firstBlock);
|
|
||||||
m_blockCount = SBig(m_blockCount);
|
|
||||||
m_reserved2 = SBig(m_reserved2);
|
|
||||||
m_commentAddr = SBig(m_commentAddr);
|
|
||||||
}
|
}
|
||||||
|
void File::swapEndian() {
|
||||||
|
m_modifiedTime = SBig(m_modifiedTime);
|
||||||
|
m_iconAddress = SBig(m_iconAddress);
|
||||||
|
m_iconFmt = SBig(m_iconFmt);
|
||||||
|
m_animSpeed = SBig(m_animSpeed);
|
||||||
|
m_firstBlock = SBig(m_firstBlock);
|
||||||
|
m_blockCount = SBig(m_blockCount);
|
||||||
|
m_reserved2 = SBig(m_reserved2);
|
||||||
|
m_commentAddr = SBig(m_commentAddr);
|
||||||
}
|
}
|
||||||
|
} // namespace kabufuda
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "kabufuda/SRAM.hpp"
|
#include "kabufuda/SRAM.hpp"
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const SRAM g_SRAM =
|
const SRAM g_SRAM =
|
||||||
{{
|
{{
|
||||||
|
@ -27,4 +26,4 @@ const SRAM g_SRAM =
|
||||||
0x00, 0x00
|
0x00, 0x00
|
||||||
}};
|
}};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
|
@ -1,45 +1,41 @@
|
||||||
#include "kabufuda/Util.hpp"
|
#include "kabufuda/Util.hpp"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
uint64_t getGCTime() {
|
||||||
uint64_t getGCTime()
|
time_t sysTime, tzDiff, tzDST;
|
||||||
{
|
struct tm* gmTime;
|
||||||
time_t sysTime, tzDiff, tzDST;
|
|
||||||
struct tm* gmTime;
|
|
||||||
|
|
||||||
time(&sysTime);
|
time(&sysTime);
|
||||||
|
|
||||||
// Account for DST where needed
|
// Account for DST where needed
|
||||||
gmTime = localtime(&sysTime);
|
gmTime = localtime(&sysTime);
|
||||||
if (gmTime->tm_isdst == 1)
|
if (gmTime->tm_isdst == 1)
|
||||||
tzDST = 3600;
|
tzDST = 3600;
|
||||||
else
|
else
|
||||||
tzDST = 0;
|
tzDST = 0;
|
||||||
|
|
||||||
// Lazy way to get local time in sec
|
// Lazy way to get local time in sec
|
||||||
gmTime = gmtime(&sysTime);
|
gmTime = gmtime(&sysTime);
|
||||||
tzDiff = sysTime - mktime(gmTime);
|
tzDiff = sysTime - mktime(gmTime);
|
||||||
|
|
||||||
return (uint64_t)(sysTime + tzDiff + tzDST) - 0x386D4380;
|
return (uint64_t)(sysTime + tzDiff + tzDST) - 0x386D4380;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
{
|
*checksum = 0;
|
||||||
|
*checksumInv = 0;
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
*checksum += SBig(data[i]);
|
||||||
|
*checksumInv += SBig(uint16_t(data[i] ^ 0xFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
*checksum = SBig(*checksum);
|
||||||
|
*checksumInv = SBig(*checksumInv);
|
||||||
|
if (*checksum == 0xFFFF)
|
||||||
*checksum = 0;
|
*checksum = 0;
|
||||||
|
if (*checksumInv == 0xFFFF)
|
||||||
*checksumInv = 0;
|
*checksumInv = 0;
|
||||||
for (size_t i = 0; i < len; ++i)
|
|
||||||
{
|
|
||||||
*checksum += SBig(data[i]);
|
|
||||||
*checksumInv += SBig(uint16_t(data[i] ^ 0xFFFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
*checksum = SBig(*checksum);
|
|
||||||
*checksumInv = SBig(*checksumInv);
|
|
||||||
if (*checksum == 0xFFFF)
|
|
||||||
*checksum = 0;
|
|
||||||
if (*checksumInv == 0xFFFF)
|
|
||||||
*checksumInv = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace kabufuda
|
||||||
|
|
|
@ -1,43 +1,36 @@
|
||||||
#include "kabufuda/WideStringConvert.hpp"
|
#include "kabufuda/WideStringConvert.hpp"
|
||||||
#include "utf8proc.h"
|
#include "utf8proc.h"
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda {
|
||||||
{
|
std::string WideToUTF8(std::wstring_view src) {
|
||||||
std::string WideToUTF8(std::wstring_view src)
|
std::string retval;
|
||||||
{
|
retval.reserve(src.length());
|
||||||
std::string retval;
|
for (wchar_t ch : src) {
|
||||||
retval.reserve(src.length());
|
utf8proc_uint8_t mb[4];
|
||||||
for (wchar_t ch : src)
|
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
|
||||||
{
|
if (c < 0) {
|
||||||
utf8proc_uint8_t mb[4];
|
fprintf(stderr, "invalid UTF-8 character while encoding");
|
||||||
utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb);
|
return retval;
|
||||||
if (c < 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "invalid UTF-8 character while encoding");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
retval.append(reinterpret_cast<char*>(mb), c);
|
|
||||||
}
|
}
|
||||||
return retval;
|
retval.append(reinterpret_cast<char*>(mb), c);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring UTF8ToWide(std::string_view src)
|
std::wstring UTF8ToWide(std::string_view src) {
|
||||||
{
|
std::wstring retval;
|
||||||
std::wstring retval;
|
retval.reserve(src.length());
|
||||||
retval.reserve(src.length());
|
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data());
|
||||||
const utf8proc_uint8_t* buf = reinterpret_cast<const utf8proc_uint8_t*>(src.data());
|
while (*buf) {
|
||||||
while (*buf)
|
utf8proc_int32_t wc;
|
||||||
{
|
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
|
||||||
utf8proc_int32_t wc;
|
if (len < 0) {
|
||||||
utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc);
|
fprintf(stderr, "invalid UTF-8 character while decoding");
|
||||||
if (len < 0)
|
return retval;
|
||||||
{
|
|
||||||
fprintf(stderr, "invalid UTF-8 character while decoding");
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
buf += len;
|
|
||||||
retval += wchar_t(wc);
|
|
||||||
}
|
}
|
||||||
return retval;
|
buf += len;
|
||||||
}
|
retval += wchar_t(wc);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
} // namespace kabufuda
|
||||||
|
|
|
@ -5,32 +5,30 @@
|
||||||
#include "hecl/winsupport.hpp"
|
#include "hecl/winsupport.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The memmem() function finds the start of the first occurrence of the
|
* The memmem() function finds the start of the first occurrence of the
|
||||||
* substring 'needle' of length 'nlen' in the memory area 'haystack' of
|
* substring 'needle' of length 'nlen' in the memory area 'haystack' of
|
||||||
* length 'hlen'.
|
* length 'hlen'.
|
||||||
*
|
*
|
||||||
* The return value is a pointer to the beginning of the sub-string, or
|
* The return value is a pointer to the beginning of the sub-string, or
|
||||||
* NULL if the substring is not found.
|
* NULL if the substring is not found.
|
||||||
*/
|
*/
|
||||||
void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen)
|
void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen) {
|
||||||
{
|
int needle_first;
|
||||||
int needle_first;
|
const uint8_t* p = static_cast<const uint8_t*>(haystack);
|
||||||
const uint8_t *p = static_cast<const uint8_t*>(haystack);
|
size_t plen = hlen;
|
||||||
size_t plen = hlen;
|
|
||||||
|
|
||||||
if (!nlen)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
needle_first = *(unsigned char *)needle;
|
|
||||||
|
|
||||||
while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1))))
|
|
||||||
{
|
|
||||||
if (!memcmp(p, needle, nlen))
|
|
||||||
return (void *)p;
|
|
||||||
|
|
||||||
p++;
|
|
||||||
plen = hlen - (p - static_cast<const uint8_t*>(haystack));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!nlen)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
needle_first = *(unsigned char*)needle;
|
||||||
|
|
||||||
|
while (plen >= nlen && (p = static_cast<const uint8_t*>(memchr(p, needle_first, plen - nlen + 1)))) {
|
||||||
|
if (!memcmp(p, needle, nlen))
|
||||||
|
return (void*)p;
|
||||||
|
|
||||||
|
p++;
|
||||||
|
plen = hlen - (p - static_cast<const uint8_t*>(haystack));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,30 @@
|
||||||
#include "kabufuda/Card.hpp"
|
#include "kabufuda/Card.hpp"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
int main()
|
int main() {
|
||||||
{
|
kabufuda::Card mc{"GM8E", "01"};
|
||||||
kabufuda::Card mc{"GM8E", "01"};
|
mc.open(_SYS_STR("test.USA.raw"));
|
||||||
mc.open(_SYS_STR("test.USA.raw"));
|
mc.format(kabufuda::ECardSlot::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::FileHandle f;
|
kabufuda::FileHandle f;
|
||||||
mc.openFile("MetroidPrime A", f);
|
mc.openFile("MetroidPrime A", f);
|
||||||
for (uint32_t i = 0; i < 127; i++)
|
for (uint32_t i = 0; i < 127; i++) {
|
||||||
{
|
char name[32] = {'\0'};
|
||||||
char name[32] = {'\0'};
|
sprintf(name, "Metroid Prime %i", i);
|
||||||
sprintf(name, "Metroid Prime %i", i);
|
kabufuda::ECardResult res = mc.createFile(name, kabufuda::BlockSize, f);
|
||||||
kabufuda::ECardResult res = mc.createFile(name, kabufuda::BlockSize, f);
|
if (res == kabufuda::ECardResult::INSSPACE || res == kabufuda::ECardResult::NOFILE)
|
||||||
if (res == kabufuda::ECardResult::INSSPACE || res == kabufuda::ECardResult::NOFILE)
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
mc.setPublic(f, true);
|
mc.setPublic(f, true);
|
||||||
mc.setCanCopy(f, true);
|
mc.setCanCopy(f, true);
|
||||||
mc.setCanMove(f, true);
|
mc.setCanMove(f, true);
|
||||||
kabufuda::CardStat stat = {};
|
kabufuda::CardStat stat = {};
|
||||||
mc.setStatus(f, stat);
|
mc.setStatus(f, stat);
|
||||||
mc.asyncWrite(f, "Test\0", strlen("Test") + 1);
|
mc.asyncWrite(f, "Test\0", strlen("Test") + 1);
|
||||||
mc.seek(f, 32, kabufuda::SeekOrigin::Begin);
|
mc.seek(f, 32, kabufuda::SeekOrigin::Begin);
|
||||||
mc.asyncWrite(f, "Test\0", strlen("Test") + 1);
|
mc.asyncWrite(f, "Test\0", strlen("Test") + 1);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue