diff --git a/include/kabufuda/Card.hpp b/include/kabufuda/Card.hpp index 3ef6793..200fe7f 100644 --- a/include/kabufuda/Card.hpp +++ b/include/kabufuda/Card.hpp @@ -55,14 +55,14 @@ struct ProbeResults struct CardStat { - /* read-only (Set by CARDGetStatus) */ + /* 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 CARDGetStatus/CARDSetStatus) */ + /* 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. */ @@ -70,7 +70,7 @@ struct CardStat uint16_t x36_iconSpeed; uint32_t x38_commentAddr; /* offset to the pair of 32 byte character strings. */ - /* read-only (Set by CARDGetStatus) */ + /* read-only (Set by Card::getStatus) */ uint32_t x3c_offsetBanner; uint32_t x40_offsetBannerTlut; uint32_t x44_offsetIcon[CARD_ICON_MAX]; @@ -163,13 +163,13 @@ public: * @brief openFile * @param filename */ - std::unique_ptr openFile(const char* filename); + ECardResult openFile(const char* filename, std::unique_ptr& handleOut); /** * @brief openFile * @param fileno */ - std::unique_ptr openFile(uint32_t fileno); + ECardResult openFile(uint32_t fileno, std::unique_ptr& handleOut); /** * @brief createFile @@ -296,6 +296,22 @@ public: */ bool canMove(const std::unique_ptr& 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 std::unique_ptr& fh, 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 std::unique_ptr& fh, const CardStat& stat); + /** * @brief gameId * @param fh diff --git a/lib/kabufuda/Card.cpp b/lib/kabufuda/Card.cpp index 6b274df..b57f305 100644 --- a/lib/kabufuda/Card.cpp +++ b/lib/kabufuda/Card.cpp @@ -123,22 +123,29 @@ Card::~Card() m_fileHandle = nullptr; } -std::unique_ptr Card::openFile(const char* filename) +ECardResult Card::openFile(const char* filename, std::unique_ptr& handleOut) { + handleOut.reset(); File* f = m_currentDir->getFile(m_game, m_maker, filename); + if (!f || f->m_game[0] == 0xFF) + return ECardResult::NOFILE; int32_t idx = m_currentDir->indexForFile(f); - if (f && idx != -1) + if (idx != -1) { - return std::make_unique(idx); + handleOut = std::make_unique(idx); + return ECardResult::READY; } - return nullptr; + return ECardResult::FATAL_ERROR; } -std::unique_ptr Card::openFile(uint32_t fileno) +ECardResult Card::openFile(uint32_t fileno, std::unique_ptr& handleOut) { - if (fileno >= 127) - return nullptr; - return std::make_unique(fileno); + handleOut.reset(); + File* f = m_currentDir->getFile(fileno); + if (!f || f->m_game[0] == 0xFF) + return ECardResult::NOFILE; + handleOut = std::make_unique(fileno); + return ECardResult::READY; } void Card::_updateDirAndBat() @@ -177,6 +184,8 @@ File* Card::_fileFromHandle(const std::unique_ptr& fh) const ECardResult Card::createFile(const char* filename, size_t size, std::unique_ptr& handleOut) { + handleOut.reset(); + if (strlen(filename) > 32) return ECardResult::NAMETOOLONG; if (m_currentDir->getFile(m_game, m_maker, filename)) @@ -484,6 +493,118 @@ bool Card::canMove(const std::unique_ptr& fh) const 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 std::unique_ptr& fh, CardStat& statOut) const +{ + File* file = _fileFromHandle(fh); + 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 ; i& fh, const CardStat& stat) +{ + File* file = _fileFromHandle(fh); + 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; + + return ECardResult::READY; +} + const char* Card::gameId(const std::unique_ptr& fh) const { File* file = _fileFromHandle(fh); @@ -619,11 +740,12 @@ bool Card::copyFileTo(const std::unique_ptr& fh, Card& dest) return false; /* Check to make sure dest does not already contain fh */ - if (dest.openFile(toCopy->m_filename) != nullptr) + std::unique_ptr tmpHandle; + dest.openFile(toCopy->m_filename, tmpHandle); + if (tmpHandle) return false; /* Try to allocate a new file */ - std::unique_ptr tmpHandle; dest.createFile(toCopy->m_filename, toCopy->m_blockCount * BlockSize, tmpHandle); if (!tmpHandle) return false; @@ -792,7 +914,7 @@ void Card::format(ECardSlot id, ECardSize size, EEncoding encoding) ProbeResults Card::probeCardFile(const SystemString& filename) { Sstat stat; - if (Stat(filename.c_str(), &stat)) + if (Stat(filename.c_str(), &stat) || !S_ISREG(stat.st_mode)) return { ECardResult::NOCARD, 0, 0 }; return { ECardResult::READY, uint32_t(stat.st_size / BlockSize) / MbitToBlocks, 0x2000 }; } diff --git a/lib/kabufuda/File.cpp b/lib/kabufuda/File.cpp index 560c43c..fc8e1dd 100644 --- a/lib/kabufuda/File.cpp +++ b/lib/kabufuda/File.cpp @@ -11,9 +11,7 @@ File::File(const char* filename) { memset(__raw, 0, 0x40); memset(m_filename, 0, 32); - size_t len = strlen(filename); - len = std::min(len, 32); - memcpy(m_filename, filename, len); + strncpy(m_filename, filename, 32); } void File::swapEndian() { diff --git a/test/main.cpp b/test/main.cpp index 2638daa..5a046c6 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -13,7 +13,8 @@ int main() if (!mc2) mc2.format(kabufuda::ECardSlot::SlotA, kabufuda::ECardSize::Card2043Mb); - std::unique_ptr f = mc.openFile("MetroidPrime A"); + std::unique_ptr f; + mc.openFile("MetroidPrime A", f); if (!f) { mc.createFile("MetroidPrime A", kabufuda::BlockSize, f);