Files
commandergenius/src/fileio/CPatcher.cpp
2009-07-24 15:53:49 +00:00

185 lines
3.6 KiB
C++

/*
* CPatcher.cpp
*
* Created on: 19.07.2009
* Author: gerstrong
*/
#include "CPatcher.h"
#include <dirent.h>
#include <string.h>
#include <fstream>
#include "../FindFile.h"
CPatcher::CPatcher(int episode, int version,unsigned char *data, const std::string& datadir) {
m_episode = episode;
m_version = version;
m_data = data;
m_datadirectory = datadir;
if(m_datadirectory != "") m_datadirectory += "/";
}
CPatcher::~CPatcher() {
while(!m_TextList.empty())
{
delete *(m_TextList.begin());
m_TextList.pop_front();
}
}
void CPatcher::patchMemory()
{
if(!loadPatchfile()) return;
// If the file was found and read into the m_TextList,
// then read out of the list the patch commands and apply them to the
// Exe-file data m_data
// change to the proper directory
chdir("data");
chdir(m_datadirectory.c_str());
// TODO: Extend this part further with more commands
while(!m_TextList.empty())
{
char line[256];
strcpy(line,*(m_TextList.begin()));
if(strncmp(line,"\%version",strlen("\%version")) == 0)
{
char *verstring;
char detected_version[5];
verstring = line + strlen("\%version");
sscanf(verstring,"%s",detected_version);
if((!strcmp(detected_version,"1.31") && m_version == 131 )
|| (!strcmp(detected_version,"1.1") && m_version == 110 )
|| !strcmp(detected_version,"ALL"))
{
while(!m_TextList.empty())
{
// Get the next line
strcpy(line,*(m_TextList.begin()));
// Now we really start to process the commands
if( strncmp(line,"\%patchfile",strlen("\%patchfile")) == 0 )
{
unsigned long offset;
char *newbuf;
char patch_file_name[256];
newbuf = line + strlen("\%patchfile");
sscanf(newbuf,"%lx %s",&offset,patch_file_name); // Only hexadecimal numbers supported
patchMemfromFile((const char*)patch_file_name,offset);
}
if(!m_TextList.empty())
{
delete *(m_TextList.begin());
m_TextList.pop_front();
}
}
}
}
if(!m_TextList.empty())
{
delete *(m_TextList.begin());
m_TextList.pop_front();
}
}
// change back to "data" dir
char curdir[256];
while(1)
{
char *reldir;
getcwd(curdir,256);
reldir = curdir+strlen(curdir)-strlen("data");
if(strcmp(reldir,"data"))
chdir("..");
else
break;
}
chdir("..");
}
bool CPatcher::loadPatchfile()
{
bool ret = false;
chdir("data");
chdir(m_datadirectory.c_str());
// Detect the patchfile
DIR *dir = opendir(".");
struct dirent *dp;
if(dir)
{
while( ( dp = readdir(dir) ) )
{
if(strstr(dp->d_name,".pat"))
{
// The file was found! now read it into the memory!
char* buf;
std::ifstream Patchfile; OpenGameFileR(Patchfile, dp->d_name);
while(!Patchfile.eof())
{
buf = new char[256];
Patchfile.getline(buf,256);
m_TextList.push_back(buf);
}
Patchfile.close();
ret = true;
break;
}
}
}
char curdir[256];
while(1)
{
char *reldir;
getcwd(curdir,256);
reldir = curdir+strlen(curdir)-strlen("data");
if(strcmp(reldir,"data"))
chdir("..");
else
break;
}
chdir("..");
closedir(dir);
return ret;
}
void CPatcher::patchMemfromFile(const std::string& patch_file_name, int offset)
{
unsigned char *buf_to_patch;
unsigned char byte;
std::ifstream Patchfile; OpenGameFileR(Patchfile, patch_file_name, std::ios::binary);
if(!Patchfile) return;
buf_to_patch = m_data + offset;
// TODO: Add a routine which checks the sizes of the file.
long counter = 0;
while(!Patchfile.eof())
{
byte = (unsigned char) Patchfile.get();
memcpy(buf_to_patch+counter,&byte,1); // one byte every time ;-)
counter++;
}
Patchfile.close();
}