diff --git a/.clang-format b/.clang-format index 2573430..6ed326e 100644 --- a/.clang-format +++ b/.clang-format @@ -1,5 +1,5 @@ --- -IndentWidth: 4 +BasedOnStyle: LLVM ColumnLimit: 120 UseTab: Never --- @@ -8,7 +8,6 @@ DerivePointerAlignment: false PointerAlignment: Left AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false -BreakBeforeBraces: Allman IndentCaseLabels: false AllowShortBlocksOnASingleLine: true AlignOperands: true @@ -24,6 +23,6 @@ NamespaceIndentation: None BinPackArguments: true BinPackParameters: true SortIncludes: false -AccessModifierOffset: -4 +AccessModifierOffset: -2 ConstructorInitializerIndentWidth: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: true diff --git a/include/kabufuda/AsyncIO.hpp b/include/kabufuda/AsyncIO.hpp index 33923d2..1132b9c 100644 --- a/include/kabufuda/AsyncIO.hpp +++ b/include/kabufuda/AsyncIO.hpp @@ -11,40 +11,38 @@ using SizeReturn = DWORD; #include "Util.hpp" #include -namespace kabufuda -{ +namespace kabufuda { -class AsyncIO -{ +class AsyncIO { #ifndef _WIN32 - int m_fd = -1; - std::vector> m_queue; + int m_fd = -1; + std::vector> m_queue; #else - HANDLE m_fh = INVALID_HANDLE_VALUE; - std::vector> m_queue; + HANDLE m_fh = INVALID_HANDLE_VALUE; + std::vector> m_queue; #endif - void _waitForOperation(size_t qIdx) const; - size_t m_maxBlock = 0; + void _waitForOperation(size_t qIdx) const; + size_t m_maxBlock = 0; + public: - AsyncIO() = default; - AsyncIO(SystemStringView filename, bool truncate = false); - ~AsyncIO(); - AsyncIO(AsyncIO&& other); - AsyncIO& operator=(AsyncIO&& other); - AsyncIO(const AsyncIO* other) = delete; - AsyncIO& operator=(const AsyncIO& other) = delete; - void resizeQueue(size_t queueSz) { m_queue.resize(queueSz); } - 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); - ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const; - ECardResult pollStatus() const; - void waitForCompletion() const; + AsyncIO() = default; + AsyncIO(SystemStringView filename, bool truncate = false); + ~AsyncIO(); + AsyncIO(AsyncIO&& other); + AsyncIO& operator=(AsyncIO&& other); + AsyncIO(const AsyncIO* other) = delete; + AsyncIO& operator=(const AsyncIO& other) = delete; + void resizeQueue(size_t queueSz) { m_queue.resize(queueSz); } + 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); + ECardResult pollStatus(size_t qIdx, SizeReturn* szRet = nullptr) const; + ECardResult pollStatus() const; + void waitForCompletion() const; #ifndef _WIN32 - operator bool() const { return m_fd != -1; } + operator bool() const { return m_fd != -1; } #else - operator bool() const { return m_fh != INVALID_HANDLE_VALUE; } + operator bool() const { return m_fh != INVALID_HANDLE_VALUE; } #endif }; -} - +} // namespace kabufuda diff --git a/include/kabufuda/BlockAllocationTable.hpp b/include/kabufuda/BlockAllocationTable.hpp index cc9eaca..8fb1634 100644 --- a/include/kabufuda/BlockAllocationTable.hpp +++ b/include/kabufuda/BlockAllocationTable.hpp @@ -2,39 +2,36 @@ #include "Constants.hpp" -namespace kabufuda -{ -class BlockAllocationTable -{ - friend class Card; +namespace kabufuda { +class BlockAllocationTable { + friend class Card; #pragma pack(push, 4) - union { - struct - { - uint16_t m_checksum; - uint16_t m_checksumInv; - uint16_t m_updateCounter; - uint16_t m_freeBlocks; - uint16_t m_lastAllocated; - uint16_t m_map[0xFFB]; - }; - uint8_t __raw[BlockSize]; + union { + struct { + uint16_t m_checksum; + uint16_t m_checksumInv; + uint16_t m_updateCounter; + uint16_t m_freeBlocks; + uint16_t m_lastAllocated; + uint16_t m_map[0xFFB]; }; + uint8_t __raw[BlockSize]; + }; #pragma pack(pop) - void swapEndian(); - void updateChecksum(); - bool valid() const; + void swapEndian(); + void updateChecksum(); + bool valid() const; public: - explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks)); - BlockAllocationTable(uint8_t data[BlockSize]); - ~BlockAllocationTable() = default; + explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks)); + BlockAllocationTable(uint8_t data[BlockSize]); + ~BlockAllocationTable() = default; - uint16_t getNextBlock(uint16_t block) const; - uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const; - bool clear(uint16_t first, uint16_t count); - uint16_t allocateBlocks(uint16_t count, uint16_t maxBlocks); - uint16_t numFreeBlocks() const { return m_freeBlocks; } + uint16_t getNextBlock(uint16_t block) const; + uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const; + bool clear(uint16_t first, uint16_t count); + uint16_t allocateBlocks(uint16_t count, uint16_t maxBlocks); + uint16_t numFreeBlocks() const { return m_freeBlocks; } }; -} +} // namespace kabufuda diff --git a/include/kabufuda/Card.hpp b/include/kabufuda/Card.hpp index aa8d56e..1733a79 100644 --- a/include/kabufuda/Card.hpp +++ b/include/kabufuda/Card.hpp @@ -13,316 +13,309 @@ #define CARD_FILENAME_MAX 32 #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: - FileHandle() = default; - uint32_t getFileNo() const { return idx; } - operator bool() const { return getFileNo() != -1; } + FileHandle() = default; + uint32_t getFileNo() const { return idx; } + operator bool() const { return getFileNo() != -1; } }; -struct ProbeResults -{ - ECardResult x0_error; - uint32_t x4_cardSize; /* in megabits */ - uint32_t x8_sectorSize; /* in bytes */ +struct ProbeResults { + ECardResult x0_error; + uint32_t x4_cardSize; /* in megabits */ + uint32_t x8_sectorSize; /* in bytes */ }; -struct CardStat -{ - /* read-only (Set by Card::getStatus) */ - char x0_fileName[CARD_FILENAME_MAX]; - uint32_t x20_length; - uint32_t x24_time; /* seconds since 01/01/2000 midnight */ - uint8_t x28_gameName[4]; - uint8_t x2c_company[2]; +struct CardStat { + /* read-only (Set by Card::getStatus) */ + char x0_fileName[CARD_FILENAME_MAX]; + uint32_t x20_length; + uint32_t x24_time; /* seconds since 01/01/2000 midnight */ + uint8_t x28_gameName[4]; + uint8_t x2c_company[2]; - /* read/write (Set by Card::getStatus/Card::setStatus) */ - uint8_t x2e_bannerFormat; - uint8_t x2f___padding; - uint32_t x30_iconAddr; /* offset to the banner, bannerTlut, icon, iconTlut data set. */ - uint16_t x34_iconFormat; - uint16_t x36_iconSpeed; - uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */ + /* read/write (Set by Card::getStatus/Card::setStatus) */ + uint8_t x2e_bannerFormat; + uint8_t x2f___padding; + uint32_t x30_iconAddr; /* offset to the banner, bannerTlut, icon, iconTlut data set. */ + uint16_t x34_iconFormat; + uint16_t x36_iconSpeed; + uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */ - /* read-only (Set by Card::getStatus) */ - uint32_t x3c_offsetBanner; - uint32_t x40_offsetBannerTlut; - uint32_t x44_offsetIcon[CARD_ICON_MAX]; - uint32_t x64_offsetIconTlut; - uint32_t x68_offsetData; + /* read-only (Set by Card::getStatus) */ + uint32_t x3c_offsetBanner; + uint32_t x40_offsetBannerTlut; + uint32_t x44_offsetIcon[CARD_ICON_MAX]; + uint32_t x64_offsetIconTlut; + uint32_t x68_offsetData; - uint32_t GetFileLength() const { return x20_length; } - uint32_t GetTime() const { return x24_time; } - EImageFormat GetBannerFormat() const { return EImageFormat(x2e_bannerFormat & 0x3); } - void SetBannerFormat(EImageFormat fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | uint8_t(fmt); } - EImageFormat GetIconFormat(int idx) const { return EImageFormat((x34_iconFormat >> (idx * 2)) & 0x3); } - void SetIconFormat(EImageFormat fmt, int idx) - { - x34_iconFormat &= ~(0x3 << (idx * 2)); - x34_iconFormat |= uint16_t(fmt) << (idx * 2); - } - void SetIconSpeed(EAnimationSpeed sp, int idx) - { - x36_iconSpeed &= ~(0x3 << (idx * 2)); - x36_iconSpeed |= uint16_t(sp) << (idx * 2); - } - uint32_t GetIconAddr() const { return x30_iconAddr; } - void SetIconAddr(uint32_t addr) { x30_iconAddr = addr; } - uint32_t GetCommentAddr() const { return x38_commentAddr; } - void SetCommentAddr(uint32_t addr) { x38_commentAddr = addr; } + uint32_t GetFileLength() const { return x20_length; } + uint32_t GetTime() const { return x24_time; } + EImageFormat GetBannerFormat() const { return EImageFormat(x2e_bannerFormat & 0x3); } + void SetBannerFormat(EImageFormat fmt) { x2e_bannerFormat = (x2e_bannerFormat & ~0x3) | uint8_t(fmt); } + EImageFormat GetIconFormat(int idx) const { return EImageFormat((x34_iconFormat >> (idx * 2)) & 0x3); } + void SetIconFormat(EImageFormat fmt, int idx) { + x34_iconFormat &= ~(0x3 << (idx * 2)); + x34_iconFormat |= uint16_t(fmt) << (idx * 2); + } + void SetIconSpeed(EAnimationSpeed sp, int idx) { + x36_iconSpeed &= ~(0x3 << (idx * 2)); + x36_iconSpeed |= uint16_t(sp) << (idx * 2); + } + uint32_t GetIconAddr() const { return x30_iconAddr; } + void SetIconAddr(uint32_t addr) { x30_iconAddr = addr; } + uint32_t GetCommentAddr() const { return x38_commentAddr; } + void SetCommentAddr(uint32_t addr) { x38_commentAddr = addr; } }; -class Card -{ +class Card { #pragma pack(push, 4) - struct CardHeader - { - uint8_t m_serial[12]; - uint64_t m_formatTime; - int32_t m_sramBias; - uint32_t m_sramLanguage; - uint32_t m_unknown; - uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */ - uint16_t m_sizeMb; - uint16_t m_encoding; - uint8_t __padding[468]; - uint16_t m_updateCounter; - uint16_t m_checksum; - uint16_t m_checksumInv; - void _swapEndian(); - }; - union { - CardHeader m_ch; - uint8_t __raw[BlockSize]; - }; - CardHeader m_tmpCh; + struct CardHeader { + uint8_t m_serial[12]; + uint64_t m_formatTime; + int32_t m_sramBias; + uint32_t m_sramLanguage; + uint32_t m_unknown; + uint16_t m_deviceId; /* 0 for Slot A, 1 for Slot B */ + uint16_t m_sizeMb; + uint16_t m_encoding; + uint8_t __padding[468]; + uint16_t m_updateCounter; + uint16_t m_checksum; + uint16_t m_checksumInv; + void _swapEndian(); + }; + union { + CardHeader m_ch; + uint8_t __raw[BlockSize]; + }; + CardHeader m_tmpCh; #pragma pack(pop) - SystemString m_filename; - AsyncIO m_fileHandle; - Directory m_dirs[2]; - BlockAllocationTable m_bats[2]; - Directory m_tmpDirs[2]; - BlockAllocationTable m_tmpBats[2]; - uint8_t m_currentDir; - uint8_t m_currentBat; + SystemString m_filename; + AsyncIO m_fileHandle; + Directory m_dirs[2]; + BlockAllocationTable m_bats[2]; + Directory m_tmpDirs[2]; + BlockAllocationTable m_tmpBats[2]; + uint8_t m_currentDir; + uint8_t m_currentBat; - uint16_t m_maxBlock; - char m_game[5] = {'\0'}; - char m_maker[3] = {'\0'}; + uint16_t m_maxBlock; + char m_game[5] = {'\0'}; + char m_maker[3] = {'\0'}; - void _updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat); - void _updateChecksum(); - File* _fileFromHandle(const FileHandle& fh) const; - void _deleteFile(File& f, BlockAllocationTable& bat); + void _updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat); + void _updateChecksum(); + File* _fileFromHandle(const FileHandle& fh) const; + void _deleteFile(File& f, BlockAllocationTable& bat); - bool m_dirty = false; - bool m_opened = false; - ECardResult _pumpOpen(); + bool m_dirty = false; + bool m_opened = false; + ECardResult _pumpOpen(); public: - Card(); - /** - * @brief Card - * @param other - */ - Card(const Card& other) = delete; - Card& operator=(const Card& other) = delete; - Card(Card&& other); - Card& operator=(Card&& other); + Card(); + /** + * @brief Card + * @param other + */ + Card(const Card& other) = delete; + Card& operator=(const Card& other) = delete; + Card(Card&& other); + Card& operator=(Card&& other); - /** - * @brief Card - * @param filepath - * @param game - * @param maker - */ - Card(const char* game = nullptr, const char* maker = nullptr); - ~Card(); + /** + * @brief Card + * @param filepath + * @param game + * @param maker + */ + Card(const char* game = nullptr, const char* maker = nullptr); + ~Card(); - /** - * @brief openFile - * @param filename - */ - ECardResult openFile(const char* filename, FileHandle& handleOut); + /** + * @brief openFile + * @param filename + */ + ECardResult openFile(const char* filename, FileHandle& handleOut); - /** - * @brief openFile - * @param fileno - */ - ECardResult openFile(uint32_t fileno, FileHandle& handleOut); + /** + * @brief openFile + * @param fileno + */ + ECardResult openFile(uint32_t fileno, FileHandle& handleOut); - /** - * @brief createFile - * @param filename - * @return - */ - ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut); + /** + * @brief createFile + * @param filename + * @return + */ + ECardResult createFile(const char* filename, size_t size, FileHandle& handleOut); - /** - * @brief closeFile - * @param fh FileHandle to close - * @return - */ - ECardResult closeFile(FileHandle& fh); + /** + * @brief closeFile + * @param fh FileHandle to close + * @return + */ + ECardResult closeFile(FileHandle& fh); - /** - * @brief firstFile - * @return - */ - FileHandle firstFile(); + /** + * @brief firstFile + * @return + */ + FileHandle firstFile(); - /** - * @brief nextFile - * @param cur - * @return - */ - FileHandle nextFile(const FileHandle& cur); + /** + * @brief nextFile + * @param cur + * @return + */ + FileHandle nextFile(const FileHandle& cur); - /** - * @brief getFilename - * @param fh - * @return - */ - const char* getFilename(const FileHandle& fh); + /** + * @brief getFilename + * @param fh + * @return + */ + const char* getFilename(const FileHandle& fh); - /** - * @brief deleteFile - * @param fh - */ - void deleteFile(const FileHandle& fh); + /** + * @brief deleteFile + * @param fh + */ + void deleteFile(const FileHandle& fh); - /** - * @brief deleteFile - * @param filename - */ - ECardResult deleteFile(const char* filename); + /** + * @brief deleteFile + * @param filename + */ + ECardResult deleteFile(const char* filename); - /** - * @brief deleteFile - * @param fileno - */ - ECardResult deleteFile(uint32_t fileno); + /** + * @brief deleteFile + * @param fileno + */ + ECardResult deleteFile(uint32_t fileno); - /** - * @brief renameFile - * @param oldName - * @param newName - */ - ECardResult renameFile(const char* oldName, const char* newName); + /** + * @brief renameFile + * @param oldName + * @param newName + */ + ECardResult renameFile(const char* oldName, const char* newName); - /** - * @brief write - * @param fh - * @param buf - * @param size - */ - ECardResult asyncWrite(FileHandle& fh, const void* buf, size_t size); + /** + * @brief write + * @param fh + * @param buf + * @param size + */ + ECardResult asyncWrite(FileHandle& fh, const void* buf, size_t size); - /** - * @brief read - * @param fh - * @param dst - * @param size - */ - ECardResult asyncRead(FileHandle& fh, void* dst, size_t size); + /** + * @brief read + * @param fh + * @param dst + * @param size + */ + ECardResult asyncRead(FileHandle& fh, void* dst, size_t size); - /** - * @brief seek - * @param fh - * @param pos - * @param whence - */ - void seek(FileHandle& fh, int32_t pos, SeekOrigin whence); + /** + * @brief seek + * @param fh + * @param pos + * @param whence + */ + void seek(FileHandle& fh, int32_t pos, SeekOrigin whence); - /** - * @brief Returns the current offset of the specified file - * @param fh The file to retrieve the offset from - * @return The offset or -1 if an invalid handle is passed - */ - int32_t tell(const FileHandle& fh); + /** + * @brief Returns the current offset of the specified file + * @param fh The file to retrieve the offset from + * @return The offset or -1 if an invalid handle is passed + */ + int32_t tell(const FileHandle& fh); - /** - * @brief setPublic - * @param fh - * @param pub - */ - void setPublic(const FileHandle& fh, bool pub); + /** + * @brief setPublic + * @param fh + * @param pub + */ + void setPublic(const FileHandle& fh, bool pub); - /** - * @brief isPublic - * @param fh - * @return - */ - bool isPublic(const FileHandle& fh) const; + /** + * @brief isPublic + * @param fh + * @return + */ + bool isPublic(const FileHandle& fh) const; - /** - * @brief setCanCopy - * @param fh - * @param copy - */ - void setCanCopy(const FileHandle& fh, bool copy) const; + /** + * @brief setCanCopy + * @param fh + * @param copy + */ + void setCanCopy(const FileHandle& fh, bool copy) const; - /** - * @brief canCopy - * @param fh - * @return - */ - bool canCopy(const FileHandle& fh) const; + /** + * @brief canCopy + * @param fh + * @return + */ + bool canCopy(const FileHandle& fh) const; - /** - * @brief setCanMove - * @param fh - * @param move - */ - void setCanMove(const FileHandle& fh, bool move); + /** + * @brief setCanMove + * @param fh + * @param move + */ + void setCanMove(const FileHandle& fh, bool move); - /** - * @brief canMove - * @param fh - * @return - */ - bool canMove(const FileHandle& fh) const; + /** + * @brief canMove + * @param fh + * @return + */ + bool canMove(const FileHandle& fh) const; - /** - * @brief getStatus - * @param fh Handle of requested file - * @param statOut Structure to fill with file stat - * @return NOFILE or READY - */ - ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const; + /** + * @brief getStatus + * @param fh Handle of requested file + * @param statOut Structure to fill with file stat + * @return NOFILE or READY + */ + ECardResult getStatus(const FileHandle& fh, CardStat& statOut) const; - /** - * @brief getStatus - * @param fileNo Number of requested file - * @param statOut Structure to fill with file stat - * @return NOFILE or READY - */ - ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const; + /** + * @brief getStatus + * @param fileNo Number of requested file + * @param statOut Structure to fill with file stat + * @return NOFILE or READY + */ + ECardResult getStatus(uint32_t fileNo, CardStat& statOut) const; - /** - * @brief setStatus - * @param fh Handle of requested file - * @param statOut Structure to access for file stat - * @return NOFILE or READY - */ - ECardResult setStatus(const FileHandle& fh, const CardStat& stat); + /** + * @brief setStatus + * @param fh Handle of requested file + * @param statOut Structure to access for file stat + * @return NOFILE or READY + */ + ECardResult setStatus(const FileHandle& fh, const CardStat& stat); - /** - * @brief setStatus - * @param fileNo Number of requested file - * @param statOut Structure to access for file stat - * @return NOFILE or READY - */ - ECardResult setStatus(uint32_t fileNo, const CardStat& stat); + /** + * @brief setStatus + * @param fileNo Number of requested file + * @param statOut Structure to access for file stat + * @return NOFILE or READY + */ + ECardResult setStatus(uint32_t fileNo, const CardStat& stat); #if 0 // TODO: Async-friendly implementations /** @@ -342,98 +335,97 @@ public: bool moveFileTo(FileHandle& fh, Card& dest); #endif - /** - * @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" - * @sa openFile - */ - void setCurrentGame(const char* 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" + * @sa openFile + */ + void setCurrentGame(const char* game); - /** - * @brief Returns the currently selected game - * @return The selected game, or nullptr - */ - const uint8_t* getCurrentGame() const; + /** + * @brief Returns the currently selected game + * @return The selected game, or nullptr + */ + const uint8_t* getCurrentGame() const; - /** - * @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" - * @sa openFile - */ - void setCurrentMaker(const char* 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" + * @sa openFile + */ + void setCurrentMaker(const char* maker); - /** - * @brief Returns the currently selected maker - * @return The selected maker, or nullptr - */ - const uint8_t* getCurrentMaker() const; + /** + * @brief Returns the currently selected maker + * @return The selected maker, or nullptr + */ + const uint8_t* getCurrentMaker() const; - /** - * @brief Retrieves the format assigned serial - * @param serial - */ - void getSerial(uint64_t& serial); + /** + * @brief Retrieves the format assigned serial + * @param serial + */ + void getSerial(uint64_t& serial); - /** - * @brief Retrieves the checksum values of the Card system header - * @param checksum The checksum of the system header - * @param inverse The inverser checksum of the system header - */ - void getChecksum(uint16_t& checksum, uint16_t& inverse); + /** + * @brief Retrieves the checksum values of the Card system header + * @param checksum The checksum of the system header + * @param inverse The inverser checksum of the system header + */ + void getChecksum(uint16_t& checksum, uint16_t& inverse); - /** - * @brief Retrieves the available storage and directory space - * @param bytesNotUsed Number of free bytes out - * @param filesNotUsed Number of free files out - */ - void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed); + /** + * @brief Retrieves the available storage and directory space + * @param bytesNotUsed Number of free bytes out + * @param filesNotUsed Number of free files out + */ + void getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed); - /** - * @brief Formats the memory card and assigns a new serial - * @param size The desired size of the file @sa ECardSize - * @param encoding The desired encoding @sa EEncoding - */ - void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII); + /** + * @brief Formats the memory card and assigns a new serial + * @param size The desired size of the file @sa ECardSize + * @param encoding The desired encoding @sa EEncoding + */ + void format(ECardSlot deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII); - /** - * @brief Returns basic stats about a card image without opening a handle - * @return ProbeResults structure - */ - static ProbeResults probeCardFile(SystemStringView filename); + /** + * @brief Returns basic stats about a card image without opening a handle + * @return ProbeResults structure + */ + static ProbeResults probeCardFile(SystemStringView filename); - /** - * @brief Writes any changes to the Card instance immediately to disk.
- * Note: Under normal circumstances there is no need to call this function. - */ - void commit(); + /** + * @brief Writes any changes to the Card instance immediately to disk.
+ * Note: Under normal circumstances there is no need to call this function. + */ + void commit(); - /** - * @brief Opens card image (does nothing if currently open path matches) - */ - bool open(SystemStringView filepath); + /** + * @brief Opens card image (does nothing if currently open path matches) + */ + bool open(SystemStringView filepath); - /** - * @brief Commits changes to disk and closes host file - */ - void close(); + /** + * @brief Commits changes to disk and closes host file + */ + void close(); - /** - * @brief Access host filename of card - */ - SystemStringView cardFilename() const { return m_filename; } + /** + * @brief Access host filename of card + */ + SystemStringView cardFilename() const { return m_filename; } - /** - * @brief Gets card-scope error state - * @return READY, BROKEN, or NOCARD - */ - ECardResult getError() const; + /** + * @brief Gets card-scope error state + * @return READY, BROKEN, or NOCARD + */ + ECardResult getError() const; - /** - * @brief Block caller until any asynchronous I/O operations have completed - */ - void waitForCompletion() const; + /** + * @brief Block caller until any asynchronous I/O operations have completed + */ + void waitForCompletion() const; - operator bool() const { return getError() == ECardResult::READY; } + operator bool() const { return getError() == ECardResult::READY; } }; -} - +} // namespace kabufuda diff --git a/include/kabufuda/Constants.hpp b/include/kabufuda/Constants.hpp index f7f6fee..998a1fd 100644 --- a/include/kabufuda/Constants.hpp +++ b/include/kabufuda/Constants.hpp @@ -3,8 +3,7 @@ #include #include "Util.hpp" -namespace kabufuda -{ +namespace kabufuda { uint32_t constexpr BlockSize = 0x2000; uint32_t constexpr MaxFiles = 127; uint32_t constexpr FSTBlocks = 5; @@ -14,64 +13,50 @@ uint32_t constexpr BATSize = 0xFFB; /** * @brief The EPermissions enum */ -enum class EPermissions : uint8_t -{ - Public = (1 << 2), - NoCopy = (1 << 3), - NoMove = (1 << 4), - Global = (1 << 5), - Company = (1 << 6) +enum class EPermissions : uint8_t { + Public = (1 << 2), + NoCopy = (1 << 3), + NoMove = (1 << 4), + Global = (1 << 5), + Company = (1 << 6) }; ENABLE_BITWISE_ENUM(EPermissions) -enum class EImageFormat : uint8_t -{ - None, - C8, - RGB5A3, +enum class EImageFormat : uint8_t { + None, + C8, + RGB5A3, }; -enum class EAnimationType -{ - Loop = 0, - Bounce = 2, +enum class EAnimationType { + Loop = 0, + Bounce = 2, }; -enum class EAnimationSpeed -{ - End, - Fast, - Middle, - Slow, +enum class EAnimationSpeed { + End, + Fast, + Middle, + Slow, }; -enum class SeekOrigin -{ - Begin, - Current, - End -}; +enum class SeekOrigin { Begin, Current, End }; /** * @brief The ECardSlot enum */ -enum class ECardSlot : uint16_t -{ - SlotA, - SlotB -}; +enum class ECardSlot : uint16_t { SlotA, SlotB }; /** * @brief The ECardSize enum */ -enum class ECardSize : uint16_t -{ - Card59Mb = 0x04, - Card123Mb = 0x08, - Card251Mb = 0x10, - Card507Mb = 0x20, - Card1019Mb = 0x40, - Card2043Mb = 0x80 +enum class ECardSize : uint16_t { + Card59Mb = 0x04, + Card123Mb = 0x08, + Card251Mb = 0x10, + Card507Mb = 0x20, + Card1019Mb = 0x40, + Card2043Mb = 0x80 }; static constexpr uint32_t BannerWidth = 96; @@ -82,10 +67,8 @@ static constexpr uint32_t IconHeight = 32; /** * @brief The EEncoding enum */ -enum class EEncoding : uint16_t -{ - ASCII, /**< Standard ASCII Encoding */ - SJIS /**< SJIS Encoding for japanese */ +enum class EEncoding : uint16_t { + ASCII, /**< Standard ASCII Encoding */ + SJIS /**< SJIS Encoding for japanese */ }; -} - +} // namespace kabufuda diff --git a/include/kabufuda/Directory.hpp b/include/kabufuda/Directory.hpp index b4073f5..8e8f9c4 100644 --- a/include/kabufuda/Directory.hpp +++ b/include/kabufuda/Directory.hpp @@ -2,41 +2,37 @@ #include "File.hpp" -namespace kabufuda -{ -class Directory -{ - friend class Card; +namespace kabufuda { +class Directory { + friend class Card; #pragma pack(push, 4) - union { - struct - { - File m_files[MaxFiles]; - uint8_t __padding[0x3a]; - uint16_t m_updateCounter; - uint16_t m_checksum; - uint16_t m_checksumInv; - }; - uint8_t __raw[BlockSize]; + union { + struct { + File m_files[MaxFiles]; + uint8_t __padding[0x3a]; + uint16_t m_updateCounter; + uint16_t m_checksum; + uint16_t m_checksumInv; }; + uint8_t __raw[BlockSize]; + }; #pragma pack(pop) - void swapEndian(); - void updateChecksum(); - bool valid() const; + void swapEndian(); + void updateChecksum(); + bool valid() const; public: - Directory(); - Directory(uint8_t data[BlockSize]); - ~Directory() = default; + Directory(); + Directory(uint8_t data[BlockSize]); + ~Directory() = default; - bool hasFreeFile() const; - int32_t numFreeFiles() const; - File* getFirstFreeFile(const char* game, const char* maker, const char* filename); - File* getFirstNonFreeFile(uint32_t start, const char* game, const char* maker); - File* getFile(const char* game, const char* maker, const char* filename); - File* getFile(uint32_t idx); - int32_t indexForFile(File* f); + bool hasFreeFile() const; + int32_t numFreeFiles() const; + File* getFirstFreeFile(const char* game, const char* maker, const char* filename); + File* getFirstNonFreeFile(uint32_t start, const char* game, const char* maker); + File* getFile(const char* game, const char* maker, const char* filename); + File* getFile(uint32_t idx); + int32_t indexForFile(File* f); }; -} - +} // namespace kabufuda diff --git a/include/kabufuda/File.hpp b/include/kabufuda/File.hpp index f20852e..ea8e0ab 100644 --- a/include/kabufuda/File.hpp +++ b/include/kabufuda/File.hpp @@ -2,44 +2,40 @@ #include "Constants.hpp" -namespace kabufuda -{ -class File -{ - friend class IFileHandle; - friend class Directory; - friend class Card; +namespace kabufuda { +class File { + friend class IFileHandle; + friend class Directory; + friend class Card; #pragma pack(push, 4) - union { - struct - { - uint8_t m_game[4]; - uint8_t m_maker[2]; - uint8_t m_reserved; - uint8_t m_bannerFlags; - char m_filename[0x20]; - uint32_t m_modifiedTime; - uint32_t m_iconAddress; - uint16_t m_iconFmt; - uint16_t m_animSpeed; - EPermissions m_permissions; - int8_t m_copyCounter; - uint16_t m_firstBlock; - uint16_t m_blockCount; - uint16_t m_reserved2; - uint32_t m_commentAddr; - }; - uint8_t __raw[0x40]; + union { + struct { + uint8_t m_game[4]; + uint8_t m_maker[2]; + uint8_t m_reserved; + uint8_t m_bannerFlags; + char m_filename[0x20]; + uint32_t m_modifiedTime; + uint32_t m_iconAddress; + uint16_t m_iconFmt; + uint16_t m_animSpeed; + EPermissions m_permissions; + int8_t m_copyCounter; + uint16_t m_firstBlock; + uint16_t m_blockCount; + uint16_t m_reserved2; + uint32_t m_commentAddr; }; + uint8_t __raw[0x40]; + }; #pragma pack(pop) - void swapEndian(); + void swapEndian(); public: - File(); - File(char data[0x40]); - File(const char* filename); - ~File() = default; + File(); + File(char data[0x40]); + File(const char* filename); + ~File() = default; }; -} - +} // namespace kabufuda diff --git a/include/kabufuda/SRAM.hpp b/include/kabufuda/SRAM.hpp index da622e5..979e75d 100644 --- a/include/kabufuda/SRAM.hpp +++ b/include/kabufuda/SRAM.hpp @@ -25,50 +25,46 @@ must not be misrepresented as being the original software. distribution. -------------------------------------------------------------*/ -namespace kabufuda -{ -#pragma pack(push,1) -union SRAMFlags -{ - uint8_t Hex; - struct - { - uint8_t : 2; - 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 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 - }; +namespace kabufuda { +#pragma pack(push, 1) +union SRAMFlags { + uint8_t Hex; + struct { + uint8_t : 2; + 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 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 -{ - uint8_t p_SRAM[64]; - struct // Stored configuration value from the system SRAM area - { - uint16_t checksum; // Holds the block checksum. - uint16_t checksum_inv; // Holds the inverse block checksum - uint32_t ead0; // Unknown attribute - uint32_t ead1; // Unknown attribute - uint32_t counter_bias; // Bias value for the realtime clock - int8_t display_offsetH; // Pixel offset for the VI - uint8_t ntd; // Unknown attribute - uint8_t lang; // Language of system - SRAMFlags flags; // Device and operations flag +union SRAM { + uint8_t p_SRAM[64]; + struct // Stored configuration value from the system SRAM area + { + uint16_t checksum; // Holds the block checksum. + uint16_t checksum_inv; // Holds the inverse block checksum + uint32_t ead0; // Unknown attribute + uint32_t ead1; // Unknown attribute + uint32_t counter_bias; // Bias value for the realtime clock + int8_t display_offsetH; // Pixel offset for the VI + uint8_t ntd; // Unknown attribute + uint8_t lang; // Language of system + SRAMFlags flags; // Device and operations flag - // Stored configuration value from the extended SRAM area - 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 - 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 __padding0; // reserved - uint8_t flashID_chksum[2]; // 8-bit checksum of unlock flash ID - uint32_t __padding1; // padding - }; + // Stored configuration value from the extended SRAM area + 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 + 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 __padding0; // reserved + uint8_t flashID_chksum[2]; // 8-bit checksum of unlock flash ID + uint32_t __padding1; // padding + }; }; #pragma pack(pop) extern const SRAM g_SRAM; -} - +} // namespace kabufuda diff --git a/include/kabufuda/Util.hpp b/include/kabufuda/Util.hpp index 64efe89..3490550 100644 --- a/include/kabufuda/Util.hpp +++ b/include/kabufuda/Util.hpp @@ -39,77 +39,68 @@ #ifndef ENABLE_BITWISE_ENUM #define ENABLE_BITWISE_ENUM(type) \ - constexpr type operator|(type a, type b) \ - { \ - using T = std::underlying_type_t; \ - return type(static_cast(a) | static_cast(b)); \ - } \ - constexpr type operator&(type a, type b) \ - { \ - using T = std::underlying_type_t; \ - return type(static_cast(a) & static_cast(b)); \ - } \ - inline type& operator|=(type& a, const type& b) \ - { \ - using T = std::underlying_type_t; \ - a = type(static_cast(a) | static_cast(b)); \ - return a; \ - } \ - inline type& operator&=(type& a, const type& b) \ - { \ - using T = std::underlying_type_t; \ - a = type(static_cast(a) & static_cast(b)); \ - return a; \ - } \ - inline type operator~(const type& key) \ - { \ - using T = std::underlying_type_t; \ - return type(~static_cast(key)); \ - } + constexpr type operator|(type a, type b) { \ + using T = std::underlying_type_t; \ + return type(static_cast(a) | static_cast(b)); \ + } \ + constexpr type operator&(type a, type b) { \ + using T = std::underlying_type_t; \ + return type(static_cast(a) & static_cast(b)); \ + } \ + inline type& operator|=(type& a, const type& b) { \ + using T = std::underlying_type_t; \ + a = type(static_cast(a) | static_cast(b)); \ + return a; \ + } \ + inline type& operator&=(type& a, const type& b) { \ + using T = std::underlying_type_t; \ + a = type(static_cast(a) & static_cast(b)); \ + return a; \ + } \ + inline type operator~(const type& key) { \ + using T = std::underlying_type_t; \ + return type(~static_cast(key)); \ + } #endif -namespace kabufuda -{ +namespace kabufuda { /* Type-sensitive byte swappers */ template -static inline T bswap16(T val) -{ +static inline T bswap16(T val) { #if __GNUC__ - return __builtin_bswap16(val); + return __builtin_bswap16(val); #elif _WIN32 - return _byteswap_ushort(val); + return _byteswap_ushort(val); #else - return (val = (val << 8) | ((val >> 8) & 0xFF)); + return (val = (val << 8) | ((val >> 8) & 0xFF)); #endif } template -static inline T bswap32(T val) -{ +static inline T bswap32(T val) { #if __GNUC__ - return __builtin_bswap32(val); + return __builtin_bswap32(val); #elif _WIN32 - return _byteswap_ulong(val); + return _byteswap_ulong(val); #else - val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16; - val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8; - return val; + val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16; + val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8; + return val; #endif } template -static inline T bswap64(T val) -{ +static inline T bswap64(T val) { #if __GNUC__ - return __builtin_bswap64(val); + return __builtin_bswap64(val); #elif _WIN32 - return _byteswap_uint64(val); + return _byteswap_uint64(val); #else - return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) | - ((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) | - ((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) | - ((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56); + return ((val & 0xFF00000000000000ULL) >> 56) | ((val & 0x00FF000000000000ULL) >> 40) | + ((val & 0x0000FF0000000000ULL) >> 24) | ((val & 0x000000FF00000000ULL) >> 8) | + ((val & 0x00000000FF000000ULL) << 8) | ((val & 0x0000000000FF0000ULL) << 24) | + ((val & 0x000000000000FF00ULL) << 40) | ((val & 0x00000000000000FFULL) << 56); #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 int64_t SBig(int64_t val) { return bswap64(val); } static inline uint64_t SBig(uint64_t val) { return bswap64(val); } -static inline float SBig(float val) -{ - int32_t ival = bswap32(*((int32_t*)(&val))); - return *((float*)(&ival)); +static inline float SBig(float val) { + int32_t ival = bswap32(*((int32_t*)(&val))); + return *((float*)(&ival)); } -static inline double SBig(double val) -{ - int64_t ival = bswap64(*((int64_t*)(&val))); - return *((double*)(&ival)); +static inline double SBig(double val) { + int64_t ival = bswap64(*((int64_t*)(&val))); + return *((double*)(&ival)); } #ifndef SBIG #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 int64_t SLittle(int64_t val) { return bswap64(val); } static inline uint64_t SLittle(uint64_t val) { return bswap64(val); } -static inline float SLittle(float val) -{ - int32_t ival = bswap32(*((int32_t*)(&val))); - return *((float*)(&ival)); +static inline float SLittle(float val) { + int32_t ival = bswap32(*((int32_t*)(&val))); + return *((float*)(&ival)); } -static inline double SLittle(double val) -{ - int64_t ival = bswap64(*((int64_t*)(&val))); - return *((double*)(&ival)); +static inline double SLittle(double val) { + int64_t ival = bswap64(*((int64_t*)(&val))); + return *((double*)(&ival)); } #ifndef SLITTLE #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; 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); } -class SystemUTF8Conv -{ - std::string m_utf8; +class SystemUTF8Conv { + std::string m_utf8; public: - explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {} - std::string_view str() const { return m_utf8; } - const char* c_str() const { return m_utf8.c_str(); } - std::string operator+(std::string_view other) const { return m_utf8 + other.data(); } + explicit SystemUTF8Conv(SystemStringView str) : m_utf8(WideToUTF8(str)) {} + std::string_view str() const { return m_utf8; } + const char* c_str() const { return m_utf8.c_str(); } + 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(); } -class SystemStringConv -{ - std::wstring m_sys; +class SystemStringConv { + std::wstring m_sys; public: - explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {} - SystemStringView sys_str() const { return m_sys; } - const SystemChar* c_str() const { return m_sys.c_str(); } - std::wstring operator+(const std::wstring_view other) const { return m_sys + other.data(); } + explicit SystemStringConv(std::string_view str) : m_sys(UTF8ToWide(str)) {} + SystemStringView sys_str() const { return m_sys; } + const SystemChar* c_str() const { return m_sys.c_str(); } + 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 #define _SYS_STR(val) L##val #endif @@ -219,28 +206,28 @@ typedef std::string SystemString; typedef std::string_view SystemStringView; 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); } -class SystemUTF8Conv -{ - std::string_view m_utf8; +class SystemUTF8Conv { + std::string_view m_utf8; public: - explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {} - std::string_view str() const { return m_utf8; } - const char* c_str() const { return m_utf8.data(); } - std::string operator+(std::string_view other) const { return std::string(m_utf8) + other.data(); } + explicit SystemUTF8Conv(SystemStringView str) : m_utf8(str) {} + std::string_view str() const { return m_utf8; } + const char* c_str() const { return m_utf8.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(); } -class SystemStringConv -{ - SystemStringView m_sys; +class SystemStringConv { + SystemStringView m_sys; public: - explicit SystemStringConv(std::string_view str) : m_sys(str) {} - SystemStringView sys_str() const { return m_sys; } - const SystemChar* c_str() const { return m_sys.data(); } - std::string operator+(std::string_view other) const { return std::string(m_sys) + other.data(); } + explicit SystemStringConv(std::string_view str) : m_sys(str) {} + SystemStringView sys_str() const { return m_sys; } + const SystemChar* c_str() const { return m_sys.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 #define _SYS_STR(val) val #endif @@ -250,28 +237,24 @@ typedef struct stat Sstat; uint64_t getGCTime(); #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 #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 -static inline int Stat(const SystemChar* path, Sstat* statOut) -{ +static inline int Stat(const SystemChar* path, Sstat* statOut) { #if CARD_UCS2 - size_t 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'}; - return _wstat(fixPath, statOut); - } - return _wstat(path, statOut); + size_t 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'}; + return _wstat(fixPath, statOut); + } + return _wstat(path, statOut); #else - return stat(path, statOut); + return stat(path, statOut); #endif } @@ -286,22 +269,20 @@ void calculateChecksumBE(const uint16_t* data, size_t len, uint16_t* checksum, u #undef NOFILE -enum class ECardResult -{ - CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */ - FATAL_ERROR = -128, - ENCODING = -13, - NAMETOOLONG = -12, - INSSPACE = -9, - NOENT = -8, - EXIST = -7, - BROKEN = -6, - IOERROR = -5, - NOFILE = -4, - NOCARD = -3, - WRONGDEVICE = -2, - BUSY = -1, - READY = 0 +enum class ECardResult { + CRC_MISMATCH = -1003, /* Extension enum for Retro's CRC check */ + FATAL_ERROR = -128, + ENCODING = -13, + NAMETOOLONG = -12, + INSSPACE = -9, + NOENT = -8, + EXIST = -7, + BROKEN = -6, + IOERROR = -5, + NOFILE = -4, + NOCARD = -3, + WRONGDEVICE = -2, + BUSY = -1, + READY = 0 }; -} - +} // namespace kabufuda diff --git a/include/kabufuda/WideStringConvert.hpp b/include/kabufuda/WideStringConvert.hpp index af1436e..776c5b3 100644 --- a/include/kabufuda/WideStringConvert.hpp +++ b/include/kabufuda/WideStringConvert.hpp @@ -2,9 +2,7 @@ #include -namespace kabufuda -{ +namespace kabufuda { std::string WideToUTF8(std::wstring_view src); std::wstring UTF8ToWide(std::string_view src); -} - +} // namespace kabufuda diff --git a/include/kabufuda/winsupport.hpp b/include/kabufuda/winsupport.hpp index d40ada7..da9e8e1 100644 --- a/include/kabufuda/winsupport.hpp +++ b/include/kabufuda/winsupport.hpp @@ -8,5 +8,4 @@ #endif #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); diff --git a/lib/kabufuda/AsyncIOPosix.cpp b/lib/kabufuda/AsyncIOPosix.cpp index 1028ed5..39854c1 100644 --- a/lib/kabufuda/AsyncIOPosix.cpp +++ b/lib/kabufuda/AsyncIOPosix.cpp @@ -1,161 +1,141 @@ #include "kabufuda/AsyncIO.hpp" -namespace kabufuda -{ +namespace kabufuda { -AsyncIO::AsyncIO(SystemStringView filename, bool truncate) -{ - m_fd = open(filename.data(), O_RDWR | O_CREAT | (truncate ? O_TRUNC : 0)); +AsyncIO::AsyncIO(SystemStringView filename, bool truncate) { + m_fd = open(filename.data(), O_RDWR | O_CREAT | (truncate ? O_TRUNC : 0)); } -AsyncIO::~AsyncIO() -{ - if (*this) - { - aio_cancel(m_fd, nullptr); - close(m_fd); - } +AsyncIO::~AsyncIO() { + if (*this) { + aio_cancel(m_fd, nullptr); + close(m_fd); + } } -AsyncIO::AsyncIO(AsyncIO&& other) -{ - m_fd = other.m_fd; - other.m_fd = -1; - m_queue = std::move(other.m_queue); - m_maxBlock = other.m_maxBlock; +AsyncIO::AsyncIO(AsyncIO&& other) { + m_fd = other.m_fd; + other.m_fd = -1; + m_queue = std::move(other.m_queue); + m_maxBlock = other.m_maxBlock; } -AsyncIO& AsyncIO::operator=(AsyncIO&& other) -{ - if (*this) - { - aio_cancel(m_fd, nullptr); - close(m_fd); - } - m_fd = other.m_fd; - other.m_fd = -1; - m_queue = std::move(other.m_queue); - m_maxBlock = other.m_maxBlock; - return *this; +AsyncIO& AsyncIO::operator=(AsyncIO&& other) { + if (*this) { + aio_cancel(m_fd, nullptr); + close(m_fd); + } + m_fd = other.m_fd; + other.m_fd = -1; + m_queue = std::move(other.m_queue); + m_maxBlock = other.m_maxBlock; + return *this; } -void AsyncIO::_waitForOperation(size_t qIdx) const -{ - auto& aio = const_cast(this)->m_queue[qIdx]; - if (aio.first.aio_fildes == 0) - return; - const struct aiocb* aiop = &aio.first; - struct timespec ts = {2, 0}; - while (aio_suspend(&aiop, 1, &ts) && errno == EINTR) {} - if (aio_error(&aio.first) != EINPROGRESS) - aio.second = aio_return(&aio.first); +void AsyncIO::_waitForOperation(size_t qIdx) const { + auto& aio = const_cast(this)->m_queue[qIdx]; + if (aio.first.aio_fildes == 0) + return; + const struct aiocb* aiop = &aio.first; + struct timespec ts = {2, 0}; + while (aio_suspend(&aiop, 1, &ts) && errno == EINTR) {} + if (aio_error(&aio.first) != EINPROGRESS) + 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(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(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; + 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) -{ - 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(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(this)->m_queue[qIdx]; +ECardResult AsyncIO::pollStatus() const { + ECardResult result = ECardResult::READY; + for (auto it = const_cast(this)->m_queue.begin(); + it != const_cast(this)->m_queue.begin() + m_maxBlock; ++it) { + auto& aio = *it; if (aio.first.aio_fildes == 0) - { - if (szRet) - *szRet = aio.second; - return ECardResult::READY; - } - switch (aio_error(&aio.first)) - { + continue; + switch (aio_error(&aio.first)) { case 0: - aio.second = aio_return(&aio.first); - aio.first.aio_fildes = 0; - if (szRet) - *szRet = aio.second; - return ECardResult::READY; + aio.second = aio_return(&aio.first); + aio.first.aio_fildes = 0; + break; case EINPROGRESS: - return ECardResult::BUSY; + if (result > ECardResult::BUSY) + result = ECardResult::BUSY; + break; default: - aio.second = aio_return(&aio.first); - aio.first.aio_fildes = 0; - if (szRet) - *szRet = aio.second; - return ECardResult::IOERROR; + aio.second = aio_return(&aio.first); + aio.first.aio_fildes = 0; + if (result > ECardResult::IOERROR) + result = ECardResult::IOERROR; + break; } -} - -ECardResult AsyncIO::pollStatus() const -{ - ECardResult result = ECardResult::READY; - for (auto it = const_cast(this)->m_queue.begin(); - it != const_cast(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(this)->m_maxBlock = 0; - return result; -} - -void AsyncIO::waitForCompletion() const -{ - for (size_t i=0 ; i(this)->m_maxBlock = 0; + return result; } +void AsyncIO::waitForCompletion() const { + for (size_t i = 0; i < m_maxBlock; ++i) + _waitForOperation(i); + const_cast(this)->m_maxBlock = 0; } + +} // namespace kabufuda diff --git a/lib/kabufuda/AsyncIOWin32.cpp b/lib/kabufuda/AsyncIOWin32.cpp index 6112f76..e5b2932 100644 --- a/lib/kabufuda/AsyncIOWin32.cpp +++ b/lib/kabufuda/AsyncIOWin32.cpp @@ -1,191 +1,153 @@ #include "kabufuda/AsyncIO.hpp" -namespace kabufuda -{ +namespace kabufuda { #undef min #undef max -static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) -{ - aio.Internal = 0; - aio.InternalHigh = 0; - aio.Offset = offset; - aio.OffsetHigh = 0; +static void ResetOverlapped(OVERLAPPED& aio, DWORD offset = 0) { + aio.Internal = 0; + aio.InternalHigh = 0; + aio.Offset = offset; + aio.OffsetHigh = 0; } -AsyncIO::AsyncIO(SystemStringView filename, bool truncate) -{ +AsyncIO::AsyncIO(SystemStringView filename, bool truncate) { #if WINDOWS_STORE - CREATEFILE2_EXTENDED_PARAMETERS parms = {}; - parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); - parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; - parms.dwFileFlags = FILE_FLAG_OVERLAPPED; - m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms); + CREATEFILE2_EXTENDED_PARAMETERS parms = {}; + parms.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); + parms.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; + parms.dwFileFlags = FILE_FLAG_OVERLAPPED; + m_fh = CreateFile2(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + truncate ? CREATE_ALWAYS : OPEN_ALWAYS, &parms); #else - m_fh = CreateFileW(filename.data(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, truncate ? CREATE_ALWAYS : OPEN_ALWAYS, - FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr); + m_fh = CreateFileW(filename.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, + truncate ? CREATE_ALWAYS : OPEN_ALWAYS, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, nullptr); #endif } -AsyncIO::~AsyncIO() -{ - if (*this) - { - if (CancelIoEx(m_fh, nullptr)) - waitForCompletion(); - CloseHandle(m_fh); - } +AsyncIO::~AsyncIO() { + if (*this) { + if (CancelIoEx(m_fh, nullptr)) + waitForCompletion(); + CloseHandle(m_fh); + } } -AsyncIO::AsyncIO(AsyncIO&& other) -{ - m_fh = other.m_fh; - other.m_fh = INVALID_HANDLE_VALUE; - m_queue = std::move(other.m_queue); - m_maxBlock = other.m_maxBlock; +AsyncIO::AsyncIO(AsyncIO&& other) { + m_fh = other.m_fh; + other.m_fh = INVALID_HANDLE_VALUE; + m_queue = std::move(other.m_queue); + m_maxBlock = other.m_maxBlock; } -AsyncIO& AsyncIO::operator=(AsyncIO&& other) -{ - if (*this) - { - if (CancelIoEx(m_fh, nullptr)) - waitForCompletion(); - CloseHandle(m_fh); - } - m_fh = other.m_fh; - other.m_fh = INVALID_HANDLE_VALUE; - m_queue = std::move(other.m_queue); - m_maxBlock = other.m_maxBlock; - return *this; +AsyncIO& AsyncIO::operator=(AsyncIO&& other) { + if (*this) { + if (CancelIoEx(m_fh, nullptr)) + waitForCompletion(); + CloseHandle(m_fh); + } + m_fh = other.m_fh; + other.m_fh = INVALID_HANDLE_VALUE; + m_queue = std::move(other.m_queue); + m_maxBlock = other.m_maxBlock; + return *this; } -void AsyncIO::_waitForOperation(size_t qIdx) const -{ - auto& aio = const_cast(this)->m_queue[qIdx]; - if (aio.first.hEvent == 0) - return; - GetOverlappedResult(m_fh, &aio.first, &aio.second, TRUE); +void AsyncIO::_waitForOperation(size_t qIdx) const { + auto& aio = const_cast(this)->m_queue[qIdx]; + if (aio.first.hEvent == 0) + return; + 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(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); 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) -{ - 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(this)->m_queue[qIdx]; +ECardResult AsyncIO::pollStatus() const { + ECardResult result = ECardResult::READY; + for (auto it = const_cast(this)->m_queue.begin(); + it != const_cast(this)->m_queue.begin() + m_maxBlock; ++it) { + auto& aio = *it; if (aio.first.hEvent == 0) - { - if (szRet) - *szRet = aio.second; - return ECardResult::READY; + 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 (GetOverlappedResult(m_fh, &aio.first, &aio.second, FALSE)) - { - 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(this)->m_queue.begin(); - it != const_cast(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(this)->m_maxBlock = 0; - return result; -} - -void AsyncIO::waitForCompletion() const -{ - for (size_t i=0 ; i(this)->m_maxBlock = 0; + return result; } +void AsyncIO::waitForCompletion() const { + for (size_t i = 0; i < m_maxBlock; ++i) + _waitForOperation(i); + const_cast(this)->m_maxBlock = 0; } + +} // namespace kabufuda diff --git a/lib/kabufuda/BlockAllocationTable.cpp b/lib/kabufuda/BlockAllocationTable.cpp index f77a27d..c6bb702 100644 --- a/lib/kabufuda/BlockAllocationTable.cpp +++ b/lib/kabufuda/BlockAllocationTable.cpp @@ -2,112 +2,97 @@ #include "kabufuda/Util.hpp" #include -namespace kabufuda -{ -void BlockAllocationTable::swapEndian() -{ - m_checksum = SBig(m_checksum); - m_checksumInv = SBig(m_checksumInv); - m_updateCounter = SBig(m_updateCounter); - m_freeBlocks = SBig(m_freeBlocks); - m_lastAllocated = SBig(m_lastAllocated); - std::for_each(std::begin(m_map), std::end(m_map), [](uint16_t& val) { val = SBig(val); }); +namespace kabufuda { +void BlockAllocationTable::swapEndian() { + m_checksum = SBig(m_checksum); + m_checksumInv = SBig(m_checksumInv); + m_updateCounter = SBig(m_updateCounter); + m_freeBlocks = SBig(m_freeBlocks); + 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() -{ - swapEndian(); - calculateChecksumBE(reinterpret_cast(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv); - swapEndian(); +void BlockAllocationTable::updateChecksum() { + swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv); + swapEndian(); } -bool BlockAllocationTable::valid() const -{ - uint16_t ckSum, ckSumInv; - const_cast(*this).swapEndian(); - calculateChecksumBE(reinterpret_cast(__raw + 4), 0xFFE, &ckSum, &ckSumInv); - bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv); - const_cast(*this).swapEndian(); - return res; +bool BlockAllocationTable::valid() const { + uint16_t ckSum, ckSumInv; + const_cast(*this).swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw + 4), 0xFFE, &ckSum, &ckSumInv); + bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv); + const_cast(*this).swapEndian(); + return res; } -BlockAllocationTable::BlockAllocationTable(uint32_t blockCount) -{ - memset(__raw, 0, BlockSize); - m_freeBlocks = uint16_t(blockCount - FSTBlocks); - m_lastAllocated = 4; - updateChecksum(); +BlockAllocationTable::BlockAllocationTable(uint32_t blockCount) { + memset(__raw, 0, BlockSize); + m_freeBlocks = uint16_t(blockCount - FSTBlocks); + m_lastAllocated = 4; + updateChecksum(); } -uint16_t BlockAllocationTable::getNextBlock(uint16_t block) const -{ - 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; - } - +uint16_t BlockAllocationTable::getNextBlock(uint16_t block) const { + if ((block < FSTBlocks) || (block > (BATSize - FSTBlocks))) return 0xFFFF; + + return m_map[block - FSTBlocks]; } -bool BlockAllocationTable::clear(uint16_t first, uint16_t count) -{ - std::vector blocks; - while (first != 0xFFFF && first != 0) - { - blocks.push_back(first); - first = getNextBlock(first); +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; +} + +bool BlockAllocationTable::clear(uint16_t first, uint16_t count) { + std::vector 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) - { - size_t length = blocks.size(); - if (length != count) - return false; + if (freeBlock == 0xFFFF) + return 0xFFFF; - 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 (freeBlock == 0xFFFF) - return 0xFFFF; - - m_lastAllocated = freeBlock; - m_freeBlocks -= tmpCount; - } - return firstBlock; -} + m_lastAllocated = freeBlock; + m_freeBlocks -= tmpCount; + } + return firstBlock; } +} // namespace kabufuda diff --git a/lib/kabufuda/Card.cpp b/lib/kabufuda/Card.cpp index 472365f..ca723f7 100644 --- a/lib/kabufuda/Card.cpp +++ b/lib/kabufuda/Card.cpp @@ -5,699 +5,623 @@ #include #include -namespace kabufuda -{ +namespace kabufuda { #define ROUND_UP_8192(val) (((val) + 8191) & ~8191) -static void NullFileAccess() -{ - fprintf(stderr, "Attempted to access null file\n"); -} +static void NullFileAccess() { fprintf(stderr, "Attempted to access null file\n"); } -void Card::CardHeader::_swapEndian() -{ - m_formatTime = SBig(m_formatTime); - m_sramBias = SBig(m_sramBias); - m_sramLanguage = SBig(m_sramLanguage); - m_unknown = SBig(m_unknown); - m_deviceId = SBig(m_deviceId); - m_sizeMb = SBig(m_sizeMb); - m_encoding = SBig(m_encoding); - m_updateCounter = SBig(m_updateCounter); - m_checksum = SBig(m_checksum); - m_checksumInv = SBig(m_checksumInv); +void Card::CardHeader::_swapEndian() { + m_formatTime = SBig(m_formatTime); + m_sramBias = SBig(m_sramBias); + m_sramLanguage = SBig(m_sramLanguage); + m_unknown = SBig(m_unknown); + m_deviceId = SBig(m_deviceId); + m_sizeMb = SBig(m_sizeMb); + m_encoding = SBig(m_encoding); + m_updateCounter = SBig(m_updateCounter); + m_checksum = SBig(m_checksum); + m_checksumInv = SBig(m_checksumInv); } Card::Card() { memset(__raw, 0xFF, BlockSize); } -Card::Card(Card&& other) -{ - memmove(__raw, other.__raw, BlockSize); - m_filename = std::move(other.m_filename); - m_fileHandle = std::move(other.m_fileHandle); - m_dirs[0] = std::move(other.m_dirs[0]); - m_dirs[1] = std::move(other.m_dirs[1]); - m_bats[0] = std::move(other.m_bats[0]); - m_bats[1] = std::move(other.m_bats[1]); - m_currentDir = other.m_currentDir; - m_currentBat = other.m_currentBat; +Card::Card(Card&& other) { + memmove(__raw, other.__raw, BlockSize); + m_filename = std::move(other.m_filename); + m_fileHandle = std::move(other.m_fileHandle); + m_dirs[0] = std::move(other.m_dirs[0]); + m_dirs[1] = std::move(other.m_dirs[1]); + m_bats[0] = std::move(other.m_bats[0]); + m_bats[1] = std::move(other.m_bats[1]); + m_currentDir = other.m_currentDir; + m_currentBat = other.m_currentBat; - m_maxBlock = other.m_maxBlock; - memmove(m_game, other.m_game, 5); - memmove(m_maker, other.m_maker, 3); + m_maxBlock = other.m_maxBlock; + memmove(m_game, other.m_game, 5); + memmove(m_maker, other.m_maker, 3); } -Card& Card::operator=(Card&& other) -{ - close(); +Card& Card::operator=(Card&& other) { + close(); - memmove(__raw, other.__raw, BlockSize); - m_filename = std::move(other.m_filename); - m_fileHandle = std::move(other.m_fileHandle); - m_dirs[0] = std::move(other.m_dirs[0]); - m_dirs[1] = std::move(other.m_dirs[1]); - m_bats[0] = std::move(other.m_bats[0]); - m_bats[1] = std::move(other.m_bats[1]); - m_currentDir = other.m_currentDir; - m_currentBat = other.m_currentBat; + memmove(__raw, other.__raw, BlockSize); + m_filename = std::move(other.m_filename); + m_fileHandle = std::move(other.m_fileHandle); + m_dirs[0] = std::move(other.m_dirs[0]); + m_dirs[1] = std::move(other.m_dirs[1]); + m_bats[0] = std::move(other.m_bats[0]); + m_bats[1] = std::move(other.m_bats[1]); + m_currentDir = other.m_currentDir; + m_currentBat = other.m_currentBat; - m_maxBlock = other.m_maxBlock; - memmove(m_game, other.m_game, 5); - memmove(m_maker, other.m_maker, 3); + m_maxBlock = other.m_maxBlock; + memmove(m_game, other.m_game, 5); + memmove(m_maker, other.m_maker, 3); - return *this; + return *this; } -ECardResult Card::_pumpOpen() -{ - if (m_opened) - return ECardResult::READY; - - if (!m_fileHandle) - return ECardResult::NOCARD; - - ECardResult res = m_fileHandle.pollStatus(); - if (res == ECardResult::READY) - { - m_ch._swapEndian(); - m_maxBlock = m_ch.m_sizeMb * MbitToBlocks; - m_fileHandle.resizeQueue(m_maxBlock); - - m_dirs[0].swapEndian(); - m_dirs[1].swapEndian(); - m_bats[0].swapEndian(); - m_bats[1].swapEndian(); - - /* Check for data integrity, restoring valid data in case of corruption if possible */ - if (!m_dirs[0].valid() && m_dirs[1].valid()) - m_dirs[0] = m_dirs[1]; - else if (!m_dirs[1].valid() && m_dirs[0].valid()) - m_dirs[1] = m_dirs[0]; - if (!m_bats[0].valid() && m_bats[1].valid()) - m_bats[0] = m_bats[1]; - else if (!m_bats[1].valid() && m_bats[0].valid()) - m_bats[1] = m_bats[0]; - - if (m_dirs[0].m_updateCounter > m_dirs[1].m_updateCounter) - m_currentDir = 0; - else - m_currentDir = 1; - - if (m_bats[0].m_updateCounter > m_bats[1].m_updateCounter) - m_currentBat = 0; - else - m_currentBat = 1; - - m_opened = true; - } - - return res; -} - -Card::Card(const char* game, const char* maker) -{ - memset(__raw, 0xFF, BlockSize); - if (game && strlen(game) == 4) - memcpy(m_game, game, 4); - if (maker && strlen(maker) == 2) - memcpy(m_maker, maker, 2); -} - -Card::~Card() -{ - close(); -} - -ECardResult Card::openFile(const char* filename, FileHandle& handleOut) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - handleOut = {}; - File* f = m_dirs[m_currentDir].getFile(m_game, m_maker, filename); - if (!f || f->m_game[0] == 0xFF) - return ECardResult::NOFILE; - int32_t idx = m_dirs[m_currentDir].indexForFile(f); - if (idx != -1) - { - handleOut = FileHandle(idx); - return ECardResult::READY; - } - return ECardResult::FATAL_ERROR; -} - -ECardResult Card::openFile(uint32_t fileno, FileHandle& handleOut) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - handleOut = {}; - File* f = m_dirs[m_currentDir].getFile(fileno); - if (!f || f->m_game[0] == 0xFF) - return ECardResult::NOFILE; - handleOut = FileHandle(fileno); +ECardResult Card::_pumpOpen() { + if (m_opened) return ECardResult::READY; -} -void Card::_updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat) -{ - m_currentDir = !m_currentDir; - Directory& updateDir = m_dirs[m_currentDir]; - updateDir = dir; - updateDir.m_updateCounter++; - updateDir.updateChecksum(); + if (!m_fileHandle) + return ECardResult::NOCARD; - m_currentBat = !m_currentBat; - BlockAllocationTable& updateBat = m_bats[m_currentBat]; - updateBat = bat; - updateBat.m_updateCounter++; - updateBat.updateChecksum(); - - m_dirty = true; -} - -void Card::_updateChecksum() -{ - m_ch._swapEndian(); - calculateChecksumBE(reinterpret_cast(__raw), 0xFE, &m_ch.m_checksum, &m_ch.m_checksumInv); + ECardResult res = m_fileHandle.pollStatus(); + if (res == ECardResult::READY) { m_ch._swapEndian(); + m_maxBlock = m_ch.m_sizeMb * MbitToBlocks; + m_fileHandle.resizeQueue(m_maxBlock); + + m_dirs[0].swapEndian(); + m_dirs[1].swapEndian(); + m_bats[0].swapEndian(); + m_bats[1].swapEndian(); + + /* Check for data integrity, restoring valid data in case of corruption if possible */ + if (!m_dirs[0].valid() && m_dirs[1].valid()) + m_dirs[0] = m_dirs[1]; + else if (!m_dirs[1].valid() && m_dirs[0].valid()) + m_dirs[1] = m_dirs[0]; + if (!m_bats[0].valid() && m_bats[1].valid()) + m_bats[0] = m_bats[1]; + else if (!m_bats[1].valid() && m_bats[0].valid()) + m_bats[1] = m_bats[0]; + + if (m_dirs[0].m_updateCounter > m_dirs[1].m_updateCounter) + m_currentDir = 0; + else + m_currentDir = 1; + + if (m_bats[0].m_updateCounter > m_bats[1].m_updateCounter) + m_currentBat = 0; + else + m_currentBat = 1; + + m_opened = true; + } + + return res; } -File* Card::_fileFromHandle(const FileHandle& fh) const -{ - if (!fh) - { - NullFileAccess(); - return nullptr; - } - return const_cast(m_dirs[m_currentDir]).getFile(fh.idx); +Card::Card(const char* game, const char* maker) { + memset(__raw, 0xFF, BlockSize); + if (game && strlen(game) == 4) + memcpy(m_game, game, 4); + if (maker && strlen(maker) == 2) + memcpy(m_maker, maker, 2); } -ECardResult Card::createFile(const char* filename, size_t size, - FileHandle& handleOut) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; +Card::~Card() { close(); } - handleOut = {}; +ECardResult Card::openFile(const char* filename, FileHandle& handleOut) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; - if (size <= 0) - return ECardResult::FATAL_ERROR; - if (strlen(filename) > 32) - return ECardResult::NAMETOOLONG; - if (m_dirs[m_currentDir].getFile(m_game, m_maker, filename)) - return ECardResult::EXIST; - uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize; - if (neededBlocks > m_bats[m_currentBat].numFreeBlocks()) - return ECardResult::INSSPACE; - if (!m_dirs[m_currentDir].hasFreeFile()) - return ECardResult::NOENT; - - Directory dir = m_dirs[m_currentDir]; - BlockAllocationTable bat = m_bats[m_currentBat]; - File* f = dir.getFirstFreeFile(m_game, m_maker, filename); - uint16_t block = bat.allocateBlocks(neededBlocks, m_maxBlock - FSTBlocks); - if (f && block != 0xFFFF) - { - f->m_modifiedTime = uint32_t(getGCTime()); - f->m_firstBlock = block; - f->m_blockCount = neededBlocks; - - handleOut = FileHandle(dir.indexForFile(f)); - _updateDirAndBat(dir, bat); - return ECardResult::READY; - } - - return ECardResult::FATAL_ERROR; -} - -ECardResult Card::closeFile(FileHandle& fh) -{ - fh.offset = 0; + handleOut = {}; + File* f = m_dirs[m_currentDir].getFile(m_game, m_maker, filename); + if (!f || f->m_game[0] == 0xFF) + return ECardResult::NOFILE; + int32_t idx = m_dirs[m_currentDir].indexForFile(f); + if (idx != -1) { + handleOut = FileHandle(idx); return ECardResult::READY; + } + return ECardResult::FATAL_ERROR; } -FileHandle Card::firstFile() -{ - File* f = m_dirs[m_currentDir].getFirstNonFreeFile(0, m_game, m_maker); - if (f) - return FileHandle(m_dirs[m_currentDir].indexForFile(f)); +ECardResult Card::openFile(uint32_t fileno, FileHandle& handleOut) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + handleOut = {}; + File* f = m_dirs[m_currentDir].getFile(fileno); + if (!f || f->m_game[0] == 0xFF) + return ECardResult::NOFILE; + handleOut = FileHandle(fileno); + return ECardResult::READY; +} + +void Card::_updateDirAndBat(const Directory& dir, const BlockAllocationTable& bat) { + m_currentDir = !m_currentDir; + Directory& updateDir = m_dirs[m_currentDir]; + updateDir = dir; + updateDir.m_updateCounter++; + updateDir.updateChecksum(); + + m_currentBat = !m_currentBat; + BlockAllocationTable& updateBat = m_bats[m_currentBat]; + updateBat = bat; + updateBat.m_updateCounter++; + updateBat.updateChecksum(); + + m_dirty = true; +} + +void Card::_updateChecksum() { + m_ch._swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw), 0xFE, &m_ch.m_checksum, &m_ch.m_checksumInv); + m_ch._swapEndian(); +} + +File* Card::_fileFromHandle(const FileHandle& fh) const { + if (!fh) { + NullFileAccess(); + return nullptr; + } + return const_cast(m_dirs[m_currentDir]).getFile(fh.idx); +} + +ECardResult Card::createFile(const char* filename, size_t size, FileHandle& handleOut) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + handleOut = {}; + + if (size <= 0) + return ECardResult::FATAL_ERROR; + if (strlen(filename) > 32) + return ECardResult::NAMETOOLONG; + if (m_dirs[m_currentDir].getFile(m_game, m_maker, filename)) + return ECardResult::EXIST; + uint16_t neededBlocks = ROUND_UP_8192(size) / BlockSize; + if (neededBlocks > m_bats[m_currentBat].numFreeBlocks()) + return ECardResult::INSSPACE; + if (!m_dirs[m_currentDir].hasFreeFile()) + return ECardResult::NOENT; + + Directory dir = m_dirs[m_currentDir]; + BlockAllocationTable bat = m_bats[m_currentBat]; + File* f = dir.getFirstFreeFile(m_game, m_maker, filename); + uint16_t block = bat.allocateBlocks(neededBlocks, m_maxBlock - FSTBlocks); + if (f && block != 0xFFFF) { + f->m_modifiedTime = uint32_t(getGCTime()); + f->m_firstBlock = block; + f->m_blockCount = neededBlocks; + + handleOut = FileHandle(dir.indexForFile(f)); + _updateDirAndBat(dir, bat); + return ECardResult::READY; + } + + return ECardResult::FATAL_ERROR; +} + +ECardResult Card::closeFile(FileHandle& fh) { + fh.offset = 0; + return ECardResult::READY; +} + +FileHandle Card::firstFile() { + File* f = m_dirs[m_currentDir].getFirstNonFreeFile(0, m_game, m_maker); + if (f) + return FileHandle(m_dirs[m_currentDir].indexForFile(f)); + + return {}; +} + +FileHandle Card::nextFile(const FileHandle& cur) { + if (!cur) { + NullFileAccess(); return {}; + } + File* next = m_dirs[m_currentDir].getFirstNonFreeFile(cur.idx + 1, m_game, m_maker); + if (!next) + return {}; + return FileHandle(m_dirs[m_currentDir].indexForFile(next)); } -FileHandle Card::nextFile(const FileHandle& cur) -{ - if (!cur) - { - NullFileAccess(); - return {}; - } - File* next = m_dirs[m_currentDir].getFirstNonFreeFile(cur.idx + 1, m_game, m_maker); - if (!next) - return {}; - return FileHandle(m_dirs[m_currentDir].indexForFile(next)); +const char* Card::getFilename(const FileHandle& fh) { + File* f = _fileFromHandle(fh); + if (!f) + return nullptr; + return f->m_filename; } -const char* Card::getFilename(const FileHandle& fh) -{ - File* f = _fileFromHandle(fh); - if (!f) - return nullptr; - return f->m_filename; +void Card::_deleteFile(File& f, BlockAllocationTable& bat) { + uint16_t block = f.m_firstBlock; + while (block != 0xFFFF) { + /* TODO: add a fragmentation check */ + uint16_t nextBlock = bat.getNextBlock(block); + bat.clear(block, 1); + block = nextBlock; + } + f = File(); } -void Card::_deleteFile(File& f, BlockAllocationTable& bat) -{ - uint16_t block = f.m_firstBlock; - while (block != 0xFFFF) - { - /* TODO: add a fragmentation check */ - uint16_t nextBlock = bat.getNextBlock(block); - bat.clear(block, 1); - block = nextBlock; - } - f = File(); +void Card::deleteFile(const FileHandle& fh) { + if (!fh) { + NullFileAccess(); + return; + } + Directory dir = m_dirs[m_currentDir]; + BlockAllocationTable bat = m_bats[m_currentBat]; + _deleteFile(*dir.getFile(fh.idx), bat); + _updateDirAndBat(dir, bat); } -void Card::deleteFile(const FileHandle& fh) -{ - if (!fh) - { - NullFileAccess(); - return; - } - Directory dir = m_dirs[m_currentDir]; +ECardResult Card::deleteFile(const char* filename) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + Directory dir = m_dirs[m_currentDir]; + File* f = dir.getFile(m_game, m_maker, filename); + if (!f) + return ECardResult::NOFILE; + + BlockAllocationTable bat = m_bats[m_currentBat]; + _deleteFile(*f, bat); + _updateDirAndBat(dir, bat); + return ECardResult::READY; +} + +ECardResult Card::deleteFile(uint32_t fileno) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + Directory dir = m_dirs[m_currentDir]; + File* f = dir.getFile(fileno); + if (!f) + return ECardResult::NOFILE; + + BlockAllocationTable bat = m_bats[m_currentBat]; + _deleteFile(*f, bat); + _updateDirAndBat(dir, bat); + return ECardResult::READY; +} + +ECardResult Card::renameFile(const char* oldName, const char* newName) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + if (strlen(newName) > 32) + return ECardResult::NAMETOOLONG; + + Directory dir = m_dirs[m_currentDir]; + File* f = dir.getFile(m_game, m_maker, oldName); + if (!f) + return ECardResult::NOFILE; + + if (File* replF = dir.getFile(m_game, m_maker, newName)) { BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*dir.getFile(fh.idx), bat); + _deleteFile(*replF, bat); + strncpy(f->m_filename, newName, 32); _updateDirAndBat(dir, bat); -} - -ECardResult Card::deleteFile(const char* filename) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - Directory dir = m_dirs[m_currentDir]; - File* f = dir.getFile(m_game, m_maker, filename); - if (!f) - return ECardResult::NOFILE; - - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*f, bat); - _updateDirAndBat(dir, bat); - return ECardResult::READY; -} - -ECardResult Card::deleteFile(uint32_t fileno) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - Directory dir = m_dirs[m_currentDir]; - File* f = dir.getFile(fileno); - if (!f) - return ECardResult::NOFILE; - - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*f, bat); - _updateDirAndBat(dir, bat); - return ECardResult::READY; -} - -ECardResult Card::renameFile(const char* oldName, const char* newName) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - if (strlen(newName) > 32) - return ECardResult::NAMETOOLONG; - - Directory dir = m_dirs[m_currentDir]; - File* f = dir.getFile(m_game, m_maker, oldName); - if (!f) - return ECardResult::NOFILE; - - if (File* replF = dir.getFile(m_game, m_maker, newName)) - { - BlockAllocationTable bat = m_bats[m_currentBat]; - _deleteFile(*replF, bat); - strncpy(f->m_filename, newName, 32); - _updateDirAndBat(dir, bat); - } - else - { - strncpy(f->m_filename, newName, 32); - _updateDirAndBat(dir, m_bats[m_currentBat]); - } - return ECardResult::READY; -} - -ECardResult Card::asyncWrite(FileHandle& fh, const void* buf, size_t size) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - if (!fh) - { - NullFileAccess(); - return ECardResult::NOFILE; - } - File* file = m_dirs[m_currentDir].getFile(fh.idx); - if (!file) - return ECardResult::NOFILE; - - /* Block handling is a little different from cache handling, - * since each block can be in an arbitrary location we must - * first find our starting block. - */ - const uint16_t blockId = uint16_t(fh.offset / BlockSize); - uint16_t block = file->m_firstBlock; - for (uint16_t i = 0; i < blockId; i++) - block = m_bats[m_currentBat].getNextBlock(block); - - const uint8_t* tmpBuf = reinterpret_cast(buf); - uint16_t curBlock = block; - uint32_t blockOffset = fh.offset % BlockSize; - size_t rem = size; - while (rem) - { - if (curBlock == 0xFFFF) - return ECardResult::NOFILE; - - size_t cacheSize = rem; - if (cacheSize + blockOffset > BlockSize) - cacheSize = BlockSize - blockOffset; - uint32_t offset = (curBlock * BlockSize) + blockOffset; - if (!m_fileHandle.asyncWrite(curBlock, tmpBuf, cacheSize, offset)) - return ECardResult::FATAL_ERROR; - tmpBuf += cacheSize; - rem -= cacheSize; - blockOffset += cacheSize; - if (blockOffset >= BlockSize) - { - curBlock = m_bats[m_currentBat].getNextBlock(curBlock); - blockOffset = 0; - } - } - fh.offset += size; - - return ECardResult::READY; -} - -ECardResult Card::asyncRead(FileHandle& fh, void* dst, size_t size) -{ - ECardResult openRes = _pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - if (!fh) - { - NullFileAccess(); - return ECardResult::NOFILE; - } - File* file = m_dirs[m_currentDir].getFile(fh.idx); - if (!file) - return ECardResult::NOFILE; - /* Block handling is a little different from cache handling, - * since each block can be in an arbitrary location we must - * first find our starting block. - */ - const uint16_t blockId = uint16_t(fh.offset / BlockSize); - uint16_t block = file->m_firstBlock; - for (uint16_t i = 0; i < blockId; i++) - block = m_bats[m_currentBat].getNextBlock(block); - - uint8_t* tmpBuf = reinterpret_cast(dst); - uint16_t curBlock = block; - uint32_t blockOffset = fh.offset % BlockSize; - size_t rem = size; - while (rem) - { - if (curBlock == 0xFFFF) - return ECardResult::NOFILE; - - size_t cacheSize = rem; - if (cacheSize + blockOffset > BlockSize) - cacheSize = BlockSize - blockOffset; - uint32_t offset = (curBlock * BlockSize) + blockOffset; - if (!m_fileHandle.asyncRead(curBlock, tmpBuf, cacheSize, offset)) - return ECardResult::FATAL_ERROR; - tmpBuf += cacheSize; - rem -= cacheSize; - blockOffset += cacheSize; - if (blockOffset >= BlockSize) - { - curBlock = m_bats[m_currentBat].getNextBlock(curBlock); - blockOffset = 0; - } - } - fh.offset += size; - - return ECardResult::READY; -} - -void Card::seek(FileHandle& fh, int32_t pos, SeekOrigin whence) -{ - if (!fh) - { - NullFileAccess(); - return; - } - File* file = m_dirs[m_currentDir].getFile(fh.idx); - if (!file) - return; - - switch (whence) - { - case SeekOrigin::Begin: - fh.offset = pos; - break; - case SeekOrigin::Current: - fh.offset += pos; - break; - case SeekOrigin::End: - fh.offset = int32_t(file->m_blockCount * BlockSize) - pos; - break; - } -} - -int32_t Card::tell(const FileHandle& fh) -{ - return fh.offset; -} - -void Card::setPublic(const FileHandle& fh, bool pub) -{ - File* file = _fileFromHandle(fh); - if (!file) - return; - - if (pub) - file->m_permissions |= EPermissions::Public; - else - file->m_permissions &= ~EPermissions::Public; -} - -bool Card::isPublic(const FileHandle& fh) const -{ - File* file = _fileFromHandle(fh); - if (!file) - return false; - - return bool(file->m_permissions & EPermissions::Public); -} - -void Card::setCanCopy(const FileHandle& fh, bool copy) const -{ - File* file = _fileFromHandle(fh); - if (!file) - return; - - if (copy) - file->m_permissions &= ~EPermissions::NoCopy; - else - file->m_permissions |= EPermissions::NoCopy; -} - -bool Card::canCopy(const FileHandle& fh) const -{ - File* file = _fileFromHandle(fh); - if (!file) - return false; - - return !bool(file->m_permissions & EPermissions::NoCopy); -} - -void Card::setCanMove(const FileHandle& fh, bool move) -{ - File* file = _fileFromHandle(fh); - if (!file) - return; - - if (move) - file->m_permissions &= ~EPermissions::NoMove; - else - file->m_permissions |= EPermissions::NoMove; -} - -bool Card::canMove(const FileHandle& fh) const -{ - File* file = _fileFromHandle(fh); - if (!file) - return false; - - return !bool(file->m_permissions & EPermissions::NoMove); -} - -static uint32_t BannerSize(EImageFormat fmt) -{ - switch (fmt) - { - default: - case EImageFormat::None: - return 0; - case EImageFormat::C8: - return 3584; - case EImageFormat::RGB5A3: - return 6144; - } -} - -static uint32_t IconSize(EImageFormat fmt) -{ - switch (fmt) - { - default: - case EImageFormat::None: - return 0; - case EImageFormat::C8: - return 1024; - case EImageFormat::RGB5A3: - return 2048; - } -} - -static uint32_t TlutSize(EImageFormat fmt) -{ - switch (fmt) - { - default: - case EImageFormat::None: - case EImageFormat::RGB5A3: - return 0; - case EImageFormat::C8: - return 512; - } -} - -ECardResult Card::getStatus(const FileHandle& fh, CardStat& statOut) const -{ - if (!fh) - { - NullFileAccess(); - return ECardResult::NOFILE; - } - return getStatus(fh.idx, statOut); -} - -ECardResult Card::getStatus(uint32_t fileNo, CardStat& statOut) const -{ - ECardResult openRes = const_cast(this)->_pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - const File* file = const_cast(m_dirs[m_currentDir]).getFile(fileNo); - if (!file || file->m_game[0] == 0xFF) - return ECardResult::NOFILE; - - strncpy(statOut.x0_fileName, file->m_filename, 32); - statOut.x20_length = file->m_blockCount * BlockSize; - statOut.x24_time = file->m_modifiedTime; - memcpy(statOut.x28_gameName, file->m_game, 4); - memcpy(statOut.x2c_company, file->m_maker, 2); - - statOut.x2e_bannerFormat = file->m_bannerFlags; - statOut.x30_iconAddr = file->m_iconAddress; - statOut.x34_iconFormat = file->m_iconFmt; - statOut.x36_iconSpeed = file->m_animSpeed; - statOut.x38_commentAddr = file->m_commentAddr; - - if (file->m_iconAddress == -1) - { - statOut.x3c_offsetBanner = -1; - statOut.x40_offsetBannerTlut = -1; - for (int i=0 ; im_commentAddr + 64; - } - else - { - uint32_t cur = file->m_iconAddress; - statOut.x3c_offsetBanner = cur; - cur += BannerSize(statOut.GetBannerFormat()); - statOut.x40_offsetBannerTlut = cur; - cur += TlutSize(statOut.GetBannerFormat()); - bool palette = false; - for (int i=0 ; im_game[0] == 0xFF) - return ECardResult::NOFILE; - - file->m_bannerFlags = stat.x2e_bannerFormat; - file->m_iconAddress = stat.x30_iconAddr; - file->m_iconFmt = stat.x34_iconFormat; - file->m_animSpeed = stat.x36_iconSpeed; - file->m_commentAddr = stat.x38_commentAddr; - + } else { + strncpy(f->m_filename, newName, 32); _updateDirAndBat(dir, m_bats[m_currentBat]); - return ECardResult::READY; + } + return ECardResult::READY; +} + +ECardResult Card::asyncWrite(FileHandle& fh, const void* buf, size_t size) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + if (!fh) { + NullFileAccess(); + return ECardResult::NOFILE; + } + File* file = m_dirs[m_currentDir].getFile(fh.idx); + if (!file) + return ECardResult::NOFILE; + + /* Block handling is a little different from cache handling, + * since each block can be in an arbitrary location we must + * first find our starting block. + */ + const uint16_t blockId = uint16_t(fh.offset / BlockSize); + uint16_t block = file->m_firstBlock; + for (uint16_t i = 0; i < blockId; i++) + block = m_bats[m_currentBat].getNextBlock(block); + + const uint8_t* tmpBuf = reinterpret_cast(buf); + uint16_t curBlock = block; + uint32_t blockOffset = fh.offset % BlockSize; + size_t rem = size; + while (rem) { + if (curBlock == 0xFFFF) + return ECardResult::NOFILE; + + size_t cacheSize = rem; + if (cacheSize + blockOffset > BlockSize) + cacheSize = BlockSize - blockOffset; + uint32_t offset = (curBlock * BlockSize) + blockOffset; + if (!m_fileHandle.asyncWrite(curBlock, tmpBuf, cacheSize, offset)) + return ECardResult::FATAL_ERROR; + tmpBuf += cacheSize; + rem -= cacheSize; + blockOffset += cacheSize; + if (blockOffset >= BlockSize) { + curBlock = m_bats[m_currentBat].getNextBlock(curBlock); + blockOffset = 0; + } + } + fh.offset += size; + + return ECardResult::READY; +} + +ECardResult Card::asyncRead(FileHandle& fh, void* dst, size_t size) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + if (!fh) { + NullFileAccess(); + return ECardResult::NOFILE; + } + File* file = m_dirs[m_currentDir].getFile(fh.idx); + if (!file) + return ECardResult::NOFILE; + /* Block handling is a little different from cache handling, + * since each block can be in an arbitrary location we must + * first find our starting block. + */ + const uint16_t blockId = uint16_t(fh.offset / BlockSize); + uint16_t block = file->m_firstBlock; + for (uint16_t i = 0; i < blockId; i++) + block = m_bats[m_currentBat].getNextBlock(block); + + uint8_t* tmpBuf = reinterpret_cast(dst); + uint16_t curBlock = block; + uint32_t blockOffset = fh.offset % BlockSize; + size_t rem = size; + while (rem) { + if (curBlock == 0xFFFF) + return ECardResult::NOFILE; + + size_t cacheSize = rem; + if (cacheSize + blockOffset > BlockSize) + cacheSize = BlockSize - blockOffset; + uint32_t offset = (curBlock * BlockSize) + blockOffset; + if (!m_fileHandle.asyncRead(curBlock, tmpBuf, cacheSize, offset)) + return ECardResult::FATAL_ERROR; + tmpBuf += cacheSize; + rem -= cacheSize; + blockOffset += cacheSize; + if (blockOffset >= BlockSize) { + curBlock = m_bats[m_currentBat].getNextBlock(curBlock); + blockOffset = 0; + } + } + fh.offset += size; + + return ECardResult::READY; +} + +void Card::seek(FileHandle& fh, int32_t pos, SeekOrigin whence) { + if (!fh) { + NullFileAccess(); + return; + } + File* file = m_dirs[m_currentDir].getFile(fh.idx); + if (!file) + return; + + switch (whence) { + case SeekOrigin::Begin: + fh.offset = pos; + break; + case SeekOrigin::Current: + fh.offset += pos; + break; + case SeekOrigin::End: + fh.offset = int32_t(file->m_blockCount * BlockSize) - pos; + break; + } +} + +int32_t Card::tell(const FileHandle& fh) { return fh.offset; } + +void Card::setPublic(const FileHandle& fh, bool pub) { + File* file = _fileFromHandle(fh); + if (!file) + return; + + if (pub) + file->m_permissions |= EPermissions::Public; + else + file->m_permissions &= ~EPermissions::Public; +} + +bool Card::isPublic(const FileHandle& fh) const { + File* file = _fileFromHandle(fh); + if (!file) + return false; + + return bool(file->m_permissions & EPermissions::Public); +} + +void Card::setCanCopy(const FileHandle& fh, bool copy) const { + File* file = _fileFromHandle(fh); + if (!file) + return; + + if (copy) + file->m_permissions &= ~EPermissions::NoCopy; + else + file->m_permissions |= EPermissions::NoCopy; +} + +bool Card::canCopy(const FileHandle& fh) const { + File* file = _fileFromHandle(fh); + if (!file) + return false; + + return !bool(file->m_permissions & EPermissions::NoCopy); +} + +void Card::setCanMove(const FileHandle& fh, bool move) { + File* file = _fileFromHandle(fh); + if (!file) + return; + + if (move) + file->m_permissions &= ~EPermissions::NoMove; + else + file->m_permissions |= EPermissions::NoMove; +} + +bool Card::canMove(const FileHandle& fh) const { + File* file = _fileFromHandle(fh); + if (!file) + return false; + + return !bool(file->m_permissions & EPermissions::NoMove); +} + +static uint32_t BannerSize(EImageFormat fmt) { + switch (fmt) { + default: + case EImageFormat::None: + return 0; + case EImageFormat::C8: + return 3584; + case EImageFormat::RGB5A3: + return 6144; + } +} + +static uint32_t IconSize(EImageFormat fmt) { + switch (fmt) { + default: + case EImageFormat::None: + return 0; + case EImageFormat::C8: + return 1024; + case EImageFormat::RGB5A3: + return 2048; + } +} + +static uint32_t TlutSize(EImageFormat fmt) { + switch (fmt) { + default: + case EImageFormat::None: + case EImageFormat::RGB5A3: + return 0; + case EImageFormat::C8: + return 512; + } +} + +ECardResult Card::getStatus(const FileHandle& fh, CardStat& statOut) const { + if (!fh) { + NullFileAccess(); + return ECardResult::NOFILE; + } + return getStatus(fh.idx, statOut); +} + +ECardResult Card::getStatus(uint32_t fileNo, CardStat& statOut) const { + ECardResult openRes = const_cast(this)->_pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + const File* file = const_cast(m_dirs[m_currentDir]).getFile(fileNo); + if (!file || file->m_game[0] == 0xFF) + return ECardResult::NOFILE; + + strncpy(statOut.x0_fileName, file->m_filename, 32); + statOut.x20_length = file->m_blockCount * BlockSize; + statOut.x24_time = file->m_modifiedTime; + memcpy(statOut.x28_gameName, file->m_game, 4); + memcpy(statOut.x2c_company, file->m_maker, 2); + + statOut.x2e_bannerFormat = file->m_bannerFlags; + statOut.x30_iconAddr = file->m_iconAddress; + statOut.x34_iconFormat = file->m_iconFmt; + statOut.x36_iconSpeed = file->m_animSpeed; + statOut.x38_commentAddr = file->m_commentAddr; + + if (file->m_iconAddress == -1) { + statOut.x3c_offsetBanner = -1; + statOut.x40_offsetBannerTlut = -1; + for (int i = 0; i < CARD_ICON_MAX; ++i) + statOut.x44_offsetIcon[i] = -1; + statOut.x64_offsetIconTlut = -1; + statOut.x68_offsetData = file->m_commentAddr + 64; + } else { + uint32_t cur = file->m_iconAddress; + statOut.x3c_offsetBanner = cur; + cur += BannerSize(statOut.GetBannerFormat()); + statOut.x40_offsetBannerTlut = cur; + cur += TlutSize(statOut.GetBannerFormat()); + bool palette = false; + for (int i = 0; i < CARD_ICON_MAX; ++i) { + statOut.x44_offsetIcon[i] = cur; + EImageFormat fmt = statOut.GetIconFormat(i); + if (fmt == EImageFormat::C8) + palette = true; + cur += IconSize(fmt); + } + if (palette) { + statOut.x64_offsetIconTlut = cur; + cur += TlutSize(EImageFormat::C8); + } else + statOut.x64_offsetIconTlut = -1; + statOut.x68_offsetData = cur; + } + + return ECardResult::READY; +} + +ECardResult Card::setStatus(const FileHandle& fh, const CardStat& stat) { + if (!fh) { + NullFileAccess(); + return ECardResult::NOFILE; + } + return setStatus(fh.idx, stat); +} + +ECardResult Card::setStatus(uint32_t fileNo, const CardStat& stat) { + ECardResult openRes = _pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + Directory dir = m_dirs[m_currentDir]; + File* file = dir.getFile(fileNo); + if (!file || file->m_game[0] == 0xFF) + return ECardResult::NOFILE; + + file->m_bannerFlags = stat.x2e_bannerFormat; + file->m_iconAddress = stat.x30_iconAddr; + file->m_iconFmt = stat.x34_iconFormat; + file->m_animSpeed = stat.x36_iconSpeed; + file->m_commentAddr = stat.x38_commentAddr; + + _updateDirAndBat(dir, m_bats[m_currentBat]); + return ECardResult::READY; } #if 0 // TODO: Async-friendly implementations @@ -761,240 +685,218 @@ bool Card::moveFileTo(FileHandle& fh, Card& dest) } #endif -void Card::setCurrentGame(const char* game) -{ - if (game == nullptr) - { - memset(m_game, 0, 2); - return; - } +void Card::setCurrentGame(const char* game) { + if (game == nullptr) { + memset(m_game, 0, 2); + return; + } - if (strlen(game) != 4) - return; + if (strlen(game) != 4) + return; - memcpy(m_game, game, 4); + memcpy(m_game, game, 4); } -const uint8_t* Card::getCurrentGame() const -{ - if (strlen(m_game) == 4) - return reinterpret_cast(m_game); +const uint8_t* Card::getCurrentGame() const { + if (strlen(m_game) == 4) + return reinterpret_cast(m_game); - return nullptr; + return nullptr; } -void Card::setCurrentMaker(const char* maker) -{ - if (maker == nullptr) - { - memset(m_maker, 0, 2); - return; - } +void Card::setCurrentMaker(const char* maker) { + if (maker == nullptr) { + memset(m_maker, 0, 2); + return; + } - if (strlen(maker) != 2) - return; + if (strlen(maker) != 2) + return; - memcpy(m_maker, maker, 2); + memcpy(m_maker, maker, 2); } -const uint8_t* Card::getCurrentMaker() const -{ - if (strlen(m_maker) == 2) - return reinterpret_cast(m_maker); - return nullptr; +const uint8_t* Card::getCurrentMaker() const { + if (strlen(m_maker) == 2) + return reinterpret_cast(m_maker); + return nullptr; } -void Card::getSerial(uint64_t& serial) -{ - m_ch._swapEndian(); - uint32_t serialBuf[8]; - for (uint32_t i = 0; i < 8; i++) - serialBuf[i] = SBig(*reinterpret_cast(__raw + (i * 4))); - serial = uint64_t(serialBuf[0] ^ serialBuf[2] ^ serialBuf[4] ^ serialBuf[6]) << 32 | - (serialBuf[1] ^ serialBuf[3] ^ serialBuf[5] ^ serialBuf[7]); - m_ch._swapEndian(); +void Card::getSerial(uint64_t& serial) { + m_ch._swapEndian(); + uint32_t serialBuf[8]; + for (uint32_t i = 0; i < 8; i++) + serialBuf[i] = SBig(*reinterpret_cast(__raw + (i * 4))); + serial = uint64_t(serialBuf[0] ^ serialBuf[2] ^ serialBuf[4] ^ serialBuf[6]) << 32 | + (serialBuf[1] ^ serialBuf[3] ^ serialBuf[5] ^ serialBuf[7]); + m_ch._swapEndian(); } -void Card::getChecksum(uint16_t& checksum, uint16_t& inverse) -{ - checksum = m_ch.m_checksum; - inverse = m_ch.m_checksumInv; +void Card::getChecksum(uint16_t& checksum, uint16_t& inverse) { + checksum = m_ch.m_checksum; + inverse = m_ch.m_checksumInv; } -void Card::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) -{ - bytesNotUsed = m_bats[m_currentBat].numFreeBlocks() * 0x2000; - filesNotUsed = m_dirs[m_currentDir].numFreeFiles(); +void Card::getFreeBlocks(int32_t& bytesNotUsed, int32_t& filesNotUsed) { + bytesNotUsed = m_bats[m_currentBat].numFreeBlocks() * 0x2000; + filesNotUsed = m_dirs[m_currentDir].numFreeFiles(); } static std::unique_ptr DummyBlock; -void Card::format(ECardSlot id, ECardSize size, EEncoding encoding) -{ - memset(__raw, 0xFF, BlockSize); - uint64_t rand = uint64_t(getGCTime()); - m_ch.m_formatTime = rand; - for (int i = 0; i < 12; i++) - { - rand = (((rand * uint64_t(0x41c64e6d)) + uint64_t(0x3039)) >> 16); - m_ch.m_serial[i] = uint8_t(g_SRAM.flash_id[uint32_t(id)][i] + uint32_t(rand)); - rand = (((rand * uint64_t(0x41c64e6d)) + uint64_t(0x3039)) >> 16); - rand &= uint64_t(0x7fffULL); - } - - m_ch.m_sramBias = int32_t(SBig(g_SRAM.counter_bias)); - m_ch.m_sramLanguage = uint32_t(SBig(g_SRAM.lang)); - m_ch.m_unknown = 0; /* 1 works for slot A, 0 both */ - m_ch.m_deviceId = 0; - m_ch.m_sizeMb = uint16_t(size); - m_maxBlock = m_ch.m_sizeMb * MbitToBlocks; - m_ch.m_encoding = uint16_t(encoding); - _updateChecksum(); - m_dirs[0] = Directory(); - m_dirs[1] = m_dirs[0]; - m_bats[0] = BlockAllocationTable(uint32_t(size) * MbitToBlocks); - m_bats[1] = m_bats[0]; - m_currentDir = 1; - m_currentBat = 1; - - m_fileHandle = {}; - m_fileHandle = AsyncIO(m_filename.c_str(), true); - - if (m_fileHandle) - { - uint32_t blockCount = (uint32_t(size) * MbitToBlocks) - 5; - - m_tmpCh = m_ch; - m_tmpCh._swapEndian(); - m_fileHandle.resizeQueue(5 + blockCount); - m_fileHandle.asyncWrite(0, &m_tmpCh, BlockSize, 0); - m_tmpDirs[0] = m_dirs[0]; - m_tmpDirs[0].swapEndian(); - m_fileHandle.asyncWrite(1, m_tmpDirs[0].__raw, BlockSize, BlockSize * 1); - m_tmpDirs[1] = m_dirs[1]; - m_tmpDirs[1].swapEndian(); - m_fileHandle.asyncWrite(2, m_tmpDirs[1].__raw, BlockSize, BlockSize * 2); - m_tmpBats[0] = m_bats[0]; - m_tmpBats[0].swapEndian(); - m_fileHandle.asyncWrite(3, m_tmpBats[0].__raw, BlockSize, BlockSize * 3); - m_tmpBats[1] = m_bats[1]; - m_tmpBats[1].swapEndian(); - m_fileHandle.asyncWrite(4, m_tmpBats[1].__raw, BlockSize, BlockSize * 4); - if (!DummyBlock) - { - DummyBlock.reset(new uint8_t[BlockSize]); - memset(DummyBlock.get(), 0xFF, BlockSize); - } - for (uint32_t i=0 ; i> 16); + m_ch.m_serial[i] = uint8_t(g_SRAM.flash_id[uint32_t(id)][i] + uint32_t(rand)); + rand = (((rand * uint64_t(0x41c64e6d)) + uint64_t(0x3039)) >> 16); + rand &= uint64_t(0x7fffULL); + } + + m_ch.m_sramBias = int32_t(SBig(g_SRAM.counter_bias)); + m_ch.m_sramLanguage = uint32_t(SBig(g_SRAM.lang)); + m_ch.m_unknown = 0; /* 1 works for slot A, 0 both */ + m_ch.m_deviceId = 0; + m_ch.m_sizeMb = uint16_t(size); + m_maxBlock = m_ch.m_sizeMb * MbitToBlocks; + m_ch.m_encoding = uint16_t(encoding); + _updateChecksum(); + m_dirs[0] = Directory(); + m_dirs[1] = m_dirs[0]; + m_bats[0] = BlockAllocationTable(uint32_t(size) * MbitToBlocks); + m_bats[1] = m_bats[0]; + m_currentDir = 1; + m_currentBat = 1; + + m_fileHandle = {}; + m_fileHandle = AsyncIO(m_filename.c_str(), true); + + if (m_fileHandle) { + uint32_t blockCount = (uint32_t(size) * MbitToBlocks) - 5; + + m_tmpCh = m_ch; + m_tmpCh._swapEndian(); + m_fileHandle.resizeQueue(5 + blockCount); + m_fileHandle.asyncWrite(0, &m_tmpCh, BlockSize, 0); + m_tmpDirs[0] = m_dirs[0]; + m_tmpDirs[0].swapEndian(); + m_fileHandle.asyncWrite(1, m_tmpDirs[0].__raw, BlockSize, BlockSize * 1); + m_tmpDirs[1] = m_dirs[1]; + m_tmpDirs[1].swapEndian(); + m_fileHandle.asyncWrite(2, m_tmpDirs[1].__raw, BlockSize, BlockSize * 2); + m_tmpBats[0] = m_bats[0]; + m_tmpBats[0].swapEndian(); + m_fileHandle.asyncWrite(3, m_tmpBats[0].__raw, BlockSize, BlockSize * 3); + m_tmpBats[1] = m_bats[1]; + m_tmpBats[1].swapEndian(); + m_fileHandle.asyncWrite(4, m_tmpBats[1].__raw, BlockSize, BlockSize * 4); + if (!DummyBlock) { + DummyBlock.reset(new uint8_t[BlockSize]); + memset(DummyBlock.get(), 0xFF, BlockSize); } + for (uint32_t i = 0; i < blockCount; ++i) + m_fileHandle.asyncWrite(i + 5, DummyBlock.get(), BlockSize, BlockSize * (i + 5)); + m_dirty = false; + } } -ProbeResults Card::probeCardFile(SystemStringView filename) -{ - Sstat stat; - if (Stat(filename.data(), &stat) || !S_ISREG(stat.st_mode)) - return { ECardResult::NOCARD, 0, 0 }; - return { ECardResult::READY, uint32_t(stat.st_size / BlockSize) / MbitToBlocks, 0x2000 }; +ProbeResults Card::probeCardFile(SystemStringView filename) { + Sstat stat; + if (Stat(filename.data(), &stat) || !S_ISREG(stat.st_mode)) + return {ECardResult::NOCARD, 0, 0}; + return {ECardResult::READY, uint32_t(stat.st_size / BlockSize) / MbitToBlocks, 0x2000}; } -void Card::commit() -{ - if (!m_dirty) - return; - if (m_fileHandle) - { - m_tmpCh = m_ch; - m_tmpCh._swapEndian(); - m_fileHandle.asyncWrite(0, &m_tmpCh, BlockSize, 0); - m_tmpDirs[0] = m_dirs[0]; - m_tmpDirs[0].updateChecksum(); - m_tmpDirs[0].swapEndian(); - m_fileHandle.asyncWrite(1, m_tmpDirs[0].__raw, BlockSize, BlockSize * 1); - m_tmpDirs[1] = m_dirs[1]; - m_tmpDirs[1].updateChecksum(); - m_tmpDirs[1].swapEndian(); - m_fileHandle.asyncWrite(2, m_tmpDirs[1].__raw, BlockSize, BlockSize * 2); - m_tmpBats[0] = m_bats[0]; - m_tmpBats[0].updateChecksum(); - m_tmpBats[0].swapEndian(); - m_fileHandle.asyncWrite(3, m_tmpBats[0].__raw, BlockSize, BlockSize * 3); - m_tmpBats[1] = m_bats[1]; - m_tmpBats[1].updateChecksum(); - m_tmpBats[1].swapEndian(); - m_fileHandle.asyncWrite(4, m_tmpBats[1].__raw, BlockSize, BlockSize * 4); - m_dirty = false; - } +void Card::commit() { + if (!m_dirty) + return; + if (m_fileHandle) { + m_tmpCh = m_ch; + m_tmpCh._swapEndian(); + m_fileHandle.asyncWrite(0, &m_tmpCh, BlockSize, 0); + m_tmpDirs[0] = m_dirs[0]; + m_tmpDirs[0].updateChecksum(); + m_tmpDirs[0].swapEndian(); + m_fileHandle.asyncWrite(1, m_tmpDirs[0].__raw, BlockSize, BlockSize * 1); + m_tmpDirs[1] = m_dirs[1]; + m_tmpDirs[1].updateChecksum(); + m_tmpDirs[1].swapEndian(); + m_fileHandle.asyncWrite(2, m_tmpDirs[1].__raw, BlockSize, BlockSize * 2); + m_tmpBats[0] = m_bats[0]; + m_tmpBats[0].updateChecksum(); + m_tmpBats[0].swapEndian(); + m_fileHandle.asyncWrite(3, m_tmpBats[0].__raw, BlockSize, BlockSize * 3); + m_tmpBats[1] = m_bats[1]; + m_tmpBats[1].updateChecksum(); + m_tmpBats[1].swapEndian(); + m_fileHandle.asyncWrite(4, m_tmpBats[1].__raw, BlockSize, BlockSize * 4); + m_dirty = false; + } } -bool Card::open(SystemStringView filepath) -{ - m_opened = false; - m_filename = filepath; - m_fileHandle = AsyncIO(m_filename); - if (m_fileHandle) - { - m_fileHandle.resizeQueue(5); - if (!m_fileHandle.asyncRead(0, __raw, BlockSize, 0)) - return false; - if (!m_fileHandle.asyncRead(1, m_dirs[0].__raw, BlockSize, BlockSize * 1)) - return false; - if (!m_fileHandle.asyncRead(2, m_dirs[1].__raw, BlockSize, BlockSize * 2)) - return false; - if (!m_fileHandle.asyncRead(3, m_bats[0].__raw, BlockSize, BlockSize * 3)) - return false; - if (!m_fileHandle.asyncRead(4, m_bats[1].__raw, BlockSize, BlockSize * 4)) - return false; - return true; - } - return false; +bool Card::open(SystemStringView filepath) { + m_opened = false; + m_filename = filepath; + m_fileHandle = AsyncIO(m_filename); + if (m_fileHandle) { + m_fileHandle.resizeQueue(5); + if (!m_fileHandle.asyncRead(0, __raw, BlockSize, 0)) + return false; + if (!m_fileHandle.asyncRead(1, m_dirs[0].__raw, BlockSize, BlockSize * 1)) + return false; + if (!m_fileHandle.asyncRead(2, m_dirs[1].__raw, BlockSize, BlockSize * 2)) + return false; + if (!m_fileHandle.asyncRead(3, m_bats[0].__raw, BlockSize, BlockSize * 3)) + return false; + if (!m_fileHandle.asyncRead(4, m_bats[1].__raw, BlockSize, BlockSize * 4)) + return false; + return true; + } + return false; } -void Card::close() -{ - m_opened = false; - if (m_fileHandle) - { - commit(); - m_fileHandle.waitForCompletion(); - m_fileHandle = {}; - } -} - -ECardResult Card::getError() const -{ - if (!m_fileHandle) - return ECardResult::NOCARD; - - ECardResult pollRes = m_fileHandle.pollStatus(); - if (pollRes != ECardResult::READY) - return pollRes; - - ECardResult openRes = const_cast(this)->_pumpOpen(); - if (openRes != ECardResult::READY) - return openRes; - - uint16_t ckSum, ckSumInv; - const_cast(*this).m_ch._swapEndian(); - calculateChecksumBE(reinterpret_cast(__raw), 0xFE, &ckSum, &ckSumInv); - bool res = (ckSum == m_ch.m_checksum && ckSumInv == m_ch.m_checksumInv); - const_cast(*this).m_ch._swapEndian(); - - if (!res) - return ECardResult::BROKEN; - if (!m_dirs[0].valid() && !m_dirs[1].valid()) - return ECardResult::BROKEN; - if (!m_bats[0].valid() && !m_bats[1].valid()) - return ECardResult::BROKEN; - - return ECardResult::READY; -} - -void Card::waitForCompletion() const -{ - if (!m_fileHandle) - return; +void Card::close() { + m_opened = false; + if (m_fileHandle) { + commit(); m_fileHandle.waitForCompletion(); + m_fileHandle = {}; + } } + +ECardResult Card::getError() const { + if (!m_fileHandle) + return ECardResult::NOCARD; + + ECardResult pollRes = m_fileHandle.pollStatus(); + if (pollRes != ECardResult::READY) + return pollRes; + + ECardResult openRes = const_cast(this)->_pumpOpen(); + if (openRes != ECardResult::READY) + return openRes; + + uint16_t ckSum, ckSumInv; + const_cast(*this).m_ch._swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw), 0xFE, &ckSum, &ckSumInv); + bool res = (ckSum == m_ch.m_checksum && ckSumInv == m_ch.m_checksumInv); + const_cast(*this).m_ch._swapEndian(); + + if (!res) + return ECardResult::BROKEN; + if (!m_dirs[0].valid() && !m_dirs[1].valid()) + return ECardResult::BROKEN; + if (!m_bats[0].valid() && !m_bats[1].valid()) + return ECardResult::BROKEN; + + return ECardResult::READY; } + +void Card::waitForCompletion() const { + if (!m_fileHandle) + return; + m_fileHandle.waitForCompletion(); +} +} // namespace kabufuda diff --git a/lib/kabufuda/Directory.cpp b/lib/kabufuda/Directory.cpp index 4b10581..7234b35 100644 --- a/lib/kabufuda/Directory.cpp +++ b/lib/kabufuda/Directory.cpp @@ -2,131 +2,111 @@ #include "kabufuda/Util.hpp" #include -namespace kabufuda -{ -void Directory::swapEndian() -{ - std::for_each(std::begin(m_files), std::end(m_files), [](File& f) { f.swapEndian(); }); +namespace kabufuda { +void Directory::swapEndian() { + std::for_each(std::begin(m_files), std::end(m_files), [](File& f) { f.swapEndian(); }); - m_updateCounter = SBig(m_updateCounter); - m_checksum = SBig(m_checksum); - m_checksumInv = SBig(m_checksumInv); + m_updateCounter = SBig(m_updateCounter); + m_checksum = SBig(m_checksum); + m_checksumInv = SBig(m_checksumInv); } -void Directory::updateChecksum() -{ - swapEndian(); - calculateChecksumBE(reinterpret_cast(__raw), 0xFFE, &m_checksum, &m_checksumInv); - swapEndian(); +void Directory::updateChecksum() { + swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw), 0xFFE, &m_checksum, &m_checksumInv); + swapEndian(); } -bool Directory::valid() const -{ - uint16_t ckSum, ckSumInv; - const_cast(*this).swapEndian(); - calculateChecksumBE(reinterpret_cast(__raw), 0xFFE, &ckSum, &ckSumInv); - bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv); - const_cast(*this).swapEndian(); - return res; +bool Directory::valid() const { + uint16_t ckSum, ckSumInv; + const_cast(*this).swapEndian(); + calculateChecksumBE(reinterpret_cast(__raw), 0xFFE, &ckSum, &ckSumInv); + bool res = (ckSum == m_checksum && ckSumInv == m_checksumInv); + const_cast(*this).swapEndian(); + return res; } -Directory::Directory() -{ - memset(__raw, 0xFF, BlockSize); - m_updateCounter = 0; - updateChecksum(); +Directory::Directory() { + memset(__raw, 0xFF, BlockSize); + m_updateCounter = 0; + updateChecksum(); } Directory::Directory(uint8_t data[]) { memcpy(__raw, data, BlockSize); } -bool Directory::hasFreeFile() const -{ - for (uint16_t i = 0; i < 127; i++) - if (m_files[i].m_game[0] == 0xFF) - return true; - return false; +bool Directory::hasFreeFile() const { + for (uint16_t i = 0; i < 127; i++) + if (m_files[i].m_game[0] == 0xFF) + return true; + return false; } -int32_t Directory::numFreeFiles() const -{ - int32_t ret = 0; - for (uint16_t i = 0; i < 127; i++) - if (m_files[i].m_game[0] == 0xFF) - ++ret; - return ret; +int32_t Directory::numFreeFiles() const { + int32_t ret = 0; + for (uint16_t i = 0; i < 127; i++) + if (m_files[i].m_game[0] == 0xFF) + ++ret; + return ret; } -File* Directory::getFirstFreeFile(const char* game, const char* maker, const char* filename) -{ - for (uint16_t i = 0; i < 127; i++) - { - if (m_files[i].m_game[0] == 0xFF) - { - File* ret = &m_files[i]; - *ret = File(filename); - if (game && strlen(game) == 4) - memcpy(ret->m_game, game, 4); - if (maker && strlen(maker) == 2) - memcpy(ret->m_maker, maker, 2); - return ret; - } +File* Directory::getFirstFreeFile(const char* game, const char* maker, const char* filename) { + for (uint16_t i = 0; i < 127; i++) { + if (m_files[i].m_game[0] == 0xFF) { + File* ret = &m_files[i]; + *ret = File(filename); + if (game && strlen(game) == 4) + memcpy(ret->m_game, game, 4); + 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) -{ - for (uint16_t i = start; i < 127; i++) - { - if (m_files[i].m_game[0] != 0xFF) - { - File* ret = &m_files[i]; - if (game && std::strlen(game) == 4 && - std::strncmp(reinterpret_cast(ret->m_game), game, 4) != 0) - continue; - if (maker && std::strlen(maker) == 2 && - std::strncmp(reinterpret_cast(ret->m_maker), maker, 2) != 0) - continue; - return ret; - } +File* Directory::getFirstNonFreeFile(uint32_t start, const char* game, const char* maker) { + for (uint16_t i = start; i < 127; i++) { + if (m_files[i].m_game[0] != 0xFF) { + File* ret = &m_files[i]; + if (game && std::strlen(game) == 4 && std::strncmp(reinterpret_cast(ret->m_game), game, 4) != 0) + continue; + if (maker && std::strlen(maker) == 2 && std::strncmp(reinterpret_cast(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 &m_files[idx]; } -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]; - } +int32_t Directory::indexForFile(File* f) { + if (!f) + return -1; - return nullptr; -} - -File* Directory::getFile(uint32_t idx) -{ - 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); -} + 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 diff --git a/lib/kabufuda/File.cpp b/lib/kabufuda/File.cpp index fc8e1dd..b4abefd 100644 --- a/lib/kabufuda/File.cpp +++ b/lib/kabufuda/File.cpp @@ -1,27 +1,24 @@ #include "kabufuda/File.hpp" #include "kabufuda/Util.hpp" -namespace kabufuda -{ +namespace kabufuda { File::File() { memset(__raw, 0xFF, 0x40); } File::File(char data[]) { memcpy(__raw, data, 0x40); } -File::File(const char* filename) -{ - memset(__raw, 0, 0x40); - memset(m_filename, 0, 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); +File::File(const char* filename) { + memset(__raw, 0, 0x40); + memset(m_filename, 0, 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); } +} // namespace kabufuda diff --git a/lib/kabufuda/SRAM.cpp b/lib/kabufuda/SRAM.cpp index 7a2d395..18914fa 100644 --- a/lib/kabufuda/SRAM.cpp +++ b/lib/kabufuda/SRAM.cpp @@ -1,6 +1,5 @@ #include "kabufuda/SRAM.hpp" -namespace kabufuda -{ +namespace kabufuda { // clang-format off const SRAM g_SRAM = {{ @@ -27,4 +26,4 @@ const SRAM g_SRAM = 0x00, 0x00 }}; // clang-format on -} +} // namespace kabufuda diff --git a/lib/kabufuda/Util.cpp b/lib/kabufuda/Util.cpp index 8cb0d69..e9b0a59 100644 --- a/lib/kabufuda/Util.cpp +++ b/lib/kabufuda/Util.cpp @@ -1,45 +1,41 @@ #include "kabufuda/Util.hpp" #include -namespace kabufuda -{ -uint64_t getGCTime() -{ - time_t sysTime, tzDiff, tzDST; - struct tm* gmTime; +namespace kabufuda { +uint64_t getGCTime() { + time_t sysTime, tzDiff, tzDST; + struct tm* gmTime; - time(&sysTime); + time(&sysTime); - // Account for DST where needed - gmTime = localtime(&sysTime); - if (gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; + // Account for DST where needed + gmTime = localtime(&sysTime); + if (gmTime->tm_isdst == 1) + tzDST = 3600; + else + tzDST = 0; - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - tzDiff = sysTime - mktime(gmTime); + // Lazy way to get local time in sec + gmTime = gmtime(&sysTime); + 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; + if (*checksumInv == 0xFFFF) *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 diff --git a/lib/kabufuda/WideStringConvert.cpp b/lib/kabufuda/WideStringConvert.cpp index 7aca689..afa9da9 100644 --- a/lib/kabufuda/WideStringConvert.cpp +++ b/lib/kabufuda/WideStringConvert.cpp @@ -1,43 +1,36 @@ #include "kabufuda/WideStringConvert.hpp" #include "utf8proc.h" -namespace kabufuda -{ -std::string WideToUTF8(std::wstring_view src) -{ - std::string retval; - retval.reserve(src.length()); - for (wchar_t ch : src) - { - utf8proc_uint8_t mb[4]; - utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb); - if (c < 0) - { - fprintf(stderr, "invalid UTF-8 character while encoding"); - return retval; - } - retval.append(reinterpret_cast(mb), c); +namespace kabufuda { +std::string WideToUTF8(std::wstring_view src) { + std::string retval; + retval.reserve(src.length()); + for (wchar_t ch : src) { + utf8proc_uint8_t mb[4]; + utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb); + if (c < 0) { + fprintf(stderr, "invalid UTF-8 character while encoding"); + return retval; } - return retval; + retval.append(reinterpret_cast(mb), c); + } + return retval; } -std::wstring UTF8ToWide(std::string_view src) -{ - std::wstring retval; - retval.reserve(src.length()); - const utf8proc_uint8_t* buf = reinterpret_cast(src.data()); - while (*buf) - { - utf8proc_int32_t wc; - utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc); - if (len < 0) - { - fprintf(stderr, "invalid UTF-8 character while decoding"); - return retval; - } - buf += len; - retval += wchar_t(wc); +std::wstring UTF8ToWide(std::string_view src) { + std::wstring retval; + retval.reserve(src.length()); + const utf8proc_uint8_t* buf = reinterpret_cast(src.data()); + while (*buf) { + utf8proc_int32_t wc; + utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc); + if (len < 0) { + fprintf(stderr, "invalid UTF-8 character while decoding"); + return retval; } - return retval; -} + buf += len; + retval += wchar_t(wc); + } + return retval; } +} // namespace kabufuda diff --git a/lib/kabufuda/winsupport.cpp b/lib/kabufuda/winsupport.cpp index 0fe195f..663feb6 100644 --- a/lib/kabufuda/winsupport.cpp +++ b/lib/kabufuda/winsupport.cpp @@ -5,32 +5,30 @@ #include "hecl/winsupport.hpp" /* -* The memmem() function finds the start of the first occurrence of the -* substring 'needle' of length 'nlen' in the memory area 'haystack' of -* length 'hlen'. -* -* The return value is a pointer to the beginning of the sub-string, or -* NULL if the substring is not found. -*/ -void *memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen) -{ - int needle_first; - const uint8_t *p = static_cast(haystack); - size_t plen = hlen; - - if (!nlen) - return NULL; - - needle_first = *(unsigned char *)needle; - - while (plen >= nlen && (p = static_cast(memchr(p, needle_first, plen - nlen + 1)))) - { - if (!memcmp(p, needle, nlen)) - return (void *)p; - - p++; - plen = hlen - (p - static_cast(haystack)); - } + * The memmem() function finds the start of the first occurrence of the + * substring 'needle' of length 'nlen' in the memory area 'haystack' of + * length 'hlen'. + * + * The return value is a pointer to the beginning of the sub-string, or + * NULL if the substring is not found. + */ +void* memmem(const void* haystack, size_t hlen, const void* needle, size_t nlen) { + int needle_first; + const uint8_t* p = static_cast(haystack); + size_t plen = hlen; + if (!nlen) return NULL; + + needle_first = *(unsigned char*)needle; + + while (plen >= nlen && (p = static_cast(memchr(p, needle_first, plen - nlen + 1)))) { + if (!memcmp(p, needle, nlen)) + return (void*)p; + + p++; + plen = hlen - (p - static_cast(haystack)); + } + + return NULL; } diff --git a/test/main.cpp b/test/main.cpp index cafa73f..0b19179 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,32 +1,30 @@ #include "kabufuda/Card.hpp" #include -int main() -{ - kabufuda::Card mc{"GM8E", "01"}; - mc.open(_SYS_STR("test.USA.raw")); - mc.format(kabufuda::ECardSlot::SlotA, kabufuda::ECardSize::Card2043Mb); - uint64_t a = 0; - mc.getSerial(a); +int main() { + kabufuda::Card mc{"GM8E", "01"}; + mc.open(_SYS_STR("test.USA.raw")); + mc.format(kabufuda::ECardSlot::SlotA, kabufuda::ECardSize::Card2043Mb); + uint64_t a = 0; + mc.getSerial(a); - kabufuda::FileHandle f; - mc.openFile("MetroidPrime A", f); - for (uint32_t i = 0; i < 127; i++) - { - char name[32] = {'\0'}; - sprintf(name, "Metroid Prime %i", i); - kabufuda::ECardResult res = mc.createFile(name, kabufuda::BlockSize, f); - if (res == kabufuda::ECardResult::INSSPACE || res == kabufuda::ECardResult::NOFILE) - break; + kabufuda::FileHandle f; + mc.openFile("MetroidPrime A", f); + for (uint32_t i = 0; i < 127; i++) { + char name[32] = {'\0'}; + sprintf(name, "Metroid Prime %i", i); + kabufuda::ECardResult res = mc.createFile(name, kabufuda::BlockSize, f); + if (res == kabufuda::ECardResult::INSSPACE || res == kabufuda::ECardResult::NOFILE) + break; - mc.setPublic(f, true); - mc.setCanCopy(f, true); - mc.setCanMove(f, true); - kabufuda::CardStat stat = {}; - mc.setStatus(f, stat); - mc.asyncWrite(f, "Test\0", strlen("Test") + 1); - mc.seek(f, 32, kabufuda::SeekOrigin::Begin); - mc.asyncWrite(f, "Test\0", strlen("Test") + 1); - } - return 0; + mc.setPublic(f, true); + mc.setCanCopy(f, true); + mc.setCanMove(f, true); + kabufuda::CardStat stat = {}; + mc.setStatus(f, stat); + mc.asyncWrite(f, "Test\0", strlen("Test") + 1); + mc.seek(f, 32, kabufuda::SeekOrigin::Begin); + mc.asyncWrite(f, "Test\0", strlen("Test") + 1); + } + return 0; }