begin rewriting and vastly simplifying compact flash fat generation code so that it is more amenable to bugfixing
This commit is contained in:
parent
c1f2d4629a
commit
b68eba259b
|
@ -19,7 +19,7 @@ libdesmume_a_SOURCES = \
|
|||
common.cpp common.h \
|
||||
debug.cpp debug.h \
|
||||
Disassembler.cpp Disassembler.h \
|
||||
emufile.h emufile.cpp fat.h FIFO.cpp FIFO.h \
|
||||
emufat.h emufat.cpp emufat_types.h emufile.h emufile.cpp fat.h FIFO.cpp FIFO.h \
|
||||
firmware.cpp firmware.h GPU.cpp GPU.h \
|
||||
GPU_osd.h \
|
||||
mem.h mc.cpp mc.h \
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* Copyright (C) 2006 yopyop
|
||||
Copyright (C) 2006 Mic
|
||||
Copyright (C) 2009 CrazyMax
|
||||
Copyright (C) 2009 DeSmuME team
|
||||
Copyright (C) 2009-2010 DeSmuME team
|
||||
|
||||
This file is part of DeSmuME
|
||||
|
||||
|
@ -28,6 +27,9 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../emufat.h"
|
||||
#include <stack>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef _MSC_VER
|
||||
|
@ -77,9 +79,6 @@ typedef struct {
|
|||
#define CF_CMD_READ 0x20
|
||||
#define CF_CMD_WRITE 0x30
|
||||
|
||||
static int disk_image = -1;
|
||||
static off_t file_size;
|
||||
|
||||
static u16 cf_reg_sts,
|
||||
cf_reg_lba1,
|
||||
cf_reg_lba2,
|
||||
|
@ -119,6 +118,8 @@ static BOOL cflashDeviceEnabled = FALSE;
|
|||
|
||||
static std::string sFlashPath;
|
||||
|
||||
static EMUFILE* file;
|
||||
|
||||
// ===========================
|
||||
BOOL inited;
|
||||
|
||||
|
@ -245,8 +246,14 @@ static void add_file(char *fname, FsEntry * entry, int fileLevel)
|
|||
}
|
||||
}
|
||||
|
||||
enum EListCallbackArg {
|
||||
EListCallbackArg_Item, EListCallbackArg_Pop
|
||||
};
|
||||
|
||||
typedef void (*ListCallback)(FsEntry* fs, EListCallbackArg);
|
||||
|
||||
// List all files and subdirectories recursively
|
||||
static void list_files(const char *filepath)
|
||||
static void list_files(const char *filepath, ListCallback list_callback)
|
||||
{
|
||||
char DirSpec[255+1], SubDir[255+1];
|
||||
FsEntry entry;
|
||||
|
@ -265,12 +272,14 @@ static void list_files(const char *filepath)
|
|||
if (hFind == NULL) return;
|
||||
|
||||
fname = (strlen(entry.cAlternateFileName)>0) ? entry.cAlternateFileName : entry.cFileName;
|
||||
add_file(fname, &entry, fileLevel);
|
||||
list_callback(&entry,EListCallbackArg_Item);
|
||||
//add_file(fname, &entry, fileLevel);
|
||||
|
||||
while (FsReadNext(hFind, &entry) != 0)
|
||||
{
|
||||
fname = (strlen(entry.cAlternateFileName)>0) ? entry.cAlternateFileName : entry.cFileName;
|
||||
add_file(fname, &entry, fileLevel);
|
||||
//add_file(fname, &entry, fileLevel);
|
||||
list_callback(&entry,EListCallbackArg_Item);
|
||||
printf("cflash added %s\n",fname);
|
||||
|
||||
if (numFiles==MAXFILES-1) break;
|
||||
|
@ -280,7 +289,8 @@ static void list_files(const char *filepath)
|
|||
if (strlen(fname)+strlen(filepath)+2 < 256)
|
||||
{
|
||||
sprintf(SubDir, "%s%c%s", filepath, FS_SEPARATOR, fname);
|
||||
list_files(SubDir);
|
||||
list_files(SubDir, list_callback);
|
||||
list_callback(&entry, EListCallbackArg_Pop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,213 +299,307 @@ static void list_files(const char *filepath)
|
|||
FsClose(hFind);
|
||||
if (dwError != FS_ERR_NO_MORE_FILES) return;
|
||||
|
||||
if (numFiles < MAXFILES)
|
||||
{
|
||||
fileLink[numFiles].parent = fileLevel;
|
||||
files[numFiles++].name[0] = 0;
|
||||
}
|
||||
//if (numFiles < MAXFILES)
|
||||
//{
|
||||
// fileLink[numFiles].parent = fileLevel;
|
||||
// files[numFiles++].name[0] = 0;
|
||||
//}
|
||||
}
|
||||
|
||||
static u32 dataSectors = 0;
|
||||
void count_ListCallback(FsEntry* fs, EListCallbackArg arg)
|
||||
{
|
||||
if(arg == EListCallbackArg_Pop) return;
|
||||
u32 sectors = 1;
|
||||
if(fs->flags & FS_IS_DIR)
|
||||
{
|
||||
}
|
||||
else
|
||||
sectors += (fs->fileSize+511)/512 + 1;
|
||||
dataSectors += sectors;
|
||||
}
|
||||
|
||||
static std::string currPath;
|
||||
static EmuFatFile currFatFile;
|
||||
static std::stack<EmuFatFile> fatStack;
|
||||
static std::stack<std::string> pathStack;
|
||||
void build_ListCallback(FsEntry* fs, EListCallbackArg arg)
|
||||
{
|
||||
char* fname = (strlen(fs->cAlternateFileName)>0) ? fs->cAlternateFileName : fs->cFileName;
|
||||
|
||||
if(arg == EListCallbackArg_Pop)
|
||||
{
|
||||
currFatFile = fatStack.top();
|
||||
fatStack.pop();
|
||||
currPath = pathStack.top();
|
||||
pathStack.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
if(fs->flags & FS_IS_DIR)
|
||||
{
|
||||
if(!strcmp(fname,".")) return;
|
||||
if(!strcmp(fname,"..")) return;
|
||||
|
||||
pathStack.push(currPath);
|
||||
fatStack.push(currFatFile);
|
||||
|
||||
EmuFatFile newDir;
|
||||
newDir.makeDir(&currFatFile,fname);
|
||||
newDir.sync();
|
||||
currFatFile = newDir;
|
||||
|
||||
currPath = currPath + std::string(1,FS_SEPARATOR) + fname;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string path = currPath + std::string(1,FS_SEPARATOR) + fname;
|
||||
|
||||
FILE* inf = fopen(path.c_str(),"rb");
|
||||
fseek(inf,0,SEEK_END);
|
||||
long len = ftell(inf);
|
||||
fseek(inf,0,SEEK_SET);
|
||||
u8 *buf = new u8[len];
|
||||
fread(buf,1,len,inf);
|
||||
fclose(inf);
|
||||
|
||||
EmuFatFile f;
|
||||
f.open(&currFatFile,fname,EO_RDWR | EO_CREAT);
|
||||
f.write(buf,len);
|
||||
f.close();
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Set up the MBR, FAT and DIR_ENTs
|
||||
static BOOL cflash_build_fat()
|
||||
{
|
||||
int i,j,k,l,
|
||||
clust,numClusters,
|
||||
clusterNum2,rootCluster;
|
||||
int fileLevel;
|
||||
dataSectors = 0;
|
||||
currPath = sFlashPath;
|
||||
list_files(sFlashPath.c_str(), count_ListCallback);
|
||||
|
||||
numFiles = 0;
|
||||
fileLevel = -1;
|
||||
maxLevel = -1;
|
||||
dataSectors += 16*1024*1024/512; //add 16MB worth of write space. this is probably enough for anyone, but maybe it should be configurable.
|
||||
//we could always suggest to users to add a big file to their directory to overwrite (that would cause the image to get padded)
|
||||
|
||||
delete file;
|
||||
file = new EMUFILE_MEMORY(dataSectors*512+1);
|
||||
EmuFat fat(file);
|
||||
EmuFatVolume vol;
|
||||
u8 ok = vol.init(&fat);
|
||||
vol.format(dataSectors);
|
||||
|
||||
files = (DIR_ENT *) malloc(MAXFILES*sizeof(DIR_ENT));
|
||||
memset(files,0,MAXFILES*sizeof(DIR_ENT));
|
||||
if (files == NULL) return FALSE;
|
||||
fileLink = (FILE_INFO *) malloc(MAXFILES*sizeof(FILE_INFO));
|
||||
if (fileLink == NULL)
|
||||
{
|
||||
free(files);
|
||||
return FALSE;
|
||||
}
|
||||
reconstruct(&currFatFile);
|
||||
currFatFile.openRoot(&vol);
|
||||
|
||||
for (i=0; i<MAXFILES; i++)
|
||||
{
|
||||
files[i].attrib = 0;
|
||||
files[i].name[0] = FILE_FREE;
|
||||
files[i].fileSize = 0;
|
||||
list_files(sFlashPath.c_str(), build_ListCallback);
|
||||
|
||||
fileLink[i].filesInDir = 0;
|
||||
FILE* outf = fopen("d:\\test.ima","wb");
|
||||
EMUFILE_MEMORY* memf = (EMUFILE_MEMORY*)file;
|
||||
fwrite(memf->buf(),1,memf->size(),outf);
|
||||
fclose(outf);
|
||||
|
||||
extraDirEntries[i] = NULL;
|
||||
numExtraEntries[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
list_files(sFlashPath.c_str());
|
||||
//int i,j,k,l,
|
||||
//clust,numClusters,
|
||||
//clusterNum2,rootCluster;
|
||||
//int fileLevel;
|
||||
|
||||
k = 0;
|
||||
clusterNum = rootCluster = (SECRESV + SECPERFAT)/SECPERCLUS;
|
||||
numClusters = 0;
|
||||
clust = 0;
|
||||
numRootFiles = 0;
|
||||
//numFiles = 0;
|
||||
//fileLevel = -1;
|
||||
//maxLevel = -1;
|
||||
|
||||
// Allocate memory to hold information about the files
|
||||
dirEntries = (DIR_ENT *) malloc(numFiles*sizeof(DIR_ENT));
|
||||
if (dirEntries==NULL) return FALSE;
|
||||
//files = (DIR_ENT *) malloc(MAXFILES*sizeof(DIR_ENT));
|
||||
//memset(files,0,MAXFILES*sizeof(DIR_ENT));
|
||||
//if (files == NULL) return FALSE;
|
||||
//fileLink = (FILE_INFO *) malloc(MAXFILES*sizeof(FILE_INFO));
|
||||
//if (fileLink == NULL)
|
||||
//{
|
||||
// free(files);
|
||||
// return FALSE;
|
||||
//}
|
||||
|
||||
dirEntryLink = (FILE_INFO *) malloc(numFiles*sizeof(FILE_INFO));
|
||||
if (dirEntryLink==NULL)
|
||||
{
|
||||
free(dirEntries);
|
||||
return FALSE;
|
||||
}
|
||||
dirEntriesInCluster = (int *) malloc(NUMCLUSTERS*sizeof(int));
|
||||
if (dirEntriesInCluster==NULL)
|
||||
{
|
||||
free(dirEntries);
|
||||
free(dirEntryLink);
|
||||
return FALSE;
|
||||
}
|
||||
dirEntryPtr = (DIR_ENT **) malloc(NUMCLUSTERS*sizeof(DIR_ENT*));
|
||||
if (dirEntryPtr==NULL)
|
||||
{
|
||||
free(dirEntries);
|
||||
free(dirEntryLink);
|
||||
free(dirEntriesInCluster);
|
||||
return FALSE;
|
||||
}
|
||||
//for (i=0; i<MAXFILES; i++)
|
||||
//{
|
||||
// files[i].attrib = 0;
|
||||
// files[i].name[0] = FILE_FREE;
|
||||
// files[i].fileSize = 0;
|
||||
|
||||
memset(dirEntriesInCluster, 0, NUMCLUSTERS*sizeof(int));
|
||||
memset(dirEntryPtr, NULL, NUMCLUSTERS*sizeof(DIR_ENT*));
|
||||
// fileLink[i].filesInDir = 0;
|
||||
|
||||
// Change the hierarchical layout to a flat one
|
||||
for (i=0; i<=maxLevel; i++)
|
||||
{
|
||||
clusterNum2 = clusterNum;
|
||||
for (j=0; j<numFiles; j++)
|
||||
{
|
||||
if (fileLink[j].parent == i)
|
||||
{
|
||||
if (dirEntryPtr[clusterNum] == NULL)
|
||||
dirEntryPtr[clusterNum] = &dirEntries[k];
|
||||
dirEntryLink[k] = fileLink[j];
|
||||
dirEntries[k++] = files[j];
|
||||
if ((files[j].attrib & ATTRIB_LFN)==0)
|
||||
{
|
||||
if (files[j].attrib & ATTRIB_DIR)
|
||||
{
|
||||
if (strncmp((char*)&files[j].name[0],". ",NAME_LEN)==0)
|
||||
dirEntries[k-1].startCluster = dirEntryLink[k-1].level;
|
||||
else
|
||||
if (strncmp((char*)&files[j].name[0],".. ",NAME_LEN)==0)
|
||||
{
|
||||
dirEntries[k-1].startCluster = dirEntryLink[k-1].parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
clust++;
|
||||
dirEntries[k-1].startCluster = clust;
|
||||
l = (fileLink[fileLink[j].level].filesInDir)>>8;
|
||||
clust += l;
|
||||
numClusters += l;
|
||||
}
|
||||
}
|
||||
else
|
||||
dirEntries[k-1].startCluster = clusterNum;
|
||||
}
|
||||
if (i==0) numRootFiles++;
|
||||
dirEntriesInCluster[clusterNum]++;
|
||||
if (dirEntriesInCluster[clusterNum]==256)
|
||||
clusterNum++;
|
||||
}
|
||||
}
|
||||
clusterNum = clusterNum2 + ((fileLink[i].filesInDir)>>8) + 1;
|
||||
numClusters++;
|
||||
}
|
||||
// extraDirEntries[i] = NULL;
|
||||
// numExtraEntries[i] = 0;
|
||||
//}
|
||||
|
||||
// Free the file indexing buffer
|
||||
free(files);
|
||||
free(fileLink);
|
||||
//list_files(sFlashPath.c_str());
|
||||
|
||||
// Set up the MBR
|
||||
MBR.bytesPerSector = 512;
|
||||
MBR.numFATs = 1;
|
||||
// replaced strcpy with strncpy. It doesnt matter here, as the strings are constant
|
||||
// but we should extingish all unrestricted strcpy,strcat from the project
|
||||
strncpy((char*)&MBR.OEMName[0],"DESMUM",8);
|
||||
strncpy((char*)&MBR.fat16.fileSysType[0],"FAT16 ",8);
|
||||
MBR.reservedSectors = SECRESV;
|
||||
MBR.numSectors = 524288;
|
||||
MBR.numSectorsSmall = 0;
|
||||
MBR.sectorsPerCluster = SECPERCLUS;
|
||||
MBR.sectorsPerFAT = SECPERFAT;
|
||||
MBR.rootEntries = 512;
|
||||
MBR.fat16.signature = 0xAA55;
|
||||
MBR.mediaDesc = 1;
|
||||
//k = 0;
|
||||
//clusterNum = rootCluster = (SECRESV + SECPERFAT)/SECPERCLUS;
|
||||
//numClusters = 0;
|
||||
//clust = 0;
|
||||
//numRootFiles = 0;
|
||||
|
||||
filesysFAT = 0 + MBR.reservedSectors;
|
||||
filesysRootDir = filesysFAT + (MBR.numFATs * MBR.sectorsPerFAT);
|
||||
filesysData = filesysRootDir + ((MBR.rootEntries * sizeof(DIR_ENT)) / 512);
|
||||
//// Allocate memory to hold information about the files
|
||||
//dirEntries = (DIR_ENT *) malloc(numFiles*sizeof(DIR_ENT));
|
||||
//if (dirEntries==NULL) return FALSE;
|
||||
|
||||
// Set up the cluster values for all subdirectories
|
||||
clust = filesysData / SECPERCLUS;
|
||||
firstDirEntCluster = clust;
|
||||
for (i=1; i<numFiles; i++)
|
||||
{
|
||||
if (((dirEntries[i].attrib & ATTRIB_DIR)!=0) && ((dirEntries[i].attrib & ATTRIB_LFN)==0))
|
||||
{
|
||||
if (dirEntries[i].startCluster > rootCluster)
|
||||
dirEntries[i].startCluster += clust-rootCluster;
|
||||
}
|
||||
}
|
||||
lastDirEntCluster = clust+numClusters-1;
|
||||
//dirEntryLink = (FILE_INFO *) malloc(numFiles*sizeof(FILE_INFO));
|
||||
//if (dirEntryLink==NULL)
|
||||
//{
|
||||
// free(dirEntries);
|
||||
// return FALSE;
|
||||
//}
|
||||
//dirEntriesInCluster = (int *) malloc(NUMCLUSTERS*sizeof(int));
|
||||
//if (dirEntriesInCluster==NULL)
|
||||
//{
|
||||
// free(dirEntries);
|
||||
// free(dirEntryLink);
|
||||
// return FALSE;
|
||||
//}
|
||||
//dirEntryPtr = (DIR_ENT **) malloc(NUMCLUSTERS*sizeof(DIR_ENT*));
|
||||
//if (dirEntryPtr==NULL)
|
||||
//{
|
||||
// free(dirEntries);
|
||||
// free(dirEntryLink);
|
||||
// free(dirEntriesInCluster);
|
||||
// return FALSE;
|
||||
//}
|
||||
|
||||
// Set up the cluster values for all files
|
||||
clust += numClusters; //clusterNum;
|
||||
for (i=0; i<numFiles; i++)
|
||||
{
|
||||
if (((dirEntries[i].attrib & ATTRIB_DIR)==0) && ((dirEntries[i].attrib & ATTRIB_LFN)==0))
|
||||
{
|
||||
dirEntries[i].startCluster = clust;
|
||||
clust += (dirEntries[i].fileSize/(512*SECPERCLUS));
|
||||
clust++;
|
||||
}
|
||||
}
|
||||
lastFileDataCluster = clust-1;
|
||||
//memset(dirEntriesInCluster, 0, NUMCLUSTERS*sizeof(int));
|
||||
//memset(dirEntryPtr, NULL, NUMCLUSTERS*sizeof(DIR_ENT*));
|
||||
|
||||
// Set up the FAT16
|
||||
memset(FAT16,0,SECPERFAT*256*sizeof(u16));
|
||||
FAT16[0] = 0xFF01;
|
||||
FAT16[1] = 0xFFFF;
|
||||
for (i=2; i<=lastDirEntCluster; i++)
|
||||
FAT16[i] = 0xFFFF;
|
||||
k = 2;
|
||||
for (i=0; i<numFiles; i++)
|
||||
{
|
||||
if (((dirEntries[i].attrib & ATTRIB_LFN)==0) && (dirEntries[i].name[0] != FILE_FREE))
|
||||
{
|
||||
j = 0;
|
||||
l = dirEntries[i].fileSize - (512*SECPERCLUS);
|
||||
while (l > 0)
|
||||
{
|
||||
if (dirEntries[i].startCluster+j < MAXFILES)
|
||||
FAT16[dirEntries[i].startCluster+j] = dirEntries[i].startCluster+j+1;
|
||||
j++;
|
||||
l -= (512*16);
|
||||
}
|
||||
if ((dirEntries[i].attrib & ATTRIB_DIR)==0)
|
||||
{
|
||||
if (dirEntries[i].startCluster+j < MAXFILES)
|
||||
FAT16[dirEntries[i].startCluster+j] = 0xFFFF;
|
||||
}
|
||||
k = dirEntries[i].startCluster+j;
|
||||
}
|
||||
}
|
||||
//// Change the hierarchical layout to a flat one
|
||||
//for (i=0; i<=maxLevel; i++)
|
||||
//{
|
||||
// clusterNum2 = clusterNum;
|
||||
// for (j=0; j<numFiles; j++)
|
||||
// {
|
||||
// if (fileLink[j].parent == i)
|
||||
// {
|
||||
// if (dirEntryPtr[clusterNum] == NULL)
|
||||
// dirEntryPtr[clusterNum] = &dirEntries[k];
|
||||
// dirEntryLink[k] = fileLink[j];
|
||||
// dirEntries[k++] = files[j];
|
||||
// if ((files[j].attrib & ATTRIB_LFN)==0)
|
||||
// {
|
||||
// if (files[j].attrib & ATTRIB_DIR)
|
||||
// {
|
||||
// if (strncmp((char*)&files[j].name[0],". ",NAME_LEN)==0)
|
||||
// dirEntries[k-1].startCluster = dirEntryLink[k-1].level;
|
||||
// else
|
||||
// if (strncmp((char*)&files[j].name[0],".. ",NAME_LEN)==0)
|
||||
// {
|
||||
// dirEntries[k-1].startCluster = dirEntryLink[k-1].parent;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// clust++;
|
||||
// dirEntries[k-1].startCluster = clust;
|
||||
// l = (fileLink[fileLink[j].level].filesInDir)>>8;
|
||||
// clust += l;
|
||||
// numClusters += l;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// dirEntries[k-1].startCluster = clusterNum;
|
||||
// }
|
||||
// if (i==0) numRootFiles++;
|
||||
// dirEntriesInCluster[clusterNum]++;
|
||||
// if (dirEntriesInCluster[clusterNum]==256)
|
||||
// clusterNum++;
|
||||
// }
|
||||
// }
|
||||
// clusterNum = clusterNum2 + ((fileLink[i].filesInDir)>>8) + 1;
|
||||
// numClusters++;
|
||||
//}
|
||||
|
||||
for (i=(filesysData/SECPERCLUS); i<NUMCLUSTERS; i++)
|
||||
{
|
||||
if (dirEntriesInCluster[i]==256)
|
||||
FAT16[i] = i+1;
|
||||
}
|
||||
//// Free the file indexing buffer
|
||||
//free(files);
|
||||
//free(fileLink);
|
||||
|
||||
//// Set up the MBR
|
||||
//MBR.bytesPerSector = 512;
|
||||
//MBR.numFATs = 1;
|
||||
//// replaced strcpy with strncpy. It doesnt matter here, as the strings are constant
|
||||
//// but we should extingish all unrestricted strcpy,strcat from the project
|
||||
//strncpy((char*)&MBR.OEMName[0],"DESMUM",8);
|
||||
//strncpy((char*)&MBR.fat16.fileSysType[0],"FAT16 ",8);
|
||||
//MBR.reservedSectors = SECRESV;
|
||||
//MBR.numSectors = 524288;
|
||||
//MBR.numSectorsSmall = 0;
|
||||
//MBR.sectorsPerCluster = SECPERCLUS;
|
||||
//MBR.sectorsPerFAT = SECPERFAT;
|
||||
//MBR.rootEntries = 512;
|
||||
//MBR.fat16.signature = 0xAA55;
|
||||
//MBR.mediaDesc = 1;
|
||||
|
||||
//filesysFAT = 0 + MBR.reservedSectors;
|
||||
//filesysRootDir = filesysFAT + (MBR.numFATs * MBR.sectorsPerFAT);
|
||||
//filesysData = filesysRootDir + ((MBR.rootEntries * sizeof(DIR_ENT)) / 512);
|
||||
|
||||
//// Set up the cluster values for all subdirectories
|
||||
//clust = filesysData / SECPERCLUS;
|
||||
//firstDirEntCluster = clust;
|
||||
//for (i=1; i<numFiles; i++)
|
||||
//{
|
||||
// if (((dirEntries[i].attrib & ATTRIB_DIR)!=0) && ((dirEntries[i].attrib & ATTRIB_LFN)==0))
|
||||
// {
|
||||
// if (dirEntries[i].startCluster > rootCluster)
|
||||
// dirEntries[i].startCluster += clust-rootCluster;
|
||||
// }
|
||||
//}
|
||||
//lastDirEntCluster = clust+numClusters-1;
|
||||
|
||||
//// Set up the cluster values for all files
|
||||
//clust += numClusters; //clusterNum;
|
||||
//for (i=0; i<numFiles; i++)
|
||||
//{
|
||||
// if (((dirEntries[i].attrib & ATTRIB_DIR)==0) && ((dirEntries[i].attrib & ATTRIB_LFN)==0))
|
||||
// {
|
||||
// dirEntries[i].startCluster = clust;
|
||||
// clust += (dirEntries[i].fileSize/(512*SECPERCLUS));
|
||||
// clust++;
|
||||
// }
|
||||
//}
|
||||
//lastFileDataCluster = clust-1;
|
||||
|
||||
//// Set up the FAT16
|
||||
//memset(FAT16,0,SECPERFAT*256*sizeof(u16));
|
||||
//FAT16[0] = 0xFF01;
|
||||
//FAT16[1] = 0xFFFF;
|
||||
//for (i=2; i<=lastDirEntCluster; i++)
|
||||
//FAT16[i] = 0xFFFF;
|
||||
//k = 2;
|
||||
//for (i=0; i<numFiles; i++)
|
||||
//{
|
||||
// if (((dirEntries[i].attrib & ATTRIB_LFN)==0) && (dirEntries[i].name[0] != FILE_FREE))
|
||||
// {
|
||||
// j = 0;
|
||||
// l = dirEntries[i].fileSize - (512*SECPERCLUS);
|
||||
// while (l > 0)
|
||||
// {
|
||||
// if (dirEntries[i].startCluster+j < MAXFILES)
|
||||
// FAT16[dirEntries[i].startCluster+j] = dirEntries[i].startCluster+j+1;
|
||||
// j++;
|
||||
// l -= (512*16);
|
||||
// }
|
||||
// if ((dirEntries[i].attrib & ATTRIB_DIR)==0)
|
||||
// {
|
||||
// if (dirEntries[i].startCluster+j < MAXFILES)
|
||||
// FAT16[dirEntries[i].startCluster+j] = 0xFFFF;
|
||||
// }
|
||||
// k = dirEntries[i].startCluster+j;
|
||||
// }
|
||||
//}
|
||||
|
||||
//for (i=(filesysData/SECPERCLUS); i<NUMCLUSTERS; i++)
|
||||
//{
|
||||
// if (dirEntriesInCluster[i]==256)
|
||||
// FAT16[i] = i+1;
|
||||
//}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -540,25 +644,12 @@ static BOOL cflash_init()
|
|||
{
|
||||
sFlashPath = CFlash_Path;
|
||||
INFO("Using CFlash disk image file %s\n", sFlashPath.c_str());
|
||||
disk_image = OPEN_FN( sFlashPath.c_str(), OPEN_MODE);
|
||||
|
||||
if ( disk_image != -1)
|
||||
file = new EMUFILE_FILE(sFlashPath.c_str(),"rb+");
|
||||
if(file->fail())
|
||||
{
|
||||
file_size = LSEEK_FN( disk_image, 0, SEEK_END);
|
||||
if (0 && file_size == -1)
|
||||
{
|
||||
CFLASHLOG( "Error when seeking to end of disk image" );
|
||||
}
|
||||
else
|
||||
{
|
||||
LSEEK_FN( disk_image, 0, SEEK_SET);
|
||||
CFLASHLOG( "Disk image size = %ld (%ld sectors)\n", file_size, file_size / 512);
|
||||
init_good = TRUE;
|
||||
}
|
||||
CFLASHLOG("Failed to open file %s\n", sFlashPath.c_str());
|
||||
delete file;
|
||||
}
|
||||
else
|
||||
// TODO: create image if not exist
|
||||
CFLASHLOG("Failed to open file %s: \"%s\"\n", sFlashPath.c_str(), strerror( errno));
|
||||
}
|
||||
|
||||
// READY
|
||||
|
@ -692,126 +783,16 @@ static unsigned int cflash_read(unsigned int address)
|
|||
case CF_REG_DATA:
|
||||
if (cf_reg_cmd == CF_CMD_READ)
|
||||
{
|
||||
if (!CFlash_IsUsingPath())
|
||||
if(file)
|
||||
{
|
||||
if ( disk_image != -1)
|
||||
{
|
||||
u8 data[2];
|
||||
#if 0
|
||||
if (currLBA < buffered_start_index || currLBA >= (buffered_start_index + BUFFERED_BLOCK_SIZE))
|
||||
{
|
||||
size_t read_bytes = 0;
|
||||
LSEEK_FN( disk_image, currLBA, SEEK_SET);
|
||||
|
||||
while (read_bytes < BUFFERED_BLOCK_SIZE)
|
||||
{
|
||||
size_t cur_read = READ_FN( disk_image, &block_buffer[read_bytes],
|
||||
BUFFERED_BLOCK_SIZE - read_bytes);
|
||||
|
||||
if ( cur_read == -1)
|
||||
{
|
||||
CFLASHLOG( "Error during read: %s\n", strerror(errno) );
|
||||
break;
|
||||
}
|
||||
read_bytes += cur_read;
|
||||
}
|
||||
|
||||
CFLASHLOG( "Read %d bytes\n", read_bytes);
|
||||
|
||||
buffered_start_index = currLBA;
|
||||
}
|
||||
data[0] = block_buffer[currLBA - buffered_start_index];
|
||||
data[1] = block_buffer[currLBA + 1 - buffered_start_index];
|
||||
#else
|
||||
LSEEK_FN( disk_image, currLBA, SEEK_SET);
|
||||
elems_read += READ_FN( disk_image, data, 2);
|
||||
#endif
|
||||
ret_value = data[1] << 8 | data[0];
|
||||
}
|
||||
currLBA += 2;
|
||||
}
|
||||
else // use path
|
||||
{
|
||||
unsigned char *p;
|
||||
int i;
|
||||
u32 cluster,cluster2,cluster3,fileLBA;
|
||||
cluster = (currLBA / (512 * SECPERCLUS));
|
||||
cluster2 = (((currLBA/512) - filesysData) / SECPERCLUS) + 2;
|
||||
|
||||
// Reading from the MBR
|
||||
if (currLBA < 512 && currLBA >= 0)
|
||||
{
|
||||
p = (unsigned char*)&MBR;
|
||||
ret_value = T1ReadWord(p, currLBA);
|
||||
|
||||
// Reading the FAT
|
||||
}
|
||||
else
|
||||
if (((u32)currLBA >= filesysFAT*512) && ((u32)currLBA < filesysRootDir*512))
|
||||
{
|
||||
p = (unsigned char*)&FAT16[0];
|
||||
ret_value = T1ReadWord(p, currLBA - filesysFAT * 512);
|
||||
|
||||
// Reading directory entries
|
||||
}
|
||||
else
|
||||
if (((u32)currLBA >= filesysRootDir*512) && (cluster <= (u32)lastDirEntCluster))
|
||||
{
|
||||
cluster3 = ((currLBA - (SECRESV * 512)) / (512 * SECPERCLUS));
|
||||
i = (currLBA-(((cluster3-(filesysRootDir/SECPERCLUS))*SECPERCLUS+filesysRootDir)*512)); //(currLBA - cluster*BYTESPERCLUS);
|
||||
if (i < (dirEntriesInCluster[cluster3]*32))
|
||||
{
|
||||
p = (unsigned char*)dirEntryPtr[cluster3];
|
||||
ret_value = T1ReadWord(p, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i /= 32;
|
||||
i -= dirEntriesInCluster[cluster3];
|
||||
if ((i>=0)&&(i<numExtraEntries[cluster3]))
|
||||
{
|
||||
p = (unsigned char*)extraDirEntries[cluster3];
|
||||
ret_value = T1ReadWord(p, i * 32 + (currLBA & 0x1F));
|
||||
}
|
||||
else
|
||||
if ((currLBA&0x1F)==0)
|
||||
ret_value = FILE_FREE;
|
||||
else
|
||||
ret_value = 0;
|
||||
}
|
||||
// Reading file data
|
||||
}
|
||||
else
|
||||
if ((cluster2 > (u32)lastDirEntCluster) && (cluster2 <= (u32)lastFileDataCluster))
|
||||
{
|
||||
//else if ((cluster>lastDirEntCluster)&&(cluster<=lastFileDataCluster)) {
|
||||
fileLBA = currLBA - (filesysData-32)*512; // 32 = # sectors used for the root entries
|
||||
|
||||
// Check if the read is from the currently opened file
|
||||
if ((fileLBA >= fileStartLBA) && (fileLBA < fileEndLBA))
|
||||
{
|
||||
cluster = (fileLBA / (512 * SECPERCLUS));
|
||||
ret_value = fread_buffered(activeDirEnt,cluster-dirEntries[activeDirEnt].startCluster,(fileLBA-fileStartLBA)&(BYTESPERCLUS-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i=0; i<numFiles; i++)
|
||||
{
|
||||
if ((fileLBA>=(u32)(dirEntries[i].startCluster*512*SECPERCLUS)) &&
|
||||
(fileLBA <(dirEntries[i].startCluster*512*SECPERCLUS)+dirEntries[i].fileSize) &&
|
||||
((dirEntries[i].attrib & (ATTRIB_DIR|ATTRIB_LFN))==0))
|
||||
{
|
||||
cluster = (fileLBA / (512 * SECPERCLUS));
|
||||
ret_value = fread_buffered(i,cluster-dirEntries[i].startCluster,fileLBA&(BYTESPERCLUS-1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
currLBA += 2;
|
||||
u8 data[2];
|
||||
file->fseek(currLBA, SEEK_SET);
|
||||
elems_read += file->fread(data,2);
|
||||
ret_value = data[1] << 8 | data[0];
|
||||
}
|
||||
currLBA += 2;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case CF_REG_CMD:
|
||||
break;
|
||||
|
@ -838,7 +819,6 @@ static void cflash_write(unsigned int address,unsigned int data)
|
|||
case CF_REG_DATA:
|
||||
if (cf_reg_cmd == CF_CMD_WRITE)
|
||||
{
|
||||
if (!CFlash_IsUsingPath())
|
||||
{
|
||||
sector_data[sector_write_index] = (data >> 0) & 0xff;
|
||||
sector_data[sector_write_index + 1] = (data >> 8) & 0xff;
|
||||
|
@ -850,22 +830,21 @@ static void cflash_write(unsigned int address,unsigned int data)
|
|||
CFLASHLOG( "Write sector to %ld\n", currLBA);
|
||||
size_t written = 0;
|
||||
|
||||
if (currLBA + 512 < file_size)
|
||||
{
|
||||
if (disk_image != -1)
|
||||
//TODO - calling size() every time we write something is sort of unnecessarily slow in the case of disk-backed files...
|
||||
if(file)
|
||||
if(currLBA + 512 < file->size())
|
||||
{
|
||||
LSEEK_FN( disk_image, currLBA, SEEK_SET);
|
||||
file->fseek(currLBA,SEEK_SET);
|
||||
|
||||
while(written < 512)
|
||||
{
|
||||
size_t cur_write =
|
||||
WRITE_FN( disk_image, §or_data[written], 512 - written);
|
||||
size_t todo = 512-written;
|
||||
file->fwrite(§or_data[written], todo);
|
||||
size_t cur_write = todo;
|
||||
written += cur_write;
|
||||
|
||||
if ( cur_write == (size_t)-1) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CFLASHLOG("Wrote %u bytes\n", written);
|
||||
|
||||
|
@ -873,9 +852,6 @@ static void cflash_write(unsigned int address,unsigned int data)
|
|||
sector_write_index = 0;
|
||||
}
|
||||
}
|
||||
else // TODO: write to real partition
|
||||
{
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -917,11 +893,8 @@ static void cflash_close( void)
|
|||
if (!inited) return;
|
||||
if (!CFlash_IsUsingPath())
|
||||
{
|
||||
if (disk_image != -1)
|
||||
{
|
||||
CLOSE_FN(disk_image);
|
||||
disk_image = -1;
|
||||
}
|
||||
delete file;
|
||||
file = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,699 @@
|
|||
//Copyright (C) 2009-2010 DeSmuME team
|
||||
//based on Arduino SdFat Library ( http://code.google.com/p/sdfatlib/ )
|
||||
/*
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMUFAT_H
|
||||
#define EMUFAT_H
|
||||
|
||||
#include "emufat_types.h"
|
||||
#include "emufile.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// use the gnu style oflag in open()
|
||||
/** open() oflag for reading */
|
||||
static const u8 EO_READ = 0X01;
|
||||
/** open() oflag - same as O_READ */
|
||||
static const u8 EO_RDONLY = EO_READ;
|
||||
/** open() oflag for write */
|
||||
static const u8 EO_WRITE = 0X02;
|
||||
/** open() oflag - same as O_WRITE */
|
||||
static const u8 EO_WRONLY = EO_WRITE;
|
||||
/** open() oflag for reading and writing */
|
||||
static const u8 EO_RDWR = (EO_READ | EO_WRITE);
|
||||
/** open() oflag mask for access modes */
|
||||
static const u8 EO_ACCMODE = (EO_READ | EO_WRITE);
|
||||
/** The file offset shall be set to the end of the file prior to each write. */
|
||||
static const u8 EO_APPEND = 0X04;
|
||||
/** synchronous writes - call sync() after each write */
|
||||
static const u8 EO_SYNC = 0X08;
|
||||
/** create the file if nonexistent */
|
||||
static const u8 EO_CREAT = 0X10;
|
||||
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
|
||||
static const u8 EO_EXCL = 0X20;
|
||||
/** truncate the file to zero length */
|
||||
static const u8 EO_TRUNC = 0X40;
|
||||
|
||||
|
||||
//Value for byte 510 of boot block or MBR
|
||||
static const u8 BOOTSIG0 = 0X55;
|
||||
//Value for byte 511 of boot block or MBR
|
||||
static const u8 BOOTSIG1 = 0XAA;
|
||||
|
||||
static void (*dateTime_)(u16* date, u16* time) = NULL;
|
||||
|
||||
|
||||
#include "PACKED.h"
|
||||
|
||||
//A partition table entry for a MBR formatted storage device.
|
||||
//The MBR partition table has four entries.
|
||||
struct __PACKED TPartitionRecord {
|
||||
//Boot Indicator . Indicates whether the volume is the active
|
||||
//partition. Legal values include: 0X00. Do not use for booting.
|
||||
//0X80 Active partition.
|
||||
u8 boot;
|
||||
|
||||
//Head part of Cylinder-head-sector address of the first block in
|
||||
//the partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||
u8 beginHead;
|
||||
|
||||
struct
|
||||
{
|
||||
//Sector part of Cylinder-head-sector address of the first block in
|
||||
//the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||
u32 beginSector : 6;
|
||||
//High bits cylinder for first block in partition.
|
||||
u32 beginCylinderHigh : 2;
|
||||
};
|
||||
|
||||
//Combine beginCylinderLow with beginCylinderHigh. Legal values
|
||||
//are 0-1023. Only used in old PC BIOS.
|
||||
u8 beginCylinderLow;
|
||||
//Partition type. See defines that begin with PART_TYPE_ for
|
||||
//some Microsoft partition types.
|
||||
u8 type;
|
||||
|
||||
//head part of cylinder-head-sector address of the last sector in the
|
||||
//partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||
u8 endHead;
|
||||
|
||||
struct
|
||||
{
|
||||
//Sector part of cylinder-head-sector address of the last sector in
|
||||
//the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||
u32 endSector : 6;
|
||||
// High bits of end cylinder
|
||||
u32 endCylinderHigh : 2;
|
||||
};
|
||||
|
||||
//Combine endCylinderLow with endCylinderHigh. Legal values
|
||||
//are 0-1023. Only used in old PC BIOS.
|
||||
u8 endCylinderLow;
|
||||
|
||||
//Logical block address of the first block in the partition.
|
||||
u32 firstSector;
|
||||
|
||||
//Length of the partition, in blocks.
|
||||
u32 totalSectors;
|
||||
};
|
||||
|
||||
//Master Boot Record:
|
||||
//The first block of a storage device that is formatted with a MBR.
|
||||
struct __PACKED TMasterBootRecord {
|
||||
//Code Area for master boot program.
|
||||
u8 codeArea[440];
|
||||
//Optional WindowsNT disk signature. May contain more boot code.
|
||||
u32 diskSignature;
|
||||
//Usually zero but may be more boot code.
|
||||
u16 usuallyZero;
|
||||
//Partition tables.
|
||||
TPartitionRecord part[4];
|
||||
//First MBR signature byte. Must be 0X55
|
||||
u8 mbrSig0;
|
||||
//Second MBR signature byte. Must be 0XAA
|
||||
u8 mbrSig1;
|
||||
};
|
||||
|
||||
//BIOS parameter block
|
||||
//The BIOS parameter block describes the physical layout of a FAT volume.
|
||||
struct __PACKED TBiosParmBlock {
|
||||
//Count of bytes per sector. This value may take on only the
|
||||
//following values: 512, 1024, 2048 or 4096
|
||||
u16 bytesPerSector;
|
||||
//Number of sectors per allocation unit. This value must be a
|
||||
//power of 2 that is greater than 0. The legal values are
|
||||
//1, 2, 4, 8, 16, 32, 64, and 128.
|
||||
u8 sectorsPerCluster;
|
||||
//Number of sectors before the first FAT.
|
||||
//This value must not be zero.
|
||||
u16 reservedSectorCount;
|
||||
//The count of FAT data structures on the volume. This field should
|
||||
//always contain the value 2 for any FAT volume of any type.
|
||||
u8 fatCount;
|
||||
//For FAT12 and FAT16 volumes, this field contains the count of
|
||||
//32-byte directory entries in the root directory. For FAT32 volumes,
|
||||
//this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||
//value should always specify a count that when multiplied by 32
|
||||
//results in a multiple of bytesPerSector. FAT16 volumes should
|
||||
//use the value 512.
|
||||
u16 rootDirEntryCount;
|
||||
//This field is the old 16-bit total count of sectors on the volume.
|
||||
//This count includes the count of all sectors in all four regions
|
||||
//of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||
//must be non-zero. For FAT32 volumes, this field must be 0. For
|
||||
//FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||
//totalSectors32 is 0 if the total sector count fits
|
||||
//(is less than 0x10000).
|
||||
u16 totalSectors16;
|
||||
//This dates back to the old MS-DOS 1.x media determination and is
|
||||
//no longer usually used for anything. 0xF8 is the standard value
|
||||
//for fixed (non-removable) media. For removable media, 0xF0 is
|
||||
//frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||
u8 mediaType;
|
||||
//Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||
//On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||
//contains the FAT size count.
|
||||
u16 sectorsPerFat16;
|
||||
//Sectors per track for interrupt 0x13. Not used otherwise.
|
||||
u16 sectorsPerTrack;
|
||||
//Number of heads for interrupt 0x13. Not used otherwise.
|
||||
u16 headCount;
|
||||
//Count of hidden sectors preceding the partition that contains this
|
||||
//FAT volume. This field is generally only relevant for media
|
||||
//visible on interrupt 0x13.
|
||||
u32 hiddenSectors;
|
||||
//This field is the new 32-bit total count of sectors on the volume.
|
||||
//This count includes the count of all sectors in all four regions
|
||||
//of the volume. This field can be 0; if it is 0, then
|
||||
//totalSectors16 must be non-zero.
|
||||
u32 totalSectors32;
|
||||
//Count of sectors occupied by one FAT on FAT32 volumes.
|
||||
u32 sectorsPerFat32;
|
||||
//This field is only defined for FAT32 media and does not exist on
|
||||
//FAT12 and FAT16 media.
|
||||
//Bits 0-3 -- Zero-based number of active FAT.
|
||||
// Only valid if mirroring is disabled.
|
||||
//Bits 4-6 -- Reserved.
|
||||
//Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||
// -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
|
||||
//Bits 8-15 -- Reserved.
|
||||
u16 fat32Flags;
|
||||
//FAT32 version. High byte is major revision number.
|
||||
//Low byte is minor revision number. Only 0.0 define.
|
||||
u16 fat32Version;
|
||||
//Cluster number of the first cluster of the root directory for FAT32.
|
||||
//This usually 2 but not required to be 2.
|
||||
u32 fat32RootCluster;
|
||||
//Sector number of FSINFO structure in the reserved area of the
|
||||
//FAT32 volume. Usually 1.
|
||||
u16 fat32FSInfo;
|
||||
//If non-zero, indicates the sector number in the reserved area
|
||||
//of the volume of a copy of the boot record. Usually 6.
|
||||
//No value other than 6 is recommended.
|
||||
u16 fat32BackBootBlock;
|
||||
//Reserved for future expansion. Code that formats FAT32 volumes
|
||||
//should always set all of the bytes of this field to 0.
|
||||
u8 fat32Reserved[12];
|
||||
};
|
||||
|
||||
//Boot sector for a FAT16 or FAT32 volume.
|
||||
struct __PACKED TFat32BootSector {
|
||||
//X86 jmp to boot program
|
||||
u8 jmpToBootCode[3];
|
||||
//informational only - don't depend on it
|
||||
u8 oemName[8];
|
||||
//BIOS Parameter Block
|
||||
TBiosParmBlock bpb;
|
||||
//for int0x13 use value 0X80 for hard drive
|
||||
u8 driveNumber;
|
||||
//used by Windows NT - should be zero for FAT
|
||||
u8 reserved1;
|
||||
//0X29 if next three fields are valid
|
||||
u8 bootSignature;
|
||||
//usually generated by combining date and time
|
||||
u32 volumeSerialNumber;
|
||||
//should match volume label in root dir
|
||||
u8 volumeLabel[11];
|
||||
//informational only - don't depend on it
|
||||
u8 fileSystemType[8];
|
||||
//X86 boot code
|
||||
u8 bootCode[420];
|
||||
//must be 0X55
|
||||
u8 bootSectorSig0;
|
||||
//must be 0XAA
|
||||
u8 bootSectorSig1;
|
||||
};
|
||||
|
||||
#include "PACKED_END.h"
|
||||
|
||||
// End Of Chain values for FAT entries
|
||||
//FAT16 end of chain value used by Microsoft.
|
||||
static const u16 FAT16EOC = 0XFFFF;
|
||||
//Minimum value for FAT16 EOC. Use to test for EOC.
|
||||
static const u16 FAT16EOC_MIN = 0XFFF8;
|
||||
//FAT32 end of chain value used by Microsoft.
|
||||
static const u32 FAT32EOC = 0X0FFFFFFF;
|
||||
//Minimum value for FAT32 EOC. Use to test for EOC.
|
||||
static const u32 FAT32EOC_MIN = 0X0FFFFFF8;
|
||||
//Mask a for FAT32 entry. Entries are 28 bits.
|
||||
static const u32 FAT32MASK = 0X0FFFFFFF;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//\struct directoryEntry
|
||||
//\brief FAT short directory entry
|
||||
//Short means short 8.3 name, not the entry size.
|
||||
//
|
||||
//Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||
//basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
|
||||
//format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||
//16-bit word):
|
||||
//
|
||||
//Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||
//inclusive (1980-2107).
|
||||
//
|
||||
//Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
|
||||
//Bits 0-4: Day of month, valid value range 1-31 inclusive.
|
||||
//Time Format. A FAT directory entry time stamp is a 16-bit field that has
|
||||
//a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||
//16-bit word, bit 15 is the MSB of the 16-bit word).
|
||||
//
|
||||
//Bits 11-15: Hours, valid value range 0-23 inclusive.
|
||||
//
|
||||
//Bits 5-10: Minutes, valid value range 0-59 inclusive.
|
||||
//
|
||||
//Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
|
||||
//
|
||||
//The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||
struct TDirectoryEntry {
|
||||
//Short 8.3 name.
|
||||
//The first eight bytes contain the file name with blank fill.
|
||||
//The last three bytes contain the file extension with blank fill.
|
||||
|
||||
u8 name[11];
|
||||
//Entry attributes.
|
||||
//The upper two bits of the attribute byte are reserved and should
|
||||
//always be set to 0 when a file is created and never modified or
|
||||
//looked at after that. See defines that begin with DIR_ATT_.
|
||||
|
||||
u8 attributes;
|
||||
|
||||
//Reserved for use by Windows NT. Set value to 0 when a file is
|
||||
//created and never modify or look at it after that.
|
||||
|
||||
u8 reservedNT;
|
||||
|
||||
//The granularity of the seconds part of creationTime is 2 seconds
|
||||
//so this field is a count of tenths of a second and its valid
|
||||
//value range is 0-199 inclusive. (WHG note - seems to be hundredths)
|
||||
|
||||
u8 creationTimeTenths;
|
||||
//Time file was created.
|
||||
u16 creationTime;
|
||||
//Date file was created.
|
||||
u16 creationDate;
|
||||
|
||||
//Last access date. Note that there is no last access time, only
|
||||
//a date. This is the date of last read or write. In the case of
|
||||
//a write, this should be set to the same date as lastWriteDate.
|
||||
|
||||
u16 lastAccessDate;
|
||||
|
||||
//High word of this entry's first cluster number (always 0 for a
|
||||
//FAT12 or FAT16 volume).
|
||||
|
||||
u16 firstClusterHigh;
|
||||
//Time of last write. File creation is considered a write.
|
||||
u16 lastWriteTime;
|
||||
// Date of last write. File creation is considered a write.
|
||||
u16 lastWriteDate;
|
||||
// Low word of this entry's first cluster number.
|
||||
u16 firstClusterLow;
|
||||
//32-bit unsigned holding this file's size in bytes.
|
||||
u32 fileSize;
|
||||
};
|
||||
|
||||
//escape for name[0] = 0xE5
|
||||
static const u8 DIR_NAME_0XE5 = 0x05;
|
||||
//name[0] value for entry that is free after being "deleted"
|
||||
static const u8 DIR_NAME_DELETED = 0xE5;
|
||||
//name[0] value for entry that is free and no allocated entries follow
|
||||
static const u8 DIR_NAME_FREE = 0x00;
|
||||
//file is read-only
|
||||
static const u8 DIR_ATT_READ_ONLY = 0x01;
|
||||
//File should hidden in directory listings
|
||||
static const u8 DIR_ATT_HIDDEN = 0x02;
|
||||
//Entry is for a system file
|
||||
static const u8 DIR_ATT_SYSTEM = 0x04;
|
||||
//Directory entry contains the volume label
|
||||
static const u8 DIR_ATT_VOLUME_ID = 0x08;
|
||||
//Entry is for a directory
|
||||
static const u8 DIR_ATT_DIRECTORY = 0x10;
|
||||
//Old DOS archive bit for backup support
|
||||
static const u8 DIR_ATT_ARCHIVE = 0x20;
|
||||
//Test value for long name entry. Test is
|
||||
//(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME.
|
||||
static const u8 DIR_ATT_LONG_NAME = 0x0F;
|
||||
//Test mask for long name entry
|
||||
static const u8 DIR_ATT_LONG_NAME_MASK = 0x3F;
|
||||
//defined attribute bits
|
||||
static const u8 DIR_ATT_DEFINED_BITS = 0x3F;
|
||||
//Directory entry is part of a long name
|
||||
static inline u8 DIR_IS_LONG_NAME(const TDirectoryEntry* dir) {
|
||||
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
|
||||
}
|
||||
//Mask for file/subdirectory tests
|
||||
static const u8 DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||
//Directory entry is for a file
|
||||
static inline u8 DIR_IS_FILE(const TDirectoryEntry* dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||
}
|
||||
//Directory entry is for a subdirectory
|
||||
static inline u8 DIR_IS_SUBDIR(const TDirectoryEntry* dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||
}
|
||||
//Directory entry is for a file or subdirectory
|
||||
static inline u8 DIR_IS_FILE_OR_SUBDIR(const TDirectoryEntry* dir) {
|
||||
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||
}
|
||||
|
||||
// flags for timestamp
|
||||
/** set the file's last access date */
|
||||
static const u8 T_ACCESS = 1;
|
||||
/** set the file's creation date and time */
|
||||
static const u8 T_CREATE = 2;
|
||||
/** Set the file's write date and time */
|
||||
static const u8 T_WRITE = 4;
|
||||
// values for type_
|
||||
/** This SdFile has not been opened. */
|
||||
static const u8 FAT_FILE_TYPE_CLOSED = 0;
|
||||
/** SdFile for a file */
|
||||
static const u8 FAT_FILE_TYPE_NORMAL = 1;
|
||||
/** SdFile for a FAT16 root directory */
|
||||
static const u8 FAT_FILE_TYPE_ROOT16 = 2;
|
||||
/** SdFile for a FAT32 root directory */
|
||||
static const u8 FAT_FILE_TYPE_ROOT32 = 3;
|
||||
/** SdFile for a subdirectory */
|
||||
static const u8 FAT_FILE_TYPE_SUBDIR = 4;
|
||||
/** Test value for directory type */
|
||||
static const u8 FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
|
||||
|
||||
/** date field for FAT directory entry */
|
||||
static inline u16 FAT_DATE(u16 year, u8 month, u8 day) {
|
||||
return (year - 1980) << 9 | month << 5 | day;
|
||||
}
|
||||
/** year part of FAT directory date field */
|
||||
static inline u16 FAT_YEAR(u16 fatDate) {
|
||||
return 1980 + (fatDate >> 9);
|
||||
}
|
||||
/** month part of FAT directory date field */
|
||||
static inline u8 FAT_MONTH(u16 fatDate) {
|
||||
return (fatDate >> 5) & 0XF;
|
||||
}
|
||||
/** day part of FAT directory date field */
|
||||
static inline u8 FAT_DAY(u16 fatDate) {
|
||||
return fatDate & 0X1F;
|
||||
}
|
||||
/** time field for FAT directory entry */
|
||||
static inline u16 FAT_TIME(u8 hour, u8 minute, u8 second) {
|
||||
return hour << 11 | minute << 5 | second >> 1;
|
||||
}
|
||||
/** hour part of FAT directory time field */
|
||||
static inline u8 FAT_HOUR(u16 fatTime) {
|
||||
return fatTime >> 11;
|
||||
}
|
||||
/** minute part of FAT directory time field */
|
||||
static inline u8 FAT_MINUTE(u16 fatTime) {
|
||||
return(fatTime >> 5) & 0X3F;
|
||||
}
|
||||
/** second part of FAT directory time field */
|
||||
static inline u8 FAT_SECOND(u16 fatTime) {
|
||||
return 2*(fatTime & 0X1F);
|
||||
}
|
||||
/** Default date for file timestamps is 1 Jan 2000 */
|
||||
static const u16 FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||
/** Default time for file timestamp is 1 am */
|
||||
static const u16 FAT_DEFAULT_TIME = (1 << 11);
|
||||
|
||||
//------------------------------------------------------
|
||||
|
||||
class EmuFat;
|
||||
class EmuFatVolume;
|
||||
class EmuFatFile;
|
||||
|
||||
union cache_t {
|
||||
/** Used to access cached file data blocks. */
|
||||
u8 data[512];
|
||||
/** Used to access cached FAT16 entries. */
|
||||
u16 fat16[256];
|
||||
/** Used to access cached FAT32 entries. */
|
||||
u32 fat32[128];
|
||||
/** Used to access cached directory entries. */
|
||||
TDirectoryEntry dir[16];
|
||||
/** Used to access a cached MasterBoot Record. */
|
||||
TMasterBootRecord mbr;
|
||||
/** Used to access to a cached FAT boot sector. */
|
||||
TFat32BootSector fbs;
|
||||
};
|
||||
|
||||
class EmuFatFile
|
||||
{
|
||||
public:
|
||||
/** Create an instance of EmuFatFile. */
|
||||
EmuFatFile() : type_(FAT_FILE_TYPE_CLOSED) {}
|
||||
|
||||
bool writeError;
|
||||
void clearUnbufferedRead(void) {
|
||||
flags_ &= ~F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
void setUnbufferedRead(void) {
|
||||
if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
u8 unbufferedRead(void) const {
|
||||
return flags_ & F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
|
||||
u8 close(void);
|
||||
u8 contiguousRange(u32* bgnBlock, u32* endBlock);
|
||||
u8 createContiguous(EmuFatFile* dirFile, const char* fileName, u32 size);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
u32 curCluster(void) const {return curCluster_;}
|
||||
/** \return The current position for a file or directory. */
|
||||
u32 curPosition(void) const {return curPosition_;}
|
||||
|
||||
u8 rmDir(void);
|
||||
u8 rmRfStar(void);
|
||||
s16 read(void) {
|
||||
u8 b;
|
||||
return read(&b, 1) == 1 ? b : -1;
|
||||
}
|
||||
s32 read(void* buf, u32 nbyte);
|
||||
s8 readDir(TDirectoryEntry* dir);
|
||||
s32 write(const void* buf, u32 nbyte);
|
||||
|
||||
u8 openRoot(EmuFatVolume* vol);
|
||||
u8 timestamp(u8 flag, u16 year, u8 month, u8 day, u8 hour, u8 minute, u8 second);
|
||||
u8 sync(void);
|
||||
u8 makeDir(EmuFatFile* dir, const char* dirName);
|
||||
u8 open(EmuFatFile* dirFile, u16 index, u8 oflag);
|
||||
u8 open(EmuFatFile* dirFile, const char* fileName, u8 oflag);
|
||||
u8 remove(EmuFatFile* dirFile, const char* fileName);
|
||||
u8 remove(void);
|
||||
u8 dirEntry(TDirectoryEntry* dir);
|
||||
u8 seekCur(u32 pos) {
|
||||
return seekSet(curPosition_ + pos);
|
||||
}
|
||||
/**
|
||||
* Set the files current position to end of file. Useful to position
|
||||
* a file for append. See seekSet().
|
||||
*/
|
||||
u8 seekEnd(void) {return seekSet(fileSize_);}
|
||||
u8 seekSet(u32 pos);
|
||||
|
||||
u8 type(void) const {return type_;}
|
||||
u8 truncate(u32 size);
|
||||
|
||||
u32 dirBlock(void) const {return dirBlock_;}
|
||||
/** \return Index of this file's directory in the block dirBlock. */
|
||||
u8 dirIndex(void) const {return dirIndex_;}
|
||||
static void dirName(const TDirectoryEntry& dir, char* name);
|
||||
/** \return The total number of bytes in a file or directory. */
|
||||
u32 fileSize(void) const {return fileSize_;}
|
||||
/** \return The first cluster number for a file or directory. */
|
||||
u32 firstCluster(void) const {return firstCluster_;}
|
||||
/** \return True if this is a SdFile for a directory else false. */
|
||||
u8 isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
|
||||
/** \return True if this is a SdFile for a file else false. */
|
||||
u8 isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
|
||||
/** \return True if this is a SdFile for an open file/directory else false. */
|
||||
u8 isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
|
||||
/** \return True if this is a SdFile for a subdirectory else false. */
|
||||
u8 isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
|
||||
/** \return True if this is a SdFile for the root directory. */
|
||||
u8 isRoot(void) const {
|
||||
return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
|
||||
}
|
||||
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind(void) {
|
||||
curPosition_ = curCluster_ = 0;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
// bits defined in flags_
|
||||
// should be 0XF
|
||||
static const u8 F_OFLAG = (EO_ACCMODE | EO_APPEND | EO_SYNC);
|
||||
// available bits
|
||||
static const u8 F_UNUSED = 0x30;
|
||||
// use unbuffered SD read
|
||||
static const u8 F_FILE_UNBUFFERED_READ = 0X40;
|
||||
// sync of directory entry required
|
||||
static const u8 F_FILE_DIR_DIRTY = 0x80;
|
||||
// make sure F_OFLAG is ok
|
||||
#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
|
||||
#error flags_ bits conflict
|
||||
#endif // flags_ bits
|
||||
|
||||
// private data
|
||||
u8 flags_; // See above for definition of flags_ bits
|
||||
u8 type_; // type of file see above for values
|
||||
u32 curCluster_; // cluster for current file position
|
||||
u32 curPosition_; // current file position in bytes from beginning
|
||||
u32 dirBlock_; // SD block that contains directory entry for file
|
||||
u8 dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
|
||||
u32 fileSize_; // file size in bytes
|
||||
u32 firstCluster_; // first cluster of file
|
||||
EmuFatVolume* vol_; // volume where file is located
|
||||
|
||||
// private functions
|
||||
u8 addCluster(void);
|
||||
u8 addDirCluster(void);
|
||||
TDirectoryEntry* cacheDirEntry(u8 action);
|
||||
static u8 make83Name(const char* str, u8* name);
|
||||
u8 openCachedEntry(u8 cacheIndex, u8 oflags);
|
||||
TDirectoryEntry* readDirCache(void);
|
||||
};
|
||||
|
||||
class EmuFatVolume
|
||||
{
|
||||
public:
|
||||
EmuFatVolume() :allocSearchStart_(2), fatType_(0) {}
|
||||
|
||||
//Initialize a FAT volume. Try partition one first then try super floppy format.
|
||||
//dev The Sd2Card where the volume is located.
|
||||
//return The value one, true, is returned for success and
|
||||
//the value zero, false, is returned for failure. Reasons for
|
||||
//failure include not finding a valid partition, not finding a valid
|
||||
//FAT file system or an I/O error.
|
||||
bool init(EmuFat* dev) { return init(dev, 1) ? true : init(dev, 0);}
|
||||
bool init(EmuFat* dev, u8 part);
|
||||
|
||||
bool format(u32 sectors);
|
||||
|
||||
// inline functions that return volume info
|
||||
//The volume's cluster size in blocks.
|
||||
u8 blocksPerCluster(void) const {return blocksPerCluster_;}
|
||||
//The number of blocks in one FAT.
|
||||
u32 blocksPerFat(void) const {return blocksPerFat_;}
|
||||
//The total number of clusters in the volume. //
|
||||
u32 clusterCount(void) const {return clusterCount_;}
|
||||
//The shift count required to multiply by blocksPerCluster. //
|
||||
u8 clusterSizeShift(void) const {return clusterSizeShift_;}
|
||||
//The logical block number for the start of file data. //
|
||||
u32 dataStartBlock(void) const {return dataStartBlock_;}
|
||||
//The number of FAT structures on the volume. //
|
||||
u8 fatCount(void) const {return fatCount_;}
|
||||
//The logical block number for the start of the first FAT. //
|
||||
u32 fatStartBlock(void) const {return fatStartBlock_;}
|
||||
//The FAT type of the volume. Values are 12, 16 or 32. //
|
||||
u8 fatType(void) const {return fatType_;}
|
||||
//The number of entries in the root directory for FAT16 volumes. //
|
||||
u32 rootDirEntryCount(void) const {return rootDirEntryCount_;}
|
||||
//The logical block number for the start of the root directory on FAT16 volumes or the first cluster number on FAT32 volumes. //
|
||||
u32 rootDirStart(void) const {return rootDirStart_;}
|
||||
|
||||
EmuFat* dev_;
|
||||
|
||||
|
||||
private:
|
||||
friend class EmuFatFile;
|
||||
|
||||
u32 allocSearchStart_; // start cluster for alloc search
|
||||
u8 blocksPerCluster_; // cluster size in blocks
|
||||
u32 blocksPerFat_; // FAT size in blocks
|
||||
u32 clusterCount_; // clusters in one FAT
|
||||
u8 clusterSizeShift_; // shift to convert cluster count to block count
|
||||
u32 dataStartBlock_; // first data block number
|
||||
u8 fatCount_; // number of FATs on volume
|
||||
u32 fatStartBlock_; // start block for first FAT
|
||||
u8 fatType_; // volume type (12, 16, OR 32)
|
||||
u16 rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||
u32 rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||
|
||||
u8 allocContiguous(u32 count, u32* curCluster);
|
||||
u8 blockOfCluster(u32 position) const {
|
||||
return (position >> 9) & (blocksPerCluster_ - 1);}
|
||||
u32 clusterStartBlock(u32 cluster) const {
|
||||
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
|
||||
u32 blockNumber(u32 cluster, u32 position) const {
|
||||
return clusterStartBlock(cluster) + blockOfCluster(position);}
|
||||
u8 fatGet(u32 cluster, u32* value) const;
|
||||
u8 fatPut(u32 cluster, u32 value);
|
||||
u8 fatPutEOC(u32 cluster) {
|
||||
return fatPut(cluster, 0x0FFFFFFF);
|
||||
}
|
||||
u8 chainSize(u32 beginCluster, u32* size) const;
|
||||
u8 freeChain(u32 cluster);
|
||||
u8 isEOC(u32 cluster) const {
|
||||
return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
|
||||
}
|
||||
u8 readData(u32 block, u16 offset, u16 count, u8* dst);
|
||||
u8 writeBlock(u32 block, const u8* dst);
|
||||
|
||||
};
|
||||
|
||||
class EmuFat
|
||||
{
|
||||
public:
|
||||
EmuFat(const char* fname, bool readonly=false);
|
||||
EmuFat();
|
||||
EmuFat(EMUFILE* fileNotToDelete);
|
||||
virtual ~EmuFat();
|
||||
|
||||
private:
|
||||
EMUFILE* m_pFile;
|
||||
bool m_readonly, m_owns;
|
||||
|
||||
friend class EmuFatVolume;
|
||||
friend class EmuFatFile;
|
||||
|
||||
// value for action argument in cacheRawBlock to indicate read from cache
|
||||
static const u8 CACHE_FOR_READ = 0;
|
||||
// value for action argument in cacheRawBlock to indicate cache dirty
|
||||
static const u8 CACHE_FOR_WRITE = 1;
|
||||
|
||||
struct Cache
|
||||
{
|
||||
Cache()
|
||||
: cacheBlockNumber_(0xFFFFFFFF)
|
||||
, cacheDirty_(0) // cacheFlush() will write block if true
|
||||
, cacheMirrorBlock_(0) // mirror block for second FAT
|
||||
{}
|
||||
|
||||
cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
u32 cacheBlockNumber_; // Logical number of block in the cache
|
||||
u8 cacheDirty_; // cacheFlush() will write block if true
|
||||
u32 cacheMirrorBlock_; // block number for mirror FAT
|
||||
} cache_;
|
||||
|
||||
u8 cacheRawBlock(u32 blockNumber, u8 action);
|
||||
void cacheSetDirty() {cache_.cacheDirty_ |= CACHE_FOR_WRITE;}
|
||||
u8 cacheZeroBlock(u32 blockNumber);
|
||||
u8 cacheFlush();
|
||||
|
||||
//IO functions:
|
||||
u8 readBlock(u32 block, u8* dst);
|
||||
u8 writeBlock(u32 blockNumber, const u8* src);
|
||||
u8 readData(u32 block, u16 offset, u16 count, u8* dst);
|
||||
|
||||
void truncate(u32 size);
|
||||
};
|
||||
|
||||
#endif //EMUFAT_H
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef EMUFAT_TYPES_H
|
||||
#define EMUFAT_TYPES_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#endif //EMUFAT_TYPES_H
|
|
@ -1,4 +1,3 @@
|
|||
#include "types.h"
|
||||
#include "emufile.h"
|
||||
|
||||
#include <vector>
|
||||
|
@ -11,4 +10,18 @@ bool EMUFILE::readAllBytes(std::vector<u8>* dstbuf, const std::string& fname)
|
|||
dstbuf->resize(size);
|
||||
file.fread(&dstbuf->at(0),size);
|
||||
return true;
|
||||
}
|
||||
|
||||
EMUFILE* EMUFILE::memwrap(EMUFILE* fp)
|
||||
{
|
||||
EMUFILE_FILE* file;
|
||||
EMUFILE_MEMORY* mem;
|
||||
file = dynamic_cast<EMUFILE_FILE*>(fp);
|
||||
mem = dynamic_cast<EMUFILE_MEMORY*>(fp);
|
||||
if(mem) return mem;
|
||||
mem = new EMUFILE_MEMORY(file->size());
|
||||
if(file->size()==0) return mem;
|
||||
file->fread(mem->buf(),file->size());
|
||||
delete file;
|
||||
return mem;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2009 DeSmuME team
|
||||
/* Copyright (C) 2009-2010 DeSmuME team
|
||||
*
|
||||
* This file is part of DeSmuME
|
||||
*
|
||||
|
@ -17,18 +17,25 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//don't use emufile for files bigger than 2GB! you have been warned! some day this will be fixed.
|
||||
|
||||
#ifndef EMUFILE_H
|
||||
#define EMUFILE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "types.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef _XBOX
|
||||
#undef min;
|
||||
#undef max;
|
||||
|
@ -43,11 +50,16 @@ public:
|
|||
: failbit(false)
|
||||
{}
|
||||
|
||||
|
||||
//takes control of the provided EMUFILE and returns a new EMUFILE which is guranteed to be in memory
|
||||
static EMUFILE* memwrap(EMUFILE* fp);
|
||||
|
||||
virtual ~EMUFILE() {}
|
||||
|
||||
static bool readAllBytes(std::vector<u8>* buf, const std::string& fname);
|
||||
|
||||
bool fail() { return failbit; }
|
||||
bool fail(bool unset=false) { bool ret = failbit; if(unset) unfail(); return ret; }
|
||||
void unfail() { failbit=false; }
|
||||
|
||||
bool eof() { return size()==ftell(); }
|
||||
|
||||
|
@ -78,6 +90,8 @@ public:
|
|||
|
||||
virtual int ftell() = 0;
|
||||
virtual int size() = 0;
|
||||
|
||||
virtual void truncate(s32 length) = 0;
|
||||
};
|
||||
|
||||
//todo - handle read-only specially?
|
||||
|
@ -94,14 +108,29 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
EMUFILE_MEMORY(std::vector<u8> *underlying) : vec(underlying), ownvec(false), pos(0), len(underlying->size()) { }
|
||||
EMUFILE_MEMORY(u32 preallocate) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) { vec->reserve(preallocate); }
|
||||
EMUFILE_MEMORY(std::vector<u8> *underlying) : vec(underlying), ownvec(false), pos(0), len((s32)underlying->size()) { }
|
||||
EMUFILE_MEMORY(u32 preallocate) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) {
|
||||
vec->resize(preallocate);
|
||||
len = preallocate;
|
||||
}
|
||||
EMUFILE_MEMORY() : vec(new std::vector<u8>()), ownvec(true), pos(0), len(0) { vec->reserve(1024); }
|
||||
EMUFILE_MEMORY(void* buf, s32 size) : vec(new std::vector<u8>()), ownvec(true), pos(0), len(size) {
|
||||
vec->resize(size);
|
||||
if(size != 0)
|
||||
memcpy(&vec[0],buf,size);
|
||||
}
|
||||
|
||||
~EMUFILE_MEMORY() {
|
||||
if(ownvec) delete vec;
|
||||
}
|
||||
|
||||
virtual void truncate(s32 length)
|
||||
{
|
||||
vec->resize(length);
|
||||
len = length;
|
||||
if(pos>length) pos=length;
|
||||
}
|
||||
|
||||
u8* buf() { return &(*vec)[0]; }
|
||||
|
||||
std::vector<u8>* get_vec() { return vec; };
|
||||
|
@ -124,9 +153,19 @@ public:
|
|||
|
||||
virtual int fgetc() {
|
||||
u8 temp;
|
||||
if(_fread(&temp,1) != 1)
|
||||
return EOF;
|
||||
else return temp;
|
||||
|
||||
//need an optimized codepath
|
||||
//if(_fread(&temp,1) != 1)
|
||||
// return EOF;
|
||||
//else return temp;
|
||||
u32 remain = len-pos;
|
||||
if(remain<1) {
|
||||
failbit = true;
|
||||
return -1;
|
||||
}
|
||||
temp = buf()[pos];
|
||||
pos++;
|
||||
return temp;
|
||||
}
|
||||
virtual int fputc(int c) {
|
||||
u8 temp = (u8)c;
|
||||
|
@ -151,9 +190,9 @@ public:
|
|||
//they handle the return values correctly
|
||||
|
||||
virtual void fwrite(const void *ptr, size_t bytes){
|
||||
reserve(pos+bytes);
|
||||
reserve(pos+(s32)bytes);
|
||||
memcpy(buf()+pos,ptr,bytes);
|
||||
pos += bytes;
|
||||
pos += (s32)bytes;
|
||||
len = std::max(pos,len);
|
||||
}
|
||||
|
||||
|
@ -180,6 +219,11 @@ public:
|
|||
return pos;
|
||||
}
|
||||
|
||||
void trim()
|
||||
{
|
||||
vec->resize(len);
|
||||
}
|
||||
|
||||
virtual int size() { return (int)len; }
|
||||
};
|
||||
|
||||
|
@ -187,14 +231,18 @@ class EMUFILE_FILE : public EMUFILE {
|
|||
protected:
|
||||
FILE* fp;
|
||||
|
||||
public:
|
||||
|
||||
EMUFILE_FILE(const char* fname, const char* mode)
|
||||
private:
|
||||
void open(const char* fname, const char* mode)
|
||||
{
|
||||
fp = fopen(fname,mode);
|
||||
if(!fp)
|
||||
failbit = true;
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
EMUFILE_FILE(const std::string& fname, const char* mode) { open(fname.c_str(),mode); }
|
||||
EMUFILE_FILE(const char* fname, const char* mode) { open(fname,mode); }
|
||||
|
||||
virtual ~EMUFILE_FILE() {
|
||||
if(NULL != fp)
|
||||
|
@ -205,6 +253,17 @@ public:
|
|||
return fp;
|
||||
}
|
||||
|
||||
bool is_open() { return fp != NULL; }
|
||||
|
||||
virtual void truncate(s32 length)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
_chsize(_fileno(fp),length);
|
||||
#else
|
||||
ftruncate(fileno(fp),length);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual int fprintf(const char *format, ...) {
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
/* Copyright (C) 2006 Guillaume Duhamel
|
||||
|
||||
This file is part of DeSmuME
|
||||
This file is part of DeSmuME
|
||||
|
||||
DeSmuME is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
DeSmuME is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
DeSmuME is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
DeSmuME is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with DeSmuME; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef FS_H
|
||||
|
@ -33,7 +33,7 @@ typedef struct {
|
|||
char cFileName[256];
|
||||
char cAlternateFileName[14];
|
||||
u32 flags;
|
||||
u32 fileSize;
|
||||
u32 fileSize;
|
||||
} FsEntry;
|
||||
|
||||
void * FsReadFirst(const char * path, FsEntry * entry);
|
||||
|
|
|
@ -1842,6 +1842,18 @@
|
|||
RelativePath="..\driver.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufat.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufat.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufat_types.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufile.cpp"
|
||||
>
|
||||
|
|
|
@ -228,6 +228,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalOptions="/MP"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
|
@ -710,6 +711,18 @@
|
|||
RelativePath="..\driver.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufat.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufat.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufat_types.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\emufile.cpp"
|
||||
>
|
||||
|
|
|
@ -445,6 +445,7 @@
|
|||
<ClCompile Include="..\debug.cpp" />
|
||||
<ClCompile Include="..\Disassembler.cpp" />
|
||||
<ClCompile Include="..\driver.cpp" />
|
||||
<ClCompile Include="..\emufat.cpp" />
|
||||
<ClCompile Include="..\emufile.cpp" />
|
||||
<ClCompile Include="..\FIFO.cpp" />
|
||||
<ClCompile Include="..\firmware.cpp" />
|
||||
|
@ -559,6 +560,8 @@
|
|||
<ClInclude Include="..\debug.h" />
|
||||
<ClInclude Include="..\Disassembler.h" />
|
||||
<ClInclude Include="..\driver.h" />
|
||||
<ClInclude Include="..\emufat.h" />
|
||||
<ClInclude Include="..\emufat_types.h" />
|
||||
<ClInclude Include="..\emufile.h" />
|
||||
<ClInclude Include="..\fat.h" />
|
||||
<ClInclude Include="..\FIFO.h" />
|
||||
|
|
|
@ -396,6 +396,9 @@
|
|||
<ClCompile Include="..\addons\slot1_retail.cpp">
|
||||
<Filter>Core\addons</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\emufat.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\addons.h">
|
||||
|
@ -728,6 +731,10 @@
|
|||
<ClInclude Include="filter\hq2x.h" />
|
||||
<ClInclude Include="filter\interp.h" />
|
||||
<ClInclude Include="filter\lq2x.h" />
|
||||
<ClInclude Include="..\emufat.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\emufat_types.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\instruction_tabdef.inc">
|
||||
|
|
Loading…
Reference in New Issue