Initial file allocation

This commit is contained in:
Phillip Stephens 2016-03-26 13:16:30 -07:00
parent 4c2d5e7214
commit b56ac5e112
3 changed files with 210 additions and 18 deletions

View File

@ -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);
}

View File

@ -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)
{

View File

@ -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;
}