Files
sfall/sfall/FileSystem.cpp
T
NovaRain 5cb3ca2a59 Removed queue9x and vector9x.
Disabled ComputeSprayMod by default.
Updated version number.
2016-11-07 10:16:57 +08:00

695 lines
14 KiB
C++

/*
* sfall
* Copyright (C) 2008, 2009, 2010 The sfall team
*
* This program 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 program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include "main.h"
#include "FalloutEngine.h"
#include "FileSystem.h"
extern void GetSavePath(char* buf, char* ftype);
struct fsFile {
char* data;
DWORD length;
char name[128];
DWORD wpos;
};
std::vector<fsFile> files;
static DWORD loadedtiles=0;
static DWORD retval;
static bool UsingFileSystem=false;
struct openFile {
DWORD pos;
fsFile* file;
openFile(fsFile* pFile) {
pos=0;
file=pFile;
}
};
struct sFile {
DWORD type;
openFile* file;
};
static void _stdcall xfclose(sFile* file) {
delete file->file;
delete file;
}
static void __declspec(naked) asm_xfclose(sFile* file) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push eax;
call xfclose;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfclose_;
}
}
static sFile* _stdcall xfopen(const char* path, const char* mode) {
for(DWORD i=0;i<files.size();i++) {
if(!_stricmp(path, files[i].name)) {
sFile* file=new sFile();
file->type=3;
file->file=new openFile(&files[i]);
return file;
}
}
return 0;
}
static __declspec(naked) sFile* asm_xfopen(const char* path, const char* mode) {
__asm {
pushad;
push edx;
push eax;
call xfopen;
test eax, eax;
jz end;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfopen_;
}
}
//db_fprintf calls xvfprintf, not xfprintf
static int _stdcall xvfprintf() {
return -1;
}
static __declspec(naked) int asm_xvfprintf(sFile* file, const char* format, void* vaargs) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
call xvfprintf;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xvfprintf_;
}
}
static int _stdcall xfgetc(sFile* file) {
if(file->file->pos>=file->file->file->length) return -1;
return file->file->file->data[file->file->pos++];
}
static __declspec(naked) int asm_xfgetc(sFile* file) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push eax;
call xfgetc;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfgetc_;
}
}
static char* _stdcall xfgets(char* buf, int max_count, sFile* file) {
if(file->file->pos>=file->file->file->length) return 0;
for(int i=0;i<max_count;i++) {
int c=xfgetc(file);
if(c==-1) {
buf[i]=0;
break;
} else {
buf[i]=(char)c;
if(!c) break;
}
}
return buf;
}
static __declspec(naked) char* asm_xfgets(char* buf, int max_count, sFile* file) {
__asm {
pushad;
mov ecx, [ebx];
cmp cl, 3;
jnz end;
push ebx;
push edx;
push eax;
call xfgets;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfgets_;
}
}
static int _stdcall xfputc(int c, sFile* file) {
return -1;
}
static __declspec(naked) int asm_xfputc(int c, sFile* file) {
__asm {
pushad;
mov ecx, [edx];
cmp cl, 3;
jnz end;
push edx;
push eax;
call xfputc;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfputc_;
}
}
static int _stdcall xfputs(const char* str, sFile* file) {
return -1;
}
static __declspec(naked) int asm_xfputs(const char* str, sFile* file) {
__asm {
pushad;
mov ecx, [edx];
cmp cl, 3;
jnz end;
push edx;
push eax;
call xfputs;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfputs_;
}
}
static int _stdcall xfungetc(int c, sFile* file) {
if(file->file->pos==0) return -1;
if(file->file->file->data[file->file->pos-1]!=c) return -1;
file->file->pos--;
return c;
}
static __declspec(naked) int asm_xfungetc(int c, sFile* file) {
__asm {
pushad;
mov ecx, [edx];
cmp cl, 3;
jnz end;
push edx;
push eax;
call xfungetc;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xungetc_;
}
}
static int _stdcall xfread(void* buf, int elsize, int count, sFile* file) {
for(int i=0;i<count;i++) {
if(file->file->pos+elsize>=file->file->file->length) return i;
memcpy(buf, &file->file->file->data[file->file->pos], elsize);
file->file->pos+=elsize;
}
return count;
}
static __declspec(naked) int asm_xfread(void* buf, int elsize, int count, sFile* file) {
__asm {
pushad;
mov edi, [ecx];
cmp di, 3;
jnz end;
push ecx;
push ebx;
push edx;
push eax;
call xfread;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfread_;
}
}
static int _stdcall xfwrite(const void* buf, int elsize, int count, sFile* file) {
return 0;
}
static __declspec(naked) int asm_xfwrite(const void* buf, int elsize, int count, sFile* file) {
__asm {
pushad;
mov edi, [ecx];
cmp di, 3;
jnz end;
push ecx;
push ebx;
push edx;
push eax;
call xfwrite;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfwrite_;
}
}
static int _stdcall xfseek(sFile* file, long pos, int origin) {
switch(origin) {
case 1:
file->file->pos+=pos;
break;
case 2:
file->file->pos=file->file->file->length+pos;
break;
case 0:
file->file->pos=pos;
break;
}
return 0;
}
static __declspec(naked) int asm_xfseek(sFile* file, long pos, int origin) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push ebx;
push edx;
push eax;
call xfseek;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfseek_;
}
}
static long _stdcall xftell(sFile* file) {
return file->file->pos;
}
static __declspec(naked) long asm_xftell(sFile* file) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push eax;
call xftell;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xftell_;
}
}
static void _stdcall xfrewind(sFile* file) {
file->file->pos=0;
}
static __declspec(naked) void asm_xfrewind(sFile* file) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push eax;
call xfrewind;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xrewind_;
}
}
static int _stdcall xfeof(sFile* file) {
if(file->file->pos>=file->file->file->length) return 1;
else return 0;
}
static __declspec(naked) int asm_xfeof(sFile* file) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push eax;
call xfeof;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfeof_;
}
}
static int _stdcall xfilelength(sFile* file) {
return file->file->file->length;
}
static __declspec(naked) int asm_xfilelength(sFile* file) {
__asm {
pushad;
mov ecx, [eax];
cmp cl, 3;
jnz end;
push eax;
call xfilelength;
mov retval, eax;
popad;
mov eax, retval;
retn;
end:
popad;
jmp xfilelength_;
}
}
void FileSystemReset() {
if(!UsingFileSystem) return;
for(DWORD i=loadedtiles;i<files.size();i++) {
if(files[i].data) delete[] files[i].data;
}
if(!loadedtiles) files.clear();
else {
for(DWORD i=files.size()-1;i>=loadedtiles;i--) files.erase(files.begin() + i);
}
}
void FileSystemSave(HANDLE h) {
DWORD count=0, unused;
if(!UsingFileSystem) {
WriteFile(h, &count, 4, &unused, 0);
return;
}
for(DWORD i=0;i<files.size();i++) {
if(files[i].data) count++;
}
WriteFile(h, &count, 4, &unused, 0);
for(DWORD i=0;i<files.size();i++) {
if(files[i].data) {
WriteFile(h, &files[i].length, 128+8, &unused, 0);
WriteFile(h, files[i].data, files[i].length, &unused, 0);
}
}
}
static void FileSystemLoad() {
FileSystemReset();
char buf[MAX_PATH];
GetSavePath(buf, "fs");
HANDLE h=CreateFileA(buf, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if(h!=INVALID_HANDLE_VALUE) {
DWORD count, read;
ReadFile(h, &count, 4, &read, 0);
if(read==4) {
for(DWORD i=0;i<count;i++) {
fsFile file;
ReadFile(h, &file.length, 128+8, &read, 0);
file.data=new char[file.length];
ReadFile(h, file.data, file.length, &read, 0);
if(UsingFileSystem) files.push_back(file);
}
}
CloseHandle(h);
}
}
static const DWORD LoadHookRetAddr=0x47CCEE;
static void __declspec(naked) FSLoadHook() {
__asm {
pushad;
call FileSystemLoad;
popad;
mov esi, 1;
jmp LoadHookRetAddr;
}
}
void FileSystemInit() {
UsingFileSystem=true;
MakeCall(0x47CCE2, &FSLoadHook, true);
HookCall(0x4C5DBD, &asm_xfclose);
HookCall(0x4C5EA5, &asm_xfclose);
HookCall(0x4C5EB4, &asm_xfclose);
HookCall(0x4C5DA9, &asm_xfopen);
HookCall(0x4C5E16, &asm_xfopen);
HookCall(0x4C5EC8, &asm_xfopen);
HookCall(0x4C5F04, &asm_xvfprintf);
HookCall(0x4C5F31, &asm_xfgetc);
HookCall(0x4C5F64, &asm_xfgetc);
HookCall(0x4C5F85, &asm_xfgets);
HookCall(0x4C5FD3, &asm_xfgets);
HookCall(0x4C5FE4, &asm_xfputc);
HookCall(0x4C61B5, &asm_xfputc);
HookCall(0x4C61E2, &asm_xfputc);
HookCall(0x4C61FE, &asm_xfputc);
HookCall(0x4C6479, &asm_xfputc);
HookCall(0x4C64B3, &asm_xfputc);
HookCall(0x4C64D2, &asm_xfputc);
HookCall(0x4C5FEC, &asm_xfputs);
HookCall(0x4C5FF4, &asm_xfungetc);
HookCall(0x4C5E5C, &asm_xfread);
HookCall(0x4C5E8A, &asm_xfread);
HookCall(0x4C5E9E, &asm_xfread);
HookCall(0x4C603D, &asm_xfread);
HookCall(0x4C6076, &asm_xfread);
HookCall(0x4C60AA, &asm_xfread);
HookCall(0x4C6162, &asm_xfread);
HookCall(0x4C60B8, &asm_xfwrite);
HookCall(0x4C60C0, &asm_xfseek);
HookCall(0x4C60C8, &asm_xftell);
HookCall(0x4C60D0, &asm_xfrewind);
HookCall(0x4C60D8, &asm_xfeof);
HookCall(0x4C5DB4, &asm_xfilelength);
HookCall(0x4C5E2D, &asm_xfilelength);
HookCall(0x4C68BC, &asm_xfilelength);
}
DWORD _stdcall FScreate(const char* path, int size) {
for(DWORD i=0;i<files.size();i++) {
if(!files[i].data) {
files[i].data=new char[size];
strcpy_s(files[i].name, path);
files[i].length=size;
files[i].wpos=0;
return i;
}
}
fsFile file;
file.data=new char[size];
strcpy_s(file.name, path);
file.length=size;
file.wpos=0;
files.push_back(file);
return files.size()-1;
}
DWORD _stdcall FScreateFromData(const char* path, void* data, int size) {
loadedtiles++;
fsFile file;
file.data=new char[size];
memcpy(file.data, data, size);
strcpy_s(file.name, path);
file.length=size;
file.wpos=0;
files.push_back(file);
return files.size()-1;
}
DWORD _stdcall FScopy(const char* path, const char* source) {
int result=FSfind(path);
if(result!=-1) return result;
DWORD fsize;
sFile* file;
const char* mode="r";
__asm {
mov eax, source;
mov edx, mode;
call xfopen_;
mov file, eax;
}
if(!file) return -1;
__asm {
mov eax, file;
call xfilelength_;
mov fsize, eax;
}
char* fdata=new char[fsize];
__asm {
mov eax, file;
call xfclose_;
mov eax, source;
mov edx, fdata;
call db_read_to_buf_;
}
fsFile* fsfile=0;
for(DWORD i=0;i<files.size();i++) {
if(!files[i].data) { result=i; fsfile=&files[i]; break; }
}
if(!fsfile) {
files.push_back(fsFile());
result=files.size()-1;
fsfile=&files[result];
}
fsfile->data=fdata;
strcpy_s(fsfile->name, path);
fsfile->length=fsize;
fsfile->wpos=0;
return result;
}
DWORD _stdcall FSfind(const char* path) {
if(!*path) return -1;
for(DWORD i=0;i<files.size();i++) {
if(!_stricmp(files[i].name, path)) return i;
}
return -1;
}
void _stdcall FSwrite_byte(DWORD id, int data) {
if(id>=files.size()||!files[id].data) return;
if(files[id].wpos+1>files[id].length) return;
files[id].data[files[id].wpos++]=(char)data;
}
void _stdcall FSwrite_short(DWORD id, int data) {
if(id>=files.size()||!files[id].data) return;
if(files[id].wpos+2>files[id].length) return;
char data2[2];
memcpy(data2, &data, 2);
char c=data2[0];
data2[0]=data2[1];
data2[1]=c;
for(int i=0;i<2;i++) files[id].data[files[id].wpos++]=data2[i];
}
void _stdcall FSwrite_int(DWORD id, int data) {
if(id>=files.size()||!files[id].data) return;
if(files[id].wpos+4>files[id].length) return;
char data2[4];
memcpy(data2, &data, 4);
char c=data2[1];
data2[1]=data2[2];
data2[2]=c;
c=data2[0];
data2[0]=data2[3];
data2[3]=c;
for(int i=0;i<4;i++) files[id].data[files[id].wpos++]=data2[i];
}
void _stdcall FSwrite_string(DWORD id, const char* data) {
if(id>=files.size()||!files[id].data) return;
if(files[id].wpos+strlen(data)+1>files[id].length) return;
memcpy(&files[id].data[files[id].wpos], data, strlen(data)+1);
files[id].wpos+=strlen(data)+1;
}
void _stdcall FSwrite_bstring(DWORD id, const char* data) {
if(id>=files.size()||!files[id].data) return;
if(files[id].wpos+strlen(data)>files[id].length) return;
memcpy(&files[id].data[files[id].wpos], data, strlen(data));
files[id].wpos+=strlen(data);
}
int _stdcall FSread_byte(DWORD id) {
if(id>=files.size()||!files[id].data) return 0;
if(files[id].wpos+1>files[id].length) return 0;
return files[id].data[files[id].wpos++];
}
int _stdcall FSread_short(DWORD id) {
if(id>=files.size()||!files[id].data) return 0;
if(files[id].wpos+2>files[id].length) return 0;
char data[2];
data[1]=files[id].data[files[id].wpos++];
data[0]=files[id].data[files[id].wpos++];
short result;
memcpy(&result, data, 2);
return result;
}
int _stdcall FSread_int(DWORD id) {
if(id>=files.size()||!files[id].data) return 0;
if(files[id].wpos+4>files[id].length) return 0;
char data[4];
data[3]=files[id].data[files[id].wpos++];
data[2]=files[id].data[files[id].wpos++];
data[1]=files[id].data[files[id].wpos++];
data[0]=files[id].data[files[id].wpos++];
int result;
memcpy(&result, data, 4);
return result;
}
void _stdcall FSdelete(DWORD id) {
if(id>=files.size()||!files[id].data) return;
files[id].length=0;
files[id].wpos=0;
files[id].name[0]=0;
delete[] files[id].data;
files[id].data=0;
}
DWORD _stdcall FSsize(DWORD id) {
if(id>=files.size()||!files[id].data) return 0;
return files[id].length;
}
DWORD _stdcall FSpos(DWORD id) {
if(id>=files.size()||!files[id].data) return 0;
return files[id].wpos;
}
void _stdcall FSseek(DWORD id, DWORD pos) {
if(id>=files.size()||!files[id].data) return;
if(pos>files[id].length) return;
files[id].wpos=pos;
}
void _stdcall FSresize(DWORD id, DWORD size) {
if(id>=files.size()||!files[id].data) return;
char* buf=files[id].data;
files[id].data=new char[size];
CopyMemory(files[id].data, buf, min(files[id].length, size));
files[id].length=size;
files[id].wpos=0;
delete[] buf;
}