kabufuda/include/Card.hpp

305 lines
7.1 KiB
C++
Raw Normal View History

2016-03-26 04:26:51 +00:00
#ifndef __CARD_HPP__
#define __CARD_HPP__
#include <string>
#include <vector>
2016-03-26 20:16:30 +00:00
#include <memory>
2016-03-26 18:34:03 +00:00
#include "Util.hpp"
namespace kabufuda
2016-03-26 04:26:51 +00:00
{
2016-03-26 18:34:03 +00:00
uint32_t constexpr BlockSize = 0x2000;
uint32_t constexpr MaxFiles = 127;
uint32_t constexpr FSTBlocks = 5;
uint32_t constexpr MbitToBlocks = 0x10;
2016-06-26 10:33:47 +00:00
uint32_t constexpr BATSize = 0xFFB;
2016-03-26 04:26:51 +00:00
2016-03-26 05:32:51 +00:00
/**
* @brief The EPermissions enum
*/
2016-03-26 04:26:51 +00:00
enum class EPermissions : uint8_t
{
};
2016-03-26 05:32:51 +00:00
/**
* @brief The EBannerFlags enum
*/
2016-03-26 04:26:51 +00:00
enum class EBannerFlags : uint8_t
{
};
2016-06-26 20:37:50 +00:00
enum class SeekOrigin
{
Begin,
Current,
End
};
2016-03-26 05:32:51 +00:00
/**
* @brief The EDeviceId enum
*/
enum class EDeviceId : 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
};
/**
* @brief The EEncoding enum
*/
enum class EEncoding : uint16_t
{
2016-03-26 18:34:03 +00:00
ASCII, /**< Standard ASCII Encoding */
SJIS /**< SJIS Encoding for japanese */
2016-03-26 05:32:51 +00:00
};
2016-03-26 04:26:51 +00:00
class File
{
2016-06-26 10:33:47 +00:00
friend class FileHandle;
2016-03-26 20:16:30 +00:00
friend class Directory;
friend class Card;
2016-03-26 18:34:03 +00:00
#pragma pack(push, 4)
2016-03-26 04:26:51 +00:00
union
{
struct
{
uint8_t m_id[4];
uint8_t m_maker[2];
uint8_t m_reserved;
uint8_t m_bannerFlags;
char m_filename[0x20];
uint32_t m_modifiedTime;
2016-03-26 20:16:30 +00:00
uint32_t m_imageOffset;
uint16_t m_iconFmt;
uint16_t m_animSpeed;
2016-03-26 04:26:51 +00:00
uint8_t m_permissions;
int8_t m_copyCounter;
uint16_t m_firstBlock;
2016-03-26 20:16:30 +00:00
uint16_t m_blockCount;
2016-03-26 04:26:51 +00:00
uint16_t m_reserved2;
uint32_t m_commentAddr;
};
2016-03-26 05:32:51 +00:00
uint8_t __raw[0x40];
2016-03-26 04:26:51 +00:00
};
2016-06-26 10:33:47 +00:00
2016-03-26 18:34:03 +00:00
#pragma pop()
2016-06-26 10:33:47 +00:00
void swapEndian();
2016-03-26 18:34:03 +00:00
2016-03-26 04:26:51 +00:00
public:
2016-06-26 20:37:50 +00:00
File();
2016-03-26 18:34:03 +00:00
File(char data[0x40]);
File(const char* filename);
2016-03-26 04:26:51 +00:00
~File() {}
};
2016-06-26 20:37:50 +00:00
class IFileHandle
2016-03-27 03:46:52 +00:00
{
2016-06-26 20:37:50 +00:00
public:
virtual ~IFileHandle() {}
2016-03-27 03:46:52 +00:00
};
2016-03-26 04:26:51 +00:00
class BlockAllocationTable
{
2016-03-26 18:34:03 +00:00
friend class Card;
#pragma pack(push, 4)
2016-03-26 04:26:51 +00:00
union
{
struct
{
uint16_t m_checksum;
uint16_t m_checksumInv;
2016-03-26 18:34:03 +00:00
uint16_t m_updateCounter;
2016-03-26 04:26:51 +00:00
uint16_t m_freeBlocks;
uint16_t m_lastAllocated;
uint16_t m_map[0xFFB];
};
2016-03-26 05:32:51 +00:00
uint8_t __raw[BlockSize];
2016-03-26 04:26:51 +00:00
};
2016-03-26 18:34:03 +00:00
#pragma pop()
2016-06-26 10:33:47 +00:00
void swapEndian();
2016-06-26 20:37:50 +00:00
void updateChecksum();
2016-06-26 10:33:47 +00:00
2016-03-26 04:26:51 +00:00
public:
2016-03-26 18:34:03 +00:00
explicit BlockAllocationTable(uint32_t blockCount = (uint32_t(ECardSize::Card2043Mb) * MbitToBlocks));
2016-03-26 04:26:51 +00:00
BlockAllocationTable(uint8_t data[BlockSize]);
~BlockAllocationTable() {}
2016-03-26 18:34:03 +00:00
2016-03-26 20:16:30 +00:00
uint16_t getNextBlock(uint16_t block) const;
2016-06-26 10:33:47 +00:00
uint16_t nextFreeBlock(uint16_t maxBlock, uint16_t startingBlock) const;
2016-03-26 20:16:30 +00:00
bool clear(uint16_t first, uint16_t count);
2016-06-26 10:33:47 +00:00
uint16_t allocateBlocks(uint16_t count, uint16_t maxBlocks);
2016-03-26 04:26:51 +00:00
};
class Directory
{
2016-03-26 18:34:03 +00:00
friend class Card;
#pragma pack(push, 4)
2016-03-26 04:26:51 +00:00
union
{
struct
{
2016-03-26 05:32:51 +00:00
File m_files[MaxFiles];
uint8_t __padding[0x3a];
2016-03-26 04:26:51 +00:00
uint16_t m_updateCounter;
uint16_t m_checksum;
uint16_t m_checksumInv;
};
2016-03-26 05:32:51 +00:00
uint8_t __raw[BlockSize];
2016-03-26 04:26:51 +00:00
};
2016-03-26 18:34:03 +00:00
#pragma pop()
2016-03-27 03:46:52 +00:00
2016-06-26 10:33:47 +00:00
void swapEndian();
2016-06-26 20:37:50 +00:00
void updateChecksum();
2016-06-26 10:33:47 +00:00
2016-03-26 04:26:51 +00:00
public:
2016-03-26 18:34:03 +00:00
Directory();
Directory(uint8_t data[BlockSize]);
2016-03-26 20:16:30 +00:00
Directory(const Directory& other);
void operator=(const Directory& other);
2016-03-26 04:26:51 +00:00
~Directory() {}
2016-03-26 20:16:30 +00:00
2016-06-26 20:37:50 +00:00
File* getFirstFreeFile(const char* game, const char* maker, const char* filename);
File* getFile(const char* game, const char* maker, const char* filename);
2016-03-26 04:26:51 +00:00
};
class Card
{
2016-03-26 18:34:03 +00:00
#pragma pack(push, 4)
2016-03-26 04:26:51 +00:00
union
{
struct
{
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;
};
2016-03-26 05:32:51 +00:00
uint8_t __raw[BlockSize];
2016-03-26 04:26:51 +00:00
};
2016-06-26 10:33:47 +00:00
2016-03-26 18:34:03 +00:00
#pragma pop()
2016-03-27 03:46:52 +00:00
2016-03-26 18:34:03 +00:00
SystemString m_filename;
2016-06-26 20:37:50 +00:00
FILE* m_fileHandle = nullptr;
2016-03-26 04:26:51 +00:00
Directory m_dir;
Directory m_dirBackup;
2016-06-26 10:33:47 +00:00
Directory* m_currentDir;
Directory* m_previousDir;
2016-03-26 04:26:51 +00:00
BlockAllocationTable m_bat;
BlockAllocationTable m_batBackup;
2016-06-26 10:33:47 +00:00
BlockAllocationTable* m_currentBat;
BlockAllocationTable* m_previousBat;
2016-03-26 04:26:51 +00:00
2016-06-26 10:33:47 +00:00
uint16_t m_maxBlock;
2016-03-26 05:32:51 +00:00
char m_game[5] = {'\0'};
char m_maker[3] = {'\0'};
2016-06-26 20:37:50 +00:00
void swapEndian();
void updateDirAndBat();
2016-03-26 04:26:51 +00:00
public:
Card();
2016-03-26 18:34:03 +00:00
Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr);
2016-03-26 05:32:51 +00:00
~Card();
2016-03-26 04:26:51 +00:00
2016-03-26 05:32:51 +00:00
/**
* @brief openFile
* @param filename
*/
2016-06-26 20:37:50 +00:00
std::unique_ptr<IFileHandle> openFile(const char* filename);
2016-03-26 20:16:30 +00:00
/**
* @brief createFile
* @param filename
* @return
*/
2016-06-26 20:37:50 +00:00
std::unique_ptr<IFileHandle> createFile(const char* filename, size_t size);
void deleteFile(const std::unique_ptr<IFileHandle>& fh);
void write(const std::unique_ptr<IFileHandle>& fh, const void* buf, size_t size);
void read(const std::unique_ptr<IFileHandle>& fh, void* dst, size_t size);
void seek(const std::unique_ptr<IFileHandle>& fh, uint32_t pos, SeekOrigin whence);
2016-03-26 05:32:51 +00:00
/**
* @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 setGame(const char* game);
/**
* @brief Returns the currently selected game
* @return The selected game, or nullptr
*/
2016-03-26 04:26:51 +00:00
const uint8_t* getGame() const;
2016-03-26 05:32:51 +00:00
/**
* @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
*/
2016-03-26 04:26:51 +00:00
void setMaker(const char* maker);
2016-03-26 05:32:51 +00:00
/**
* @brief Returns the currently selected maker
* @return The selected maker, or nullptr
*/
2016-03-26 04:26:51 +00:00
const uint8_t* getMaker() const;
2016-03-26 05:32:51 +00:00
/**
* @brief Retrieves the format assigned serial in two 32bit parts
* @param s0
* @param s1
*/
void getSerial(uint32_t* s0, uint32_t* s1);
/**
* @brief Retrieves
* @param checksum
* @param inverse
*/
void getChecksum(uint16_t* checksum, uint16_t* inverse);
/**
* @brief Formats the memory card and assigns a new serial
2016-03-26 18:34:03 +00:00
* @param size The desired size of the file @sa ECardSize
* @param encoding The desired encoding @sa EEncoding
*/
void format(EDeviceId deviceId, ECardSize size = ECardSize::Card2043Mb, EEncoding encoding = EEncoding::ASCII);
/**
* @brief getSizeMbit
* @return
2016-03-26 05:32:51 +00:00
*/
2016-03-26 18:34:03 +00:00
static uint32_t getSizeMbitFromFile(const SystemString& filename);
2016-03-26 20:16:30 +00:00
void commit();
2016-06-26 20:37:50 +00:00
operator bool() const { return m_fileHandle != nullptr; }
2016-03-26 04:26:51 +00:00
};
2016-03-26 05:32:51 +00:00
/**
* @brief calculateChecksum
* @param data
* @param len
2016-03-26 18:34:03 +00:00
* @param checksum
2016-03-26 20:16:30 +00:00
* @param checksumInv
2016-03-26 05:32:51 +00:00
*/
2016-03-26 18:34:03 +00:00
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
2016-03-26 04:26:51 +00:00
}
#endif // __CARD_HPP__