mirror of
https://github.com/AxioDL/kabufuda.git
synced 2025-06-06 06:33:45 +00:00
Initial file allocation
This commit is contained in:
parent
4c2d5e7214
commit
b56ac5e112
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory.h>
|
#include <memory>
|
||||||
|
|
||||||
#include "Util.hpp"
|
#include "Util.hpp"
|
||||||
|
|
||||||
@ -61,6 +61,8 @@ enum class EEncoding : uint16_t
|
|||||||
|
|
||||||
class File
|
class File
|
||||||
{
|
{
|
||||||
|
friend class Directory;
|
||||||
|
friend class Card;
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
@ -72,9 +74,13 @@ class File
|
|||||||
uint8_t m_bannerFlags;
|
uint8_t m_bannerFlags;
|
||||||
char m_filename[0x20];
|
char m_filename[0x20];
|
||||||
uint32_t m_modifiedTime;
|
uint32_t m_modifiedTime;
|
||||||
|
uint32_t m_imageOffset;
|
||||||
|
uint16_t m_iconFmt;
|
||||||
|
uint16_t m_animSpeed;
|
||||||
uint8_t m_permissions;
|
uint8_t m_permissions;
|
||||||
int8_t m_copyCounter;
|
int8_t m_copyCounter;
|
||||||
uint16_t m_firstBlock;
|
uint16_t m_firstBlock;
|
||||||
|
uint16_t m_blockCount;
|
||||||
uint16_t m_reserved2;
|
uint16_t m_reserved2;
|
||||||
uint32_t m_commentAddr;
|
uint32_t m_commentAddr;
|
||||||
};
|
};
|
||||||
@ -113,8 +119,10 @@ public:
|
|||||||
BlockAllocationTable(uint8_t data[BlockSize]);
|
BlockAllocationTable(uint8_t data[BlockSize]);
|
||||||
~BlockAllocationTable() {}
|
~BlockAllocationTable() {}
|
||||||
|
|
||||||
uint16_t getNextBlock() const;
|
uint16_t getNextBlock(uint16_t block) const;
|
||||||
uint16_t nextFreeBlock(uint16_t maxBlocks, uint16_t startingBlock = FSTBlocks);
|
uint16_t nextFreeBlock(uint16_t maxBlocks, uint16_t startingBlock = FSTBlocks) const;
|
||||||
|
bool clear(uint16_t first, uint16_t count);
|
||||||
|
uint16_t allocateBlocks(uint16_t count);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Directory
|
class Directory
|
||||||
@ -134,11 +142,17 @@ class Directory
|
|||||||
uint8_t __raw[BlockSize];
|
uint8_t __raw[BlockSize];
|
||||||
};
|
};
|
||||||
#pragma pop()
|
#pragma pop()
|
||||||
|
void commitFiles(FILE* mc);
|
||||||
public:
|
public:
|
||||||
Directory();
|
Directory();
|
||||||
|
|
||||||
Directory(uint8_t data[BlockSize]);
|
Directory(uint8_t data[BlockSize]);
|
||||||
|
Directory(const Directory& other);
|
||||||
|
void operator=(const Directory& other);
|
||||||
~Directory() {}
|
~Directory() {}
|
||||||
|
|
||||||
|
File* getFirstFreeFile(char* game, char* maker, const char* filename);
|
||||||
|
File* getFile(char* game, char* maker, const char* filename);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Card
|
class Card
|
||||||
@ -180,7 +194,6 @@ class Card
|
|||||||
m_checksumInv = SBig(checksum ^ 0xFFFF);
|
m_checksumInv = SBig(checksum ^ 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* m_fileHandle;
|
|
||||||
public:
|
public:
|
||||||
Card();
|
Card();
|
||||||
Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr);
|
Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr);
|
||||||
@ -190,7 +203,14 @@ public:
|
|||||||
* @brief openFile
|
* @brief openFile
|
||||||
* @param filename
|
* @param filename
|
||||||
*/
|
*/
|
||||||
void openFile(const char* filename);
|
File* openFile(const char* filename);
|
||||||
|
/**
|
||||||
|
* @brief createFile
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
File* createFile(const char* filename, size_t size);
|
||||||
|
void write(File* f, void* buf, size_t size);
|
||||||
/**
|
/**
|
||||||
* @brief Sets the current game, if not null any openFile requests will only return files that match this game
|
* @brief Sets the current game, if not null any openFile requests will only return files that match this game
|
||||||
* @param game The target game id, e.g "GM8E"
|
* @param game The target game id, e.g "GM8E"
|
||||||
@ -237,6 +257,8 @@ public:
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static uint32_t getSizeMbitFromFile(const SystemString& filename);
|
static uint32_t getSizeMbitFromFile(const SystemString& filename);
|
||||||
|
|
||||||
|
void commit();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,7 +266,7 @@ public:
|
|||||||
* @param data
|
* @param data
|
||||||
* @param len
|
* @param len
|
||||||
* @param checksum
|
* @param checksum
|
||||||
* @param checksum
|
* @param checksumInv
|
||||||
*/
|
*/
|
||||||
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv);
|
||||||
}
|
}
|
||||||
|
182
src/Card.cpp
182
src/Card.cpp
@ -2,6 +2,7 @@
|
|||||||
#include "SRAM.hpp"
|
#include "SRAM.hpp"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace kabufuda
|
namespace kabufuda
|
||||||
@ -20,14 +21,14 @@ Card::Card(const SystemString& filename, const char* game, const char* maker)
|
|||||||
if (maker && strlen(maker) == 2)
|
if (maker && strlen(maker) == 2)
|
||||||
memcpy(m_maker, maker, 2);
|
memcpy(m_maker, maker, 2);
|
||||||
|
|
||||||
m_fileHandle = Fopen(m_filename.c_str(), _S("rb"));
|
FILE* file = Fopen(m_filename.c_str(), _S("rb"));
|
||||||
if (m_fileHandle)
|
if (file)
|
||||||
{
|
{
|
||||||
fread(__raw, 1, BlockSize, m_fileHandle);
|
fread(__raw, 1, BlockSize, file);
|
||||||
fread(m_dir.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_dir.__raw, 1, BlockSize, file);
|
||||||
fread(m_dirBackup.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_dirBackup.__raw, 1, BlockSize, file);
|
||||||
fread(m_bat.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_bat.__raw, 1, BlockSize, file);
|
||||||
fread(m_batBackup.__raw, 1, BlockSize, m_fileHandle);
|
fread(m_batBackup.__raw, 1, BlockSize, file);
|
||||||
if (m_dir.m_updateCounter < m_dirBackup.m_updateCounter)
|
if (m_dir.m_updateCounter < m_dirBackup.m_updateCounter)
|
||||||
m_dirInUse = &m_dirBackup;
|
m_dirInUse = &m_dirBackup;
|
||||||
else
|
else
|
||||||
@ -44,9 +45,32 @@ Card::~Card()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::openFile(const char* filename)
|
File* Card::openFile(const char* filename)
|
||||||
{
|
{
|
||||||
|
return m_dirInUse->getFile(m_game, m_maker, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
File* Card::createFile(const char* filename, size_t size)
|
||||||
|
{
|
||||||
|
File* f = m_dirInUse->getFirstFreeFile(m_game, m_maker, filename);
|
||||||
|
uint16_t block = m_batInUse->allocateBlocks(size / BlockSize);
|
||||||
|
if (f && block != 0xFFFF)
|
||||||
|
{
|
||||||
|
f->m_firstBlock = SBig(block);
|
||||||
|
f->m_blockCount = SBig(uint16_t(size / BlockSize));
|
||||||
|
commit();
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Card::write(File* f, void* buf, size_t size)
|
||||||
|
{
|
||||||
|
FILE* mc = Fopen(m_filename.c_str(), _S("rb"));
|
||||||
|
if (mc)
|
||||||
|
{
|
||||||
|
fseek(mc, BlockSize * 5, SEEK_SET);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::setGame(const char* game)
|
void Card::setGame(const char* game)
|
||||||
@ -145,7 +169,7 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
|
|||||||
fwrite(m_bat.__raw, 1, BlockSize, f);
|
fwrite(m_bat.__raw, 1, BlockSize, f);
|
||||||
fwrite(m_batBackup.__raw, 1, BlockSize, f);
|
fwrite(m_batBackup.__raw, 1, BlockSize, f);
|
||||||
uint32_t dataLen = ((uint32_t(size) * MbitToBlocks) - 5) * BlockSize;
|
uint32_t dataLen = ((uint32_t(size) * MbitToBlocks) - 5) * BlockSize;
|
||||||
std::unique_ptr<char[]> data(new char[dataLen]);
|
std::unique_ptr<uint8_t[]> data(new uint8_t[dataLen]);
|
||||||
memset(data.get(), 0xFF, dataLen);
|
memset(data.get(), 0xFF, dataLen);
|
||||||
fwrite(data.get(), 1, dataLen, f);
|
fwrite(data.get(), 1, dataLen, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
@ -159,6 +183,25 @@ uint32_t Card::getSizeMbitFromFile(const SystemString& filename)
|
|||||||
return (stat.st_size / BlockSize) / MbitToBlocks;
|
return (stat.st_size / BlockSize) / MbitToBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Card::commit()
|
||||||
|
{
|
||||||
|
FILE* f = Fopen(m_filename.c_str(), _S("wb"));
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
fwrite(__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_dir.__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_dirBackup.__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_bat.__raw, 1, BlockSize, f);
|
||||||
|
fwrite(m_batBackup.__raw, 1, BlockSize, f);
|
||||||
|
uint32_t dataLen = ((uint32_t(m_sizeMb) * MbitToBlocks) - 5) * BlockSize;
|
||||||
|
std::unique_ptr<uint8_t[]> data(new uint8_t[dataLen]);
|
||||||
|
memset(data.get(), 0xFF, dataLen);
|
||||||
|
fwrite(data.get(), 1, dataLen, f);
|
||||||
|
m_dirInUse->commitFiles(f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
File::File(char data[])
|
File::File(char data[])
|
||||||
{
|
{
|
||||||
memcpy(__raw, data, 0x40);
|
memcpy(__raw, data, 0x40);
|
||||||
@ -178,6 +221,83 @@ BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
|
|||||||
calculateChecksum((uint16_t*)(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
calculateChecksum((uint16_t*)(__raw + 4), 0xFFE, &m_checksum, &m_checksumInv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t BlockAllocationTable::getNextBlock(uint16_t block) const
|
||||||
|
{
|
||||||
|
if ((block < FSTBlocks) || (block > 4091))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return SBig(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(0xFFB));
|
||||||
|
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<uint16_t> blocks;
|
||||||
|
while (first != 0xFFFF && first != 0)
|
||||||
|
{
|
||||||
|
blocks.push_back(first);
|
||||||
|
first = getNextBlock(first);
|
||||||
|
}
|
||||||
|
if (first > 0)
|
||||||
|
{
|
||||||
|
size_t length = blocks.size();
|
||||||
|
if (length != count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i= 0 ; i < length ; ++i)
|
||||||
|
m_map[blocks.at(i) - FSTBlocks] = 0;
|
||||||
|
m_freeBlocks = SBig(uint16_t(m_freeBlocks) + count);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t BlockAllocationTable::allocateBlocks(uint16_t count)
|
||||||
|
{
|
||||||
|
uint16_t freeBlock = nextFreeBlock(m_lastAllocated + count);
|
||||||
|
if (freeBlock != 0xFFFF)
|
||||||
|
{
|
||||||
|
while ((count--) > 0)
|
||||||
|
m_map[freeBlock + count] = 0xFFFF;
|
||||||
|
}
|
||||||
|
return freeBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Directory::commitFiles(FILE* mc)
|
||||||
|
{
|
||||||
|
for (size_t i = 0 ; i < 127 ; i++)
|
||||||
|
{
|
||||||
|
if (m_files[i].m_id[0] == 0xFF && m_files[i].m_id[1] == 0xFF &&
|
||||||
|
m_files[i].m_id[2] == 0xFF && m_files[i].m_id[3] == 0xFF)
|
||||||
|
continue;
|
||||||
|
if (m_files[i].m_firstBlock == 0xFFFF)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fseek(mc, m_files[i].m_firstBlock * BlockSize, SEEK_SET);
|
||||||
|
//fwrite(m_files[i].m_data.get(), 1, m_files[i].m_blockCount * BlockSize, mc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Directory::Directory()
|
Directory::Directory()
|
||||||
{
|
{
|
||||||
memset(__raw, 0xFF, BlockSize);
|
memset(__raw, 0xFF, BlockSize);
|
||||||
@ -190,6 +310,50 @@ Directory::Directory(uint8_t data[])
|
|||||||
memcpy((uint16_t*)__raw, data, BlockSize);
|
memcpy((uint16_t*)__raw, data, BlockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Directory::Directory(const Directory& other)
|
||||||
|
{
|
||||||
|
memcpy(__raw, other.__raw, BlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Directory::operator=(const Directory& other)
|
||||||
|
{
|
||||||
|
memcpy(__raw, other.__raw, BlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
File* Directory::getFirstFreeFile(char* game, char* maker, const char* filename)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0 ; i < 127 ; i++)
|
||||||
|
{
|
||||||
|
if (m_files[i].m_id[0] == 0xFF)
|
||||||
|
{
|
||||||
|
File* ret = &m_files[i];
|
||||||
|
if (game && strlen(game) == 4)
|
||||||
|
memcpy(ret->m_id, game, 4);
|
||||||
|
if (maker && strlen(maker) == 2)
|
||||||
|
memcpy(ret->m_maker, maker, 2);
|
||||||
|
memset(ret->m_filename, 0, 32);
|
||||||
|
memcpy(ret->m_filename, filename, 32 - strlen(filename));
|
||||||
|
return &m_files[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
File* Directory::getFile(char* game, 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))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv)
|
void calculateChecksum(uint16_t* data, size_t len, uint16_t* checksum, uint16_t* checksumInv)
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,14 @@
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
kabufuda::Card mc{_S("test.USA.raw")};
|
kabufuda::Card mc{_S("test.USA.raw"), "GM8E", "01"};
|
||||||
mc.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card123Mb);
|
mc.format(kabufuda::EDeviceId::SlotA, kabufuda::ECardSize::Card123Mb);
|
||||||
printf("File Mbit %x\n", kabufuda::Card::getSizeMbitFromFile(_S("test.USA.raw")));
|
mc.createFile("MetroidPrime A", kabufuda::BlockSize * 2);
|
||||||
|
//kabufuda::File* f = mc.openFile("MetroidPrime A");
|
||||||
|
// if (f)
|
||||||
|
// {
|
||||||
|
// char test[] = "Metroid Prime is Cool\0";
|
||||||
|
// mc.write(f, test, strlen(test));
|
||||||
|
// }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user