Redline/source/fileio.cpp

358 lines
8.4 KiB
C++
Raw Normal View History

//fileio.h
//Utilities for reading and writing to files in the game's subdirectories
//fileio works by creating a table of all files within the applications directory
//at startup. this way all files we need can be addressed simply using reference numbers.
//sometimes also refered to as "ID numbers".
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "fileio.h"
#include "platform.h"
#include "gamemem.h"
#include "error.h"
#include "parser.h"
int gFileTableSize; //size of the file reference table
int gFileTableExtendedSize;
int gFileTampered=false;
tFileTableEntry *gFileTable; //the file reference table
char gNoName[]="";
void FileInitFileTable(tFileTableEntry *fileTable,int maxSize,int *fileTableSize,int reInit);
#define kNumValidateFiles 42
char gValidateNames[][256]={
"500gt.car",
"500gthotrod.car",
"959.car",
"maserati.car",
"bmw2002.car",
"charger.car",
"chargerdragdrag.car",
"corvette.car",
"diablo.car",
"dmc12.car",
"dmc12flying.car",
"gt40.car",
"gti.car",
"mini.car",
"55ford.car",
"tt.car",
"ttpimp.car",
"viper.car",
"viperracer.car",
"accelbrake.mapinfo",
"accelbrake2.mapinfo",
"canyon.mapinfo",
"canyoncorner.mapinfo",
"city2.mapinfo",
"citycorner.mapinfo",
"downhill.mapinfo",
"highspeed.mapinfo",
"highspeedtrial.mapinfo",
"mountainside.mapinfo",
"offroad.mapinfo",
"quarter.mapinfo",
"ralley2.mapinfo",
"scorner.mapinfo",
"slalom.mapinfo",
"slalom2.mapinfo",
"snow.mapinfo",
"snowtrial.mapinfo",
"tight.mapinfo",
"canyon.road",
"city2.road",
"mountainside.road",
"ralley2.road",
"snow.road",
};
int gValidateChecksums[]={
0xc98d7f36,
0x833e4a7d,
0xdcd7e89,
0x3e6a08b7,
0x251efab,
0xed2a6577,
0x6d654b5,
0x1c468570,
0x1380a984,
0x7c69956,
0xcc2746e4,
0x22349629,
0x8d0d50b4,
0x51994161,
0x90a4cc85,
0x931cbd6c,
0xe42301b9,
0xcc9bd572,
0x1b7951e7,
0x72d87975,
0x1eb05d11,
0xa2182ab9,
0xde1122e6,
0xc44b1aab,
0x815cb099,
0x8eb6b530,
0x6c93ce2,
0x77263bb7,
0x18ebbbad,
0xc57f8785,
0x117ba80c,
0xb513b806,
0x75938236,
0x2437d140,
0xb249c233,
0x6e92dc33,
0x9e5c31de,
0x8766b155,
0x1bbdc55d,
0x28f6a9b8,
0x66e5492e,
0x8b5a55d8,
};
//Initialize file reference table
void FileInitIO()
{
gFileTableExtendedSize=0;
gFileTableSize=0;
gFileTable=(tFileTableEntry*)calloc(kMaxFiles,sizeof(tFileTableEntry));
FileInitFileTable(gFileTable,kMaxFiles,&gFileTableSize,false);
for(int i=0;i<kNumValidateFiles;i++)
{
if(FileGetChecksum(FileGetReference(gValidateNames[i]))!=gValidateChecksums[i])
{
gFileTampered=true;
printf("Bad File! %s. Found Checksum %x. Need Checksum %x.\n",FileGetName(FileGetReference(gValidateNames[i])),
FileGetChecksum(FileGetReference(gValidateNames[i])),gValidateChecksums[i]);
}
//printf("0x%x,\n",FileGetChecksum(FileGetReference(gValidateNames[i])));
}
}
void FileRescanDirectory()
{
int totalSize=gFileTableSize+gFileTableExtendedSize;
FileInitFileTable(gFileTable,kMaxFiles,&totalSize,true);
gFileTableExtendedSize=totalSize-gFileTableSize;
printf("ex:%d\n",gFileTableExtendedSize);
}
void FileReleaseData(tFileRef reference)
{
if(gFileTable[reference].loaded)
{
MemoryFreeBlock(gFileTable[reference].data);
gFileTable[reference].loaded=false;
}
}
//Compare two File Table entries for sorting and searching
int FileTableCompare(const void *a,const void *b)
{
return _stricmp(((tFileTableEntry*)a)->name,((tFileTableEntry*)b)->name);
}
int gFileErrorReporting=true;
//Search file reference table for a file matching a name and return its reference number
tFileRef FileGetReference(char *name)
{
if(*name=='\0')
return -1;
//the key to search for
tFileTableEntry key;
#ifndef __TARGET_TEXTURECOMPRESSOR
#ifndef __TARGET_TOOLAPP
snprintf(key.name,32,"%s.txr",name);
//search for an entry matching our search key
tFileTableEntry *result=(tFileTableEntry*)bsearch(&key,gFileTable,gFileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
//return results
if(result)
return result-gFileTable;
else
{
snprintf(key.name,32,"%s.ima",name);
//search for an entry matching our search key
tFileTableEntry *result=(tFileTableEntry*)bsearch(&key,gFileTable,gFileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
//return results
if(result)
return result-gFileTable;
else
{
#endif
#endif
strcpy(key.name,name);
tFileTableEntry *result=(tFileTableEntry*)bsearch(&key,gFileTable,gFileTableSize,sizeof(tFileTableEntry),&FileTableCompare);
if(result)
return result-gFileTable;
else
{
for(int i=gFileTableSize;i<gFileTableSize+gFileTableExtendedSize;i++)
if(_stricmp(gFileTable[i].name,name)==0)
return i;
if(gFileErrorReporting)
{
//or give an error message
PrintConsoleString("File not found!: %s\n",name);
}
return -1;
}
#ifndef __TARGET_TEXTURECOMPRESSOR
#ifndef __TARGET_TOOLAPP
}
}
#endif
#endif
}
tFileRef FileGetIndexedReference(tFileRef base,int i)
{
if(i>0)
{
char nameCopy[kMaxFileNameLength];
strcpy(nameCopy,FileGetName(base));
char *found=strchr(nameCopy,'.');
char indexedName[kMaxFileNameLength];
if(found)
{
*found='\0';
sprintf(indexedName,"%s#%x.%s",nameCopy,i,found+1);
}
else
sprintf(indexedName,"%s#%x",nameCopy,i);
int seek=base-1;
while(_stricmp(gFileTable[seek].name,indexedName)>0&&seek>0)
seek--;
if(_stricmp(gFileTable[seek].name,indexedName))
return base;
else
return seek;
}
else
return base;
}
tFileRef FileGetBaseReference(tFileRef ref)
{
if(ref<0||ref>=gFileTableExtendedSize+gFileTableSize)
return kFileErr;
char *found=strchr(FileGetName(ref),'.');
if(!found)
return ref;
char *cross=found;
while(*cross!='#'&&cross>FileGetName(ref))
cross--;
if(*cross!='#')
return ref;
int l=cross-FileGetName(ref);
char nameCopy[kMaxFileNameLength];
memcpy(nameCopy,FileGetName(ref),l);
strcpy(nameCopy+l,found);
tFileRef base=FileGetReference(nameCopy);
return base!=kFileErr?base:ref;
}
//platform specific, can be found in macfileio.cpp
int FileLoadData(tFileRef fileRef);
void FileStoreData(tFileRef fileRef);
//return the extension of a file given it's reference number
char *FileGetExtension(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return NULL;
char *found=NULL;
char *dot=gFileTable[reference].name;
do{
dot=strchr(dot,'.');
if(dot){
found=dot;
dot++;
}
}while(dot);
if(found)
return found;
else
return gFileTable[reference].name+strlen(gFileTable[reference].name);//'\0';
}
//return the name of a file given it's reference number
char *FileGetName(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return gNoName;
return gFileTable[reference].name;
}
//return the size of a file given it's reference number
int FileGetSize(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return 0;
if(!gFileTable[reference].loaded)
gFileTable[reference].loaded=FileLoadData(reference);
return gFileTable[reference].size;
}
//return a pointer to the file's data (and load the file if necessary)
void *FileGetDataPtr(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return NULL;
if(!gFileTable[reference].loaded)
gFileTable[reference].loaded=FileLoadData(reference);
return gFileTable[reference].loaded?gFileTable[reference].data:(void*)0;
}
unsigned int FileGetChecksum(tFileRef reference)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return 0;
return MemoryChecksum(FileGetDataPtr(reference),FileGetSize(reference));
}
//Changes a file's contents to data, and writes the file to disk.
void FileSetData(tFileRef reference,void *data)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return;
if(gFileTable[reference].loaded&&data!=gFileTable[reference].data)
MemoryFreeBlock(gFileTable[reference].data);
gFileTable[reference].data=data;
gFileTable[reference].loaded=true;
gFileTable[reference].size=MemoryBlockSize(data);
FileStoreData(reference);
}
//parses a file's data using a file format parser
//and return a pointer to parsed data structure
void* FileGetParsedDataPtr(tFileRef reference, int parserType, int dataSize)
{
if(reference<0||reference>=gFileTableExtendedSize+gFileTableSize)
return NULL;
if(!gFileTable[reference].parsed)
{
gFileTable[reference].parsedData=MemoryAllocateZeroedBlock(dataSize);
ParseFile(reference,gFileTable[reference].parsedData,parserType);
gFileTable[reference].parsed=true;
}
return gFileTable[reference].parsedData;
}