564 lines
14 KiB
C++
564 lines
14 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(const 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(const 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() const
|
|
{
|
|
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 () const
|
|
{
|
|
return base;
|
|
}
|
|
|
|
|
|
void memory_info::setBase (const string &s)
|
|
{
|
|
base = strtol(s.c_str(), NULL, 16);
|
|
}
|
|
|
|
|
|
void memory_info::setBase (const uint32_t b)
|
|
{
|
|
base = b;
|
|
}
|
|
|
|
|
|
void memory_info::setOffset (const string & key, const string & value)
|
|
{
|
|
uint32_t offset = strtol(value.c_str(), NULL, 16);
|
|
offsets[key] = offset;
|
|
}
|
|
|
|
|
|
void memory_info::setAddress (const string & key, const string & value)
|
|
{
|
|
uint32_t address = strtol(value.c_str(), NULL, 16);
|
|
addresses[key] = address;
|
|
}
|
|
|
|
|
|
void memory_info::setHexValue (const string & key, const string & value)
|
|
{
|
|
uint32_t hexval = strtol(value.c_str(), NULL, 16);
|
|
hexvals[key] = hexval;
|
|
}
|
|
|
|
|
|
void memory_info::setString (const string & key, const string & value)
|
|
{
|
|
strings[key] = value;
|
|
}
|
|
|
|
void memory_info::setLabor(const string & key, const string & value)
|
|
{
|
|
uint32_t keyInt = strtol(key.c_str(), NULL, 10);
|
|
labors[keyInt] = value;
|
|
}
|
|
|
|
void memory_info::setProfession (const string & key, const 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 (const string & key, const 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 (const string & key, const 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(const string & key,
|
|
const string & value,
|
|
const string & zero,
|
|
const string & one,
|
|
const string & two,
|
|
const string & three,
|
|
const string & four,
|
|
const 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 = g_pProcess->readDWord(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 = g_pProcess->readWord(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::getClassIDMapping(vector<string> & v_ClassID2ObjName)
|
|
{
|
|
for(uint32_t i = 0;i< classes.size();i++)
|
|
{
|
|
v_ClassID2ObjName.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_ClassID2ObjName.push_back(vec[k].classname);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// change base of all addresses
|
|
void memory_info::RebaseAddresses(const 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 (const char *key)
|
|
{
|
|
map <string, uint32_t>::iterator iter = addresses.find(key);
|
|
|
|
if(iter != addresses.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Get named offset
|
|
uint32_t memory_info::getOffset (const char *key)
|
|
{
|
|
map <string, uint32_t>::iterator iter = offsets.find(key);
|
|
if(iter != offsets.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Get named numerical value
|
|
uint32_t memory_info::getHexValue (const char *key)
|
|
{
|
|
map <string, uint32_t>::iterator iter = hexvals.find(key);
|
|
if(iter != hexvals.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Get named address
|
|
uint32_t memory_info::getAddress (const string &key)
|
|
{
|
|
map <string, uint32_t>::iterator iter = addresses.find(key);
|
|
|
|
if(iter != addresses.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Get named offset
|
|
uint32_t memory_info::getOffset (const string &key)
|
|
{
|
|
map <string, uint32_t>::iterator iter = offsets.find(key);
|
|
if(iter != offsets.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Get named numerical value
|
|
uint32_t memory_info::getHexValue (const string &key)
|
|
{
|
|
map <string, uint32_t>::iterator iter = hexvals.find(key);
|
|
if(iter != hexvals.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Get named string
|
|
std::string memory_info::getString (const string &key)
|
|
{
|
|
map <string, string>::iterator iter = strings.find(key);
|
|
if(iter != strings.end())
|
|
{
|
|
return (*iter).second;
|
|
}
|
|
return string("");
|
|
}
|
|
|
|
// Get Profession
|
|
string memory_info::getProfession (const uint32_t key) const
|
|
{
|
|
if(professions.size() > key)
|
|
{
|
|
return professions[key];
|
|
}
|
|
else
|
|
{
|
|
return string("");
|
|
}
|
|
}
|
|
|
|
// Get Job
|
|
string memory_info::getJob (const uint32_t key) const
|
|
{
|
|
if(jobs.size() > key)
|
|
{
|
|
return jobs[key];
|
|
}
|
|
return string("Job Does Not Exist");
|
|
}
|
|
|
|
string memory_info::getSkill (const uint32_t key) const
|
|
{
|
|
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 (const uint32_t traitIdx, const uint32_t traitValue) const
|
|
{
|
|
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(const uint32_t traitIdx) const
|
|
{
|
|
if(traits.size() > traitIdx)
|
|
{
|
|
return traits[traitIdx][traits[traitIdx].size()-1];
|
|
}
|
|
return string("Trait is not Defined");
|
|
}
|
|
|
|
string memory_info::getLabor (const 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;
|
|
}
|