mirror of https://github.com/AxioDL/kabufuda.git
Initial file allocation
This commit is contained in:
parent
4c2d5e7214
commit
b56ac5e112
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory.h>
|
||||
#include <memory>
|
||||
|
||||
#include "Util.hpp"
|
||||
|
||||
|
@ -61,6 +61,8 @@ enum class EEncoding : uint16_t
|
|||
|
||||
class File
|
||||
{
|
||||
friend class Directory;
|
||||
friend class Card;
|
||||
#pragma pack(push, 4)
|
||||
union
|
||||
{
|
||||
|
@ -72,9 +74,13 @@ class File
|
|||
uint8_t m_bannerFlags;
|
||||
char m_filename[0x20];
|
||||
uint32_t m_modifiedTime;
|
||||
uint32_t m_imageOffset;
|
||||
uint16_t m_iconFmt;
|
||||
uint16_t m_animSpeed;
|
||||
uint8_t m_permissions;
|
||||
int8_t m_copyCounter;
|
||||
uint16_t m_firstBlock;
|
||||
uint16_t m_blockCount;
|
||||
uint16_t m_reserved2;
|
||||
uint32_t m_commentAddr;
|
||||
};
|
||||
|
@ -113,8 +119,10 @@ public:
|
|||
BlockAllocationTable(uint8_t data[BlockSize]);
|
||||
~BlockAllocationTable() {}
|
||||
|
||||
uint16_t getNextBlock() const;
|
||||
uint16_t nextFreeBlock(uint16_t maxBlocks, uint16_t startingBlock = FSTBlocks);
|
||||
uint16_t getNextBlock(uint16_t block) const;
|
||||
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
|
||||
|
@ -134,11 +142,17 @@ class Directory
|
|||
uint8_t __raw[BlockSize];
|
||||
};
|
||||
#pragma pop()
|
||||
void commitFiles(FILE* mc);
|
||||
public:
|
||||
Directory();
|
||||
|
||||
Directory(uint8_t data[BlockSize]);
|
||||
Directory(const Directory& other);
|
||||
void operator=(const Directory& other);
|
||||
~Directory() {}
|
||||
|
||||
File* getFirstFreeFile(char* game, char* maker, const char* filename);
|
||||
File* getFile(char* game, char* maker, const char* filename);
|
||||
|
||||
};
|
||||
|
||||
class Card
|
||||
|
@ -180,7 +194,6 @@ class Card
|
|||
m_checksumInv = SBig(checksum ^ 0xFFFF);
|
||||
}
|
||||
|
||||
FILE* m_fileHandle;
|
||||
public:
|
||||
Card();
|
||||
Card(const SystemString& filepath, const char* game = nullptr, const char* maker=nullptr);
|
||||
|
@ -190,7 +203,14 @@ public:
|
|||
* @brief openFile
|
||||
* @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
|
||||
* @param game The target game id, e.g "GM8E"
|
||||
|
@ -237,6 +257,8 @@ public:
|
|||
* @return
|
||||
*/
|
||||
static uint32_t getSizeMbitFromFile(const SystemString& filename);
|
||||
|
||||
void commit();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -244,7 +266,7 @@ public:
|
|||
* @param data
|
||||
* @param len
|
||||
* @param checksum
|
||||
* @param checksum
|
||||
* @param 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
namespace kabufuda
|
||||
|
@ -20,14 +21,14 @@ Card::Card(const SystemString& filename, const char* game, const char* maker)
|
|||
if (maker && strlen(maker) == 2)
|
||||
memcpy(m_maker, maker, 2);
|
||||
|
||||
m_fileHandle = Fopen(m_filename.c_str(), _S("rb"));
|
||||
if (m_fileHandle)
|
||||
FILE* file = Fopen(m_filename.c_str(), _S("rb"));
|
||||
if (file)
|
||||
{
|
||||
fread(__raw, 1, BlockSize, m_fileHandle);
|
||||
fread(m_dir.__raw, 1, BlockSize, m_fileHandle);
|
||||
fread(m_dirBackup.__raw, 1, BlockSize, m_fileHandle);
|
||||
fread(m_bat.__raw, 1, BlockSize, m_fileHandle);
|
||||
fread(m_batBackup.__raw, 1, BlockSize, m_fileHandle);
|
||||
fread(__raw, 1, BlockSize, file);
|
||||
fread(m_dir.__raw, 1, BlockSize, file);
|
||||
fread(m_dirBackup.__raw, 1, BlockSize, file);
|
||||
fread(m_bat.__raw, 1, BlockSize, file);
|
||||
fread(m_batBackup.__raw, 1, BlockSize, file);
|
||||
if (m_dir.m_updateCounter < m_dirBackup.m_updateCounter)
|
||||
m_dirInUse = &m_dirBackup;
|
||||
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)
|
||||
|
@ -145,7 +169,7 @@ void Card::format(EDeviceId id, ECardSize size, EEncoding encoding)
|
|||
fwrite(m_bat.__raw, 1, BlockSize, f);
|
||||
fwrite(m_batBackup.__raw, 1, BlockSize, f);
|
||||
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);
|
||||
fwrite(data.get(), 1, dataLen, f);
|
||||
fclose(f);
|
||||
|
@ -159,6 +183,25 @@ uint32_t Card::getSizeMbitFromFile(const SystemString& filename)
|
|||
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[])
|
||||
{
|
||||
memcpy(__raw, data, 0x40);
|
||||
|
@ -178,6 +221,83 @@ BlockAllocationTable::BlockAllocationTable(uint32_t blockCount)
|
|||
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()
|
||||
{
|
||||
memset(__raw, 0xFF, BlockSize);
|
||||
|
@ -190,6 +310,50 @@ Directory::Directory(uint8_t data[])
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -3,8 +3,14 @@
|
|||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue