dfhack/library/DFMemInfo.cpp

516 lines
12 KiB
C++

/*
www.sourceforge.net/projects/dfhack
Copyright (c) 2009 Petr Mrázek (peterix), Kenneth Ferland (Impaler[WrG]), dorf
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include "DFCommonInternal.h"
using namespace DFHack;
memory_info::memory_info()
{
base = 0;
classindex = 0;
}
void memory_info::setVersion(const char * v)
{
version = v;
}
void memory_info::setVersion(string v)
{
version = v;
}
string memory_info::getVersion()
{
return version;
}
void memory_info::setOS(const char *os)
{
string oss = os;
if(oss == "windows")
OS = OS_WINDOWS;
else if(oss == "linux")
OS = OS_LINUX;
else
OS = OS_BAD;
}
void memory_info::setOS(string os)
{
if(os == "windows")
OS = OS_WINDOWS;
else if(os == "linux")
OS = OS_LINUX;
else
OS = OS_BAD;
}
void memory_info::setOS(OSType os)
{
if(os >= OS_WINDOWS && os < OS_BAD)
{
OS = os;
return;
}
OS = OS_BAD;
}
memory_info::OSType memory_info::getOS()
{
return OS;
}
// copy constructor
memory_info::memory_info(const memory_info &old)
{
version = old.version;
OS = old.OS;
addresses = old.addresses;
offsets = old.offsets;
hexvals = old.hexvals;
strings = old.strings;
base = old.base;
classes = old.classes;
classsubtypes = old.classsubtypes;
classindex = old.classindex;
professions = old.professions;
jobs = old.jobs;
skills = old.skills;
traits = old.traits;
labors = old.labors;
}
uint32_t memory_info::getBase ()
{
return base;
}
void memory_info::setBase (string s)
{
base = strtol(s.c_str(), NULL, 16);
}
void memory_info::setBase (uint32_t b)
{
base = b;
}
void memory_info::setOffset (string key, string value)
{
uint32_t offset = strtol(value.c_str(), NULL, 16);
offsets[key] = offset;
}
void memory_info::setAddress (string key, string value)
{
uint32_t address = strtol(value.c_str(), NULL, 16);
addresses[key] = address;
}
void memory_info::setHexValue (string key, string value)
{
uint32_t hexval = strtol(value.c_str(), NULL, 16);
hexvals[key] = hexval;
}
void memory_info::setString (string key, string value)
{
strings[key] = value;
}
void memory_info::setLabor(string key, string value)
{
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
labors[keyInt] = value;
}
void memory_info::setProfession (string key, string value)
{
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
if(professions.size() <= keyInt)
{
professions.resize(keyInt+1);
}
professions[keyInt] = value;
}
void memory_info::setJob (string key, string value)
{
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
if(jobs.size() <= keyInt)
{
jobs.resize(keyInt+1);
}
jobs[keyInt] = value;
}
void memory_info::setSkill (string key, string value)
{
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
if(skills.size() <= keyInt){
skills.resize(keyInt+1);
}
skills[keyInt] = value;
}
void memory_info::setTrait(string key,string value,string zero,string one,string two,string three,string four,string five)
{
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
if(traits.size() <= keyInt)
{
traits.resize(keyInt+1);
}
traits[keyInt].push_back(zero);
traits[keyInt].push_back(one);
traits[keyInt].push_back(two);
traits[keyInt].push_back(three);
traits[keyInt].push_back(four);
traits[keyInt].push_back(five);
traits[keyInt].push_back(value);
}
// FIXME: next three methods should use some kind of custom container so it doesn't have to search so much.
void memory_info::setClass (const char * name, const char * vtable)
{
for (uint32_t i=0; i<classes.size(); i++)
{
if(classes[i].classname == name)
{
classes[i].vtable = strtol(vtable, NULL, 16);
return;
}
}
t_class cls;
cls.assign = classindex;
cls.classname = name;
cls.is_multiclass = false;
cls.type_offset = 0;
classindex++;
cls.vtable = strtol(vtable, NULL, 16);
classes.push_back(cls);
//cout << "class " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl;
}
// find old entry by name, rewrite, return its multi index. otherwise make a new one, append an empty vector of t_type to classtypes, return its index.
uint32_t memory_info::setMultiClass (const char * name, const char * vtable, const char * typeoffset)
{
for (uint32_t i=0; i<classes.size(); i++)
{
if(classes[i].classname == name)
{
// vtable and typeoffset can be left out from the xml definition when there's already a named multiclass
if(vtable != NULL)
classes[i].vtable = strtol(vtable, NULL, 16);
if(typeoffset != NULL)
classes[i].type_offset = strtol(typeoffset, NULL, 16);
return classes[i].multi_index;
}
}
//FIXME: add checking for vtable and typeoffset here. they HAVE to be valid. maybe change the return value into a bool and pass in multi index by reference?
t_class cls;
cls.assign = classindex;
cls.classname = name;
cls.is_multiclass = true;
cls.type_offset = strtol(typeoffset, NULL, 16);
cls.vtable = strtol(vtable, NULL, 16);
cls.multi_index = classsubtypes.size();
classes.push_back(cls);
classindex++;
vector<t_type> thistypes;
classsubtypes.push_back(thistypes);
//cout << "multiclass " << name << ", assign " << cls.assign << ", vtable " << cls.vtable << endl;
return classsubtypes.size() - 1;
}
void memory_info::setMultiClassChild (uint32_t multi_index, const char * name, const char * type)
{
vector <t_type>& vec = classsubtypes[multi_index];
for (uint32_t i=0; i<vec.size(); i++)
{
if(vec[i].classname == name)
{
vec[i].type = strtol(type, NULL, 16);
return;
}
}
// new multiclass child
t_type mcc;
mcc.assign = classindex;
mcc.classname = name;
mcc.type = strtol(type, NULL, 16);
vec.push_back(mcc);
classindex++;
//cout << " classtype " << name << ", assign " << mcc.assign << ", vtable " << mcc.type << endl;
}
bool memory_info::resolveClassId(uint32_t address, int32_t & classid)
{
uint32_t vtable = MreadDWord(address);
// FIXME: stupid search. we need a better container
for(uint32_t i = 0;i< classes.size();i++)
{
if(classes[i].vtable == vtable) // got class
{
// if it is a multiclass, try resolving it
if(classes[i].is_multiclass)
{
vector <t_type>& vec = classsubtypes[classes[i].multi_index];
uint32_t type = MreadWord(address + classes[i].type_offset);
//printf ("class %d:%s offset 0x%x\n", i , classes[i].classname.c_str(), classes[i].type_offset);
// return typed building if successful
for (uint32_t k = 0; k < vec.size();k++)
{
if(vec[k].type == type)
{
//cout << " multi " << address + classes[i].type_offset << " " << vec[k].classname << endl;
classid = vec[k].assign;
return true;
}
}
}
// otherwise return the class we found
classid = classes[i].assign;
return true;
}
}
// we failed to find anything that would match
return false;
}
// Flatten vtables into a index<->name mapping
void memory_info::copyBuildings(vector<string> & v_buildingtypes)
{
for(uint32_t i = 0;i< classes.size();i++)
{
v_buildingtypes.push_back(classes[i].classname);
if(!classes[i].is_multiclass)
{
continue;
}
vector <t_type>& vec = classsubtypes[classes[i].multi_index];
for (uint32_t k = 0; k < vec.size();k++)
{
v_buildingtypes.push_back(vec[k].classname);
}
}
}
// change base of all addresses
void memory_info::RebaseAddresses(int32_t new_base)
{
map<string, uint32_t>::iterator iter;
int32_t rebase = - (int32_t)base + new_base;
for(iter = addresses.begin(); iter != addresses.end(); iter++)
{
addresses[iter->first] = iter->second + rebase;
}
}
// change base of all addresses *and* vtable entries
void memory_info::RebaseAll(int32_t new_base)
{
map<string, uint32_t>::iterator iter;
int32_t rebase = - (int32_t)base + new_base;
for(iter = addresses.begin(); iter != addresses.end(); iter++)
{
addresses[iter->first] = iter->second + rebase;
}
RebaseVTable(rebase);
}
// change all vtable entries by offset
void memory_info::RebaseVTable(int32_t offset)
{
vector<t_class>::iterator iter;
for(iter = classes.begin(); iter != classes.end(); iter++)
{
iter->vtable += offset;
}
}
// Get named address
uint32_t memory_info::getAddress (string key)
{
if(addresses.count(key))
{
return addresses[key];
}
return 0;
}
// Get named offset
uint32_t memory_info::getOffset (string key)
{
if(offsets.count(key))
{
return offsets[key];
}
return 0;
}
// Get named string
std::string memory_info::getString (string key)
{
if(strings.count(key))
{
return strings[key];
}
else return string("");
}
// Get named numerical value
uint32_t memory_info::getHexValue (string key)
{
if(hexvals.count(key))
{
return hexvals[key];
}
return 0;
}
// Get Profession
string memory_info::getProfession (uint32_t key)
{
if(professions.size() > key)
{
return professions[key];
}
else{
return string("");
}
}
// Get Job
string memory_info::getJob (uint32_t key)
{
if(jobs.size() > key){
return jobs[key];
}
return string("Job Does Not Exist");
}
string memory_info::getSkill (uint32_t key)
{
if(skills.size() > key){
return skills[key];
}
return string("Skill is not Defined");
}
// FIXME: ugly hack that needs to die
int absolute (int number)
{
if (number < 0)
return -number;
return number;
}
string memory_info::getTrait (uint32_t traitIdx, uint32_t traitValue)
{
if(traits.size() > traitIdx)
{
int diff = absolute(traitValue-50);
if(diff < 10)
{
return string("");
}
if (traitValue >= 91)
return traits[traitIdx][5];
else if (traitValue >= 76)
return traits[traitIdx][4];
else if (traitValue >= 61)
return traits[traitIdx][3];
else if (traitValue >= 25)
return traits[traitIdx][2];
else if (traitValue >= 10)
return traits[traitIdx][1];
else
return traits[traitIdx][0];
}
return string("Trait is not Defined");
}
string memory_info::getTraitName(uint32_t traitIdx)
{
if(traits.size() > traitIdx)
{
return traits[traitIdx][traits[traitIdx].size()-1];
}
return string("Trait is not Defined");
}
string memory_info::getLabor (uint32_t laborIdx)
{
if(labors.count(laborIdx))
{
return labors[laborIdx];
}
return string("");
}
// Reset everything
void memory_info::flush()
{
base = 0;
addresses.clear();
offsets.clear();
strings.clear();
hexvals.clear();
classes.clear();
classsubtypes.clear();
classindex = 0;
version = "";
OS = OS_BAD;
}