New code style refactor

This commit is contained in:
Jack Andersen 2018-12-07 19:20:24 -10:00
parent a1e2242691
commit f126245eef
22 changed files with 1906 additions and 2181 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
} }

View File

@ -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;
} }