diff --git a/include/kabufuda/Card.hpp b/include/kabufuda/Card.hpp index 6eea1c0..6c35085 100644 --- a/include/kabufuda/Card.hpp +++ b/include/kabufuda/Card.hpp @@ -65,7 +65,17 @@ class Card File* _fileFromHandle(const std::unique_ptr& fh) const; public: Card(); + /** + * @brief Card + * @param other + */ Card(const Card& other); + /** + * @brief Card + * @param filepath + * @param game + * @param maker + */ Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr); ~Card(); @@ -82,6 +92,24 @@ public: */ std::unique_ptr createFile(const char* filename, size_t size); + /** + * @brief firstFile + * @return + */ + std::unique_ptr firstFile(); + + /** + * @brief nextFile + * @param cur + * @return + */ + std::unique_ptr nextFile(const std::unique_ptr& cur); + /** + * @brief getFilename + * @param fh + * @return + */ + const char* getFilename(const std::unique_ptr& fh); /** * @brief deleteFile * @param fh @@ -161,17 +189,106 @@ public: */ bool canMove(const std::unique_ptr& fh) const; + /** + * @brief gameId + * @param fh + * @return + */ + const char* gameId(const std::unique_ptr& fh) const; + + /** + * @brief maker + * @param fh + * @return + */ + const char* maker(const std::unique_ptr& fh) const; + + /** + * @brief setBannerFormat + * @param fh + * @param fmt + */ void setBannerFormat(const std::unique_ptr& fh, EImageFormat fmt); + + /** + * @brief bannerFormat + * @param fh + * @return + */ EImageFormat bannerFormat(const std::unique_ptr& fh) const; + + /** + * @brief setIconAnimationType + * @param fh + * @param type + */ void setIconAnimationType(const std::unique_ptr& fh, EAnimationType type); + + /** + * @brief iconAnimationType + * @param fh + * @return + */ EAnimationType iconAnimationType(const std::unique_ptr& fh) const; + + /** + * @brief setIconFormat + * @param fh + * @param idx + * @param fmt + */ void setIconFormat(const std::unique_ptr& fh, uint32_t idx, EImageFormat fmt); + + /** + * @brief iconFormat + * @param fh + * @param idx + * @return + */ EImageFormat iconFormat(const std::unique_ptr& fh, uint32_t idx) const; + + /** + * @brief setIconSpeed + * @param fh + * @param idx + * @param speed + */ void setIconSpeed(const std::unique_ptr& fh, uint32_t idx, EAnimationSpeed speed); + + /** + * @brief iconSpeed + * @param fh + * @param idx + * @return + */ EAnimationSpeed iconSpeed(const std::unique_ptr& fh, uint32_t idx) const; + + /** + * @brief setImageAddress + * @param fh + * @param addr + */ void setImageAddress(const std::unique_ptr& fh, uint32_t addr); + + /** + * @brief imageAddress + * @param fh + * @return + */ int32_t imageAddress(const std::unique_ptr& fh) const; + + /** + * @brief setCommentAddress + * @param fh + * @param addr + */ void setCommentAddress(const std::unique_ptr& fh, uint32_t addr); + + /** + * @brief commentAddress + * @param fh + * @return + */ int32_t commentAddress(const std::unique_ptr& fh) const; /** @@ -195,26 +312,26 @@ public: * @param game The target game id, e.g "GM8E" * @sa openFile */ - void setGame(const char* game); + void setCurrentGame(const char* game); /** * @brief Returns the currently selected game * @return The selected game, or nullptr */ - const uint8_t* getGame() const; + const uint8_t* getCurrentGame() const; /** * @brief Sets the current maker, if not null any openFile requests will only return files that match this maker * @param maker The target maker id, e.g "01" * @sa openFile */ - void setMaker(const char* maker); + void setCurrentMaker(const char* maker); /** * @brief Returns the currently selected maker * @return The selected maker, or nullptr */ - const uint8_t* getMaker() const; + const uint8_t* getCurrentMaker() const; /** * @brief Retrieves the format assigned serial in two 32bit parts diff --git a/include/kabufuda/Directory.hpp b/include/kabufuda/Directory.hpp index d776848..38ced68 100644 --- a/include/kabufuda/Directory.hpp +++ b/include/kabufuda/Directory.hpp @@ -35,7 +35,10 @@ public: ~Directory(); 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); }; } diff --git a/include/kabufuda/File.hpp b/include/kabufuda/File.hpp index b5264a0..3e180cf 100644 --- a/include/kabufuda/File.hpp +++ b/include/kabufuda/File.hpp @@ -15,7 +15,7 @@ class File { struct { - uint8_t m_id[4]; + uint8_t m_game[4]; uint8_t m_maker[2]; uint8_t m_reserved; uint8_t m_bannerFlags; diff --git a/lib/kabufuda/Card.cpp b/lib/kabufuda/Card.cpp index e0c5eaa..9ef8375 100644 --- a/lib/kabufuda/Card.cpp +++ b/lib/kabufuda/Card.cpp @@ -15,16 +15,12 @@ IFileHandle::~IFileHandle() class FileHandle : public IFileHandle { friend class Card; - const char* game; - const char* maker; - const char* filename; + uint32_t idx; int32_t offset =0; public: FileHandle() = default; - FileHandle(const char* game, const char* maker, const char* filename) - : game(game), - maker(maker), - filename(filename) + FileHandle(uint32_t idx) + : idx(idx) {} virtual ~FileHandle(); }; @@ -139,8 +135,12 @@ Card::~Card() std::unique_ptr Card::openFile(const char* filename) { File* f = m_currentDir->getFile(m_game, m_maker, filename); - if (f) - return std::unique_ptr(new FileHandle(m_game, m_maker, filename)); + int32_t idx = m_currentDir->indexForFile(f); + if (f && idx != -1) + { + + return std::unique_ptr(new FileHandle(idx)); + } return nullptr; } @@ -173,7 +173,7 @@ File* Card::_fileFromHandle(const std::unique_ptr &fh) const if (!handle) return nullptr; - File* file = m_currentDir->getFile(handle->game, handle->maker, handle->filename); + File* file = m_currentDir->getFile(handle->idx); return file; } @@ -189,18 +189,47 @@ std::unique_ptr Card::createFile(const char* filename, size_t size) f->m_blockCount = uint16_t(size / BlockSize); - return std::unique_ptr(new FileHandle(m_game, m_maker, filename)); + return std::unique_ptr(new FileHandle(m_currentDir->indexForFile(f))); } return nullptr; } -void Card::deleteFile(const std::unique_ptr &fh) +std::unique_ptr Card::firstFile() +{ + File* f = m_currentDir->getFirstNonFreeFile(0, m_game, m_maker); + if (f) + return std::unique_ptr(new FileHandle(m_currentDir->indexForFile(f))); + + return nullptr; +} + +std::unique_ptr Card::nextFile(const std::unique_ptr& cur) +{ + FileHandle* handle = dynamic_cast(cur.get()); + if (!handle) + return nullptr; + + File* next = m_currentDir->getFirstNonFreeFile(handle->idx + 1, m_game, m_maker); + if (!next) + return nullptr; + return std::unique_ptr(new FileHandle(m_currentDir->indexForFile(next))); +} + +const char* Card::getFilename(const std::unique_ptr& fh) +{ + File* f = _fileFromHandle(fh); + if (!f) + return nullptr; + return f->m_filename; +} + +void Card::deleteFile(const std::unique_ptr& fh) { _updateDirAndBat(); if (!fh) return; FileHandle* f = dynamic_cast(fh.get()); - uint16_t block = m_currentDir->getFile(f->game, f->maker, f->filename)->m_firstBlock; + uint16_t block = m_currentDir->getFile(f->idx)->m_firstBlock; while(block != 0xFFFF) { @@ -209,7 +238,7 @@ void Card::deleteFile(const std::unique_ptr &fh) m_currentBat->clear(block, 1); block = nextBlock; } - *m_currentDir->getFile(f->game, f->maker, f->filename) = File(); + *m_currentDir->getFile(f->idx) = File(); } @@ -221,7 +250,7 @@ void Card::write(const std::unique_ptr& fh, const void* buf, size_t if (m_fileHandle) { FileHandle* f = dynamic_cast(fh.get()); - File* file = m_currentDir->getFile(f->game, f->maker, f->filename); + File* file = m_currentDir->getFile(f->idx); if (!file) return; @@ -270,7 +299,7 @@ void Card::read(const std::unique_ptr &fh, void *dst, size_t size) if (m_fileHandle) { FileHandle* f = dynamic_cast(fh.get()); - File* file = m_currentDir->getFile(f->game, f->maker, f->filename); + File* file = m_currentDir->getFile(f->idx); if (!file) return; /* Block handling is a little different from cache handling, @@ -316,7 +345,7 @@ void Card::seek(const std::unique_ptr &fh, int32_t pos, SeekOrigin return; FileHandle* f = dynamic_cast(fh.get()); - File* file = m_currentDir->getFile(f->game, f->maker, f->filename); + File* file = m_currentDir->getFile(f->idx); if (!file) return; @@ -407,6 +436,22 @@ bool Card::canMove(const std::unique_ptr &fh) const return !bool(file->m_permissions & EPermissions::NoMove); } +const char* Card::gameId(const std::unique_ptr &fh) const +{ + File* file = _fileFromHandle(fh); + if (!file) + return nullptr; + return reinterpret_cast(file->m_game); +} + +const char *Card::maker(const std::unique_ptr &fh) const +{ + File* file = _fileFromHandle(fh); + if (!file) + return nullptr; + return reinterpret_cast(file->m_maker); +} + void Card::setBannerFormat(const std::unique_ptr& fh, EImageFormat fmt) { File* file = _fileFromHandle(fh); @@ -564,7 +609,7 @@ bool Card::moveFileTo(const std::unique_ptr &fh, Card &dest) return false; } -void Card::setGame(const char* game) +void Card::setCurrentGame(const char* game) { if (game == nullptr) { @@ -578,7 +623,7 @@ void Card::setGame(const char* game) memcpy(m_game, game, 4); } -const uint8_t* Card::getGame() const +const uint8_t* Card::getCurrentGame() const { if (strlen(m_game) == 4) return reinterpret_cast(m_game); @@ -586,7 +631,7 @@ const uint8_t* Card::getGame() const return nullptr; } -void Card::setMaker(const char* maker) +void Card::setCurrentMaker(const char* maker) { if (maker == nullptr) { @@ -600,7 +645,7 @@ void Card::setMaker(const char* maker) memcpy(m_maker, maker, 2); } -const uint8_t* Card::getMaker() const +const uint8_t* Card::getCurrentMaker() const { if (strlen(m_maker) == 2) return reinterpret_cast(m_maker); diff --git a/lib/kabufuda/Directory.cpp b/lib/kabufuda/Directory.cpp index 318bf84..716f6ea 100644 --- a/lib/kabufuda/Directory.cpp +++ b/lib/kabufuda/Directory.cpp @@ -1,5 +1,6 @@ #include "kabufuda/Directory.hpp" #include "kabufuda/Util.hpp" +#include namespace kabufuda @@ -61,12 +62,12 @@ File* Directory::getFirstFreeFile(const char* game, const char* maker, const cha { for (uint16_t i = 0 ; i < 127 ; i++) { - if (m_files[i].m_id[0] == 0xFF) + if (m_files[i].m_game[0] == 0xFF) { File* ret = &m_files[i]; *ret = File(filename); if (game && strlen(game) == 4) - memcpy(ret->m_id, game, 4); + memcpy(ret->m_game, game, 4); if (maker && strlen(maker) == 2) memcpy(ret->m_maker, maker, 2); return ret; @@ -76,11 +77,29 @@ File* Directory::getFirstFreeFile(const char* game, const char* maker, const cha 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; + } + } + + 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_id, game, 4)) + 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; @@ -90,4 +109,25 @@ File* Directory::getFile(const char* game, const char* maker, const char* filena 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); +} } diff --git a/test/main.cpp b/test/main.cpp index 55da2c8..ef7abfe 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -10,10 +10,10 @@ int main() if (!mc2) mc2.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card2043Mb); - std::unique_ptr f = mc.openFile("MetroidPrime B"); + std::unique_ptr f = mc.openFile("MetroidPrime A"); if (!f) { - f = mc.createFile("MetroidPrime B", kabufuda::BlockSize); + f = mc.createFile("MetroidPrime A", kabufuda::BlockSize); mc.setPublic(f, true); mc.setCanCopy(f, true); mc.setCanMove(f, true); @@ -40,6 +40,13 @@ int main() printf("Copy succeeded!\n"); else printf("Copy failed...\n"); + + std::unique_ptr it = mc.firstFile(); + while (it) + { + printf("%.4s%.2s-%s\n", mc.gameId(it), mc.maker(it), mc.getFilename(it)); + it = mc.nextFile(it); + } } return 0; }